/// <summary> /// The function checks whether the object associated with the access token belongs /// to a user account that is a member of the local Administrators group, even if /// it currently is not elevated. /// </summary> /// <param name="userToken">The user token.</param> /// <returns> /// Returns true if the object associated with the access token belongs to user /// account that is a member of the local Administrators group. Returns false /// if the token does not. /// </returns> /// <exception cref="Win32Exception"> /// </exception> /// <exception cref="System.ComponentModel.Win32Exception">When any native Windows API call fails, the function throws a Win32Exception with the last error code.</exception> public static bool IsUserInAdminGroup(SafeTokenHandle userToken) { // Determine whether system is running Windows Vista or later operating // systems (major version >= 6) because they support linked tokens, but // previous versions (major version < 6) do not. var version = Environment.OSVersion.Version; if ((version != null) && (version.Major >= 6)) { // Running Windows Vista or later (major version >= 6). // Determine token type: limited, elevated, or default. // Allocate a buffer for the elevation type information. using var pElevationType = new SafeNativeMemory(sizeof(TOKEN_ELEVATION_TYPE)); // Retrieve token elevation type information. if (!NativeMethods.GetTokenInformation(userToken, TOKEN_INFORMATION_CLASS.TokenElevationType, pElevationType)) { throw new Win32Exception(); } // Marshal the TOKEN_ELEVATION_TYPE enum from native to .NET. var elevType = pElevationType.ReadInt32().ToEnum <TOKEN_ELEVATION_TYPE>(); // If limited, get the linked elevated token for further check. if (elevType == TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited) { // Allocate a buffer for the linked token. using var pLinkedToken = new SafeNativeMemory(IntPtr.Size); // Get the linked token. if (!NativeMethods.GetTokenInformation(userToken, TOKEN_INFORMATION_CLASS.TokenLinkedToken, pLinkedToken)) { throw new Win32Exception(); } // Marshal the linked token value from native to .NET. var hLinkedToken = pLinkedToken.ReadIntPtr(); using var linkedToken = new SafeTokenHandle(hLinkedToken); return(IsAdministrator(linkedToken)); } } // CheckTokenMembership requires an impersonation token. If we just got // a linked token, it already is an impersonation token. If we did not // get a linked token, duplicate the original into an impersonation // token for CheckTokenMembership. if (!NativeMethods.DuplicateToken(userToken, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, out var phTokenToCheck)) { throw new Win32Exception(); } using var hTokenToCheck = new SafeTokenHandle(phTokenToCheck); // Check if the token to be checked contains admin SID. return(IsAdministrator(hTokenToCheck)); }
/// <summary> /// The function checks whether the object associated with the access token belongs /// to a user account that is a member of the local Administrators group, even if /// it currently is not elevated. /// </summary> /// <param name="userToken">The user token.</param> /// <returns> /// Returns true if the object associated with the access token belongs to user /// account that is a member of the local Administrators group. Returns false /// if the token does not. /// </returns> /// <exception cref="Win32Exception"> /// </exception> /// <exception cref="System.ComponentModel.Win32Exception">When any native Windows API call fails, the function throws a Win32Exception with the last error code.</exception> public static bool IsUserInAdminGroup([NotNull] SafeTokenHandle userToken) { Contract.Requires(userToken != null); // Determine whether system is running Windows Vista or later operating // systems (major version >= 6) because they support linked tokens, but // previous versions (major version < 6) do not. var version = Environment.OSVersion.Version; if ((version != null) && (version.Major >= 6)) { // Running Windows Vista or later (major version >= 6). // Determine token type: limited, elevated, or default. // Allocate a buffer for the elevation type information. using (var pElevationType = new SafeNativeMemory(sizeof(TOKEN_ELEVATION_TYPE))) { // Retrieve token elevation type information. if (!NativeMethods.GetTokenInformation(userToken, TOKEN_INFORMATION_CLASS.TokenElevationType, pElevationType)) { throw new Win32Exception(); } // Marshal the TOKEN_ELEVATION_TYPE enum from native to .NET. var elevType = pElevationType.ReadInt32().ToEnum<TOKEN_ELEVATION_TYPE>(); // If limited, get the linked elevated token for further check. if (elevType == TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited) { // Allocate a buffer for the linked token. using (var pLinkedToken = new SafeNativeMemory(IntPtr.Size)) { // Get the linked token. if (!NativeMethods.GetTokenInformation(userToken, TOKEN_INFORMATION_CLASS.TokenLinkedToken, pLinkedToken)) { throw new Win32Exception(); } // Marshal the linked token value from native to .NET. var hLinkedToken = pLinkedToken.ReadIntPtr(); using (var linkedToken = new SafeTokenHandle(hLinkedToken)) { return IsAdministrator(linkedToken); } } } } } // CheckTokenMembership requires an impersonation token. If we just got // a linked token, it already is an impersonation token. If we did not // get a linked token, duplicate the original into an impersonation // token for CheckTokenMembership. IntPtr phTokenToCheck; if (!NativeMethods.DuplicateToken(userToken, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, out phTokenToCheck)) { throw new Win32Exception(); } using (var hTokenToCheck = new SafeTokenHandle(phTokenToCheck)) { // Check if the token to be checked contains admin SID. return IsAdministrator(hTokenToCheck); } }