Thread: GetTokenInformation() confusion

  1. #1
    Registered User
    Join Date
    Jan 2005
    Posts
    183

    Unhappy GetTokenInformation() confusion

    Heya all.

    I have spent the whole day trying to write a function that will return 0 if the process is running elevated. (It's been a while since I wrote anything Windows related.) Eventually, I wrote something close to working code:

    Code:
    int TokenIsElevated()    // Returns 0 if process is elevated, 1 if process is not elevated or -1 if a function fails.
    {
        DWORD CurrentProcPID = GetCurrentProcessId();
        
        if (!CurrentProcPID)
        {
            MessageBox(NULL, "GetCurrentProcessID function call failed.", "Test 4.exe", MB_ICONEXCLAMATION | MB_OK);
            return -1;
        }
        
        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, CurrentProcPID);
        
        if (!hProcess)
        {
            MessageBox(NULL, "OpenProcess function call failed.", "Test 4.exe", MB_ICONEXCLAMATION | MB_OK);
            CloseHandle(hProcess);
            return -1;
        }
        
        PHANDLE hToken;
        
        if(OpenProcessToken(hProcess, TOKEN_READ, hToken) == 0)
        {
            MessageBox(NULL, "OpenProcessToken function call failed.", "Test 4.exe", MB_ICONEXCLAMATION | MB_OK);
            CloseHandle(hProcess);
            CloseHandle(hToken);
            return -1;
        }
        
        TOKEN_ELEVATION_TYPE ElevationType = TokenElevationTypeDefault;
        DWORD SizeReturned = 0;
        
        if (!GetTokenInformation(hToken, TokenElevationType, &ElevationType, sizeof(ElevationType), &SizeReturned))
        {
            MessageBox(NULL, "GetTokenInformation function call failed.", "Test 4.exe", MB_ICONEXCLAMATION | MB_OK);
            CloseHandle(hProcess);
            CloseHandle(hToken);
            return -1;
        }
        
        if (ElevationType == TokenElevationTypeFull);
        {
            CloseHandle(hProcess);
            CloseHandle(hToken);
            return 0;
        }
        
        else
        {
            CloseHandle(hProcess);
            CloseHandle(hToken);
            return 1;
        }
    }
    The code compiled fine until I wrote this section:

    Code:
        TOKEN_ELEVATION_TYPE ElevationType = TokenElevationTypeDefault;
        DWORD SizeReturned = 0;
        
        if (!GetTokenInformation(hToken, TokenElevationType, &ElevationType, sizeof(ElevationType), &SizeReturned))
        {
            MessageBox(NULL, "GetTokenInformation function call failed.", "Test 4.exe", MB_ICONEXCLAMATION | MB_OK);
            CloseHandle(hProcess);
            CloseHandle(hToken);
            return -1;
        }
        
        if (ElevationType == TokenElevationTypeFull);
        {
            CloseHandle(hProcess);
            CloseHandle(hToken);
            return 0;
        }
        
        else
        {
            CloseHandle(hProcess);
            CloseHandle(hToken);
            return 1;
        }
    The above section of code will not compile because TOKEN_ELEVATION_TYPE, TokenElevationType and TokenElevationTypeFull are undefined. So I started searching the internet to find out where these definitions are (which took a very long time due to the limited documentation). I found that these were included in a Vista SDK. So I tried to create them myself by placing the following at the top of my code:

    Code:
    typedef enum _TOKEN_INFORMATION_CLASS
    {
        TokenUser = 1,
        TokenGroups,
        TokenPrivileges,
        TokenOwner,
        TokenPrimaryGroup,
        TokenDefaultDacl,
        TokenSource,
        TokenType,
        TokenImpersonationLevel,
        TokenStatistics,
        TokenRestrictedSids,
        TokenSessionId,
        TokenGroupsAndPrivileges,
        TokenSessionReference,
        TokenSandBoxInert,
        TokenAuditPolicy,
        TokenOrigin,
        TokenElevationType,
        TokenLinkedToken,
        TokenElevation,
        TokenHasRestrictions,
        TokenAccessInformation,
        TokenVirtualizationAllowed,
        TokenVirtualizationEnabled,
        TokenIntegrityLevel,
        TokenUIAccess,
        TokenMandatoryPolicy,
        TokenLogonSid,
        MaxTokenInfoClass             // MaxTokenInfoClass should always be the last enum
    }   TOKEN_INFORMATION_CLASS, *PTOKEN_INFORMATION_CLASS;
    
    typedef enum _TOKEN_ELEVATION_TYPE
    {
        TokenElevationTypeDefault = 1,
        TokenElevationTypeFull,
        TokenElevationTypeLimited,
    }   TOKEN_ELEVATION_TYPE, *PTOKEN_ELEVATION_TYPE;
    However, this results in multiple definitions of _TOKEN_INFORMATION_CLASS and _TOKEN_ELEVATION_TYPE (and their members), and, because I do not understand this code (I found it on the internet), I do not know what to do.

    Any advice would be greatly appreciated.
    Thankyou for your time.
    Necrofear

    IDE: Dev-C++ 4.9.9.2

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Say what you want about MS documentation, they always tell you what headers things are defined in: TOKEN_ELEVATION_TYPE Enumeration (Windows) (Look toward the bottom.)

  3. #3
    Registered User
    Join Date
    Jan 2005
    Posts
    183
    The definition in winnt.h is different because it lacks certain members (including ElevationType, which is the one I intended to use.) I have come across this code several times on the internet (the one with ElevationType) and I could find no one else with a similar problem. Have they explicitly excluded winnt.h??

  4. #4
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    They're defined in ntifs.h which is found in the Windows DDK version 6001.18001.

  5. #5
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Are you using the (10-year-old-or-so) winnt.h provided by Dev-C++, or the winnt.h from your system?

  6. #6
    Registered User
    Join Date
    Jan 2005
    Posts
    183
    Oh, yeah I was using the one that came with the compiler. In all honesty, I was unaware that the system had a winnt.h... Where is this? Is it best to use this or download an up to date DDK?

    EDIT: I have found a version of ntifs.h in a folder named ddk (don't know which version). I tried to include it, but it made no difference - they were still undefined. I guess it's outdated.
    Last edited by Necrofear; 10-27-2009 at 07:10 PM.

  7. #7
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    If that ddk folder is in the Dev-Cpp tree, then it's an old old file. You will need the platform SDK for the platform you are actually on. For some reason, I thought there were more header files in /system32 than there actually are. If you have VS, then VS came with those header files. If not you'll have to do some downloading (there's probably a way to get the header files without also downloading VS, but I didn't look hard enough to find it).

  8. #8
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    This is all you need for the above code:

    Code:
    typedef enum _TOKEN_ELEVATION_TYPE {
        TokenElevationTypeDefault = 1,
            TokenElevationTypeFull,
            TokenElevationTypeLimited,
    } TOKEN_ELEVATION_TYPE, *PTOKEN_ELEVATION_TYPE;
    
    TOKEN_INFORMATION_CLASS TokenElevationType;
    Here's your modified code. It still needs a lot of work but it now compiles.

    Code:
    #define _WIN32_WINNT 0x0501
    
    #include <windows.h>
    #include <stdio.h>
    
    #pragma comment (lib,"advapi32.lib")
    
    typedef enum _TOKEN_ELEVATION_TYPE {
        TokenElevationTypeDefault = 1,
            TokenElevationTypeFull,
            TokenElevationTypeLimited,
    } TOKEN_ELEVATION_TYPE, *PTOKEN_ELEVATION_TYPE;
    
    TOKEN_INFORMATION_CLASS TokenElevationType;
    
    VOID DisplayError(CHAR* pMessage)
    {
        DWORD eNum;
        CHAR sysMsg[256] = {0};
        CHAR* p;
    
        eNum = GetLastError( );
        FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, eNum,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
            sysMsg, 256, NULL );
        // Trim the end of the line and terminate it with a null
        p = sysMsg;
        while( ( *p > 31 ) || ( *p == 9 ) )
            ++p;
        do { *p-- = 0; } while( ( p >= sysMsg ) &&
            ( ( *p == '.' ) || ( *p < 33 ) ) );
        // Display the message
        printf( "\n  WARNING: %s failed with error %d (%s)", pMessage, eNum, sysMsg );
    }
    
    int TokenIsElevated(void )    // Returns 0 if process is elevated, 1 if process is not elevated or -1 if a function fails.
    {
        DWORD CurrentProcPID = GetCurrentProcessId();
    
        if (!CurrentProcPID)
        {
            // MessageBox(NULL, "GetCurrentProcessID function call failed.", "Test 4.exe", MB_ICONEXCLAMATION | MB_OK);
            DisplayError("GetCurrentProcessID function call failed.");
            return -1;
        }
    
        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, CurrentProcPID);
    
        if (!hProcess)
        {
            //MessageBox(NULL, "OpenProcess function call failed.", "Test 4.exe", MB_ICONEXCLAMATION | MB_OK);
            DisplayError("OpenProcess function call failed." );
            CloseHandle(hProcess);
            return -1;
        }
    
        HANDLE hToken;
    
        if(OpenProcessToken(hProcess, TOKEN_QUERY, &hToken) == 0)
        {
            // MessageBox(NULL, "OpenProcessToken function call failed.", "Test 4.exe", MB_ICONEXCLAMATION | MB_OK);
            DisplayError("OpenProcessToken function call failed." );
            CloseHandle(hProcess);
            CloseHandle(hToken);
            return -1;
        }
    
        TOKEN_ELEVATION_TYPE ElevationType = TokenElevationTypeFull;
        DWORD SizeReturned = 0;
    
        if (!GetTokenInformation(&hToken, TokenElevationType, &ElevationType, sizeof(ElevationType), &SizeReturned))
        {
            // MessageBox(NULL, "GetTokenInformation function call failed.", "Test 4.exe", MB_ICONEXCLAMATION | MB_OK);
            DisplayError( "GetTokenInformation function call failed.");
            CloseHandle(hProcess);
            CloseHandle(hToken);
            return -1;
        }
    
        if (ElevationType == TokenElevationTypeFull)
        {
            CloseHandle(hProcess);
            CloseHandle(hToken);
            return 0;
        }
    
        else
        {
            CloseHandle(hProcess);
            CloseHandle(hToken);
            return 1;
        }
    }
    
    int main(void)
    {
        TokenIsElevated();
        return 0;
    }
    Last edited by BobS0327; 10-27-2009 at 08:41 PM.

  9. #9
    Registered User
    Join Date
    Jan 2005
    Posts
    183
    Thankyou very much for the code Bob, will get to work on it soon.

  10. #10
    Registered User
    Join Date
    Jan 2005
    Posts
    183
    Ok, so I've been trying to fix up the code that BobS0327 provided. (Thanks again )
    The extra function that he provided (the DisplayError function) printed the following:

    Code:
    WARNING: GetTokenInformation function call failed. failed with error 87 (The parameter is incorrect)
    I have tried my best to determine the cause of the problem, (by altering variable types, using pointers in the function call, NULLifying parameters etc) but I cannot figure it out. I do not wish to be selfish and ask for an excessive amount of help, but if someone could please point me in the right direction, that'd be great.

    Thanks for your time and good day.

  11. #11
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    Change the GetTokenInformation line back to how it is in your first post. Note that if UAC is turned off, the value it returns will be TokenElevationTypeDefault for at least all local users, including administrators. Depending on what you're wanting, that might cause your function as it currently is to return wrong information.

    Also, everything above the "HANDLE hToken;" can be deleted if you change the next line to:
    if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) == 0)
    Last edited by adeyblue; 10-31-2009 at 03:47 PM.

  12. #12
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Quote Originally Posted by Necrofear View Post
    Ok, so I've been trying to fix up the code that BobS0327 provided. (Thanks again )
    The extra function that he provided (the DisplayError function) printed the following:

    Code:
    WARNING: GetTokenInformation function call failed. failed with error 87 (The parameter is incorrect)
    I have tried my best to determine the cause of the problem, (by altering variable types, using pointers in the function call, NULLifying parameters etc) but I cannot figure it out. I do not wish to be selfish and ask for an excessive amount of help, but if someone could please point me in the right direction, that'd be great.

    Thanks for your time and good day.
    It means that you are using a incorrect input parameter. That is, TokenElevationType is the incorrect input parameter. After you determine the correct parameter, you'll have to call LookUpAccoutSid. Next, you'll have to determine whether the the sid is interactive or not. Finally, you'll have to inspect the Sid to determine if it is elevated. Post your problem on the Win32 newsgroup and all of the above will be illustrated in simple to understand, complete, fully functional code snippet.

  13. #13
    Registered User
    Join Date
    Jan 2005
    Posts
    183
    Woah, looks like I jumped in at the deep end. Didn't realize that SIDs came into it at all. Ok will get to work again. Thanks for the help.
    P.S. With regards to deleting everything above the hToken declaration, I find it a little easier to understand if I am only passing variables to OpenProcessToken (as oppose to the GetCurrentProcess function itself). I realize that this may be less efficient, but I'll be the first to admit that I do get easily confused, even by my own code. Thankyou for your input though, it greatly appreciated.

  14. #14
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    This may be a much simpler approach for XP and up...

    Code:
    #include <windows.h>
    #include <stdio.h>
    #include <tchar.h>
    
    int main(void)
    {
        typedef BOOL (WINAPI *LPFNIUA)(void);
    
        HMODULE hShell32 = LoadLibrary(_T("shell32.dll"));
        LPFNIUA pIsAdmin = NULL;
    
        if (hShell32)
        {
            pIsAdmin = (LPFNIUA)GetProcAddress(hShell32, MAKEINTRESOURCE(680));
            if (pIsAdmin)
            {
                if(pIsAdmin())
                    printf(_T("User is Admin\n"));
                else printf(_T("User is NOT Admin\n"));
            }
            FreeLibrary(hShell32);
        }
        return 0;
    }

  15. #15
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Quote Originally Posted by BobS0327 View Post
    It means that you are using a incorrect input parameter. That is, TokenElevationType is the incorrect input parameter. After you determine the correct parameter, you'll have to call LookUpAccoutSid. Next, you'll have to determine whether the the sid is interactive or not. Finally, you'll have to inspect the Sid to determine if it is elevated. Post your problem on the Win32 newsgroup and all of the above will be illustrated in simple to understand, complete, fully functional code snippet.
    [EDIT] The reason you're receiving this incorrect parameter message is probably because you're using a very old compiler or your compiler is misconfigured. I'm using Visual Studio 2008 and I do NOT have to manually add the typedef for TOKEN_ELEVATION_TYPE. Once you have your compiler issues resolved, you can use TOKEN_ELEVATION_TYPE.

    If your first call to GetTokenInformation returns TokenElevationTypeLimited, you'll have to call GetTokenInformation a second time. This will get you a handle to a linked token. A linked token will exist if the user account is a Least-Privileged User Account (LUA). At this point, you'll create an Administrator SID using the CreateWellKnownSID call. Next, you'll have to call GetTokenInformation a second time with the TokenLinkedToken parameter. After which you'll have to call CheckTokenMembership with what was returned from the second calling of GetTokenInformation. By calling CheckTokenMembership, we can verify whether or not the original token contains an Admin SID. If the first call to GetTokenInformation returns anything other than TokenElevationTypeLimited, the only option you have is to call IsUserAnAdmin, a sample of this call is in a previous post.

    If you're still having problems with this task, then post on the Win32 newsgroups and a very simple, fully functional example of the above will be submitted to your post.
    Last edited by BobS0327; 11-01-2009 at 06:49 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. relative virtual addresses confusion
    By MrNoobah in forum Windows Programming
    Replies: 7
    Last Post: 10-13-2009, 08:45 PM
  2. Pointer + struct w/arrays confusion
    By Viper187 in forum C Programming
    Replies: 1
    Last Post: 07-23-2009, 09:37 AM
  3. Terrible confusion with time variables
    By LowlyIntern in forum C++ Programming
    Replies: 12
    Last Post: 08-01-2008, 07:23 AM
  4. confusion with increment and decrement operators
    By cBegginer in forum C Programming
    Replies: 6
    Last Post: 03-19-2005, 03:45 PM
  5. Unicode - a lot of confusion...
    By Jumper in forum Windows Programming
    Replies: 11
    Last Post: 07-05-2004, 07:59 AM

Tags for this Thread