Delphi - 如果是管理员,如何检查任何Windows用户?

时间:2017-07-25 13:24:19

标签: windows delphi winapi

我需要检查本地计算机上可用的帐户类型。

我已经找到了如何为当前登录的用户执行此操作:

function IsWindowsAdmin: Boolean;
var
   hAccessToken: THandle;
   ptgGroups: PTokenGroups;
   dwInfoBufferSize: DWORD;
   psidAdministrators: PSID;
   g: Integer;
   bSuccess: BOOL;
begin
   Result:= False;
   bSuccess:= OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, hAccessToken);
   if not bSuccess then
   begin
     if GetLastError = ERROR_NO_TOKEN then
       bSuccess:= OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, hAccessToken);
   end;

   if bSuccess then
   begin
     GetMem(ptgGroups, 1024);
     bSuccess:= GetTokenInformation(hAccessToken, TokenGroups, ptgGroups, 1024, dwInfoBufferSize);
     CloseHandle(hAccessToken);
     if bSuccess then
     begin
       AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2,
                                SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
                                0, 0, 0, 0, 0, 0, psidAdministrators);
       for g:= 0 to ptgGroups.GroupCount - 1 do
         if EqualSid(psidAdministrators, ptgGroups.Groups[g].Sid) then
         begin
           Result:= True;
           Break;
         end;
       FreeSid(psidAdministrators);
     end;
     FreeMem(ptgGroups);
   end;
end;

我还找到了如何让所有用户都在本地计算机上。是否可以检查任何用户是管理员还是有限帐户而无需登录每个用户?

1 个答案:

答案 0 :(得分:8)

以下是我对此主题的看法,感谢Sertac Akyuz提供NetUserEnum USER_INFO_2请求和结构的提示。

我们可以请求具有以下权限级别的用户

const
  USER_PRIV_GUEST = 0;
  USER_PRIV_USER  = 1;
  USER_PRIV_ADMIN = 2;
  USER_PRIV_ANY   = 3; // own invention

type
  TPrivLevel = USER_PRIV_GUEST..USER_PRIV_ANY;

我们需要的一些声明

const
  // some consts
  NERR_Success = 0;
  MAX_PREFERRED_LENGTH = $FFFFFFFF;

type
  NetApiStatus = DWORD;

// https://msdn.microsoft.com/en-us/library/windows/desktop/aa371337(v=vs.85).aspx
  TUserInfo2 = record
    usri2_name: LPWSTR ;
    usri2_password: LPWSTR ;
    usri2_password_age: DWORD  ;
    usri2_priv: DWORD  ;
    usri2_home_dir: LPWSTR ;
    usri2_comment: LPWSTR ;
    usri2_flags: DWORD  ;
    usri2_script_path: LPWSTR ;
    usri2_auth_flags: DWORD  ;
    usri2_full_name: LPWSTR ;
    usri2_usr_comment: LPWSTR ;
    usri2_parms: LPWSTR ;
    usri2_workstations: LPWSTR ;
    usri2_last_logon: DWORD  ;
    usri2_last_logoff: DWORD  ;
    usri2_acct_expires: DWORD  ;
    usri2_max_storage: DWORD  ;
    usri2_units_per_week: DWORD  ;
    usri2_logon_hours: PBYTE  ;
    usri2_bad_pw_count: DWORD  ;
    usri2_num_logons: DWORD  ;
    usri2_logon_server: LPWSTR ;
    usri2_country_code: DWORD  ;
    usri2_code_page: DWORD  ;
  end;
  PUSER_INFO_2 = ^TUserInfo2;
  LPUSER_INFO_2 = ^TUserInfo2;


// https://msdn.microsoft.com/en-us/library/windows/desktop/aa370304(v=vs.85).aspx
function NetApiBufferFree (Buffer: Pointer): NetApiStatus ;
                     stdcall; external 'netapi32.dll';

// https://msdn.microsoft.com/en-us/library/windows/desktop/aa370652%28v=vs.85%29.aspx
function NetUserEnum(
  servername: LPCWSTR;
  level: DWORD;
  filter: DWORD;
  var bufptr: pointer;
  prefmaxlen: DWORD;
  var entriesread: DWORD;
  var totalentries: DWORD;
  resume_handle: LPDWORD
): NetApiStatus; stdcall; external 'netapi32.dll';

PrivLevel是您要求用户和权限的权限级别的过程 users是要填充用户名的TStringList

function GetUsers(PrivLevel: TPrivLevel; users: TStrings): integer;
var
  i: integer;
  NetApiStatus: DWORD;
  bufptr: pointer;
  recptr: PUSER_INFO_2;
  EntriesRead,
  TotalEntries,
  HResume: DWORD;
begin
  HResume := 0;

  repeat
    NetApiStatus := NetUserEnum(
      nil,                         // local
      2,                           // USER_INFO_2
      0,                           // no special filter
      bufptr,
      MAX_PREFERRED_LENGTH,
      EntriesRead,
      TotalEntries,
      @HResume
    );

    if (NetApiStatus = NERR_Success) or (NetApiStatus = ERROR_MORE_DATA) then
    begin
      recptr := bufptr;
      for i := 0 to EntriesRead-1 do
      begin
        if (PrivLevel = USER_PRIV_ANY) or (recptr^.usri2_priv = PrivLevel) then
          users.Add(recptr^.usri2_name);
        inc(recptr);
      end;
      NetApiBufferFree(bufptr);
    end;

  until NetApiStatus <> ERROR_MORE_DATA;
  Result := NetApiStatus;
end;

使用示例

procedure TForm1.Button1Click(Sender: TObject);
var
  res: integer;
begin
  res := GetUsers(USER_PRIV_ADMIN, Memo.Lines);
  if res <> 0 then Memo.Lines.Add('Error getting users! Error code '+IntToStr(res));
end;

修改

我将GetUsers()更改为一个函数,并将调用中的成功/错误代码返回到NetUserEnum()

根据文档

可能返回值
NERR_Success = 0
ERROR_ACCESS_DENIED  =    5; // $0005
ERROR_INVALID_LEVEL  =  124; // $007C
ERROR_MORE_DATA      =  234; // $00EA
NERR_BufTooSmall     = 2123; // $084B
NERR_InvalidComputer = 2351; // $092F