Linux Shell authorization, sudo, and backend shell type

Hi Folks,

In older RB/RS, I could use the following logic in Linux to run elevated processes (pseudo code …):

theShell.Mode = 0
theShell.Execute "echo " + escPasswd + " | sudo -S /usr/bin/true" // start the sudo timer
theShell.Mode = 2
theShell.Executed "sudo " + someElevatedProcess // sudo clock is running, so no sudo password prompt for this command
Do
  theShell.Poll
  // Do Something with ReadAll
Loop Until not theShell.IsRunning

Now, under Xojo 15r4, I get prompted when executing the second command - but only in the Xojo shell. Executing the same sequence from an actual terminal works as expected.

Did the Xojo shell backend change, or have I missed a change in Linux sudo and pseudoTTYs? Is there something that I can configure for the Linux shell backend to get the live results again in the Xojo shell?

maybe by switching the mode they internally make a new shell?

Sorted this - more code than it used to be (or on OS X).

You need to create an interactive shell session and use Write instead of Execute and then use a thread to keep the UI responsive and handle the shelled task and a Timer to update the output TextArea. Here’s where I am so far:

  // Call this from a Thread's Run method
  Dim theShell As New Shell
  Dim escPasswd As String
  Dim Completed As Boolean

  escPasswd = BuildUserPassword  

  theShell.Canonical = True
  theShell.Backend = "/bin/bash"
  theShell.Mode = 2
  
  Timer1.Period = 25
  Timer1.Mode = 2
  
  theShell.Execute "/bin/bash -i" // the -i is important so that the shell attaches to a TTY
  theShell.WriteLine "PS1=input:\\ " // Makes it easier to catch end of command since we can't depend
                                    //  on IsRunning using a shell in this manner
  theShell.WriteLine "sudo -v" // Authenticate and start the sudo clock
  Do
    theShell.Poll
    App.SleepCurrentThread(25)
  Loop Until InStr(theShell.Result, "[sudo] password for ") <> 0
  Call theShell.ReadAll // throw it away
  theShell.WriteLine escPasswd
  Do
    theShell.Poll
    App.SleepCurrentThread(25)
  Loop Until InStr(theShell.Result, "input: ") <> 0
  theShell.WriteLine "sudo su -" // set the shell to root so the prompts stop
  Do
    theShell.Poll
    App.SleepCurrentThread(25)
    Completed = InStr(theShell.Result, "root@") <> 0
  Loop Until Completed
  Completed = False
  theShell.WriteLine "PS1=input:\\ " // repeated since the su - now has a new shell environment
  Do
    theShell.Poll
    App.SleepCurrentThread(25)
  Loop Until InStr(theShell.Result, "input: ") <> 0
  Call theShell.ReadAll
  App.SleepCurrentThread(100)
  theShell.WriteLine "tar -czvvf /tmp/tar_test.tgz -b 256 /etc"
  Do
    theShell.Poll
    Completed = InStr(theShell.Result, "input: ") <> 0
    App.SleepCurrentThread(25)
    bruOut = theShell.ReadAll
  Loop Until Completed
  App.SleepCurrentThread(250)
  Timer1.Mode = 0
  theShell.WriteLine "sudo -K"
  theShell.WriteLine "exit"

BTW - the use of /etc as the tar content is a proof that the su is working since there are many files in the /etc folder that can’t be read by a normal user.

Update to this logic.

I seems that the team at Apple have now adopted the requiretty restriction on sudo starting with Sierra. However, as expected with Apple’s low-level changes, there is no documentation about this and the manpage still includes the section"

Therefore, the logic above seems to be the only proven successful way to run a background shelled task as UID root instead of EUID.

If someone else comes up with a more elegant solution, I’d be very excited to spread the news far and wide. :slight_smile: