How to determine if an account belongs to Administrators group programmatically?

2.7k views Asked by At

My Windows has several accounts like "test1", "test2" and "test3" that belong to the Administrators group. I am developing an application program and I want that program to know if itself is run under an account that belong to the Administrators group by designing a boolean function: isCurrentUserAdminMember(), the isCurrentUserAdminMember() funtion should only return TRUE if the process is run by "test1", "test2", "test3" or the built-in Administrator account no matter whether the process is elevated.

I found some code in http://www.codeproject.com/Articles/320748/Haephrati-Elevating-during-runtime as below, but it seems only to check if the current process is elevated as an Administrator. I don't care if the process is elevated, I just want to know if the start account of the process is a member of Administrators group. And I hope the determination itself is not privilege required. Is that possible? thanks.

    BOOL IsAppRunningAsAdminMode()
    {
        BOOL fIsRunAsAdmin = FALSE;
        DWORD dwError = ERROR_SUCCESS;
        PSID pAdministratorsGroup = NULL;

        // Allocate and initialize a SID of the administrators group.
        SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
        if (!AllocateAndInitializeSid(
            &NtAuthority, 
            2, 
            SECURITY_BUILTIN_DOMAIN_RID, 
            DOMAIN_ALIAS_RID_ADMINS, 
            0, 0, 0, 0, 0, 0, 
            &pAdministratorsGroup))
        {
            dwError = GetLastError();
            goto Cleanup;
        }

        // Determine whether the SID of administrators group is enabled in 
        // the primary access token of the process.
        if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin))
        {
            dwError = GetLastError();
            goto Cleanup;
        }

    Cleanup:
        // Centralized cleanup for all allocated resources.
        if (pAdministratorsGroup)
        {
            FreeSid(pAdministratorsGroup);
            pAdministratorsGroup = NULL;
        }

        // Throw the error if something failed in the function.
        if (ERROR_SUCCESS != dwError)
        {
            throw dwError;
        }

        return fIsRunAsAdmin;
    }

At last, we achieved the goal to check the Administrators group membership as the code below, however it is USELESS as the answer and comment said, just leave here for reference in case anybody needs it for other use.

// PermTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "stdio.h"
#include "iostream"
using namespace std;
#include "windows.h"

#include <lm.h>
#pragma comment(lib, "netapi32.lib")

BOOL IsUserInGroup(const wchar_t* groupe)
{
    BOOL result = FALSE;
    SID_NAME_USE snu;
    WCHAR szDomain[256];
    DWORD dwSidSize = 0;
    DWORD dwSize = sizeof szDomain / sizeof * szDomain;

    if ((LookupAccountNameW(NULL, groupe, 0, &dwSidSize, szDomain, &dwSize, &snu) == 0)
        && (ERROR_INSUFFICIENT_BUFFER == GetLastError()))
    {
        SID* pSid = (SID*)malloc(dwSidSize);

        if (LookupAccountNameW(NULL, groupe, pSid, &dwSidSize, szDomain, &dwSize, &snu))
        {
            BOOL b;

            if (CheckTokenMembership(NULL, pSid, &b))
            {
                if (b == TRUE)
                {
                    result = TRUE;
                }
            }
            else
            {
                result = FALSE;
            }
        }

        //Si tout vas bien (la presque totalitée des cas), on delete notre pointeur
        //avec le bon operateur.
        free(pSid);
    }

    return result;
}

