How to tell if the current user is in administrators group programmatically


You can use CheckTokenMembership (http://msdn2.microsoft.com/en-us/library/aa376389.aspx) to check whether a user is in administrators group.  There is an example in the MSDN document.


The example will not work in Windows Vista. In Windows Vista, even if the user is in administrators group, the OS will create a filtered user token when user log on. The SID of administrators group is not included in the filtered user token. The full token is linked to the filtered user token, and can be retrieved with API GetTokenInformation with the new TokenLinkedToken information type.


The following is the sample code. You need to download Vista SDK to compile it. Please make sure you read the article in the reference section.


HRESULT IsUserAdmin(BOOL *pIsAdmin)
{
    int b;
    HANDLE hProcess = NULL;
    HANDLE hProcessToken = NULL;
    HANDLE hLinkedToken = NULL;
    BOOL fIsAdmin = FALSE;
    DWORD dwLength = 0;
    OSVERSIONINFO osver = {sizeof(OSVERSIONINFO)};
    HRESULT hr = S_OK;


    *pIsAdmin = FALSE;


    // get handle to our process token
    hProcess = GetCurrentProcess();
    if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hProcessToken))
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        goto Exit;
    }


    // get admin SID
    char AdminSID[SECURITY_MAX_SID_SIZE];
    dwLength = sizeof(AdminSID);
    if(!CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, &AdminSID, &dwLength))
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        goto Exit;
    }


    // check to see if the current token contains admin SID
    if (!CheckTokenMembership( NULL, &AdminSID, &fIsAdmin))
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        goto Exit;
    }


    if (fIsAdmin)
    {
        // printf(“The user is in admin group, and the process is elevated.\n”);
        *pIsAdmin = TRUE;
        goto Exit;
    }


    // if the current token does not contain admin SID, it does not mean
    // that the current user is not admin. In Vista by default the token of
    // users in administrator group has the the admin SID filtered. We nee
    // to use the unfiltered token to do the check.
    if (!GetVersionEx(&osver))
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        goto Exit;
    }


    // XP and below, we are done.
    if (osver.dwMajorVersion < 6)
    {
        // printf(“The user is not in admin group.\n”);
        goto Exit;       
    }


// get handle to linked token (will have one if we are lua)
    if (!GetTokenInformation(   hProcessToken,
                                TokenLinkedToken,
                                (VOID*) &hLinkedToken,
                                sizeof(HANDLE),
                                &dwLength) )
    {
        b = GetLastError();
        if  (   b == ERROR_NO_SUCH_LOGON_SESSION
            ||  b == ERROR_PRIVILEGE_NOT_HELD)
        {
            // printf(“The user is not in admin group.\n”);
            goto Exit;
        }


        hr = HRESULT_FROM_WIN32(b); // a real error
        goto Exit;
    }


    if (!CheckTokenMembership(   hLinkedToken, &AdminSID, &fIsAdmin))
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        goto Exit;
    }


    if (fIsAdmin)
    {
        // printf(“The user is in admin group, and the process is not elevated.\n”);
        *pIsAdmin = TRUE;
    }
    else
    {
        // printf(“The user is not in admin group.\n”);
    }


Exit:
    if (hProcess)
    {
        CloseHandle(hProcess);
    }


    if (hProcessToken)
    {
        CloseHandle(hProcessToken);
    }


    if (hLinkedToken)
    {
        CloseHandle(hLinkedToken);
    }


    return hr;
}


Reference:


Teach Your Apps To Play Nicely With Windows Vista User Account Control

Comments (7)

  1. Munish says:

    How is this different and/or better than:

    public static bool IsAdministrator

    {

    get

    {

     // Check whether the user is part of the administrator group

     AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

    WindowsPrincipal principal = (WindowsPrincipal)Thread.CurrentPrincipal;

    WindowsIdentity identity = (WindowsIdentity)principal.Identity;

    return principal.IsInRole(WindowsBuiltInRole.Administrator);

    }

    }

  2. Norman Diamond says:

    Monday, January 29, 2007 11:10 AM by Munish

    > How is this different and/or better than:

    [.Net stuff]

    Difference:  Win32 APIs vs. .Net APIs.

    Better:  Maybe or maybe not.

    If you had old Win32 code that worked in XP and you want to make it work in Vista without depending on .Net, then it might be better for your purposes.  If you’re writing new code which you don’t need to port to XP (or if you know that all your XP customers will download the .Net framework) then the .Net version is easier to understand.

  3. Why don’t you try your .Net version and see if it works in Vista?

  4. Eric says:

    I tried that .NET version and it works.  Nice little snippet there.  Now if I could only find a way to elevate to administrator in Vista in C#….

  5. You can use the verb "runas" combined with UseShellExecute in ProcessStartInfo to elevate.

  6. Jennifer Lawrence says:

    Your comment in the top says that this will NOT work in Vista,

    However, in the middle of the code, you are checking the unfiltered token to see if the user is an admin.

    So does this really work in Vista or not?

  7. Igor Krivanov says:

    Is it possible to produce the same functionality on Vista using an older version of the SDK (w/o Vista support)?

    Using other functions or something else.