Recent

Author Topic: How to pass root or sudo password to the Linux Kernel via a Lazarus GUI  (Read 25689 times)

Gizmo

  • Hero Member
  • *****
  • Posts: 831
I'm building a GUI as a front end to a Linux command line tool. I don't want the GUI to be ran as root\sudo in its entirety from the word go. I want the program to prompt the user for the password at the appropriate time, in the same way that TrueCrypt does when it actually comes to the point of mounting a volume.

Having Googled the question, ironically, the first thread I got was one I posted a while ago that briefly mentions this process as an example but I was asking more specifically about other programs then.

I am using TProcess to call the external command and read back it's output. In the middle of that code I need my program to ask for the root\sudo password and to then pass that to the Linux kernel to allow my program access to the parts of the system that the external command needs to access (specifically, dev/hdaX or /dev/sdaX).

As an example, if ran on the command line, the command would be :

dd if=/dev/hda1 of=~/image.dd

My program is calling dd, passing it the 'if' and 'of' values - it then needs to gather and pass the sudo password to dd.

Thanks

Ted
« Last Edit: September 01, 2011, 03:57:24 pm by tedsmith »

LA.Center

  • Full Member
  • ***
  • Posts: 244
    • LA.Center
Re: How to pass root or sudo password to the Linux Kernel via a Lazarus GUI
« Reply #1 on: September 01, 2011, 04:45:19 pm »
first call su and post your password and then your command,
you have to look at TProcess and console piping.


Gizmo

  • Hero Member
  • *****
  • Posts: 831
Re: How to pass root or sudo password to the Linux Kernel via a Lazarus GUI
« Reply #2 on: September 01, 2011, 10:50:16 pm »
Do you know of any examples where this has been done, or better yet, know of Lazarus applications that are open-source that implement this so I can read how they've done it?

Gizmo

  • Hero Member
  • *****
  • Posts: 831
Re: How to pass root or sudo password to the Linux Kernel via a Lazarus GUI
« Reply #3 on: September 02, 2011, 03:24:37 pm »
OK. I have got this far :

Code: Pascal  [Select][+][-]
  1.  
  2.  
  3. procedure TForm1.Button1Click(Sender: TObject);
  4. var
  5.   ChosenDisk : TProcess;
  6.   StringList : TStringList;
  7.   sudoPassword : string;
  8. begin
  9.   sudoPassword := 'MyPassword';     // I know this is bad practise but it's just to get things working for now
  10.  
  11. // SelectDirectory changed to OpenDialog given that the dd command accesses files not folders.
  12.   if OpenDialog1.Execute = true then
  13.     if FileExists(OpenDialog1.FileName) then
  14.       begin
  15.         Edit1.Caption := OpenDialog1.FileName;
  16.         ChosenDisk := TProcess.Create(nil);
  17.         StringList := TStringList.Create;
  18.         ChosenDisk.Options := ChosenDisk.Options + [poWaitOnExit, poUsePipes];
  19.         ChosenDisk.CommandLine := 'dd if='+OpenDialog1.FileName+' of=/home/ted./testimage.dd';
  20.         ChosenDisk.Input.Write(sudoPassword[1],Length(sudoPassword));
  21.         ChosenDisk.Execute;
  22.         StringList.LoadFromStream(ChosenDisk.Output);
  23.         StringList.SaveToFile('/home/ted/test.txt');
  24.         ChosenDisk.Free;
  25.         StringList.Free;
  26.       end;
  27. end;        
  28.  

But still, it doesn't do anything. :-(
« Last Edit: September 02, 2011, 03:27:30 pm by tedsmith »

BigChimp

  • Hero Member
  • *****
  • Posts: 5740
  • Add to the wiki - it's free ;)
    • FPCUp, PaperTiger scanning and other open source projects
Re: How to pass root or sudo password to the Linux Kernel via a Lazarus GUI
« Reply #4 on: September 02, 2011, 03:39:04 pm »
Ehm, you don't seem to be doing anything with the sudopassword!??!

I suspect you will have to start a shell such as bash in your tprocess first, then put su <password> line feed into the input of the process, wait for reaction, then the rest, if I understand correctly what plusplus wrote.....
Want quicker answers to your questions? Read http://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

