Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request: Add ability to give administrator password to sudo #19180

Closed
mattbell87 opened this issue Feb 24, 2016 · 17 comments
Closed

Request: Add ability to give administrator password to sudo #19180

mattbell87 opened this issue Feb 24, 2016 · 17 comments

Comments

@mattbell87
Copy link

Hi All,

I'm currently building a GUI setup script in QT for my team to automatically install some apps through Homebrew. I want my GUI app to ask for the administrator password. The problem is when sudo is called for some apps, there's no easy or reliable way I can see to insert the password.

With bash scripts I use this method: https://gist.github.com/mattbell87/90a54e968ed39c9bdf6b which I tried however Homebrew and Cask are written in ruby and wont adhere to the bash function as sudo is called directly.

Perhaps a new environment variable (or similar feature) could be added to Homebrew Cask, that when set it will pipe in the password whenever sudo is called.

Here is an example of a program that needs sudo to install:

Running: brew cask install avast
==> Downloading http://download.ff.avast.com/mac/avast_free_mac_security.dmg

==> No checksum defined for Cask avast, skipping verification

==> Running installer for avast; your password may be necessary.
==> Package installers may write to any location; options such as --appdir are ignored.

Error: Command failed to execute!

==> Failed command:
["/usr/bin/sudo", "-E", "--", "/usr/sbin/installer", "-pkg", "#<Pathname:/opt/homebrew-cask/Caskroom/avast/latest/Avast Mac Security.pkg>", "-target", "/"]

==> Output of failed command:


==> Exit status of failed command:
#<Process::Status: pid 8735 exit 1>

==> sudo: no tty present and no askpass program specified


'brew cask install avast' exited abnormally with code 1

My apologies if it's been asked already, I searched the open and closed issues and couldn't see anything.

@adidalal
Copy link
Contributor

#5667 had some discussion, I think.

