ADD: Use sudo if pkexec is not available

This commit is contained in:
Alexander Koblov 2021-08-21 21:37:48 +03:00
commit c7f1e99dce
2 changed files with 140 additions and 5 deletions

View file

@ -17,7 +17,7 @@ uses
{$IF DEFINED(MSWINDOWS)}
, Types, Windows, DCOSUtils, ShellApi, uMyWindows
{$ELSEIF DEFINED(UNIX)}
, Unix, BaseUnix, DCUnix
, Classes, Unix, BaseUnix, DCUnix, Dialogs, SyncObjs, Process, un_process
{$IF DEFINED(DARWIN)}
, DCStrUtils
{$ENDIF}
@ -74,6 +74,40 @@ end;
{$IF DEFINED(UNIX)}
const
PATH_SUDO = '/usr/bin/sudo';
PATH_PKEXEC = '/usr/bin/pkexec';
resourcestring
rsMsgPasswordEnter = 'Please enter the password:';
type
TSuperProgram = (spNone, spSudo, spPkexec);
{ TSuperUser }
TSuperUser = class(TThread)
private
FPrompt: String;
FCtl: TExProcess;
FMessage: String;
FArgs: TStringArray;
FEvent: TSimpleEvent;
private
procedure Ready;
procedure RequestPassword;
procedure OnReadLn(Str: String);
procedure OnQueryString(Str: String);
protected
procedure Execute; override;
public
constructor Create(Args: TStringArray; const StartPath: String);
destructor Destroy; override;
end;
var
SuperProgram: TSuperProgram;
function ExecuteCommand(Command: String; Args: TStringArray; StartPath: String): UIntPtr;
var
ProcessId : TPid;
@ -106,6 +140,92 @@ begin
Result := ProcessId;
end;
function ExecuteSudo(Args: TStringArray; const StartPath: String): UIntPtr;
begin
with TSuperUser.Create(Args, StartPath) do
begin
Start;
FEvent.WaitFor(INFINITE);
Result:= FCtl.Process.ProcessHandle;
end;
end;
{ TSuperUser }
procedure TSuperUser.Ready;
begin
FEvent.SetEvent;
Yield;
FreeOnTerminate:= True;
FCtl.OnOperationProgress:= nil;
end;
procedure TSuperUser.RequestPassword;
var
S: String = '';
begin
if Length(FMessage) = 0 then begin
FMessage:= rsMsgPasswordEnter
end;
if not InputQuery('Double Commander', FMessage, True, S) then
FCtl.Stop
else begin
S:= S + LineEnding;
FCtl.Process.Input.Write(S[1], Length(S));
end;
FMessage:= EmptyStr;
end;
procedure TSuperUser.OnReadLn(Str: String);
begin
FMessage:= Str;
end;
procedure TSuperUser.OnQueryString(Str: String);
begin
Synchronize(@RequestPassword)
end;
procedure TSuperUser.Execute;
var
GUID : TGUID;
Index: Integer;
begin
CreateGUID(GUID);
FPrompt:= GUIDToString(GUID);
FCtl.Process.Options:= FCtl.Process.Options + [poStderrToOutPut];
FCtl.Process.Executable:= PATH_SUDO;
FCtl.Process.Parameters.Add('-S');
FCtl.Process.Parameters.Add('-k');
FCtl.Process.Parameters.Add('-p');
FCtl.Process.Parameters.Add(FPrompt);
for Index:= 0 to High(FArgs) do begin
FCtl.Process.Parameters.Add(FArgs[Index]);
end;
FCtl.QueryString:= FPrompt;
FCtl.OnQueryString:= @OnQueryString;
FCtl.OnOperationProgress:= @Ready;
fCtl.OnProcessExit:= @Ready;
FCtl.OnReadLn:= @OnReadLn;
FCtl.Execute;
end;
constructor TSuperUser.Create(Args: TStringArray; const StartPath: String);
begin
inherited Create(True);
FCtl:= TExProcess.Create(EmptyStr);
FCtl.Process.CurrentDirectory:= StartPath;
FEvent:= TSimpleEvent.Create;
FArgs:= Args;
end;
destructor TSuperUser.Destroy;
begin
inherited Destroy;
FEvent.Free;
FCtl.Free;
end;
{$ELSEIF DEFINED(MSWINDOWS)}
function MaybeQuoteIfNotQuoted(const S: String): String;
@ -176,13 +296,28 @@ begin
AParams[Index + 1]:= Args[Index];
AParams[0] := Exe;
Result:= ExecuteCommand('/usr/bin/pkexec', AParams, sStartPath);
case SuperProgram of
spSudo: Result:= ExecuteSudo(AParams, sStartPath);
spPkexec: Result:= ExecuteCommand(PATH_PKEXEC, AParams, sStartPath);
end;
end;
{$ENDIF}
initialization
{$IF DEFINED(UNIX)}
FAdministratorPrivileges:= {$IFDEF DARWIN}True{$ELSE}(fpGetUID = 0){$ENDIF};
{$IF DEFINED(DARWIN)}
FAdministratorPrivileges:= True;
{$ELSEIF DEFINED(UNIX)}
{$IFDEF LINUX}
if fpAccess(PATH_PKEXEC, X_OK) = 0 then
SuperProgram:= spPkexec
else
{$ENDIF}
if fpAccess(PATH_SUDO, X_OK) = 0 then
SuperProgram:= spSudo
else begin
SuperProgram:= spNone;
end;
FAdministratorPrivileges:= (fpGetUID = 0) or (SuperProgram = spNone);
{$ELSE}
FAdministratorPrivileges:= (IsUserAdmin <> dupError);
{$ENDIF}

View file

@ -120,7 +120,7 @@ begin
else
begin
Sleep(1);
if Assigned(FOnQueryString) and (FProcess.Stderr.NumBytesAvailable > 0) then
if Assigned(FOnQueryString) and Assigned(FProcess.Stderr) and (FProcess.Stderr.NumBytesAvailable > 0) then
begin
SetLength(OutputBuffer, BufferSize);
// Waits for the process output