Search code examples
c++windowswinapiprivileges

Determine if User can elevate a process with c++


My application needs a function to check if the Current User is allowed to elevate a process (run as Admin). The function IsUserAnAdmin() does only tell me if the process is already elevated but in my case it is not.

Are there any other options to determine if the User is able to elevate a Process (is an admin)?


Solution

  • for check current elevation status we can query TOKEN_ELEVATION_TYPE of current process with TokenElevationType :

    • TokenElevationTypeFull - we already run elevated.
    • TokenElevationTypeLimited - we run under limited token, but have
      elevated linked token. this is usually admin account with interactive logon. we can elevate under same user.
    • TokenElevationTypeDefault - we have no linked token. here exist 2
      case:

      1. we already elevated (for check this use TokenElevation and look for TokenIsElevated from TOKEN_ELEVATION ) this can be if we run under built-in admin account
        (DOMAIN_ALIAS_RID_ADMINS 500 ) which is not filtered, or UAC is disabled in system.

      2. we run not under admin account. we can elevate in this case also, but only under another account. for this need know this account password

    demo code:

    inline ULONG BTE(BOOL f)
    {
        return f ? 0 : GetLastError();
    }
    
    void TryElevate()
    {
        WCHAR path[MAX_PATH];
        if (GetModuleFileNameW(0, path, RTL_NUMBER_OF(path)))
        {
            SHELLEXECUTEINFOW sei = { sizeof(sei), 0, 0, L"runas", path };
            ShellExecuteExW(&sei);
        }
    }
    
    ULONG CheckElevation()
    {
        HANDLE hToken;
        ULONG err = BTE(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken));
        if (!err)
        {
            ULONG cb = 0, rcb = 0x20;
            union {
                PTOKEN_USER ptu;
                PVOID buf;
            };
            static volatile UCHAR guz;
            PVOID stack = alloca(guz);
            PWSTR SzSid = 0;
    
            //++ for display user sid only
            do 
            {
                if (cb < rcb)
                {
                    cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
                }
    
                if (!(err = BTE(GetTokenInformation(hToken, ::TokenUser, buf, cb, &rcb))))
                {
                    ConvertSidToStringSidW(ptu->User.Sid, &SzSid);
                    break;
                }
    
            } while (err == ERROR_INSUFFICIENT_BUFFER);
            // -- for display user sid only
    
            union {
                TOKEN_ELEVATION te;
                TOKEN_ELEVATION_TYPE tet;
            };
    
            if (!(err = BTE(GetTokenInformation(hToken, ::TokenElevationType, &tet, sizeof(tet), &rcb))))
            {
                switch (tet)
                {
                case TokenElevationTypeDefault:
                    if (!(err = BTE(GetTokenInformation(hToken, ::TokenElevation, &te, sizeof(te), &rcb))))
                    {
                        if (te.TokenIsElevated)
                        {
                            // we are built-in admin or UAC is disabled in system
                case TokenElevationTypeFull:
                    MessageBoxW(HWND_DESKTOP, L"we run elevated", SzSid, MB_ICONINFORMATION);
                    break;
                        }
    
                        // we can not elevate under same user, but still can elevate under another admin account
                        // non admin account
                        TryElevate();
                        MessageBoxW(HWND_DESKTOP, L"Default", SzSid, MB_ICONINFORMATION);
                    }
    
                    break;
    
    
                case TokenElevationTypeLimited:
                    // this mean that we have linked token, which is elevated. we can elevate under same user
                    TryElevate();
                    MessageBoxW(HWND_DESKTOP, L"Limited", SzSid, MB_ICONINFORMATION);
                    break;
    
                default:
                    MessageBoxW(HWND_DESKTOP, L"unknown elevation type", SzSid, MB_ICONWARNING);
                    err = ERROR_GEN_FAILURE;
                }
            }
    
            if (SzSid) LocalFree(SzSid);
    
            CloseHandle(hToken);
        }
    
        return err;
    }
    

    and result:

    enter image description here