Sorry, not too familiar with the issue, but does something like this work? (Haven't looked into things, just an idea off the top of my head)

@vitorgalvao
Copy link
Member

@mattbell87 Do sudo -S -v <<< '{{your_sudo_password}}' 2> /dev/null. Works flawlessly with homebrew-cask. I use it in my own dotfiles in a function so I can call it anytime before a command that needs it.

@vitorgalvao
Copy link
Member

Wait, I think I might’ve slightly misunderstood your use case. Either way, if you see the issue linked by @adidalal, you’ll see there’s simply no interest in this. We’ll entertain a PR, but for now that’s all.

@mattbell87
Copy link
Author

No problems, I'll try @adidalal's suggestion for now, it's an interesting hack.

@mattbell87
Copy link
Author

Yes that works. Thanks @adidalal and @vitorgalvao.

For anyone with the same issue (maybe you got here using Google) here is what worked for me:

echo 'PASSWORD' | sudo -vS ; while true; do sudo -n true; sleep 60; kill -0 \"$$\" || exit; done 2>/dev/null & 

Explanation: this line gives a password to sudo then calls a loop that keeps the sudo timestamp alive until the parent process (probably bash, see next paragraph) has finished. Notice the single & at the end, this forks the while loop so that you can continue running the rest of your bash script (like installing your brew casks) while this loop runs.

Since bash is needed for this, and I'm calling apps directly from my GUI program, I need to use bash -c to call the above script, so for anyone reading this, this may help too.

After thats called you can install all your apps, whether they require sudo or not.

Update: Alternatively you can do this, if you don't want a while loop running in the background:

# fetch an app (using avast as an example)
brew cask fetch avast
# renew sudo (expires in ~5min)
sudo -S -v <<< 'password' 2> /dev/null
# install an app
brew cask install avast

Thanks to @vitorgalvao, see comments below.

@vitorgalvao
Copy link
Member

Personally, I’ll strongly suggest against the use of that solution, and again suggest my own.

That keep-alive line is potentially insecure, in that it’ll keep running and thus someone that can look at your running processes may get access to your password (there’s a stackoverflow answer with this, somewhere). It also doesn’t work in certain situations, like if you want to break up your script into multiple ones. It’s also hacky and long.

My solution, however, is shorter, mode focused (the flags it uses are made exactly for this use case), safer, and more versatile. I say this after extensive trials with that keep-alive line in my own dotfiles, to which I had to find solutions to the limitations.

You should be careful with your sudo password. Updating the timestamp indefinitely is generally a bad idea; it’s much safer to just renew it before the commands that’ll actually need it.

@mattbell87
Copy link
Author

Agreed, I'm definitely for having something more concise and less hacky if possible. The only thing is I can't see where your solution updates the keep alive in the backgound. From man sudo:

       -v          When given the -v (validate) option, sudo will update the user's time stamp file,
                   authenticating the user's password if necessary.  This extends the sudo timeout for
                   another 5 minutes (or whatever the timeout is set to in sudoers) but does not run a
                   command.

What if the script, or even one command in that script takes longer than 5 minutes?

@vitorgalvao
Copy link
Member

@mattbell87 As explained in my solution, I use a function (see the link to my dotfiles, in the comment). Then what I do is call that renew_sudo function before commands that will require it. This way it’s even explicit in the script itself when sudo is needed, and it’s called just at the needed time (i.e. you renew it just before and when you know you need it, instead of constantly whether you need it or not).

@mattbell87
Copy link
Author

Ok I've tried your solution. It worked fine, except for when a download takes longer than 5 minutes.

I used Apple Network Link Conditioner to simulate a long download time @ 192kbps and unfortunately it fails with the error in the original post.

# renew_sudo
sudo -S -v <<< 'password' 2> /dev/null
# install an app
brew cask install avast --force

@vitorgalvao
Copy link
Member

That’s an interesting case. Personally, I never bumped into that and in this particular situation I’d solve it by brew cask fetching before brew cask installing (so brew cask fetch avast {{and_other_casks}} && renew_sudo && brew cask install avast {{and_other_casks}}), but that may or not be acceptable to your situation.

@mattbell87
Copy link
Author

Good point I didn't think of doing a fetch first! 👍

I just keep thinking of worst case scenarios, like what if brew cask install some_big_app took a really long time to install and required sudo after 5 minutes (for a final step maybe). Good thing is I guess is that most apps probably only require sudo early on in their installation.

You're right about the security part of while loop. I can ps -x | grep sleep and see the password. Lucky for my situation that wouldn't matter at all, it's not like I'm using brew cask on a server here, but it could be a problem for other people.

@vitorgalvao
Copy link
Member

Probably the best solution for your case:

sudo -S -v <<< '{{your_sudo_password}}' 2> /dev/null
while true; do sudo -n true; sleep 60; kill -0 "$$" || exit; done 2>/dev/null &

This way your password will not be shown in your running processes since it will only appear in the first command, and the second will keep the renewing. It still has the problem of renewing indefinitely, but at least it won’t expose the password for the duration of the script.

On another note, that keep-alive command is usually shown in the context of that .osx script, but it was invented for another script (read the comments, and you’ll even see where the author of the .osx script learned about it).

@mattbell87
Copy link
Author

👍 awesome!

Yeah I had seen that gist after the first couple of comments on this issue. Interesting read there!

Thanks for that, I'll go with that solution.

@benknoble
Copy link

@vitorgalvao I couldn't get sudo -S -v ... to work before a lengthy brew-cask uninstall: I still get prompted for my password (a lot due to pkg utils I think). Suggestions?

@adidalal
Copy link
Contributor

@benknoble Do something like:

# helper functions
renew_sudo() {
  # helper function for when the following command needs `sudo` active but shouldn't be called with it
  sudo --stdin --validate <<< "${sudo_password}" 2> /dev/null
}

ask_details() {
  # ask for the administrator password upfront, for commands that require `sudo`
  clear
  bold_echo 'Insert the "sudo" password now (will not be echoed).'
  until sudo --non-interactive true 2> /dev/null; do # if password is wrong, keep asking
    read -s -p 'Password: ' sudo_password
    echo
    sudo --stdin --validate <<< "${sudo_password}" 2> /dev/null
  done
 
  clear
}


ask_details # get admin password
renew_sudo # to make the Caskroom on first install
brew cask install java

All credits to @vitorgalvao -> https://github.com/vitorgalvao/dotfiles

@commitay
Copy link
Contributor

SUDO_ASKPASS #32954 (comment)

@reitermarkus
Copy link
Member

@lock lock bot locked as resolved and limited conversation to collaborators May 7, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants