Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check whether a Windows user has admin privileges in C?

Is there any way of conditionally checking (strictly in C) whether a Windows user has administrator privileges or not?

I wish to do this programmatically (not simply telling the user to "Run as Administrator").

like image 825
Neeraj Barnwal Avatar asked May 11 '12 12:05

Neeraj Barnwal


People also ask

How do I check if a Windows user is Administrator?

Select Start, and type Control Panel. In the Control Panel window, select User Accounts > Change your account type. In the User Accounts window, select Properties and then select the Group Membership tab. Make sure Administrator is selected.

How do I check if a user has admin rights?

Open Control Panel, and then go to User Accounts > User Accounts. 2. Now you will see your current logged-on user account display on the right side. If your account has administrator rights, you can see the word "Administrator" under your account name.


2 Answers

There are a couple of fundamentally different ways. The most common is, unfortunately, rather tedious. It involves finding the current user's SID, then finding the groups to which he belongs, and then finding whether one of them is the Administrators group:

#include <windows.h> 
#include <vector>

bool is_administrator() { 
    HANDLE access_token; 
    DWORD buffer_size = 0; 
    PSID admin_SID; 
    TOKEN_GROUPS *group_token = NULL; 
    SID_IDENTIFIER_AUTHORITY NT_authority = SECURITY_NT_AUTHORITY; 

    if (!OpenProcessToken(GetCurrentProcess(),TOKEN_READ,&access_token)) 
        return false; 

    GetTokenInformation( 
        access_token, 
        TokenGroups, 
        group_token, 
        0, 
        &buffer_size 
        ); 

    std::vector<char> buffer(buffer_size);

    group_token = 
        reinterpret_cast<TOKEN_GROUPS*>(&buffer[0]); 

    bool succeeded = GetTokenInformation( 
        access_token, 
        TokenGroups, 
        group_token, 
        buffer_size, 
        &buffer_size 
        ); 

    CloseHandle(access_token); 
    if (!succeeded) 
        return false;

    if (!AllocateAndInitializeSid( 
        &NT_authority, 
        2, 
        SECURITY_BUILTIN_DOMAIN_RID, 
        DOMAIN_ALIAS_RID_ADMINS, 
        0,0,0,0,0,0, 
        &admin_SID 
        )) 
    {
        return false; 
    }

    bool found=false; 
    for(int i=0; !found && i < group_token->GroupCount; i++) 
        found = EqualSid(admin_SID,group_token->Groups[i].Sid); 
    FreeSid(admin_SID); 
    return found; 
} 

There's another way that's a bit simpler though:

bool is_administrator() 
{ 
        bool result; 
        DWORD rc; 
        wchar_t user_name[256]; 
        USER_INFO_1 *info; 
        DWORD size = sizeof( user_name ); 
        GetUserNameW( user_name, &size); 
        rc = NetUserGetInfo( NULL, user_name, 1, (byte **) &info ); 
        if ( rc != NERR_Success ) 
                return false; 
        result = info->usri1_priv == USER_PRIV_ADMIN; 
        NetApiBufferFree( info ); 
        return result; 
} 

In either case, if you have a domain, things can be a little hairy, because a particular user might be an administrator on the local machine, but not on the domain, or vice versa. Finding the info doesn't necessarily change much, but you may have to think a bit to figure out what you really want.

Edit: As @Benj pointed out, the first method could really use a bit of updating. While I already fixed the obvious leak it had, it's still a huge, monolithic function with no exception safety, and generally rather outdated coding style. Perhaps a small update is in order:

#include <windows.h> 
#include <vector>
#include <algorithm>

class sid {
    PSID s;
public:
    sid(SID_IDENTIFIER_AUTHORITY auth, std::vector<DWORD> sub_auths) {
        DWORD count = sub_auths.size();
        sub_auths.resize(7, DWORD());

        if (!AllocateAndInitializeSid( 
            &auth,
            count, 
            sub_auths[0], sub_auths[1], sub_auths[2], sub_auths[3],
            sub_auths[4], sub_auths[5], sub_auths[6], sub_auths[7],
            &s 
            )) 
        {
            throw std::runtime_error("Unable to allocate Admin SID");
        }
    }

    sid(PSID const &p=NULL) : s(p) {}
    bool operator==(sid const &r) const { return EqualSid(s, r.s); }
};

class access_token {
    HANDLE token;
public:
    access_token(HANDLE PID=GetCurrentProcess(), DWORD access=TOKEN_READ) {
        if (!OpenProcessToken(PID, access, &token))
            throw std::runtime_error("Unable to open process token");
    }
    operator HANDLE() { return token; }
    ~access_token() { CloseHandle(token); }
};

std::vector<sid> get_group_sids() {
    DWORD buffer_size = 0; 
    TOKEN_GROUPS *group_token = NULL; 
    std::vector<sid> groups;
    access_token token;

    GetTokenInformation(token, TokenGroups, group_token, 0, &buffer_size);

    std::vector<char> buffer(buffer_size);

    group_token = reinterpret_cast<TOKEN_GROUPS*>(&buffer[0]);

    if (GetTokenInformation(token, TokenGroups, group_token, buffer_size, &buffer_size))
        for (int i=0; i<group_token->GroupCount; i++)
            groups.push_back(group_token->Groups[i].Sid);
    return groups;
}

bool is_administrator() {
    std::vector<sid> groups = get_group_sids();

    SID_IDENTIFIER_AUTHORITY NT_authority = SECURITY_NT_AUTHORITY;
    std::vector<DWORD> sub_auths;

    sub_auths.push_back(SECURITY_BUILTIN_DOMAIN_RID);
    sub_auths.push_back(DOMAIN_ALIAS_RID_ADMINS);

    sid admin_SID(NT_authority, sub_auths);

    return std::find(groups.begin(), groups.end(), admin_SID) != groups.end();
}

#ifdef TEST
#include <iostream>
#include <iomanip>

int main() {
    std::cout << std::boolalpha << is_administrator() << "\n";
}

#endif
like image 171
Jerry Coffin Avatar answered Oct 21 '22 09:10

Jerry Coffin


A slightly different (and shorter? easier?) method adapted from some hints on MSDN:

PSID administrators_group = NULL;
SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;
BOOL result = AllocateAndInitializeSid( &nt_authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &administrators_group);
BOOL is_user_admin = FALSE;
if (result)
{
    CheckTokenMembership(NULL, administrators_group, &is_user_admin);
    FreeSid(administrators_group);
}

if (is_user_admin)
{
    // do something here for admin users...
}
like image 26
Stéphane Avatar answered Oct 21 '22 08:10

Stéphane