There are several fundamentally different ways. The most common unfortunately is quite tiring. This includes finding the current SID of the user, then find the groups to which he belongs, and then find if 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 is another way that is a bit simpler:
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 any case, if you have a domain, everything can be a little hairy, because a specific user can be a local administrator but not in a domain, or vice versa. Finding information does not necessarily change much, but you may have to think a bit to find out what you really want.
Edit: As @Benj pointed out, the first method can really use the update bit. Although I had already fixed the obvious leak, it was still a huge, monolithic function with no exception safety and generally a rather outdated coding style. Perhaps a small update is fine:
#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, rs); } }; 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