如何通过编程确定帐户是否属于管理员组?

问题描述:

我的Windows有几个帐户,如属于管理员组的“test1”,“test2”和“test3”。我正在开发一个应用程序,我希望该程序通过设计一个布尔函数来知道其本身是否属于管理员组的帐户下运行:isCurrentUserAdminMember()isCurrentUserAdminMember()函数只应返回TRUE if无论过程是否升高,该过程由“test1”,“test2”,“test3”或内置管理员帐户运行。如何通过编程确定帐户是否属于管理员组?

我发现http://www.codeproject.com/Articles/320748/Haephrati-Elevating-during-runtime中的一些代码如下,但它似乎只是检查当前进程是否升级为管理员。我不在乎流程是否升级,我只想知道流程的开始帐户是否是Administrators组的成员。我希望这个决心本身不是特权所要求的。那可能吗?谢谢。

BOOL IsAppRunningAsAdminMode() 
    { 
     BOOL fIsRunAsAdmin = FALSE; 
     DWORD dwError = ERROR_SUCCESS; 
     PSID pAdministratorsGroup = NULL; 

     // Allocate and initialize a SID of the administrators group. 
     SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; 
     if (!AllocateAndInitializeSid(
      &NtAuthority, 
      2, 
      SECURITY_BUILTIN_DOMAIN_RID, 
      DOMAIN_ALIAS_RID_ADMINS, 
      0, 0, 0, 0, 0, 0, 
      &pAdministratorsGroup)) 
     { 
      dwError = GetLastError(); 
      goto Cleanup; 
     } 

     // Determine whether the SID of administrators group is enabled in 
     // the primary access token of the process. 
     if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin)) 
     { 
      dwError = GetLastError(); 
      goto Cleanup; 
     } 

    Cleanup: 
     // Centralized cleanup for all allocated resources. 
     if (pAdministratorsGroup) 
     { 
      FreeSid(pAdministratorsGroup); 
      pAdministratorsGroup = NULL; 
     } 

     // Throw the error if something failed in the function. 
     if (ERROR_SUCCESS != dwError) 
     { 
      throw dwError; 
     } 

     return fIsRunAsAdmin; 
    } 

最后,我们实现了检查Administrators组成员身份下面的代码的目标,但它是USELESS作为答案和评论说,刚离开这里参考的情况下,任何人都需要它用于其他用途。

// PermTest.cpp : Defines the entry point for the console application. 
// 

#include "stdafx.h" 
#include "stdio.h" 
#include "iostream" 
using namespace std; 
#include "windows.h" 

#include <lm.h> 
#pragma comment(lib, "netapi32.lib") 

BOOL IsUserInGroup(const wchar_t* groupe) 
{ 
    BOOL result = FALSE; 
    SID_NAME_USE snu; 
    WCHAR szDomain[256]; 
    DWORD dwSidSize = 0; 
    DWORD dwSize = sizeof szDomain/sizeof * szDomain; 

    if ((LookupAccountNameW(NULL, groupe, 0, &dwSidSize, szDomain, &dwSize, &snu) == 0) 
     && (ERROR_INSUFFICIENT_BUFFER == GetLastError())) 
    { 
     SID* pSid = (SID*)malloc(dwSidSize); 

     if (LookupAccountNameW(NULL, groupe, pSid, &dwSidSize, szDomain, &dwSize, &snu)) 
     { 
      BOOL b; 

      if (CheckTokenMembership(NULL, pSid, &b)) 
      { 
       if (b == TRUE) 
       { 
        result = TRUE; 
       } 
      } 
      else 
      { 
       result = FALSE; 
      } 
     } 

     //Si tout vas bien (la presque totalitée des cas), on delete notre pointeur 
     //avec le bon operateur. 
     free(pSid); 
    } 

    return result; 
} 