void getUserInfo(WCHAR *domainName, WCHAR *userName)
{
    LPUSER_INFO_3 pBuf = NULL;
    int j = 0;
    DWORD nStatus = NetUserGetInfo(domainName, userName, 3, (LPBYTE *) &pBuf);

    LPUSER_INFO_2 pBuf2 = NULL;
    pBuf2 = (LPUSER_INFO_2) pBuf;
    if (pBuf)
    {
        wprintf(L"User account name: %s\\%s\n", domainName, pBuf2->usri2_name);
        wprintf(L"Privilege level: %d\n\n", pBuf2->usri2_priv);
    }



//  wprintf(L"\tPassword: %s\n", pBuf2->usri2_password);
//  wprintf(L"\tPassword age (seconds): %d\n",
//      pBuf2->usri2_password_age);
//  wprintf(L"Privilege level: %d\n\n", pBuf2->usri2_priv);
// #define USER_PRIV_GUEST     0
// #define USER_PRIV_USER      1
// #define USER_PRIV_ADMIN     2

//  wprintf(L"\tHome directory: %s\n", pBuf2->usri2_home_dir);
//  wprintf(L"\tComment: %s\n", pBuf2->usri2_comment);
//  wprintf(L"\tFlags (in hex): %x\n", pBuf2->usri2_flags);
//  wprintf(L"\tScript path: %s\n", pBuf2->usri2_script_path);
//  wprintf(L"\tAuth flags (in hex): %x\n",
//      pBuf2->usri2_auth_flags);
//  wprintf(L"\tFull name: %s\n", pBuf2->usri2_full_name);
//  wprintf(L"\tUser comment: %s\n", pBuf2->usri2_usr_comment);
//  wprintf(L"\tParameters: %s\n", pBuf2->usri2_parms);
//  wprintf(L"\tWorkstations: %s\n", pBuf2->usri2_workstations);
//  wprintf
//      (L"\tLast logon (seconds since January 1, 1970 GMT): %d\n",
//      pBuf2->usri2_last_logon);
//  wprintf
//      (L"\tLast logoff (seconds since January 1, 1970 GMT): %d\n",
//      pBuf2->usri2_last_logoff);
//  wprintf
//      (L"\tAccount expires (seconds since January 1, 1970 GMT): %d\n",
//      pBuf2->usri2_acct_expires);
//  wprintf(L"\tMax storage: %d\n", pBuf2->usri2_max_storage);
//  wprintf(L"\tUnits per week: %d\n",
//      pBuf2->usri2_units_per_week);
//  wprintf(L"\tLogon hours:");
//  for (j = 0; j < 21; j++) 
//  {
//      printf(" %x", (BYTE) pBuf2->usri2_logon_hours[j]);
//  }
//  wprintf(L"\n");
//  wprintf(L"\tBad password count: %d\n",
//      pBuf2->usri2_bad_pw_count);
//  wprintf(L"\tNumber of logons: %d\n",
//      pBuf2->usri2_num_logons);
//  wprintf(L"\tLogon server: %s\n", pBuf2->usri2_logon_server);
//  wprintf(L"\tCountry code: %d\n", pBuf2->usri2_country_code);
//  wprintf(L"\tCode page: %d\n", pBuf2->usri2_code_page);
}

#include <comdef.h>
#define MAX_NAME 256
BOOL GetLogonFromToken (HANDLE hToken, _bstr_t& strUser, _bstr_t& strdomain) 
{
    DWORD dwSize = MAX_NAME;
    BOOL bSuccess = FALSE;
    DWORD dwLength = 0;
    strUser = "";
    strdomain = "";
    PTOKEN_USER ptu = NULL;
    //Verify the parameter passed in is not NULL.
    if (NULL == hToken)
        goto Cleanup;

    if (!GetTokenInformation(
        hToken,         // handle to the access token
        TokenUser,    // get information about the token's groups 
        (LPVOID) ptu,   // pointer to PTOKEN_USER buffer
        0,              // size of buffer
        &dwLength       // receives required buffer size
        )) 
    {
        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 
            goto Cleanup;

        ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
            HEAP_ZERO_MEMORY, dwLength);

        if (ptu == NULL)
            goto Cleanup;
    }

    if (!GetTokenInformation(
        hToken,         // handle to the access token
        TokenUser,    // get information about the token's groups 
        (LPVOID) ptu,   // pointer to PTOKEN_USER buffer
        dwLength,       // size of buffer
        &dwLength       // receives required buffer size
        )) 
    {
        goto Cleanup;
    }
    SID_NAME_USE SidType;
    char lpName[MAX_NAME];
    char lpDomain[MAX_NAME];

    if( !LookupAccountSidA( NULL , ptu->User.Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType ) )                                    
    {
        DWORD dwResult = GetLastError();
        if( dwResult == ERROR_NONE_MAPPED )
            strcpy (lpName, "NONE_MAPPED" );
        else 
        {
            printf("LookupAccountSid Error %u\n", GetLastError());
        }
    }
    else
    {
//      printf( "Current user is  %s\\%s\n", 
//          lpDomain, lpName );
        strUser = lpName;
        strdomain = lpDomain;
        bSuccess = TRUE;
    }

