Проверка входа пользователя с правами администратора в неанглийских установках Windows - PullRequest
8 голосов
/ 26 октября 2010

У меня есть несколько небольших вопросов ... У меня есть программа, которая хранит список пользователей в базе данных и сравнивает при запуске программы, есть ли пользователь в списке или является администратором, прежде чем позволить им использовать его.На данный момент я использую для проверки, является ли пользователь администратором, просто сравнивая имя пользователя со строковой константой, называемой «ADMINISTRATOR».Будет ли это работать в неанглийской системе?IE использует ли Windows языковую версию 'administrator'?Или, может быть, есть перечисленная версия пользователя Admin, которую я могу использовать для проверки вместо моей строки 'ADMINISTRATOR'?(Вы знаете, как перечисляются папки Windows).Кстати, я пользуюсь Delphi 2009.Заранее спасибо!

Ответы [ 5 ]

7 голосов
/ 26 октября 2010

NEWS

В 2010 году @ChristianWimmer подверг критике мой стиль кодирования.Теперь, спустя два года, я должен снова использовать эту функцию в своей программе.Итак, я решил улучшить стиль кодирования функции.

Обзор

Для вашего удобства я выбрал небольшую часть своей личной библиотеки.Чтобы проверить, является ли учетная запись пользователя маркера доступа членом локальной группы администраторов, передайте WinBuiltinAdministratorsSid из JwaWinNT в eWellKnownSidType .Обратите внимание, что для этого требуется JEDI API Libray , поскольку модуль Delphi Windows.pas не определил CreateWellKnownSid().

Реализация

//------------------------------------------------------------------------------
// Purpose: Tests whether user account of the access token is a member of the
//   specified well known group, and report its elevation type.
// Parameter:
//   hToken [in,opt]
//     A handle to an access token having TOKEN_QUERY and TOKEN_DUPLICATE
//     access. If hToken is 0: if it is an impersonation token, the access token
//     of the calling thread is used; otherwise, the access token associated
//     with the process is used.
//   eWellKnownSidType [in]
//     Member of the WELL_KNOWN_SID_TYPE enumeration that specifies what Sid the
//     function will identify.
//   pDomainSid [in,opt]
//     A pointer to a SID that identifies the domain to use when identifying the
//     Sid. Pass nil to use the local computer.
//   peElevType [out,opt]
//     A pointer to a variable that receives the following elevation type of the
//     access token:
//       - TokenElevationTypeDefault: The access token does not have a linked
//         token. This value is reported under Windows prior to Windows Vista.
//       - TokenElevationTypeFull: The access token is an elevated token.
//       - TokenElevationTypeLimited: The access token is a limited token.
// Return value:
//   - True if user account of the access token is a member of the well known
//     group specified in eWellKnownSidType parameter.
//   - False, otherwise. To get error information, call GetLastError().
// Remarks:
//   To test whether user account of the access token is a member of local
//   administrators group, pass JwaWinNT.WinBuiltinAdministratorsSid to
//   eWellKnownSidType parameter.
// References:
//   - How To Determine Whether a Thread Is Running in User Context of
//     Local Administrator Account [MSDN]
//------------------------------------------------------------------------------
function Inu_IsMemberOfWellKnownGroup(const hToken: Windows.THandle;
    const eWellKnownSidType: JwaWinNT.WELL_KNOWN_SID_TYPE;
    const pDomainSid: JwaWinNT.PSID=nil;
    peElevType: PTokenElevationType=nil): Boolean;
var
  hAccessToken: Windows.THandle;
  rOSVerInfo: Windows.OSVERSIONINFO;
  eTET: Windows.TTokenElevationType;
  iReturnLen: Windows.DWORD;
  hTokenToCheck: Windows.THandle;
  iSidLen: Windows.DWORD;
  pGroupSid: JwaWinNT.PSID;
  bMemberOfWellKnownGroup: Windows.BOOL;
