diff --git a/PInvoke/Security/AdvApi32/WinNT.cs b/PInvoke/Security/AdvApi32/WinNT.cs
index 5dd5b477..6c4d409c 100644
--- a/PInvoke/Security/AdvApi32/WinNT.cs
+++ b/PInvoke/Security/AdvApi32/WinNT.cs
@@ -5,6 +5,7 @@ using System.Security.AccessControl;
using System.Text;
using Vanara.Extensions;
using Vanara.InteropServices;
+using static Vanara.PInvoke.Kernel32;
namespace Vanara.PInvoke
{
@@ -27,9 +28,11 @@ namespace Vanara.PInvoke
public enum ACL_INFORMATION_CLASS : uint
{
/// Indicates ACL revision information.
+ [CorrespondingType(typeof(ACL_REVISION_INFORMATION))]
AclRevisionInformation = 1,
/// Indicates ACL size information.
+ [CorrespondingType(typeof(ACL_SIZE_INFORMATION))]
AclSizeInformation
}
@@ -639,6 +642,19 @@ namespace Vanara.PInvoke
/// Returns a hash code for this instance.
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
public override int GetHashCode() => new { A = Header.AceFlags, B = Header.AceType, C = Mask }.GetHashCode();
+
+ /// Gets the SID value associated with .
+ /// A value copied from the bits associated with .
+ public SafePSID GetSid()
+ {
+ unsafe
+ {
+ fixed (int* psid = &SidStart)
+ {
+ return SafePSID.CreateFromPtr((IntPtr)(void*)psid);
+ }
+ }
+ }
}
/// The ACE_HEADER structure defines the type and size of an access control entry (ACE).
@@ -763,6 +779,290 @@ namespace Vanara.PInvoke
public CLAIM_SECURITY_ATTRIBUTE_INFORMATION_V1 Attribute;
}
+ ///
+ /// Contains information that is included immediately after the newest event log record.
+ ///
+ /// The ELF_EOF_RECORD structure is used in an event log to enable the event-logging service to reconstruct the
+ /// ELF_LOGFILE_HEADER. The event-logging service must add the ELF_EOF_RECORD to the event log. For more information
+ /// about ELF_EOF_RECORD, see Event Log File Format.
+ ///
+ ///
+ // typedef struct _EVENTLOGEOF { ULONG RecordSizeBeginning; ULONG One; ULONG Two; ULONG Three; ULONG Four; ULONG BeginRecord; ULONG
+ // EndRecord; ULONG CurrentRecordNumber; ULONG OldestRecordNumber; ULONG RecordSizeEnd;} EVENTLOGEOF, *PEVENTLOGEOF; https://msdn.microsoft.com/en-us/library/windows/desktop/bb309022(v=vs.85).aspx
+ [PInvokeData("Winnt.h", MSDNShortId = "bb309022")]
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ public struct EVENTLOGEOF
+ {
+ /// The beginning size of the ELF_EOF_RECORD. The beginning size is always 0x28.
+ public uint RecordSizeBeginning;
+
+ ///
+ /// An identifier that helps to differentiate this record from other records in the event log. The value is always set to 0x11111111.
+ ///
+ public uint One;
+
+ ///
+ /// An identifier that helps to differentiate this record from other records in the event log. The value is always set to 0x22222222.
+ ///
+ public uint Two;
+
+ ///
+ /// An identifier that helps to differentiate this record from other records in the event log. The value is always set to 0x33333333.
+ ///
+ public uint Three;
+
+ ///
+ /// An identifier that helps to differentiate this record from other records in the event log. The value is always set to 0x44444444.
+ ///
+ public uint Four;
+
+ /// The offset to the oldest record. If the event log is empty, this is set to the start of this structure.
+ public uint BeginRecord;
+
+ /// The offset to the start of this structure.
+ public uint EndRecord;
+
+ /// The record number of the next event that will be written to the event log.
+ public uint CurrentRecordNumber;
+
+ /// The record number of the oldest record in the event log. The record number will be 0 if the event log is empty.
+ public uint OldestRecordNumber;
+
+ /// The ending size of the ELF_EOF_RECORD. The ending size is always 0x28.
+ public uint RecordSizeEnd;
+ }
+
+ ///
+ /// Contains information that is included at the beginning of an event log.
+ ///
+ /// The ELF_LOGFILE_HEADER structure is used at the beginning of an event log to define information about the event log. The
+ /// event-logging service must add the ELF_LOGFILE_HEADER to the event log. For more information about how the
+ /// ELF_LOGFILE_HEADER is used, see Event Log File Format.
+ ///
+ ///
+ // typedef struct _EVENTLOGHEADER { ULONG HeaderSize; ULONG Signature; ULONG MajorVersion; ULONG MinorVersion; ULONG StartOffset;
+ // ULONG EndOffset; ULONG CurrentRecordNumber; ULONG OldestRecordNumber; ULONG MaxSize; ULONG Flags; ULONG Retention; ULONG
+ // EndHeaderSize;} EVENTLOGHEADER, *PEVENTLOGHEADER; https://msdn.microsoft.com/en-us/library/windows/desktop/bb309024(v=vs.85).aspx
+ [PInvokeData("Winnt.h", MSDNShortId = "bb309024")]
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ public struct EVENTLOGHEADER
+ {
+ /// The size of the header structure. The size is always 0x30.
+ public uint HeaderSize;
+
+ /// The signature is always 0x654c664c, which is ASCII for eLfL.
+ public uint Signature;
+
+ /// The major version number of the event log. The major version number is always set to 1.
+ public uint MajorVersion;
+
+ /// The minor version number of the event log. The minor version number is always set to 1.
+ public uint MinorVersion;
+
+ /// The offset to the oldest record in the event log.
+ public uint StartOffset;
+
+ /// The offset to the ELF_EOF_RECORD in the event log.
+ public uint EndOffset;
+
+ /// The number of the next record that will be added to the event log.
+ public uint CurrentRecordNumber;
+
+ /// The number of the oldest record in the event log. For an empty file, the oldest record number is set to 0.
+ public uint OldestRecordNumber;
+
+ ///
+ /// The maximum size, in bytes, of the event log. The maximum size is defined when the event log is created. The event-logging
+ /// service does not typically update this value, it relies on the registry configuration. The reader of the event log can use
+ /// normal file APIs to determine the size of the file. For more information about registry configuration values, see Eventlog Key.
+ ///
+ public uint MaxSize;
+
+ ///
+ /// The status of the event log. This member can be one of the following values:
+ ///
+ ///
+ ///
+ /// Value
+ /// Meaning
+ ///
+ /// -
+ /// ELF_LOGFILE_HEADER_DIRTY0x0001
+ ///
+ /// Indicates that records have been written to an event log, but the event log file has not been properly closed. For more
+ /// information about this flag, see the Remarks section.
+ ///
+ ///
+ /// -
+ /// ELF_LOGFILE_HEADER_WRAP0x0002
+ /// Indicates that records in the event log have wrapped.
+ ///
+ /// -
+ /// ELF_LOGFILE_LOGFULL_WRITTEN0x0004
+ /// Indicates that the most recent write attempt failed due to insufficient space.
+ ///
+ /// -
+ /// ELF_LOGFILE_ARCHIVE_SET0x0008
+ ///
+ /// Indicates that the archive attribute has been set for the file. Normal file APIs can also be used to determine the value of
+ /// this flag.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public ELF_FLAGS Flags;
+
+ ///
+ /// The retention value of the file when it is created. The event-logging service does not typically update this value, it relies
+ /// on the registry configuration. For more information about registry configuration values, see Eventlog Key.
+ ///
+ public uint Retention;
+
+ /// The ending size of the header structure. The size is always 0x30.
+ public uint EndHeaderSize;
+ }
+
+ /// Contains information about an event record returned by the ReadEventLog function.
+ ///
+ ///
+ /// The defined members are followed by the replacement strings for the message identified by the event identifier, the binary
+ /// information, some pad bytes to make sure the full entry is on a DWORD boundary, and finally the length of the log entry
+ /// again. Because the strings and the binary information can be of any length, no structure members are defined to reference them.
+ /// The declaration of this structure in Winnt.h describes these members as follows:
+ ///
+ ///
+ /// The source name is a variable-length string that specifies the name of the event source. The computer name is the name of the
+ /// computer that generated the event. It may be followed with some padding bytes so that the user SID is aligned on a DWORD
+ /// boundary. The user SID identifies the active user at the time this event was logged. If UserSidLength is zero, this field
+ /// may be empty.
+ ///
+ ///
+ /// The event identifier together with source name and a language identifier identify a string that describes the event in more
+ /// detail. The strings are used as replacement strings and are merged into the message string to make a complete message. The
+ /// message strings are contained in a message file specified in the source entry in the registry. To obtain the appropriate message
+ /// string from the message file, load the message file with the LoadLibrary function and use the FormatMessage function.
+ ///
+ ///
+ /// The binary information is information that is specific to the event. It could be the contents of the processor registers when a
+ /// device driver got an error, a dump of an invalid packet that was received from the network, a dump of all the structures in a
+ /// program (when the data area was detected to be corrupt), and so on. This information should be useful to the writer of the device
+ /// driver or the application in tracking down bugs or unauthorized breaks into the application.
+ ///
+ ///
+ // https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_eventlogrecord typedef struct _EVENTLOGRECORD { DWORD Length;
+ // DWORD Reserved; DWORD RecordNumber; DWORD TimeGenerated; DWORD TimeWritten; DWORD EventID; WORD EventType; WORD NumStrings; WORD
+ // EventCategory; WORD ReservedFlags; DWORD ClosingRecordNumber; DWORD StringOffset; DWORD UserSidLength; DWORD UserSidOffset; DWORD
+ // DataLength; DWORD DataOffset; } EVENTLOGRECORD, *PEVENTLOGRECORD;
+ [PInvokeData("winnt.h", MSDNShortId = "669b182a-bc81-4386-9815-6ffa09e2e743")]
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ public struct EVENTLOGRECORD
+ {
+ ///
+ /// The size of this event record, in bytes. Note that this value is stored at both ends of the entry to ease moving forward or
+ /// backward through the log. The length includes any pad bytes inserted at the end of the record for DWORD alignment.
+ ///
+ public uint Length;
+
+ /// A DWORD value that is always set to ELF_LOG_SIGNATURE (the value is 0x654c664c), which is ASCII for eLfL.
+ public uint Reserved;
+
+ ///
+ /// The number of the record. This value can be used with the EVENTLOG_SEEK_READ flag in the ReadEventLog function to begin
+ /// reading at a specified record. For more information, see Event Log Records.
+ ///
+ public uint RecordNumber;
+
+ ///
+ /// The time at which this entry was submitted. This time is measured in the number of seconds elapsed since 00:00:00 January 1,
+ /// 1970, Universal Coordinated Time.
+ ///
+ public uint TimeGenerated;
+
+ ///
+ /// The time at which this entry was received by the service to be written to the log. This time is measured in the number of
+ /// seconds elapsed since 00:00:00 January 1, 1970, Universal Coordinated Time.
+ ///
+ public uint TimeWritten;
+
+ ///
+ /// The event identifier. The value is specific to the event source for the event, and is used with source name to locate a
+ /// description string in the message file for the event source. For more information, see Event Identifiers.
+ ///
+ public uint EventID;
+
+ ///
+ /// The type of event. This member can be one of the following values.
+ ///
+ ///
+ /// Value
+ /// Meaning
+ ///
+ /// -
+ /// EVENTLOG_ERROR_TYPE 0x0001
+ /// Error event
+ ///
+ /// -
+ /// EVENTLOG_AUDIT_FAILURE 0x0010
+ /// Failure Audit event
+ ///
+ /// -
+ /// EVENTLOG_AUDIT_SUCCESS 0x0008
+ /// Success Audit event
+ ///
+ /// -
+ /// EVENTLOG_INFORMATION_TYPE 0x0004
+ /// Information event
+ ///
+ /// -
+ /// EVENTLOG_WARNING_TYPE 0x0002
+ /// Warning event
+ ///
+ ///
+ /// For more information, see Event Types.
+ ///
+ public ushort EventType;
+
+ ///
+ /// The number of strings present in the log (at the position indicated by StringOffset). These strings are merged into
+ /// the message before it is displayed to the user.
+ ///
+ public ushort NumStrings;
+
+ ///
+ /// The category for this event. The meaning of this value depends on the event source. For more information, see Event Categories.
+ ///
+ public ushort EventCategory;
+
+ /// Reserved.
+ public ushort ReservedFlags;
+
+ /// Reserved.
+ public uint ClosingRecordNumber;
+
+ /// The offset of the description strings within this event log record.
+ public uint StringOffset;
+
+ /// The size of the UserSid member, in bytes. This value can be zero if no security identifier was provided.
+ public uint UserSidLength;
+
+ ///
+ /// The offset of the security identifier (SID) within this event log record. To obtain the user name for this SID, use the
+ /// LookupAccountSid function.
+ ///
+ public uint UserSidOffset;
+
+ /// The size of the event-specific data (at the position indicated by DataOffset), in bytes.
+ public uint DataLength;
+
+ ///
+ /// The offset of the event-specific information within this event log record, in bytes. This information could be something
+ /// specific (a disk driver might log the number of retries, for example), followed by binary information specific to the event
+ /// being logged and to the source that generated the entry.
+ ///
+ public uint DataOffset;
+ }
+
///
/// Defines the mapping of generic access rights to specific and standard access rights for an object. When a client application
/// requests generic access to an object, that request is mapped to the access rights defined in this structure.
@@ -795,6 +1095,9 @@ namespace Vanara.PInvoke
GenericExecute = execute;
GenericAll = all;
}
+
+ /// The generic file mappings (FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_READ, FILE_ALL_ACCESS).
+ public static readonly GENERIC_MAPPING GenericFileMapping = new GENERIC_MAPPING((uint)FileAccess.FILE_GENERIC_READ, (uint)FileAccess.FILE_GENERIC_WRITE, (uint)FileAccess.FILE_GENERIC_READ, (uint)FileAccess.FILE_ALL_ACCESS);
}
///
@@ -1442,12 +1745,17 @@ namespace Vanara.PInvoke
/// Gets the size in bytes of this instance.
/// The size in bytes.
- public uint SizeInBytes => Marshaler.GetSize(PrivilegeCount);
+ public uint SizeInBytes => (uint)Marshal.SizeOf(typeof(uint)) * 2 + (uint)(Marshal.SizeOf(typeof(LUID_AND_ATTRIBUTES)) * (PrivilegeCount == 0 ? 1 : PrivilegeCount));
/// Returns a that represents this instance.
/// A that represents this instance.
public override string ToString() => $"Count:{PrivilegeCount}";
+ /// Initializes a new PRIVILEGE_SET the with capacity to hold the specified number of privileges.
+ /// The privilege count to allocate.
+ /// A PRIVILEGE_SET instance with sufficient capacity for marshaling.
+ public static PRIVILEGE_SET InitializeWithCapacity(int privilegeCount = 1) => new PRIVILEGE_SET() { PrivilegeCount = (uint)privilegeCount };
+
internal class Marshaler : ICustomMarshaler
{
public static ICustomMarshaler GetInstance(string cookie) => new Marshaler();
@@ -1462,9 +1770,10 @@ namespace Vanara.PInvoke
public IntPtr MarshalManagedToNative(object ManagedObj)
{
- if (!(ManagedObj is PRIVILEGE_SET)) return IntPtr.Zero;
- var ps = (PRIVILEGE_SET)ManagedObj;
- var ptr = Marshal.AllocCoTaskMem((int)GetSize(ps.PrivilegeCount));
+ if (!(ManagedObj is PRIVILEGE_SET ps)) return IntPtr.Zero;
+ var ptr = Marshal.AllocCoTaskMem((int)ps.SizeInBytes);
+ if (ps.Privilege?.Length != ps.PrivilegeCount)
+ ptr.FillMemory(0, (int)ps.SizeInBytes);
Marshal.WriteInt32(ptr, (int)ps.PrivilegeCount);
Marshal.WriteInt32(ptr, Marshal.SizeOf(typeof(int)), (int)ps.Control);
ps.Privilege.MarshalToPtr(ptr, Marshal.SizeOf(typeof(int)) * 2);
@@ -1480,8 +1789,6 @@ namespace Vanara.PInvoke
var privPtr = Marshal.ReadIntPtr(pNativeData, sz * 2);
return new PRIVILEGE_SET { PrivilegeCount = (uint)cnt, Control = ctrl, Privilege = cnt > 0 ? privPtr.ToIEnum(cnt).ToArray() : new LUID_AND_ATTRIBUTES[0] };
}
-
- internal static uint GetSize(uint privCount) => (uint)Marshal.SizeOf(typeof(uint)) * 2 + (uint)(Marshal.SizeOf(typeof(LUID_AND_ATTRIBUTES)) * (privCount == 0 ? 1 : privCount));
}
}
@@ -1694,22 +2001,26 @@ namespace Vanara.PInvoke
}
/// A SafeHandle for security descriptors. If owned, will call LocalFree on the pointer when disposed.
- public class SafeSecurityDescriptor : GenericSafeHandle
+ public class SafeSecurityDescriptor : SafeMemoryHandle, IEquatable, IEquatable, IEquatable, ISecurityObject
{
/// The null value for a SafeSecurityDescriptor.
public static readonly SafeSecurityDescriptor Null = new SafeSecurityDescriptor();
+ private const SECURITY_INFORMATION defSecInfo = SECURITY_INFORMATION.DACL_SECURITY_INFORMATION | SECURITY_INFORMATION.SACL_SECURITY_INFORMATION | SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION | SECURITY_INFORMATION.GROUP_SECURITY_INFORMATION;
+
/// Initializes a new instance of the class.
- public SafeSecurityDescriptor() : this(IntPtr.Zero) { }
+ public SafeSecurityDescriptor() : base(IntPtr.Zero, 0, false) { }
/// Initializes a new instance of the class from an existing pointer.
/// The security descriptor pointer.
/// if set to true indicates that this pointer should be freed when disposed.
- public SafeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor, bool own = true) : base((IntPtr)pSecurityDescriptor, h => { LocalMemoryMethods.Instance.FreeMem(h); return true; }, own) { }
+ public SafeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor, bool own = true) :
+ base((IntPtr)pSecurityDescriptor, (int)GetSecurityDescriptorLength(pSecurityDescriptor), own)
+ { }
/// Initializes a new instance of the class to an empty memory buffer.
/// The size of the uninitialized security descriptor.
- public SafeSecurityDescriptor(int size) : this(LocalMemoryMethods.Instance.AllocMem(size), true) { }
+ public SafeSecurityDescriptor(int size) : base(size) { }
/// Initializes a new instance of the class.
/// An array of bytes that contain an existing security descriptor.
@@ -1719,10 +2030,91 @@ namespace Vanara.PInvoke
Marshal.Copy(bytes, 0, handle, bytes.Length);
}
+ /// Initializes a new instance of the class with an SDDL string.
+ /// An SDDL value representing the security descriptor.
+ public SafeSecurityDescriptor(string sddl)
+ {
+ if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddl, SDDL_REVISION.SDDL_REVISION_1, out var sd, out var sdsz))
+ Win32Error.ThrowLastError();
+ handle = sd.DangerousGetHandle();
+ sz = (int)sdsz;
+ sd.SetHandleAsInvalid();
+ }
+
+ /// Determines whether the components of this security descriptor are valid.
+ public bool IsValidSecurityDescriptor => IsValidSecurityDescriptor(handle);
+
+ ///
+ /// Gets the length, in bytes, of a structurally valid security descriptor. The length includes the length of all associated structures.
+ ///
+ public uint Length => GetSecurityDescriptorLength(handle);
+
/// Performs an explicit conversion from to .
/// The safe security descriptor.
/// The result of the conversion.
public static implicit operator PSECURITY_DESCRIPTOR(SafeSecurityDescriptor sd) => sd.DangerousGetHandle();
+
+ /// Implements the operator !=.
+ /// The first value.
+ /// The second value.
+ /// The result of the operator.
+ public static bool operator !=(SafeSecurityDescriptor psd1, SafeSecurityDescriptor psd2) => !(psd1 == psd2);
+
+ /// Implements the operator ==.
+ /// The first value.
+ /// The second value.
+ /// The result of the operator.
+ public static bool operator ==(SafeSecurityDescriptor psd1, SafeSecurityDescriptor psd2)
+ {
+ if (ReferenceEquals(psd1, psd2)) return true;
+ if (Equals(null, psd1) || Equals(null, psd2)) return false;
+ return psd1.Equals(psd2);
+ }
+
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// An object to compare with this object.
+ /// true if the current object is equal to the parameter; otherwise, false.
+ public bool Equals(SafeSecurityDescriptor other) => Equals(other.DangerousGetHandle());
+
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// An object to compare with this object.
+ /// true if the current object is equal to the parameter; otherwise, false.
+ public bool Equals(PSECURITY_DESCRIPTOR other) => Equals(other.DangerousGetHandle());
+
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// An object to compare with this object.
+ /// true if the current object is equal to the parameter; otherwise, false.
+ public bool Equals(IntPtr other)
+ {
+ if (GetSecurityDescriptorLength(handle) != GetSecurityDescriptorLength(other)) return false;
+ var s1 = ConvertSecurityDescriptorToStringSecurityDescriptor(handle, defSecInfo);
+ var s2 = ConvertSecurityDescriptorToStringSecurityDescriptor(other, defSecInfo);
+ return string.CompareOrdinal(s1, s2) == 0;
+ }
+
+ /// Determines whether the specified is equal to the current .
+ /// The object to compare with the current object.
+ ///
+ /// true if the specified is equal to the current ; otherwise, false.
+ ///
+ public override bool Equals(object obj)
+ {
+ if (obj is SafeSecurityDescriptor psid2)
+ return Equals(psid2);
+ if (obj is PSECURITY_DESCRIPTOR psidh)
+ return Equals(psidh);
+ if (obj is IntPtr ptr)
+ return Equals(ptr);
+ return false;
+ }
+
+ /// Returns a hash code for this instance.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
+ public override int GetHashCode() => ToString().GetHashCode();
+
+ /// Returns a that represents this instance.
+ /// A that represents this instance.
+ public override string ToString() => ConvertSecurityDescriptorToStringSecurityDescriptor(handle, defSecInfo);
}
}
}
\ No newline at end of file