How to check if a Windows user has administrative rights in C?

Is there a way to conditionally check (strictly in C) whether the Windows user has administrator rights or not?

I want to do this programmatically (not just telling the user "Run as administrator").

+4
source share
4 answers

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 
+6
source

A slightly different (and shorter? Simpler?) Method, adapted from some MSDN tips:

 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... } 
+4
source

Of course you need to call:

 OpenThreadToken() 

To get a user token.

 GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwNeeded) 

To get the size of the marker group information (and allocate enough space)

 GetTokenInformation(hToken, TokenGroups, pTokenGroups, dwSize, &dwNeeded) 

To get local groups

 AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdministrators); 

To get the administrator SID

 EqualSid() 

To compare this SID with the SIDs in your local groups.

+3
source

You must use IsUserAnAdmin from SHELL32

-3
source

Source: https://habr.com/ru/post/1411975/


All Articles