void getUserInfo(WCHAR *domainName, WCHAR *userName) 
{ 
    LPUSER_INFO_3 pBuf = NULL; 
    int j = 0; 
    DWORD nStatus = NetUserGetInfo(domainName, userName, 3, (LPBYTE *) &pBuf); 

    LPUSER_INFO_2 pBuf2 = NULL; 
    pBuf2 = (LPUSER_INFO_2) pBuf; 
    if (pBuf) 
    { 
     wprintf(L"User account name: %s\\%s\n", domainName, pBuf2->usri2_name); 
     wprintf(L"Privilege level: %d\n\n", pBuf2->usri2_priv); 
    } 



// wprintf(L"\tPassword: %s\n", pBuf2->usri2_password); 
// wprintf(L"\tPassword age (seconds): %d\n", 
//  pBuf2->usri2_password_age); 
// wprintf(L"Privilege level: %d\n\n", pBuf2->usri2_priv); 
// #define USER_PRIV_GUEST  0 
// #define USER_PRIV_USER  1 
// #define USER_PRIV_ADMIN  2 

// wprintf(L"\tHome directory: %s\n", pBuf2->usri2_home_dir); 
// wprintf(L"\tComment: %s\n", pBuf2->usri2_comment); 
// wprintf(L"\tFlags (in hex): %x\n", pBuf2->usri2_flags); 
// wprintf(L"\tScript path: %s\n", pBuf2->usri2_script_path); 
// wprintf(L"\tAuth flags (in hex): %x\n", 
//  pBuf2->usri2_auth_flags); 
// wprintf(L"\tFull name: %s\n", pBuf2->usri2_full_name); 
// wprintf(L"\tUser comment: %s\n", pBuf2->usri2_usr_comment); 
// wprintf(L"\tParameters: %s\n", pBuf2->usri2_parms); 
// wprintf(L"\tWorkstations: %s\n", pBuf2->usri2_workstations); 
// wprintf 
//  (L"\tLast logon (seconds since January 1, 1970 GMT): %d\n", 
//  pBuf2->usri2_last_logon); 
// wprintf 
//  (L"\tLast logoff (seconds since January 1, 1970 GMT): %d\n", 
//  pBuf2->usri2_last_logoff); 
// wprintf 
//  (L"\tAccount expires (seconds since January 1, 1970 GMT): %d\n", 
//  pBuf2->usri2_acct_expires); 
// wprintf(L"\tMax storage: %d\n", pBuf2->usri2_max_storage); 
// wprintf(L"\tUnits per week: %d\n", 
//  pBuf2->usri2_units_per_week); 
// wprintf(L"\tLogon hours:"); 
// for (j = 0; j < 21; j++) 
// { 
//  printf(" %x", (BYTE) pBuf2->usri2_logon_hours[j]); 
// } 
// wprintf(L"\n"); 
// wprintf(L"\tBad password count: %d\n", 
//  pBuf2->usri2_bad_pw_count); 
// wprintf(L"\tNumber of logons: %d\n", 
//  pBuf2->usri2_num_logons); 
// wprintf(L"\tLogon server: %s\n", pBuf2->usri2_logon_server); 
// wprintf(L"\tCountry code: %d\n", pBuf2->usri2_country_code); 
// wprintf(L"\tCode page: %d\n", pBuf2->usri2_code_page); 
} 

#include <comdef.h> 
#define MAX_NAME 256 
BOOL GetLogonFromToken (HANDLE hToken, _bstr_t& strUser, _bstr_t& strdomain) 
{ 
    DWORD dwSize = MAX_NAME; 
    BOOL bSuccess = FALSE; 
    DWORD dwLength = 0; 
    strUser = ""; 
    strdomain = ""; 
    PTOKEN_USER ptu = NULL; 
    //Verify the parameter passed in is not NULL. 
    if (NULL == hToken) 
     goto Cleanup; 

    if (!GetTokenInformation(
     hToken,   // handle to the access token 
     TokenUser, // get information about the token's groups 
     (LPVOID) ptu, // pointer to PTOKEN_USER buffer 
     0,    // size of buffer 
     &dwLength  // receives required buffer size 
     )) 
    { 
     if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 
      goto Cleanup; 

     ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), 
      HEAP_ZERO_MEMORY, dwLength); 

     if (ptu == NULL) 
      goto Cleanup; 
    } 

    if (!GetTokenInformation(
     hToken,   // handle to the access token 
     TokenUser, // get information about the token's groups 
     (LPVOID) ptu, // pointer to PTOKEN_USER buffer 
     dwLength,  // size of buffer 
     &dwLength  // receives required buffer size 
     )) 
    { 
     goto Cleanup; 
    } 
    SID_NAME_USE SidType; 
    char lpName[MAX_NAME]; 
    char lpDomain[MAX_NAME]; 

    if(!LookupAccountSidA(NULL , ptu->User.Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType))          
    { 
     DWORD dwResult = GetLastError(); 
     if(dwResult == ERROR_NONE_MAPPED) 
      strcpy (lpName, "NONE_MAPPED"); 
     else 
     { 
      printf("LookupAccountSid Error %u\n", GetLastError()); 
     } 
    } 
    else 
    { 
//  printf("Current user is %s\\%s\n", 
//   lpDomain, lpName); 
     strUser = lpName; 
     strdomain = lpDomain; 
     bSuccess = TRUE; 
    } 

Cleanup: 

    if (ptu != NULL) 
     HeapFree(GetProcessHeap(), 0, (LPVOID)ptu); 
    return bSuccess; 
} 

