有没有什么方法有条件地检查(严格用C)Windows用户是否有pipe理员权限?
我希望以编程方式执行此操作(而不是简单地告诉用户“以pipe理员身份运行”)。
有几个根本不同的方法。 最常见的是,不幸的是,相当乏味。 它涉及到查找当前用户的SID,然后查找他所属的组,然后查找其中的一个是否是Administrators组:
#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; }
还有另外一种方法可以更简单一些:
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; }
在任何一种情况下,如果你有一个域名,事情会变得有点多毛,因为一个特定的用户可能是本地机器上的管理员,而不是域名,反之亦然。 查找信息并不一定会有太大的变化,但是您可能需要考虑一下才能确定您真正想要的内容。
编辑:正如@Benj指出的,第一种方法可以真正使用一点更新。 虽然我已经修复了明显的漏洞,但它仍然是一个巨大的,单一的功能,没有任何异常的安全性,而且通常是过时的编码风格。 也许一个小小的更新是为了:
#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
从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... }
当然你需要打电话给:
OpenThreadToken()
获取用户的令牌。
GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwNeeded)
要获得令牌组信息的大小(并分配足够的空间)
GetTokenInformation(hToken, TokenGroups, pTokenGroups, dwSize, &dwNeeded)
得到当地的团体
AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdministrators);
获取管理员的SID
EqualSid()
将SID与本地组中的SID进行比较。
您应该使用SHELL32中的IsUserAnAdmin