Delphi-код для отображения дружеских сообщений, если у вас нет разрешения на действия, требующие привилегий администратора, такие как установка службы - PullRequest
2 голосов
/ 01 декабря 2011

Клиент сообщает об ошибке из нашего приложения во время установки, которая указывает, что код в «IsWindowsAdministrator» ниже возвращает FALSE, когда установка выполняется администратором домена.Вы вошли как локальный админ, все работает нормально.Установщик (Innosetup) вызывает exe-файл, который выполняет некоторые операции диспетчера управления службами (см. Ниже), но после вызова нижеприведенного IsWindowsAdministrator для проверки статуса пользователя.

Моя причина для проверки статуса администратора заключается в следующем:перед вызовом задач диспетчера служб для работы с драйвером передайте изящную ошибку (см. ниже КОД УСТАНОВКИ ДРАЙВЕРА).Это задачи, которые я не могу легко выполнить в Innosetup, и я решил обернуть их в небольшой исполняемый файл, вызываемый установщиком.

Допустим ли код в CHECK ADMIN CODE для этой задачи?Или я должен просто отказаться от него и обернуть вызов в диспетчер управления службами в попытке-за исключением с более хорошим сообщением об ошибке?

Спасибо

===================== КОД УСТАНОВКИ ДРАЙВЕРА ========================

procedure ArtIODriver_Install( AShowSummary : boolean );
var
  hServiceControlManager : THandle;
  hService               : SC_HANDLE;
  ServiceStatus          : TServiceStatus;
  ServiceArgVectors      : PAnsiString;
begin

  If not IsWindowsAdministrator then
    Raise EArtIODriver.Create(
      'Error IODR4 - You must be a windows administrator to perform this action' );

  If not FileExists( ArtIODriver_FilePath ) then
    Raise EArtIODriver.CreateFmt(
      'Error IODR7 - Unable to locate the driver file "%s"',
      [ArtIODriver_FilePath] );

  hService := 0;
  hServiceControlManager := 0;
  try

    hServiceControlManager := OpenSCManager(
      nil,
      nil,
      SC_MANAGER_ALL_ACCESS);
    If hServiceControlManager = 0 then
      Raise EArtIODriver.CreateFmt(
        'Error IOD1 - Unable to open service control manager - %s',
        [GetWinLastErrorStr] );

    // can we see the service?
    hService := OpenService(
      hServiceControlManager,
      JustDriverName,
      SERVICE_ALL_ACCESS);
etc
etc

========= ПРОВЕРЬТЕ АДМИНИСТРАТНЫЙ КОД ================

function IsWindowsAdministrator: Boolean;
// Returns TRUE if the user has administrator priveleges
// Returns a boolean indicating whether or not user has admin
// privileges. Call only when running under NT. Win9.x will return false!
var
  hAccessToken       : tHandle;
  ptgGroups          : pTokenGroups;
  dwInfoBufferSize   : DWORD;
  psidAdministrators : PSID;
  int                : integer;            // counter
  blnResult          : boolean;            // return flag

const
  SECURITY_NT_AUTHORITY: SID_IDENTIFIER_AUTHORITY =
    (Value: (0,0,0,0,0,5)); // ntifs
  SECURITY_BUILTIN_DOMAIN_RID: DWORD = $00000020;
  DOMAIN_ALIAS_RID_ADMINS: DWORD = $00000220;
  DOMAIN_ALIAS_RID_USERS : DWORD = $00000221;
  DOMAIN_ALIAS_RID_GUESTS: DWORD = $00000222;
  DOMAIN_ALIAS_RID_POWER_: DWORD = $00000223;

begin
  Result := False;
  blnResult := OpenThreadToken( GetCurrentThread, TOKEN_QUERY,
                                True, hAccessToken );
  if ( not blnResult ) then
  begin
    if GetLastError = ERROR_NO_TOKEN then
    blnResult := OpenProcessToken( GetCurrentProcess,
                       TOKEN_QUERY, hAccessToken );
  end;

  ptgGroups := nil;

  if ( blnResult ) then
  try

    GetMem(ptgGroups, 1024);
    blnResult := GetTokenInformation( hAccessToken, TokenGroups,
                                      ptgGroups, 1024,
                                      dwInfoBufferSize );
    CloseHandle( hAccessToken );

    if ( blnResult ) then
    begin

      AllocateAndInitializeSid( SECURITY_NT_AUTHORITY, 2,
                                SECURITY_BUILTIN_DOMAIN_RID,
                                DOMAIN_ALIAS_RID_ADMINS,
                    0, 0, 0, 0, 0, 0,
                    psidAdministrators );
      {$IFOPT R+}
        {$DEFINE RMINUS}
        {$R-}
      {$ENDIF}
      for int := 0 to ptgGroups.GroupCount - 1 do

        if EqualSid( psidAdministrators,
                     ptgGroups.Groups[ int ].Sid ) then
        begin
          Result := True;
          Break;
        end;
      {$IFDEF IMINUS}
        {$R-}
        {$UNDEF IMINUS}
      {$ENDIF}

      FreeSid( psidAdministrators );
    end;

  finally
    If ptgGroups <> nil then
      FreeMem( ptgGroups );
  end;
end;

Ответы [ 2 ]

8 голосов
/ 01 декабря 2011

Вместо того, чтобы проверять, является ли пользователь администратором, вы должны просто проверить код ошибки из OpenSCManager() и / или OpenService().Если у пользователя нет достаточных прав, GetLastError() вернет ERROR_ACCESS_DENIED, например:

hServiceControlManager := OpenSCManager( 
  nil, 
  nil, 
  SC_MANAGER_ALL_ACCESS); 
If hServiceControlManager = 0 then 
Begin
  If GetLastError() = ERROR_ACCESS_DENIED then
    Raise EArtIODriver.Create('Error IODR4 - You must be a windows administrator to perform this action' ) 
  else
    Raise EArtIODriver.CreateFmt('Error IOD1 - Unable to open service control manager - %s', [GetWinLastErrorStr] );
End; 

Я использую эту технику в приложении, которое не требует прав администратора для большинства своих операций, чтобы определить, когдавручную вызвать приглашение UAC под Vista +, чтобы получить достаточные права, и это работает очень хорошо.

3 голосов
/ 02 декабря 2011

Поскольку вы запускаете исполняемый файл из программы установки, вам, вероятно, потребуется создать манифест для вашего исполняемого файла, который запрашивает повышение прав. Не спрашивайте, какие привилегии у вас есть. Спросите у Windows о необходимых вам привилегиях.

Как создать манифест для установщика Windows?

...