From 7c1740ddcaf28d30408f350ff61f32067168c7ab Mon Sep 17 00:00:00 2001 From: dahall Date: Thu, 7 Oct 2021 10:29:13 -0600 Subject: [PATCH] Code cleanup of SecurityBaseApi.cs and addition of generic GetTokenInformation overload. --- PInvoke/Security/AdvApi32/SecurityBaseApi.cs | 248 +++++++++++++++------------ 1 file changed, 142 insertions(+), 106 deletions(-) diff --git a/PInvoke/Security/AdvApi32/SecurityBaseApi.cs b/PInvoke/Security/AdvApi32/SecurityBaseApi.cs index 2f884004..655ef4e8 100644 --- a/PInvoke/Security/AdvApi32/SecurityBaseApi.cs +++ b/PInvoke/Security/AdvApi32/SecurityBaseApi.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Linq; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Security.AccessControl; @@ -14,7 +13,7 @@ namespace Vanara.PInvoke { public static partial class AdvApi32 { - private static readonly Dictionary StructSizes = new Dictionary(); + private static readonly Dictionary StructSizes = new(); /// Specifies the logon provider. public enum LogonUserProvider @@ -3975,12 +3974,8 @@ namespace Vanara.PInvoke public static T GetAclInformation(this PACL pAcl) where T : struct { if (!CorrespondingTypeAttribute.CanGet(out var c)) throw new ArgumentException("Cannot retrieve value of type T."); - using (var mem = new SafeCoTaskMemHandle(12)) - { - if (!GetAclInformation(pAcl, mem, (uint)Marshal.SizeOf(typeof(T)), c)) - throw new Win32Exception(); - return mem.ToStructure(); - } + using var mem = new SafeCoTaskMemHandle(12); + return GetAclInformation(pAcl, mem, (uint)Marshal.SizeOf(typeof(T)), c) ? mem.ToStructure() : throw new Win32Exception(); } /// The GetKernelObjectSecurity function retrieves a copy of the security descriptor that protects a kernel object. @@ -4315,44 +4310,107 @@ namespace Vanara.PInvoke [MarshalAs(UnmanagedType.Bool)] out bool lpbSaclDefaulted); /// - /// The GetTokenInformation function retrieves a specified type of information about an access token. The calling process must have - /// appropriate access rights to obtain the information. + /// + /// The GetTokenInformation function retrieves a specified type of information about an access token. The calling process + /// must have appropriate access rights to obtain the information. + /// + /// + /// To determine if a user is a member of a specific group, use the CheckTokenMembership function. To determine group membership for + /// app container tokens, use the CheckTokenMembershipEx function. + /// /// - /// + /// /// A handle to an access token from which information is retrieved. If TokenInformationClass specifies TokenSource, the handle must /// have TOKEN_QUERY_SOURCE access. For all other TokenInformationClass values, the handle must have TOKEN_QUERY access. /// - /// + /// /// Specifies a value from the TOKEN_INFORMATION_CLASS enumerated type to identify the type of information the function retrieves. - /// Any callers who check the TokenIsAppContainer and have it return 0 should also verify that the caller token is not an identify - /// level impersonation token. If the current token is not an application container but is an identity level token, you should return AccessDenied. + /// Any callers who check the TokenIsAppContainer and have it return 0 should also verify that the caller token is not an + /// identify level impersonation token. If the current token is not an app container but is an identity level token, you should + /// return AccessDenied. /// - /// - /// A pointer to a buffer the function fills with the requested information. The structure put into this buffer depends upon the type - /// of information specified by the TokenInformationClass parameter. + /// + /// A pointer to a buffer the function fills with the requested information. The structure put into this buffer depends upon the + /// type of information specified by the TokenInformationClass parameter. /// - /// - /// Specifies the size, in bytes, of the buffer pointed to by the TokenInformation parameter. If TokenInformation is NULL, this - /// parameter must be zero. + /// + /// Specifies the size, in bytes, of the buffer pointed to by the TokenInformation parameter. If TokenInformation is NULL, + /// this parameter must be zero. /// - /// + /// + /// /// A pointer to a variable that receives the number of bytes needed for the buffer pointed to by the TokenInformation parameter. If /// this value is larger than the value specified in the TokenInformationLength parameter, the function fails and stores no data in /// the buffer. + /// /// /// If the value of the TokenInformationClass parameter is TokenDefaultDacl and the token has no default DACL, the function sets the - /// variable pointed to by ReturnLength to sizeof(TOKEN_DEFAULT_DACL) and sets the DefaultDacl member of the TOKEN_DEFAULT_DACL - /// structure to NULL. + /// variable pointed to by ReturnLength to + /// sizeof( + /// TOKEN_DEFAULT_DACL + /// ) + /// and sets the DefaultDacl member of the TOKEN_DEFAULT_DACL structure to NULL. /// /// /// - /// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error - /// information, call GetLastError. + /// If the function succeeds, the return value is nonzero. + /// If the function fails, the return value is zero. To get extended error information, call GetLastError. /// + // https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-gettokeninformation + // BOOL GetTokenInformation( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength, PDWORD ReturnLength ); [DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] - [PInvokeData("securitybaseapi.h", MSDNShortId = "aa446671")] - public static extern bool GetTokenInformation(HTOKEN hObject, TOKEN_INFORMATION_CLASS tokenInfoClass, IntPtr pTokenInfo, int tokenInfoLength, out int returnLength); + [PInvokeData("securitybaseapi.h", MSDNShortId = "NF:securitybaseapi.GetTokenInformation")] + public static extern bool GetTokenInformation(HTOKEN TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, int TokenInformationLength, out int ReturnLength); + + /// + /// + /// The GetTokenInformation function retrieves a specified type of information about an access token. The calling process + /// must have appropriate access rights to obtain the information. + /// + /// + /// To determine if a user is a member of a specific group, use the CheckTokenMembership function. To determine group membership for + /// app container tokens, use the CheckTokenMembershipEx function. + /// + /// + /// The type of the structure to retrive. + /// + /// A handle to an access token from which information is retrieved. If TokenInformationClass specifies TokenSource, the handle must + /// have TOKEN_QUERY_SOURCE access. For all other TokenInformationClass values, the handle must have TOKEN_QUERY access. + /// + /// + /// Specifies a value from the TOKEN_INFORMATION_CLASS enumerated type to identify the type of information the function retrieves. + /// Any callers who check the TokenIsAppContainer and have it return 0 should also verify that the caller token is not an + /// identity level impersonation token. If the current token is not an app container but is an identity level token, you should + /// return AccessDenied. + /// + /// If this value is , the value returned will be the first member of TOKEN_INFORMATION_CLASS that + /// returns the type specified in . + /// + /// + /// The requested information. + /// + // https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-gettokeninformation + // BOOL GetTokenInformation( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength, PDWORD ReturnLength ); + [PInvokeData("securitybaseapi.h", MSDNShortId = "NF:securitybaseapi.GetTokenInformation")] + public static T GetTokenInformation(HTOKEN TokenHandle, TOKEN_INFORMATION_CLASS? TokenInformationClass = null) where T : struct + { + if (!CorrespondingTypeAttribute.CanGet(TokenInformationClass, out var ti)) + throw new InvalidCastException(); + + // Get information size + if (!GetTokenInformation(TokenHandle, ti, default, 0, out var cbSize)) + { + var e = Win32Error.GetLastError(); + if (e != Win32Error.ERROR_INSUFFICIENT_BUFFER && e != Win32Error.ERROR_BAD_LENGTH) + e.ThrowIfFailed(); + } + + // Retrieve token information. + using var pType = new SafeCoTaskMemStruct(cbSize); + Win32Error.ThrowLastErrorIfFalse(GetTokenInformation(TokenHandle, ti, pType, cbSize, out _)); + return pType.Value; + } /// /// The ImpersonateAnonymousToken function enables the specified thread to impersonate the system's anonymous logon token. To @@ -4655,22 +4713,18 @@ namespace Vanara.PInvoke [PInvokeData("securitybaseapi.h", MSDNShortId = "6ddec01f-237f-4b6a-8ea8-a126017b30c5")] public static bool InsertAccessAllowedAce(PACL pAcl, uint dwAceRevision, uint dwStartingAceIndex, AceFlags AceFlags, ACCESS_MASK AccessMask, PSID pSid) { - using (var aceMem = new SafeHeapBlock(GetRequiredAceSize(pSid, out var offset))) + using var aceMem = new SafeHeapBlock(GetRequiredAceSize(pSid, out var offset)); + // Build ACE + var ace = new ACCESS_ALLOWED_ACE { - // Build ACE - var ace = new ACCESS_ALLOWED_ACE - { - Header = new ACE_HEADER(AceType.AccessAllowed, AceFlags, aceMem.Size), - Mask = AccessMask - }; - Marshal.StructureToPtr(ace, aceMem, false); - if (!CopySid(pSid.Length(), ((IntPtr)aceMem).Offset(offset), pSid)) - return false; - // Insert - if (!AddAce(pAcl, dwAceRevision, dwStartingAceIndex, aceMem, aceMem.Size)) - return false; - return true; - } + Header = new ACE_HEADER(AceType.AccessAllowed, AceFlags, aceMem.Size), + Mask = AccessMask + }; + Marshal.StructureToPtr(ace, aceMem, false); + if (!CopySid(pSid.Length(), ((IntPtr)aceMem).Offset(offset), pSid)) + return false; + // Insert + return AddAce(pAcl, dwAceRevision, dwStartingAceIndex, aceMem, aceMem.Size); } /// @@ -4794,25 +4848,21 @@ namespace Vanara.PInvoke [PInvokeData("securitybaseapi.h", MSDNShortId = "ccf83e95-ba6f-49f5-a312-52eac90f209a")] public static bool InsertAccessAllowedObjectAce(PACL pAcl, uint dwAceRevision, uint dwStartingAceIndex, AceFlags AceFlags, ACCESS_MASK AccessMask, Guid? ObjectTypeGuid, Guid? InheritedObjectTypeGuid, PSID pSid) { - using (var aceMem = new SafeHeapBlock(GetRequiredAceSize(pSid, out var offset))) + using var aceMem = new SafeHeapBlock(GetRequiredAceSize(pSid, out var offset)); + // Build ACE + var ace = new ACCESS_ALLOWED_OBJECT_ACE { - // Build ACE - var ace = new ACCESS_ALLOWED_OBJECT_ACE - { - Header = new ACE_HEADER(AceType.AccessAllowedObject, AceFlags, aceMem.Size), - Mask = AccessMask, - Flags = (ObjectTypeGuid.HasValue ? ObjectAceFlags.ACE_OBJECT_TYPE_PRESENT : 0) | (InheritedObjectTypeGuid.HasValue ? ObjectAceFlags.ACE_INHERITED_OBJECT_TYPE_PRESENT : 0), - ObjectType = ObjectTypeGuid.GetValueOrDefault(), - InheritedObjectType = InheritedObjectTypeGuid.GetValueOrDefault(), - }; - Marshal.StructureToPtr(ace, aceMem, false); - if (!CopySid(pSid.Length(), ((IntPtr)aceMem).Offset(offset), pSid)) - return false; - // Insert - if (!AddAce(pAcl, dwAceRevision, dwStartingAceIndex, aceMem, aceMem.Size)) - return false; - return true; - } + Header = new ACE_HEADER(AceType.AccessAllowedObject, AceFlags, aceMem.Size), + Mask = AccessMask, + Flags = (ObjectTypeGuid.HasValue ? ObjectAceFlags.ACE_OBJECT_TYPE_PRESENT : 0) | (InheritedObjectTypeGuid.HasValue ? ObjectAceFlags.ACE_INHERITED_OBJECT_TYPE_PRESENT : 0), + ObjectType = ObjectTypeGuid.GetValueOrDefault(), + InheritedObjectType = InheritedObjectTypeGuid.GetValueOrDefault(), + }; + Marshal.StructureToPtr(ace, aceMem, false); + if (!CopySid(pSid.Length(), ((IntPtr)aceMem).Offset(offset), pSid)) + return false; + // Insert + return AddAce(pAcl, dwAceRevision, dwStartingAceIndex, aceMem, aceMem.Size); } /// @@ -4917,22 +4967,18 @@ namespace Vanara.PInvoke [PInvokeData("securitybaseapi.h", MSDNShortId = "e353c88c-f82e-40c0-b676-38f0060acc81")] public static bool InsertAccessDeniedAce(PACL pAcl, uint dwAceRevision, uint dwStartingAceIndex, AceFlags AceFlags, ACCESS_MASK AccessMask, PSID pSid) { - using (var aceMem = new SafeHeapBlock(GetRequiredAceSize(pSid, out var offset))) + using var aceMem = new SafeHeapBlock(GetRequiredAceSize(pSid, out var offset)); + // Build ACE + var ace = new ACCESS_DENIED_ACE { - // Build ACE - var ace = new ACCESS_DENIED_ACE - { - Header = new ACE_HEADER(AceType.AccessDenied, AceFlags, aceMem.Size), - Mask = AccessMask, - }; - Marshal.StructureToPtr(ace, aceMem, false); - if (!CopySid(pSid.Length(), ((IntPtr)aceMem).Offset(offset), pSid)) - return false; - // Insert - if (!AddAce(pAcl, dwAceRevision, dwStartingAceIndex, aceMem, aceMem.Size)) - return false; - return true; - } + Header = new ACE_HEADER(AceType.AccessDenied, AceFlags, aceMem.Size), + Mask = AccessMask, + }; + Marshal.StructureToPtr(ace, aceMem, false); + if (!CopySid(pSid.Length(), ((IntPtr)aceMem).Offset(offset), pSid)) + return false; + // Insert + return AddAce(pAcl, dwAceRevision, dwStartingAceIndex, aceMem, aceMem.Size); } /// @@ -5058,25 +5104,21 @@ namespace Vanara.PInvoke [PInvokeData("securitybaseapi.h", MSDNShortId = "1427c908-92b6-46b2-9189-a2fd93c470b1")] public static bool InsertAccessDeniedObjectAce(PACL pAcl, uint dwAceRevision, uint dwStartingAceIndex, AceFlags AceFlags, ACCESS_MASK AccessMask, Guid? ObjectTypeGuid, Guid? InheritedObjectTypeGuid, PSID pSid) { - using (var aceMem = new SafeHeapBlock(GetRequiredAceSize(pSid, out var offset))) + using var aceMem = new SafeHeapBlock(GetRequiredAceSize(pSid, out var offset)); + // Build ACE + var ace = new ACCESS_DENIED_OBJECT_ACE { - // Build ACE - var ace = new ACCESS_DENIED_OBJECT_ACE - { - Header = new ACE_HEADER(AceType.AccessDeniedObject, AceFlags, aceMem.Size), - Mask = AccessMask, - Flags = (ObjectTypeGuid.HasValue ? ObjectAceFlags.ACE_OBJECT_TYPE_PRESENT : 0) | (InheritedObjectTypeGuid.HasValue ? ObjectAceFlags.ACE_INHERITED_OBJECT_TYPE_PRESENT : 0), - ObjectType = ObjectTypeGuid.GetValueOrDefault(), - InheritedObjectType = InheritedObjectTypeGuid.GetValueOrDefault(), - }; - Marshal.StructureToPtr(ace, aceMem, false); - if (!CopySid(pSid.Length(), ((IntPtr)aceMem).Offset(offset), pSid)) - return false; - // Insert - if (!AddAce(pAcl, dwAceRevision, dwStartingAceIndex, aceMem, aceMem.Size)) - return false; - return true; - } + Header = new ACE_HEADER(AceType.AccessDeniedObject, AceFlags, aceMem.Size), + Mask = AccessMask, + Flags = (ObjectTypeGuid.HasValue ? ObjectAceFlags.ACE_OBJECT_TYPE_PRESENT : 0) | (InheritedObjectTypeGuid.HasValue ? ObjectAceFlags.ACE_INHERITED_OBJECT_TYPE_PRESENT : 0), + ObjectType = ObjectTypeGuid.GetValueOrDefault(), + InheritedObjectType = InheritedObjectTypeGuid.GetValueOrDefault(), + }; + Marshal.StructureToPtr(ace, aceMem, false); + if (!CopySid(pSid.Length(), ((IntPtr)aceMem).Offset(offset), pSid)) + return false; + // Insert + return AddAce(pAcl, dwAceRevision, dwStartingAceIndex, aceMem, aceMem.Size); } /// @@ -6083,8 +6125,8 @@ namespace Vanara.PInvoke public static bool SetTokenInformation(HTOKEN TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, T TokenInformation) { if (!CorrespondingTypeAttribute.CanSet(TokenInformationClass, typeof(T))) throw new InvalidCastException(); - using (var mem = SafeHGlobalHandle.CreateFromStructure(TokenInformation)) - return SetTokenInformation(TokenHandle, TokenInformationClass, mem, mem.Size); + using var mem = SafeHGlobalHandle.CreateFromStructure(TokenInformation); + return SetTokenInformation(TokenHandle, TokenInformationClass, mem, mem.Size); } internal static int GetSize() where T : struct @@ -6118,7 +6160,7 @@ namespace Vanara.PInvoke /// close the duplicate handle. /// /// - public static readonly SafeHTOKEN CurrentProcessToken = new SafeHTOKEN((IntPtr)4, false); + public static readonly SafeHTOKEN CurrentProcessToken = new((IntPtr)4, false); /// /// Retrieves a pseudo-handle that you can use as a shorthand way to refer to the token that is currently in effect for the @@ -6139,7 +6181,7 @@ namespace Vanara.PInvoke /// close the duplicate handle. /// /// - public static readonly SafeHTOKEN CurrentThreadEffectiveToken = new SafeHTOKEN((IntPtr)6, false); + public static readonly SafeHTOKEN CurrentThreadEffectiveToken = new((IntPtr)6, false); /// /// Retrieves a pseudo-handle that you can use as a shorthand way to refer to the impersonation token that was assigned to the @@ -6160,7 +6202,7 @@ namespace Vanara.PInvoke /// close the duplicate handle. /// /// - public static readonly SafeHTOKEN CurrentThreadToken = new SafeHTOKEN((IntPtr)5, false); + public static readonly SafeHTOKEN CurrentThreadToken = new((IntPtr)5, false); /// Initializes a new instance of the class and assigns an existing handle. /// An object that represents the pre-existing handle to use. @@ -6318,13 +6360,7 @@ namespace Vanara.PInvoke /// an identify level impersonation token. If the current token is not an application container but is an identity level token, /// you should return AccessDenied. /// - public T GetInfo(TOKEN_INFORMATION_CLASS? tokenInfoClass = null) - { - if (!CorrespondingTypeAttribute.CanGet(tokenInfoClass, out var ti)) - throw new InvalidCastException(); - using var pType = GetInfo(ti); - return ((IntPtr)pType).Convert(pType.Size); - } + public T GetInfo(TOKEN_INFORMATION_CLASS? tokenInfoClass = null) where T : struct => GetTokenInformation(this, tokenInfoClass); /// /// Retrieves a specified type of information about an access token. The calling process must have appropriate access rights to @@ -6349,7 +6385,7 @@ namespace Vanara.PInvoke // Retrieve token information. var pType = new SafeCoTaskMemHandle(cbSize); - if (!GetTokenInformation(this, tokenInfoClass, pType, cbSize, out cbSize)) + if (!GetTokenInformation(this, tokenInfoClass, pType, cbSize, out _)) Win32Error.ThrowLastError(); return pType;