Open source including papertiger OCR/PDF scanning:
https://bitbucket.org/reiniero

Lazarus trunk+FPC trunk x86, Windows x64 unless otherwise specified

BeniBela

  • Hero Member
  • *****
  • Posts: 905
    • homepage
Re: How to pass root or sudo password to the Linux Kernel via a Lazarus GUI
« Reply #5 on: September 02, 2011, 04:20:09 pm »
e I need my program to ask for the root\sudo password and to then pass that to the Linux kernel

Never ask for the root password.

Call a secure program that does it, e.g. gksudo ... or xterm -e sudo ...

Gizmo

  • Hero Member
  • *****
  • Posts: 831
Re: How to pass root or sudo password to the Linux Kernel via a Lazarus GUI
« Reply #6 on: September 02, 2011, 05:09:17 pm »
Does
Code: [Select]
ChosenDisk.Input.Write(sudoPassword[1],Length(sudoPassword)); not do something with the password? i.e. pass it to the command
Code: [Select]
ChosenDisk.CommandLine := 'dd if='+OpenDialog1.FileName+' of=/home/ted./testimage.dd';??
 

Shebuka

  • Sr. Member
  • ****
  • Posts: 427
Re: How to pass root or sudo password to the Linux Kernel via a Lazarus GUI
« Reply #7 on: September 02, 2011, 06:39:29 pm »
Does
Code: [Select]
ChosenDisk.Input.Write(sudoPassword[1],Length(sudoPassword)); not do something with the password? i.e. pass it to the command
Code: [Select]
ChosenDisk.CommandLine := 'dd if='+OpenDialog1.FileName+' of=/home/ted./testimage.dd';??
No, because you must firs execute it to be asked to the password, but as you execute a tprocess you can't input in it any data anymore as i know...

Gizmo

  • Hero Member
  • *****
  • Posts: 831
Re: How to pass root or sudo password to the Linux Kernel via a Lazarus GUI
« Reply #8 on: September 03, 2011, 05:08:52 pm »
I thought that's what the Process.Input.XXX methods allowed, providing pipes were enabled? i.e. it provides the ability to pass additional "stuff" to a command. I thought it would be Process.Input.Write('MyPassword') or Process.Input.ReadAnsiString(PasswordString); or something?

There must be a way of doing it with FPC and Lazarus being what they are. I can't be that difficult to do, given the libraries that exist with this language.

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3538
Re: How to pass root or sudo password to the Linux Kernel via a Lazarus GUI
« Reply #9 on: September 03, 2011, 05:30:56 pm »
I thought that's what the Process.Input.XXX methods allowed, providing pipes were enabled? i.e. it provides the ability to pass additional "stuff" to a command. I thought it would be Process.Input.Write('MyPassword') or Process.Input.ReadAnsiString(PasswordString); or something?

You are right, Process.Input.Write(PasswordString[1], Length(PasswordString)) will send the password via pipes to the process. But are you really sure that the process is reading the pipe for the password? I think that no, it is not. I think that it works like this in the console:

1> the console starts the app
2> the app makes a system call to request for privileges
3> the console detects this sys call and requests for the password and solves the privileges and then resumes the process

So the process is not reading anything from the pipe here, the console application took care of that. If you want this behavior you would need to execute "bash" with command line instructions to run the program that you want to call. Then send the password via pipes to bash. Bash reads the pipe for the password.

I think that there are more elegant ways to solve this, like requesting root access for your program and then run the program, although I don't know how to implement that.

Drewski

  • Jr. Member
  • **
  • Posts: 55
Re: How to pass root or sudo password to the Linux Kernel via a Lazarus GUI
« Reply #10 on: September 03, 2011, 09:41:43 pm »
OK. I have got this far :
Code: Pascal  [Select][+][-]
  1.         ChosenDisk.CommandLine := 'dd if='+OpenDialog1.FileName+' of=/home/ted./testimage.dd';
  2.         ChosenDisk.Input.Write(sudoPassword[1],Length(sudoPassword));
  3.         ChosenDisk.Execute;  
  4.  