HRESULT GetUserFromProcess(_bstr_t& strUser, _bstr_t& strdomain) 
{ 
    //HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,procId); 
    HANDLE hProcess = GetCurrentProcess(); 
    if(hProcess == NULL) 
     return E_FAIL; 
    HANDLE hToken = NULL; 

    if(!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) 
    { 
     CloseHandle(hProcess); 
     return E_FAIL; 
    } 
    BOOL bres = GetLogonFromToken (hToken, strUser, strdomain); 

    CloseHandle(hToken); 
    CloseHandle(hProcess); 
    return bres?S_OK:E_FAIL; 
} 



int _tmain(int argc, _TCHAR* argv[]) 
{ 
    //cout << IsUserInGroup(L"administrators"); 


    getUserInfo(L"adtest.net", L"Administrator"); 
    getUserInfo(NULL, L"Administrator"); 
    getUserInfo(NULL, L"test"); 
    getUserInfo(NULL, L"test2"); 
    getUserInfo(NULL, L"testnormal"); 

    _bstr_t username; 
    _bstr_t domain; 
    GetUserFromProcess(username, domain); 
    cout << "Current account running this program is: " << endl << domain << "\\" << username << endl; 

    getchar(); 
    return 0; 
} 
+1

为什么你需要这个?知道调用过程是否以管理员用户身份运行几乎是没有用的,特别是在UAC中管理员用户没有完全管理权限而没有提升的情况下。如果您需要执行需要管理员权限的特定操作,则只需执行该操作,并在需要时让其失败。您可以检测到错误并将其报告给用户,并在需要时提示提升。 –

+0

非常合理,我们最终使用UAC方式,让动作失败并显示UAC。 – hsluoyz

您可以通过打开你的进程令牌(OpenProcessToken,使用GetTokenInformation上市的SID和比较各个SID到Administrators SID做到这一点

微软在这里的示例代码:Searching for a SID in an Access Token in C++

然而,这很少有用,即使用户不是管理员组的成员,他们仍然可以通过提供管理用户名和密码来升级,所以不应该(例如)只在用户处于管理员组

+0

我刚刚使用另一种方式作为补充说,我首先使用** GetTokenInformation **获取帐户名称,然后使用** NetUserGetInfo **获取其特权级别,此方法更好,因为此方法也适用于Domain Admins 。缺点是它只能检查管理员,而不是普通的组。对于普通团体会员检查,你的方法更好。无论如何,这种方法毫无意义,正如你所说的,最后我们选择检查特权管理员权限,而不仅仅是管理员组成员,谢谢! – hsluoyz

+0

在一般情况下使用NetUserGetInfo会很棘手 - 您首先必须识别用户帐户所在的域,然后找到域控制器。我认为它只会确定帐户是否在域中享有特权,而不是在本地机器上享有特权,尽管我不确定这一点。我认为要更容易地枚举令牌中的组,并且不依赖于网络。但最简单的是检查高程。 :-) –

bool IsMemberOfGroup(const char *pszGroupName){ 
bool bFound = false; 

HANDLE hToken=INVALID_HANDLE_VALUE; 
BOOL bSuccess = OpenProcessToken(GetCurrentProcess(), 
            TOKEN_QUERY,//|TOKEN_QUERY_SOURCE, 
            &hToken); 
if (bSuccess) 
{ 
    DWORD dwSizeToken=0; 
    DWORD dwSizeName=0; 
    DWORD dwSizeReferencedDomainName = 0; 
    // Get group information: 
    GetTokenInformation(hToken, TokenGroups, NULL, dwSizeToken, &dwSizeToken); 
    { 
     const int MAX_NAME = 256; 
     char *psName = new char[MAX_NAME]; 
     char *psDomain = new char[MAX_NAME]; 
     char *pBuf = new char[dwSizeToken+10]; 
     TOKEN_GROUPS *pGroupInfo = (TOKEN_GROUPS *)pBuf; 
     bSuccess = GetTokenInformation(hToken, TokenGroups, pGroupInfo, dwSizeToken, &dwSizeToken); 
     if (bSuccess) 
     { 
      // find the group name we are looking for 
      for (UINT uiGroupNdx = 0; uiGroupNdx < pGroupInfo->GroupCount && !bFound; uiGroupNdx++) 
      { 
       SID_NAME_USE SidType; 
       dwSizeName = MAX_NAME; 
       dwSizeReferencedDomainName = MAX_NAME; 

       bSuccess = LookupAccountSid(NULL, // local system, 
              pGroupInfo->Groups[uiGroupNdx].Sid, 
              psName, 
              &dwSizeName, 
              psDomain, 
              &dwSizeReferencedDomainName, 
              &SidType); 
       if (bSuccess) 
       { 
        if (SidTypeGroup == SidType) 
        { 
         if (!lstrcmpi(pszGroupName, psName)) 
         { 
          bFound = true; 
         } 
        } 
       } 
      } 
     } 

     delete [] pBuf; 
     delete [] psName; 
     delete [] psDomain; 
    } 

    CloseHandle(hToken); 
} 

return bFound; 
}