Cleanup: 

    if (ptu != NULL)
        HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
    return bSuccess;
}

HRESULT GetUserFromProcess( _bstr_t& strUser, _bstr_t& strdomain)
{
    //HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,procId); 
    HANDLE hProcess = GetCurrentProcess();
    if(hProcess == NULL)
        return E_FAIL;
    HANDLE hToken = NULL;

    if( !OpenProcessToken( hProcess, TOKEN_QUERY, &hToken ) )
    {
        CloseHandle( hProcess );
        return E_FAIL;
    }
    BOOL bres = GetLogonFromToken (hToken, strUser,  strdomain);

    CloseHandle( hToken );
    CloseHandle( hProcess );
    return bres?S_OK:E_FAIL;
}



int _tmain(int argc, _TCHAR* argv[])
{
    //cout << IsUserInGroup(L"administrators");


    getUserInfo(L"adtest.net", L"Administrator");
    getUserInfo(NULL, L"Administrator");
    getUserInfo(NULL, L"test");
    getUserInfo(NULL, L"test2");
    getUserInfo(NULL, L"testnormal");

    _bstr_t username;
    _bstr_t domain;
    GetUserFromProcess(username, domain);
    cout << "Current account running this program is: " << endl << domain << "\\" << username << endl;

    getchar();
    return 0;
}
2

There are 2 answers

2
Harry Johnston On BEST ANSWER

You can do this by opening your process token (OpenProcessToken, listing the SIDs using GetTokenInformation and comparing each SID to the Administrators SID.

Microsoft have sample code here: Searching for a SID in an Access Token in C++

However, this is rarely a useful thing to do. Even if the user is not a member of the Administrators group, they can still elevate by providing an administrative username and password, so you should not (for example) only offer elevation if the user is in the Administrators group.

0
JanO On
bool IsMemberOfGroup(const char *pszGroupName){
bool bFound = false;

HANDLE hToken=INVALID_HANDLE_VALUE;
BOOL bSuccess = OpenProcessToken( GetCurrentProcess(),
                                    TOKEN_QUERY,//|TOKEN_QUERY_SOURCE,
                                    &hToken);
if ( bSuccess )
{
    DWORD   dwSizeToken=0;
    DWORD   dwSizeName=0;
    DWORD   dwSizeReferencedDomainName = 0;
    // Get group information:
    GetTokenInformation(hToken, TokenGroups, NULL, dwSizeToken, &dwSizeToken);
    {
        const int MAX_NAME = 256;
        char *psName    = new char[MAX_NAME];
        char *psDomain  = new char[MAX_NAME];
        char *pBuf = new char[dwSizeToken+10];
        TOKEN_GROUPS *pGroupInfo = (TOKEN_GROUPS *)pBuf;
        bSuccess = GetTokenInformation(hToken, TokenGroups, pGroupInfo, dwSizeToken, &dwSizeToken);
        if ( bSuccess )
        {
            // find the group name we are looking for
            for ( UINT uiGroupNdx = 0; uiGroupNdx < pGroupInfo->GroupCount && !bFound; uiGroupNdx++ )
            {
                SID_NAME_USE    SidType;
                dwSizeName = MAX_NAME;
                dwSizeReferencedDomainName = MAX_NAME;

                bSuccess = LookupAccountSid(NULL,   // local system,
                                            pGroupInfo->Groups[uiGroupNdx].Sid,
                                            psName,
                                            &dwSizeName,
                                            psDomain,
                                            &dwSizeReferencedDomainName,
                                            &SidType);
                if ( bSuccess )
                {
                    if ( SidTypeGroup == SidType )
                    {
                        if ( !lstrcmpi(pszGroupName, psName) )
                        {
                            bFound = true;
                        }
                    }
                }
            }
        }

        delete [] pBuf;
        delete [] psName;
        delete [] psDomain;
    }

    CloseHandle(hToken);
}

return bFound;
}