But still, it doesn't do anything. :-(

There are a couple of problems  with this.
1. 
Code: Pascal  [Select][+][-]
  1. 'dd if='+OpenDialog1.FileName+' of=/home/ted./testimage.dd';

dd is a simple program that doesn't know anything about permissions. To run dd with advanced permissions you need to either have your program running as root or use sudo to advance the permissions. Something like "
Code: Pascal  [Select][+][-]
  1. 'sudo dd if='+OpenDialog1.FileName+' of=/home/ted./testimage.dd';
"

2.
Code: Pascal  [Select][+][-]
  1. ChosenDisk.Input.Write(sudoPassword[1],Length(sudoPassword));
  2. ChosenDisk.Execute;
  3.  
These lines are in reverse to the order they should be. ChosenDisk.Input may not be available to write to until Execute is called though I'm unsure of this.

The following program may be useful to you as a source of information about running a program with escalated privileges using sudo:

Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   Classes, Process;
  7.  
  8.  
  9. Function Min(A, B: Integer): Integer;
  10. begin
  11.   if A < B then Result := A
  12.   else Result := B;
  13. end;
  14.  
  15. procedure RunsLsRoot;
  16. var
  17.   Proc: TProcess;
  18.   Buf: array [0..511] of char;
  19.   RCount: Integer;
  20.   PW: String;
  21.   ExitCode: Integer;
  22. begin
  23.   Proc := TProcess.Create(nil);
  24.   Proc.Options := [poUsePipes];
  25.   Proc.CommandLine := 'sudo -S ls /root'; // -S causes sudo to read the password from stdin.
  26.   Proc.Execute;
  27.  
  28.   // write the password to stdin of sudo
  29.   PW := 'myhiddenpassword' + LineEnding;
  30.   Proc.Input.Write(PW[1], Length(PW));
  31.  
  32.   // main loop to read output from stdout and stderr of sudo
  33.   while Proc.Running or (Proc.Output.NumBytesAvailable > 0) or (Proc.Stderr.NumBytesAvailable > 0) do
  34.   begin
  35.     // read stdout and write to our stdout
  36.     while Proc.Output.NumBytesAvailable > 0 do
  37.     begin
  38.       RCount := Min(512, Proc.Output.NumBytesAvailable);
  39.       Proc.Output.Read(Buf, RCount);
  40.       Write(StdOut, Copy(Buf,0,Rcount));
  41.     end;
  42.     // read stderr and write to our stderr
  43.     while Proc.Stderr.NumBytesAvailable > 0 do
  44.     begin
  45.       RCount := Min(512, Proc.Stderr.NumBytesAvailable);
  46.       Proc.Stderr.Read(Buf, RCount);
  47.       Write(StdErr, Copy(Buf,0,Rcount));
  48.     end;
  49.   end;
  50.   ExitCode := Proc.ExitStatus;
  51.   Proc.Free;
  52.   Halt(ExitCode);
  53. end;
  54.  
  55. begin
  56.   RunsLsRoot;
  57. end.
  58.  


This can be improved but has the core of what's needed.

Regards,

Andrew

   

BigChimp

  • Hero Member
  • *****
  • Posts: 5740
  • Add to the wiki - it's free ;)
    • FPCUp, PaperTiger scanning and other open source projects
Re: How to pass root or sudo password to the Linux Kernel via a Lazarus GUI
« Reply #11 on: September 04, 2011, 12:59:26 am »
Hi Andrew,

Would you mind if I put that program up on the wiki as an example?

Thanks,
BigChimp

I'd modify it to something like this (compiles, but not tested on Linux/OSX):
Code: [Select]
program rootls;

{ Demonstrates using TProcess, redirecting stdout/stderr to our stdout/stderr,
calling sudo on Linux/OSX, and supplying input on stdin}
{$mode objfpc}{$H+}