begin
  Result := False;
  hAccessToken := 0;
  hTokenToCheck := 0;
  pGroupSid := nil;
  try
    if hToken = 0 then begin // If the caller doesn't supply a token handle,
      // Get the calling thread's access token
      if not Windows.OpenThreadToken(Windows.GetCurrentThread(),
          Windows.TOKEN_QUERY or Windows.TOKEN_DUPLICATE,
          True, hAccessToken) then begin
        if Windows.GetLastError() <> Windows.ERROR_NO_TOKEN then
          Exit();
        // If no thread token exists, retry against process token
        if not Windows.OpenProcessToken(Windows.GetCurrentProcess(),
            Windows.TOKEN_QUERY or Windows.TOKEN_DUPLICATE, hAccessToken) then
          Exit();
      end;
    end
    else // If the caller supplies a token handle,
      hAccessToken := hToken;
    // Determine whether the system is running Windows Vista or later because
    // because they support linked tokens, previous versions don't.
    rOSVerInfo.dwOSVersionInfoSize := SizeOf(Windows.OSVERSIONINFO);
    if not Windows.GetVersionEx(rOSVerInfo) then
      Exit();
    if rOSVerInfo.dwMajorVersion >= 6 then begin
      // Retrieve information about the elevation level of the access token
      if not Windows.GetTokenInformation(hAccessToken,
          Windows.TokenElevationType, @eTET,
          SizeOf(Windows.TTokenElevationType), iReturnLen) then
        Exit();
      // If the access token is a limited token, retrieve the linked token
      // information from the access token.
      if eTET = Windows.TokenElevationTypeLimited then begin
        if not Windows.GetTokenInformation(hAccessToken,
            Windows.TokenLinkedToken, @hTokenToCheck,
            SizeOf(Windows.TTokenLinkedToken), iReturnLen) then
          Exit();
      end;
      // Report the elevation type if it is wanted
      if Assigned(peElevType) then
        peElevType^ := eTET;
    end
    else begin // if rOSVerInfo.dwMajorVersion < 6
      // There is no concept of elevation prior to Windows Vista
      if Assigned(peElevType) then
        peElevType^ := Windows.TokenElevationTypeDefault;
    end;
    // CheckTokenMembership() requires an impersonation token. If we just got a
    // linked token, it is already an impersonation token. Otherwise, duplicate
    // the original as an impersonation token for CheckTokenMembership().
    if (hTokenToCheck = 0) and (not Windows.DuplicateToken(hAccessToken,
        Windows.SecurityIdentification, @hTokenToCheck)) then
      Exit();
    // Allocate enough memory for the longest possible Sid
    iSidLen := JwaWinNT.SECURITY_MAX_SID_SIZE;
    pGroupSid := JwaWinNT.PSid(Windows.LocalAlloc(Windows.LMEM_FIXED, iSidLen));
    if not Assigned(pGroupSid) then
      Exit();
    // Create a Sid for the predefined alias as specified in eWellKnownSidType
    if not JwaWinBase.CreateWellKnownSid(eWellKnownSidType, pDomainSid,
        pGroupSid, iSidLen) then
      Exit();
    // Now, check presence of the created Sid in the user and group Sids of the
    // access token. In other words, it determines whether the user is a member
    // of the well known group specified in eWellKnownSidType parameter.
    if not JwaWinBase.CheckTokenMembership(hTokenToCheck, pGroupSid,
        bMemberOfWellKnownGroup) then
      Exit();
    Result := bMemberOfWellKnownGroup;
  finally
    // Close the access token handle
    if hAccessToken <> 0 then
      Windows.CloseHandle(hAccessToken);
    // Close the new duplicate token handle if exists
    if (hTokenToCheck <> 0) then
      Windows.CloseHandle(hTokenToCheck);
    // Free the allocated memory for the Sid created by CreateWellKnownSid()
    if Assigned(pGroupSid) then
      Windows.LocalFree(Windows.HLOCAL(pGroupSid));
  end;
end; // endfunction Inu_IsMemberOfWellKnownGroup
//==============================================================================
7 голосов
/ 26 октября 2010

Нет, не делай так.Это обязательно сломается.Вы можете получить список всех групп, членом которых является пользователь, и проверить, является ли один из SID S-1-5-32-544, который является SID группы администраторов.Существует список известных SID.Существует также SID для исходной учетной записи администратора.

Вот список:

http://support.microsoft.com/kb/243330

2 голосов
/ 26 октября 2010

Это выдержка из JwsclToken.pas из JEDI API & WSCL.Обе функции выполняют одну и ту же проверку, но по-разному.Вы видите, как мало кода используется?Тот же код в простом WinAPI будет как минимум в 5 раз больше.Конечно, вы можете просто вызвать эти функции из самого устройства. Не нужно копировать здесь !

function JwCheckAdministratorAccess: boolean;
var
  SD: TJwSecurityDescriptor;
begin
  if not Assigned(JwAdministratorsSID) then
    JwInitWellKnownSIDs;

  SD := TJwSecurityDescriptor.Create;
  try
    SD.PrimaryGroup := JwNullSID;
    SD.Owner   := JwAdministratorsSID;
    SD.OwnDACL := True;

    SD.DACL.Add(TJwDiscretionaryAccessControlEntryAllow.Create(nil,
      [], STANDARD_RIGHTS_ALL, JwAdministratorsSID, False));

    Result := TJwSecureGeneralObject.AccessCheck(SD, nil,
      STANDARD_RIGHTS_ALL, TJwSecurityGenericMapping);
  finally
    FreeAndNil(SD);
  end;
end;

function JwIsMemberOfAdministratorsGroup: boolean;
var
  Token: TJwSecurityToken;
begin
  Token := TJwSecurityToken.CreateTokenEffective(TOKEN_READ or
    TOKEN_DUPLICATE);
  try
    Token.ConvertToImpersonatedToken(SecurityImpersonation, MAXIMUM_ALLOWED);
    Result := Token.CheckTokenMembership(JwAdministratorsSID)
  finally
    FreeAndNil(Token);
  end;
end;
1 голос
/ 26 октября 2010

Существует функция CreateWellKnownSid .

Но явная проверка учетной записи администратора может быть не очень хорошей идеей.Просто выполните операцию и запросите повышение прав, если вы получили сообщение об ошибке «Отказано в доступе».

1 голос
/ 26 октября 2010

Это зависит от версии Windows до версии Windows ... в предварительной версии ... Администратор имя пользователя на основном языке Windows ... например, на испанском языке это Администрадор .

В пост-висте нет администратора. Вы должны сохранить и проверить права пользователя.

Я нашел эту функцию IsAdmin , и вы тоже можете найти ее полезной ...

...