2012-05-11 2 views

답변

3

물론 당신이 호출 할 필요가 :

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() 

공동 mpare 귀하의 로컬 그룹에있는 SID와 SID.

+0

감사합니다 , 이것이 도움이되었지만, 처음에는 GetTokenInformation에 대한 첫 번째 호출이 오류를 반환한다는 것이 확인되지 않았습니다. 나는 GetLastError() == ERROR_INSUFFICIENT_MEMORY를 확인한다. – TBD

+1

이것은 실제로 Win32 프로그래밍에서 실제로 일반적으로 사용되는 패턴입니다. API가 두 번 호출되는 것을 볼 때마다, NULL로 처음으로 첫 번째 호출이 두 번째 호출에 적합한 메모리를 할당 할 수 있도록 크기를 얻는 경우가 일반적입니다. – Benj

6

근본적으로 다른 두 가지 방법이 있습니다. 가장 일반적 인 은 불행히도 다소 지루합니다. 그런 다음 그룹을 발견, 현재 사용자의 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, 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 
+0

첫 번째 예에서 'new char [buffer_size]'는 어디에서 삭제됩니까? – Benj

+0

'벡터 ' – Benj

+1

@Benj : Done에 항상 빠른 모드를 줄 수 있습니다. 훨씬 더 예쁘지 만 적어도 그만큼 나쁘지는 않았을 것입니다 ... –

-3

당신은 shell32를

+0

UAC가 설정된 Win8/10에서 IsUserAnAdmin이 Administrators 그룹의 구성원 인 사용자를 올바르게 식별하지 못합니다. – jeffm

4

약간 다른에서 IsUserAnAdmin를 사용해야합니다 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... 
} 
+0

테스트하지는 않았지만 UAC 사용 가능 컴퓨터에서 작동하는지 여부를 알면 UAC 권한 상승을 확인해야하며 관리자 그룹 구성원 일 필요는 없습니다. – TaterJuice

관련 문제