uses
  Classes,
  Math, {for min}
  Process;

  procedure RunsLsRoot;
  var
    Proc: TProcess;
    CharBuffer: array [0..511] of char;
    RestCount: integer;
    ExitCode: integer;
    SudoPassword: string;
  begin
    WriteLn('Please enter the sudo password:');
    Readln(SudoPassword);
    ExitCode := -1; //Start out with failure, let's see later if it works
    Proc := TProcess.Create(nil); //Create a new process
    try
      Proc.Options := [poUsePipes]; //Use pipes to redirect program stdin,stdout,stderr
      Proc.CommandLine := 'sudo -S ls /root'; //Run ls /root as root using sudo
      // -S causes sudo to read the password from stdin.
      Proc.Execute; //start it. sudo will now probably ask for a password

      // write the password to stdin of sudo
      SudoPassword := SudoPassword + LineEnding;
      Proc.Input.Write(SudoPassword[1], Length(SudoPassword));
      SudoPassword := 'password'; //hope this will scramble memory
      SudoPassword := ''; // and make the program a bit safer from snooping?!?

      // main loop to read output from stdout and stderr of sudo
      while Proc.Running or (Proc.Output.NumBytesAvailable > 0) or
        (Proc.Stderr.NumBytesAvailable > 0) do
      begin
        // read stdout and write to our stdout
        while Proc.Output.NumBytesAvailable > 0 do
        begin
          RestCount := Min(512, Proc.Output.NumBytesAvailable); //Read up to buffer, not more
          Proc.Output.Read(CharBuffer, RestCount);
          Write(StdOut, Copy(CharBuffer, 0, RestCount));
        end;
        // read stderr and write to our stderr
        while Proc.Stderr.NumBytesAvailable > 0 do
        begin
          RestCount := Min(512, Proc.Stderr.NumBytesAvailable); //Read up to buffer, not more
          Proc.Stderr.Read(CharBuffer, RestCount);
          Write(StdErr, Copy(CharBuffer, 0, RestCount));
        end;
      end;
      ExitCode := Proc.ExitStatus;
    finally
      Proc.Free;
      Halt(ExitCode);
    end;
  end;

begin
  RunsLsRoot;
end.
« Last Edit: September 04, 2011, 01:39:50 am by BigChimp »
Want quicker answers to your questions? Read http://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

Open source including papertiger OCR/PDF scanning:
https://bitbucket.org/reiniero

Lazarus trunk+FPC trunk x86, Windows x64 unless otherwise specified

Drewski

  • Jr. Member
  • **
  • Posts: 55
Re: How to pass root or sudo password to the Linux Kernel via a Lazarus GUI
« Reply #12 on: September 04, 2011, 01:30:37 am »
Yes of course you can put it in the wiki  :)
I like the changes that you made. The variable RCount I had thought of as ReadCount though, RestCount confuses me. (ZZzzzz....)

Regards,

Andrew Haines

BigChimp

  • Hero Member
  • *****
  • Posts: 5740
  • Add to the wiki - it's free ;)
    • FPCUp, PaperTiger scanning and other open source projects
Re: How to pass root or sudo password to the Linux Kernel via a Lazarus GUI
« Reply #13 on: September 04, 2011, 01:40:10 am »
Readcount it is  :)
See http://wiki.lazarus.freepascal.org/Executing_External_Programs#Redirecting_input_and_output_and_running_under_root

Now, if you could adapt that sample to include the option of using su, or on windows runas...  :D Just kidding, thanks for the sample.
« Last Edit: September 04, 2011, 01:55:09 am by BigChimp »
Want quicker answers to your questions? Read http://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

Open source including papertiger OCR/PDF scanning:
https://bitbucket.org/reiniero

Lazarus trunk+FPC trunk x86, Windows x64 unless otherwise specified

Gizmo

  • Hero Member
  • *****
  • Posts: 831
Re: How to pass root or sudo password to the Linux Kernel via a Lazarus GUI
« Reply #14 on: November 18, 2011, 03:12:15 pm »
Sorry for the delay in replying guys. I had forgot about this and got sidelined with another aspect of my program.

Ironically, I did a Google search again, found the new wiki entry and thought "that's cool - that is what I need to do", then clicked on the referenced link and found that it comes back here to where I originally got the discussion going. I'm glad that my post has generated a useful wiki article that will help others like me, I am sure and thank you muchly Andy for writing it.

Ted

 

TinyPortal © 2005-2018