none
How to check if the logged on user is an administrator?

    Question

  • Hi,

    In my C# software, i am trying to check if the logged on user is an administrator or not.
    I am using that code to do it:

    bool IsAnAdministrator ()
    {
       WindowsIdentity  identity = 
          WindowsIdentity.GetCurrent();
       WindowsPrincipal principal = 
          new WindowsPrincipal (identity);
       return principal.IsInRole 
          (WindowsBuiltInRole.Administrator);
    }

    It works when running on a Windows XP system, but when it runs on a Windows Server 2003 system, it always returns true.

    Can somebody tell me why and what to do to achieve this under Windows Server 2003?

    Thanks
    Monday, November 05, 2007 10:08 AM

Answers

  • I use the following code:

    SecurityIdentifier sidAdmin = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);

     if (user.IsInRole(sidAdmin))

        ...

     

    It is more reliable than the other method in my opinion.  Of course you might need to expand the list of roles to check but the above should work.  You should also test Vista with UAC enabled as it works a little different.  The above code, for example, will return false under Vista unless the user has elevated their privileges.  That is what you want though, I assume.

     

    Michael Taylor - 11/5/07

    http://p3net.mvps.org

     

    Monday, November 05, 2007 1:53 PM
    Moderator
  • Hello GovindhM

    We later found a more reliable way to check if the primary access token of the process belongs to user account that is a member of the local Administrors group.  (See code below. The complete sample code can be downloaded from http://code.msdn.microsoft.com/CSUACSelfElevation-644673d3.  The original code that I posted above cannot detect if the user belongs to a non-built-in Admin group, and this group is a member of the built-in admin group.

     

            /// <summary>
            /// The function checks whether the primary access token of the process belongs 
            /// to user account that is a member of the local Administrators group, even if 
            /// it currently is not elevated.
            /// </summary>
            /// <returns>
            /// Returns true if the primary access token of the process belongs to user 
            /// account that is a member of the local Administrators group. Returns false 
            /// if the token does not.
            /// </returns>
            /// <exception cref="System.ComponentModel.Win32Exception">
            /// When any native Windows API call fails, the function throws a Win32Exception 
            /// with the last error code.
            /// </exception>
            internal bool IsUserInAdminGroup()
            {
                bool fInAdminGroup = false;
                SafeTokenHandle hToken = null;
                SafeTokenHandle hTokenToCheck = null;
                IntPtr pElevationType = IntPtr.Zero;
                IntPtr pLinkedToken = IntPtr.Zero;
                int cbSize = 0;
    
                try
                {
                    // Open the access token of the current process for query and duplicate.
                    if (!NativeMethods.OpenProcessToken(Process.GetCurrentProcess().Handle,
                        NativeMethods.TOKEN_QUERY | NativeMethods.TOKEN_DUPLICATE, out hToken))
                    {
                        throw new Win32Exception();
                    }
    
                    // 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.
                    if (Environment.OSVersion.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.
                        cbSize = sizeof(TOKEN_ELEVATION_TYPE);
                        pElevationType = Marshal.AllocHGlobal(cbSize);
                        if (pElevationType == IntPtr.Zero)
                        {
                            throw new Win32Exception();
                        }
    
                        // Retrieve token elevation type information.
                        if (!NativeMethods.GetTokenInformation(hToken, 
                            TOKEN_INFORMATION_CLASS.TokenElevationType, pElevationType,
                            cbSize, out cbSize))
                        {
                            throw new Win32Exception();
                        }
    
                        // Marshal the TOKEN_ELEVATION_TYPE enum from native to .NET.
                        TOKEN_ELEVATION_TYPE elevType = (TOKEN_ELEVATION_TYPE)
                            Marshal.ReadInt32(pElevationType);
    
                        // If limited, get the linked elevated token for further check.
                        if (elevType == TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited)
                        {
                            // Allocate a buffer for the linked token.
                            cbSize = IntPtr.Size;
                            pLinkedToken = Marshal.AllocHGlobal(cbSize);
                            if (pLinkedToken == IntPtr.Zero)
                            {
                                throw new Win32Exception();
                            }
    
                            // Get the linked token.
                            if (!NativeMethods.GetTokenInformation(hToken,
                                TOKEN_INFORMATION_CLASS.TokenLinkedToken, pLinkedToken,
                                cbSize, out cbSize))
                            {
                                throw new Win32Exception();
                            }
    
                            // Marshal the linked token value from native to .NET.
                            IntPtr hLinkedToken = Marshal.ReadIntPtr(pLinkedToken);
                            hTokenToCheck = new SafeTokenHandle(hLinkedToken);
                        }
                    }
                    
                    // 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 (hTokenToCheck == null)
                    {
                        if (!NativeMethods.DuplicateToken(hToken,
                            SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
                            out hTokenToCheck))
                        {
                            throw new Win32Exception();
                        }
                    }
    
                    // Check if the token to be checked contains admin SID.
                    WindowsIdentity id = new WindowsIdentity(hTokenToCheck.DangerousGetHandle());
                    WindowsPrincipal principal = new WindowsPrincipal(id);
                    fInAdminGroup = principal.IsInRole(WindowsBuiltInRole.Administrator);
                }
                finally
                {
                    // Centralized cleanup for all allocated resources. 
                    if (hToken != null)
                    {
                        hToken.Close();
                        hToken = null;
                    }
                    if (hTokenToCheck != null)
                    {
                        hTokenToCheck.Close();
                        hTokenToCheck = null;
                    }
                    if (pElevationType != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(pElevationType);
                        pElevationType = IntPtr.Zero;
                    }
                    if (pLinkedToken != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(pLinkedToken);
                        pLinkedToken = IntPtr.Zero;
                    }
                }
    
                return fInAdminGroup;
            }
    


    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Tuesday, September 20, 2011 1:05 AM
    Moderator
  • Take a look at how I do it on my blog: Security Principles and Local Admin Rights in C# .Net . In there I set the Principle policy such as:

    System.AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

    before getting such information. That allows for processing to work with the OS system token which will be geared toward the current user and windows security on the current thread.


    Monday, November 05, 2007 3:13 PM
    Moderator

All replies

  • I use the following code:

    SecurityIdentifier sidAdmin = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);

     if (user.IsInRole(sidAdmin))

        ...

     

    It is more reliable than the other method in my opinion.  Of course you might need to expand the list of roles to check but the above should work.  You should also test Vista with UAC enabled as it works a little different.  The above code, for example, will return false under Vista unless the user has elevated their privileges.  That is what you want though, I assume.

     

    Michael Taylor - 11/5/07

    http://p3net.mvps.org

     

    Monday, November 05, 2007 1:53 PM
    Moderator
  • Take a look at how I do it on my blog: Security Principles and Local Admin Rights in C# .Net . In there I set the Principle policy such as:

    System.AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

    before getting such information. That allows for processing to work with the OS system token which will be geared toward the current user and windows security on the current thread.


    Monday, November 05, 2007 3:13 PM
    Moderator
  • None of the examples always check if the "logged on user" is an administrator, they only check if the user credentials of the currently running thread is in the administrators group.

     

    Could you be more specific in what you want to accomplish?  i.e. do you want to know if the user credentials used to execute your application is in the administrators group, or do you really want to test if the "logged on user" is in the administrators group?  Depending on how the application is executed, you may not have access to the "logged on user".  If the application is executed with "Run As..." the credentials of the user running the application will be different than the user to logged on to Windows.  Also, if some sort of impersonate is being used on the current thread the user credentials for that thread will be different than the logged on user.

     

    Monday, November 05, 2007 5:16 PM
    Moderator
  • I'm looking for a way to find out (in Vista) if the *logged on user* is in the administrators group.
    Is that even possible if the application is running non-elevated?

    thanks,
    Johannes
    Tuesday, February 05, 2008 9:50 AM
  • Well I found out how to do it using Win32 calls. If anyone knows if it's possible in the .NET FW let me know!


    Code Snippet
    [DllImport("kernel32")]
    static extern IntPtr GetCurrentProcess();

    [DllImport("advapi32")]
    static extern bool OpenProcessToken(IntPtr ProcessHandle, Int32 DesiredAccess, ref IntPtr TokenHandle);

    [DllImport("advapi32")]
    static extern bool GetTokenInformation(IntPtr hToken, UInt32 tokenInfoClass, IntPtr TokenInformation,
                                           Int32 tokeInfoLength, ref Int32 reqLength);

    [DllImport("advapi32")]
    static extern bool IsWellKnownSid(IntPtr pSid, Int32 sidType);

    [StructLayout(LayoutKind.Sequential)]
    public struct _SID_AND_ATTRIBUTES
    {
        public IntPtr Sid;
        public Int32 Attributes;
    }

    // Returns true if the user that started the process is a member of the admin group
    // (which does not necessarily mean that the process has admin privileges)
    static bool IsAdmin()
    {
        bool isAdmin = false;
        IntPtr token = IntPtr.Zero;
        OpenProcessToken(GetCurrentProcess(), 0x0008, ref token); // TOKEN_QUERY = 0x0008
        Int32 len = 0;
        GetTokenInformation(token, 2, IntPtr.Zero, 0, ref len); // TOKEN_GROUPS = 2
        IntPtr ti = Marshal.AllocHGlobal(len);
        GetTokenInformation(token, 2, ti, len, ref len);
        int nGroups = Marshal.ReadInt32(ti);
        UInt32 pSaa = (UInt32)ti + 4;
        for (int i = 0; i < nGroups; i++)
        {
            _SID_AND_ATTRIBUTES saa = (_SID_AND_ATTRIBUTES)Marshal.PtrToStructure((IntPtr)pSaa, typeof(_SID_AND_ATTRIBUTES));
            if (IsWellKnownSid(saa.Sid, 26)) isAdmin = true; // WinBuiltinAdministratorsSid = 26
            pSaa += Marshal.SizeOf(typeof(_SID_AND_ATTRIBUTES));
        }
        Marshal.FreeHGlobal(ti);
        return isAdmin;
    }



    Tuesday, February 05, 2008 3:41 PM
  • Does the following not work in Vista?

    Code Snippet
        WindowsPrincipal windowsPrincipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
        bool isAdministrator = windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);

     

     

     

    • Proposed as answer by R-G Thursday, March 07, 2013 7:01 AM
    • Unproposed as answer by nobugzMVP, Moderator Monday, November 25, 2013 12:37 PM
    Tuesday, February 05, 2008 4:08 PM
    Moderator
  •  Peter Ritchie wrote:

    Does the following not work in Vista?

    Code Snippet
        WindowsPrincipal windowsPrincipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
        bool isAdministrator = windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);

     



    No, it returns false if UAC is enabled and the process isn't elevated.

    Tuesday, February 05, 2008 4:36 PM
  • Right, if the process isn't elevated, the currently running user doesn't have administrative access rights...

     

    Tuesday, February 05, 2008 4:38 PM
    Moderator
  • Correct. But I wasn't looking for process access rights, rather if the user was a (potential) admin


    Tuesday, February 05, 2008 4:44 PM
  • There's nothing in .NET to entirely do what you want.  Once you get the SID you can instantiate a SecurityIdentifier object then use SecurityIdentifier.IsWellKnown instead of IsWellKnownSid.  You could replace GetCurrentProcess with Process.GetCurrentProcess().Handle.

    Tuesday, February 05, 2008 5:02 PM
    Moderator
  •  If you are using .NET 3.5 or better the following code from System.DirectoryServices.AccountManagement will give you all authorized groups including the admin group even if not currently elevated.

    try
    {
        
    var userCurrent = System.DirectoryServices.AccountManagement.UserPrincipal.Current;
        
    var Groups = userCurrent.GetAuthorizationGroups();

        var IsPotentialAdmin = Groups.Any(p => p.Sid == new SecurityIdentifier("S-1-5-32-544"));

        return IsPotentialAdmin;
    }
    catch (Exception ex)
    {
        
    // this will cause access denied if user is not admin or in "Pre-Windows 2000 combatiblity" group
        
    return false;
    }

     

    • Proposed as answer by kshaban Tuesday, January 27, 2009 9:46 AM
    Tuesday, January 27, 2009 9:45 AM
  • Hello

    I happened to see this old thread. Considering that OP's query in this thread is a very typical coding scenario, I have worked out code samples to demonstrate how to do the following things in three different langauges: VC++, VC#, VB.NET: CppUACSelfElevation, CSUACSelfElevation, and VBUACSelfElevation.

    1) how to determine if the user running the application is a member of the Administrators group, which does not necessarily mean that the process has admin privileges.

    2) how to determine if the primary access token associated with the process has administrative privileges.

    3) how to determine if the process is elevated to high privilege level.

    You can download the samples CppUACSelfElevation, CSUACSelfElevation, and VBUACSelfElevation from my team's project: Microsoft All-In-One Code Framework. Please download a changeset >= 37857 from http://cfx.codeplex.com/SourceControl/list/changesets.

    For example, this is the code snippet of determine if the user running the application is a member of the Administrators group in VC#, which is queried by the customer.

    Please let me know if you have any questions or feedback regarding the samples or the project.

    Happy holidays!

            /// <summary>
            /// The function returns true if the user who is running the application is a 
            /// member of the Administrators group, which does not necessarily mean that 
            /// the process has admin privileges.
            /// </summary>
            /// <returns></returns>
            internal bool IsAdministrator()
            {
                bool fIsAdmin = false;
    
                // Open the access token of the current process with TOKEN_QUERY.
                SafeWaitHandle hToken;
                NativeMethod.OpenProcessToken(Process.GetCurrentProcess().Handle,
                    NativeMethod.TOKEN_QUERY, out hToken);
                if (hToken.IsInvalid)
                {
                    // If the handle is invalid, get the last Win32 error and throw a 
                    // Win32Exception
                    Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
                }
    
                IntPtr pTokenGroups = IntPtr.Zero;
                try
                {
                    int cbTokenGroups;
    
                    // Then we must query the size of the group information associated with 
                    // the token. Note that we expect GetTokenInformation to return FALSE 
                    // because we've given it a NULL buffer. On exit cbTokenGroups will 
                    // tell the size of the group information.
                    NativeMethod.GetTokenInformation(hToken,
                        TOKEN_INFORMATION_CLASS.TokenGroups, IntPtr.Zero, 0,
                        out cbTokenGroups);
    
                    // Now we allocate a buffer for the group information.
                    pTokenGroups = Marshal.AllocHGlobal(cbTokenGroups);
    
                    // Now we ask for the group information again. This may fail if an 
                    // administrator has added this account to an additional group between 
                    // our first call to GetTokenInformation and this one.
                    if (NativeMethod.GetTokenInformation(hToken,
                        TOKEN_INFORMATION_CLASS.TokenGroups, pTokenGroups, cbTokenGroups,
                        out cbTokenGroups))
                    {
                        // Get the token group number from the first two words
                        int nGroups = Marshal.ReadInt32(pTokenGroups);
    
                        // Finally we'll iterate through the list of groups for this access
                        // token looking for a match against the builtin admin group SID.
                        ulong pTokenGroup = (ulong)pTokenGroups + 4;
                        for (int i = 0; i < nGroups; i++)
                        {
                            // Marshal the SID_AND_ATTRIBUTES struct from native to .NET
                            SID_AND_ATTRIBUTES tokenGroup = (SID_AND_ATTRIBUTES)
                                Marshal.PtrToStructure((IntPtr)pTokenGroup,
                                typeof(SID_AND_ATTRIBUTES));
    
                            SecurityIdentifier si = new SecurityIdentifier(tokenGroup.Sid);
                            if (si.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid))
                            {
                                // Match the builtin admin group SID, so the user belongs
                                // to the local administrators group.
                                fIsAdmin = true;
                                break;
                            }
    
                            pTokenGroup += (ulong)Marshal.SizeOf(typeof(SID_AND_ATTRIBUTES));
                        }
                    }
                }
                finally
                {
                    // Free the token group buffer.
                    if (pTokenGroups != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(pTokenGroups);
                    }
    
                    hToken.Close();
                }
    
                return fIsAdmin;
            }

    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Monday, December 28, 2009 1:49 PM
    Moderator
  • Thanks for the sample code.  Just what I needed.

    I had to change 

    ulong pTokenGroup = (ulong)pTokenGroups + 4;

     to 

    ulong pTokenGroup = (ulong)pTokenGroups + (ulong)IntPtr.Size;

     
    to support 64-bit environment.

     



    • Edited by GovindhM Monday, September 19, 2011 7:06 PM
    Monday, September 19, 2011 7:05 PM
  • Hello GovindhM

    We later found a more reliable way to check if the primary access token of the process belongs to user account that is a member of the local Administrors group.  (See code below. The complete sample code can be downloaded from http://code.msdn.microsoft.com/CSUACSelfElevation-644673d3.  The original code that I posted above cannot detect if the user belongs to a non-built-in Admin group, and this group is a member of the built-in admin group.

     

            /// <summary>
            /// The function checks whether the primary access token of the process belongs 
            /// to user account that is a member of the local Administrators group, even if 
            /// it currently is not elevated.
            /// </summary>
            /// <returns>
            /// Returns true if the primary access token of the process belongs to user 
            /// account that is a member of the local Administrators group. Returns false 
            /// if the token does not.
            /// </returns>
            /// <exception cref="System.ComponentModel.Win32Exception">
            /// When any native Windows API call fails, the function throws a Win32Exception 
            /// with the last error code.
            /// </exception>
            internal bool IsUserInAdminGroup()
            {
                bool fInAdminGroup = false;
                SafeTokenHandle hToken = null;
                SafeTokenHandle hTokenToCheck = null;
                IntPtr pElevationType = IntPtr.Zero;
                IntPtr pLinkedToken = IntPtr.Zero;
                int cbSize = 0;
    
                try
                {
                    // Open the access token of the current process for query and duplicate.
                    if (!NativeMethods.OpenProcessToken(Process.GetCurrentProcess().Handle,
                        NativeMethods.TOKEN_QUERY | NativeMethods.TOKEN_DUPLICATE, out hToken))
                    {
                        throw new Win32Exception();
                    }
    
                    // 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.
                    if (Environment.OSVersion.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.
                        cbSize = sizeof(TOKEN_ELEVATION_TYPE);
                        pElevationType = Marshal.AllocHGlobal(cbSize);
                        if (pElevationType == IntPtr.Zero)
                        {
                            throw new Win32Exception();
                        }
    
                        // Retrieve token elevation type information.
                        if (!NativeMethods.GetTokenInformation(hToken, 
                            TOKEN_INFORMATION_CLASS.TokenElevationType, pElevationType,
                            cbSize, out cbSize))
                        {
                            throw new Win32Exception();
                        }
    
                        // Marshal the TOKEN_ELEVATION_TYPE enum from native to .NET.
                        TOKEN_ELEVATION_TYPE elevType = (TOKEN_ELEVATION_TYPE)
                            Marshal.ReadInt32(pElevationType);
    
                        // If limited, get the linked elevated token for further check.
                        if (elevType == TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited)
                        {
                            // Allocate a buffer for the linked token.
                            cbSize = IntPtr.Size;
                            pLinkedToken = Marshal.AllocHGlobal(cbSize);
                            if (pLinkedToken == IntPtr.Zero)
                            {
                                throw new Win32Exception();
                            }
    
                            // Get the linked token.
                            if (!NativeMethods.GetTokenInformation(hToken,
                                TOKEN_INFORMATION_CLASS.TokenLinkedToken, pLinkedToken,
                                cbSize, out cbSize))
                            {
                                throw new Win32Exception();
                            }
    
                            // Marshal the linked token value from native to .NET.
                            IntPtr hLinkedToken = Marshal.ReadIntPtr(pLinkedToken);
                            hTokenToCheck = new SafeTokenHandle(hLinkedToken);
                        }
                    }
                    
                    // 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 (hTokenToCheck == null)
                    {
                        if (!NativeMethods.DuplicateToken(hToken,
                            SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
                            out hTokenToCheck))
                        {
                            throw new Win32Exception();
                        }
                    }
    
                    // Check if the token to be checked contains admin SID.
                    WindowsIdentity id = new WindowsIdentity(hTokenToCheck.DangerousGetHandle());
                    WindowsPrincipal principal = new WindowsPrincipal(id);
                    fInAdminGroup = principal.IsInRole(WindowsBuiltInRole.Administrator);
                }
                finally
                {
                    // Centralized cleanup for all allocated resources. 
                    if (hToken != null)
                    {
                        hToken.Close();
                        hToken = null;
                    }
                    if (hTokenToCheck != null)
                    {
                        hTokenToCheck.Close();
                        hTokenToCheck = null;
                    }
                    if (pElevationType != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(pElevationType);
                        pElevationType = IntPtr.Zero;
                    }
                    if (pLinkedToken != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(pLinkedToken);
                        pLinkedToken = IntPtr.Zero;
                    }
                }
    
                return fInAdminGroup;
            }
    


    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Tuesday, September 20, 2011 1:05 AM
    Moderator