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

Handling Casks #40

Closed
DomT4 opened this issue Feb 26, 2021 · 27 comments
Closed

Handling Casks #40

DomT4 opened this issue Feb 26, 2021 · 27 comments

Comments

@DomT4
Copy link
Owner

DomT4 commented Feb 26, 2021

Issue:

  • Currently Casks that use sudo to upgrade can block this command from executing successfully when people use autoupdate to execute upgrade on their behalf, because of the hang on silently waiting for sudo authorisation.
  • Homebrew explicitly does not support launching brew upgrade with sudo, immediately bailing on the command, meaning we can't execute the Cask upgrade command as root to work around the issue.

Potential Fix:

  • Using Homebrew's API to work out which Casks are outdated, and which of those Casks need sudo usage to upgrade, only passing those non-sudo Casks to the upgrade command.

Problems with Fix:

  • Likely to be computationally expensive, making the command very slow to execute.
  • Leaves sudo Casks behind intentionally; would need to find a way to gracefully notify the user to their presence & reason for not upgrading.
  • Leaning on Homebrew's API so heavily to work out what casks are outdated and which of those need sudo has a very real potential to be fragile and prone to breaking.
  • Quite a lot of work for something I'm not sure how widely is a use-case yet.

Hacky Temporary Workaround

  • Use SUDO_ASKPASS as Homebrew seems to intentionally support that for non-interactive installs, and works when tested locally.
  • I don't really want to settle on that as a long-term solution because I'm a tad uncomfortable asking people to simply leave their sudo passwords sat on the filesystem unguarded in plaintext.

Related Issues:

@whazor
Copy link

whazor commented Mar 22, 2021

Maybe it is possible to make a custom brew-autoupdate user with special sudo rights that can only install casks?

@whazor
Copy link

whazor commented Mar 22, 2021

Follow multi-user homebrew guide: https://medium.com/@leifhanack/homebrew-multi-user-setup-e10cb5849d59
Running autoupdate service under a different use: https://apple.stackexchange.com/a/93174
Allowing sudo without password: add file under /private/etc/sudoers.d/brew-sudo with brew ALL=(ALL) NOPASSWD: ALL

@JarryShaw
Copy link

Use SUDO_ASKPASS as Homebrew seems to intentionally support that for non-interactive installs, and works when tested locally.

Actually I had also encountered such problem when implementing my own auto-updater for Mac, MacDaily. So basically, my solution was to temporarily set SUDO_ASKPASS to a tailored AppleScript program at runtime to request sudo password on the fly.

My implementation for the AppleScript is at macdaily/res/askpass.applescript, which was originally inspired from another Homebrew formula called ssh-askpass.

@CiaronHowell
Copy link

Out of curiosity @JarryShaw , how hard was it to implement? Tempted to look further into it and attempt it myself, especially if no one else has got around to it yet :)

@marlonrichert
Copy link

marlonrichert commented Aug 2, 2021

Hacky Temporary Workaround

  • Use SUDO_ASKPASS as Homebrew seems to intentionally support that for non-interactive installs, and works when tested locally.
  • I don't really want to settle on that as a long-term solution because I'm a tad uncomfortable asking people to simply leave their sudo passwords sat on the filesystem unguarded in plaintext.

Setting NOPASSWD in /etc/sudoers might be a better alternative.

@JarryShaw
Copy link

Out of curiosity @JarryShaw , how hard was it to implement? Tempted to look further into it and attempt it myself, especially if no one else has got around to it yet :)

@CiaronHowell It was quite a simple task with some tests lol
as you may have known, AppleScript is never well documented but still easy to understand...

Setting NOPASSWD in /etc/sudoers might be a better alternative.

I don't quite like this idea... 🔗
and I suppose doing so may require either user manually editing their /etc/sudoers or the Command itself modifying the file when installation -- seems not very brew-ish

@whazor
Copy link

whazor commented Aug 5, 2021

NOPASSWD should be acceptable as you would only allow the auto update command to be executed. Installation should be a manual action to make the user aware, auto updating with sudo rights is inherently a security risk. That is also why I would understand for brew not to support this. However I hope it will exist anyway, perhaps unofficially.

@CiaronHowell
Copy link

@CiaronHowell It was quite a simple task with some tests lol
as you may have known, AppleScript is never well documented but still easy to understand...

Thank you, I'll give it a go soon 😄

@regulskimichal
Copy link

I use PAM for sudo. The issue I encounter is that when autoupdater spawns a new process with sudo, the prompt does not include any useful information about the command which supposed to run. As a Linux user, MacOS messages are not useful at all. I would like to know what exactly sudo tries to run, not just that it wants to escalate permissions. If we were able to change this behavior, PAM authentication would be a perfect solution IMO.
image

@Omoeba
Copy link

Omoeba commented Nov 15, 2021

I made a one-liner script to store my password in the keychain following this guide. It should be a lot more secure than storing your password in plaintext.

@regulskimichal
Copy link

I made a one-liner script to store my password in the keychain following this guide. It should be a lot more secure than storing your password in plaintext.

Could you share details of how you use that script?

@Omoeba
Copy link

Omoeba commented Nov 17, 2021

I made a one-liner script to store my password in the keychain following this guide. It should be a lot more secure than storing your password in plaintext.

Could you share details of how you use that script?

I added export SUDO_ASKPASS="/Users/$(whoami)/getpass.sh" to "/Users/$(whoami)/Library/Application Support/com.github.domt4.homebrew-autoupdate/brew_autoupdate". The script is named getpass.sh.

@NikSWE
Copy link

NikSWE commented Nov 18, 2021

My implementation for the AppleScript is at macdaily/res/askpass.applescript, which was originally inspired from another Homebrew formula called ssh-askpass.

This could be a potential solution if we're able to capture which cask requires sudo privilege

@SwiftWinds
Copy link

I made a one-liner script to store my password in the keychain following this guide. It should be a lot more secure than storing your password in plaintext.

note that the script in the guide must be slightly modified, since SUDO_ASKPASS expects a script that spits just your password to standard out when invoked.

Here's what my getpass.sh contained:

pw_name="CLI"
pw_account="matt"

if ! cli_password=$(security find-generic-password -w -s "$pw_name" -a "$pw_account"); then
  echo "error $?"
  exit 1
fi

echo "$cli_password"

@hybras
Copy link

hybras commented Jul 31, 2022

I use PAM for sudo .. the prompt does not include any useful information about the command which supposed to run

I was going to suggest this, but you beat me to to it! I check which process is requesting sudo access with sudo procs --tree sudo. I'm sure there's an equivalent incantation using ps. And yes, I see the irony of using sudo to check where sudo is being invoked.

@tmillr
Copy link

tmillr commented Oct 11, 2022

I wonder if pinentry could be used via SUDO_ASKPASS? I believe it doesn't require a terminal for password input as it uses its own gui prompt. This is what the gpgagent daemon uses (or can be setup to use).

@SwiftWinds
Copy link

SwiftWinds commented Jun 13, 2023

TL;DR solution (using getpass.sh)

(assuming your username is "mateowang" and password is "password123")

  1. security add-generic-password -s 'CLI' -a 'mateowang' -w 'password123' -T /usr/bin/security 1
  2. run security find-generic-password -w -s 'CLI' -a 'mateowang' and confirm that it outputs 'password123' 1
  3. write:
    pw_name="CLI"
    pw_account="mateowang"
    
    if ! cli_password=$(security find-generic-password -w -s "$pw_name" -a "$pw_account"); then
      echo "error $?"
      exit 1
    fi
    
    echo "$cli_password"
    to ~/getpass.sh 2
  4. chmod +x ~/getpass.sh
  5. add export SUDO_ASKPASS="/Users/$(whoami)/getpass.sh" to "/Users/$(whoami)/Library/Application Support/com.github.domt4.homebrew-autoupdate/brew_autoupdate". (Note: you may have to :w! if you're using vim as it is a read-only file.) 3

@benwaco
Copy link

benwaco commented Jun 17, 2023

TL;DR solution (using getpass.sh)

(assuming your username is "mateowang" and password is "password123")

  1. security add-generic-password -s 'CLI' -a 'mateowang' -w 'password123' -T /usr/bin/security 1

  2. run security find-generic-password -w -s 'CLI' -a 'mateowang' and confirm that it outputs 'password123' 1

  3. write:

    pw_name="CLI"
    pw_account="mateowang"
    
    if ! cli_password=$(security find-generic-password -w -s "$pw_name" -a "$pw_account"); then
      echo "error $?"
      exit 1
    fi
    
    echo "$cli_password"

    to ~/getpass.sh 2

  4. chmod +x ~/getpass.sh

  5. add export SUDO_ASKPASS="/Users/$(whoami)/getpass.sh" to "/Users/$(whoami)/Library/Application Support/com.github.domt4.homebrew-autoupdate/brew_autoupdate". (Note: you may have to :w! if you're using vim as it is a read-only file.) 3

Any security risks when using this?

@conuaunoc
Copy link

Setting NOPASSWD in /etc/sudoers might be a better alternative.

I don't quite like this idea... 🔗 and I suppose doing so may require either user manually editing their /etc/sudoers or the Command itself modifying the file when installation -- seems not very brew-ish

You don't need to modify /etc/sudoers, just create a new file in /private/etc/sudoers.d

@toobuntu
Copy link
Contributor

I wonder if pinentry could be used via SUDO_ASKPASS? I believe it doesn't require a terminal for password input as it uses its own gui prompt. This is what the gpgagent daemon uses (or can be setup to use).

Yes, it can. milanvarady/Applite#5 (comment)

@swissbuechi
Copy link
Contributor

swissbuechi commented Oct 25, 2023

I wonder if pinentry could be used via SUDO_ASKPASS? I believe it doesn't require a terminal for password input as it uses its own gui prompt. This is what the gpgagent daemon uses (or can be setup to use).

Yes, it works and is in my opinion the most secure and user-friendly solution.

Setup

Dependency

brew install pinentry-mac

Create Password Script

nano $HOME/getpass.sh

getpass.sh:

#!/bin/bash
PW="$(printf "%s\n" "SETOK OK" "SETCANCEL Cancel" "SETDESC homebrew-autoupdate needs your admin password to complete the task" "SETPROMPT Enter Password:$
echo "$PW"

Invoke Password Script when homebrew-autoupdate runs

sudo nano "/Users/$(whoami)/Library/Application Support/com.github.domt4.homebrew-autoupdate/brew_autoupdate"

add: export SUDO_ASKPASS=${HOME}/getpass.sh before the last line.

Test

Test Password Dialog

export SUDO_ASKPASS=${HOME}/getpass.sh

sudo -i -A

Screenshot 2023-10-25 at 09 33 18

Test homebrew-autoupdate

launchctl start com.github.domt4.homebrew-autoupdate

tail -f ~/Library/Logs/com.github.domt4.homebrew-autoupdate/com.github.domt4.homebrew-autoupdate.out

@mietzen
Copy link

mietzen commented Oct 25, 2023

I wonder if pinentry could be used via SUDO_ASKPASS? I believe it doesn't require a terminal for password input as it uses its own gui prompt. This is what the gpgagent daemon uses (or can be setup to use).

Yes, it works and is in my opinion the most secure and user-friendly solution.

Setup

Dependency

brew install pinentry-mac

Create Password Script

nano $HOME/getpass.sh

getpass.sh:

#!/bin/bash
PW="$(printf "%s\n" "SETOK OK" "SETCANCEL Cancel" "SETDESC homebrew-autoupdate needs your admin password to complete the task" "SETPROMPT Enter Password:$
echo "$PW"

Invoke Password Script when homebrew-autoupdate runs

sudo nano "/Users/$(whoami)/Library/Application Support/com.github.domt4.homebrew-autoupdate/brew_autoupdate"

add: export SUDO_ASKPASS=${HOME}/getpass.sh before the last line.

Test

Test Password Dialog

export SUDO_ASKPASS=${HOME}/getpass.sh

sudo -i -A

Screenshot 2023-10-25 at 09 33 18 ### Test homebrew-autoupdate `launchctl start com.github.domt4.homebrew-autoupdate `

tail -f ~/Library/Logs/com.github.domt4.homebrew-autoupdate/com.github.domt4.homebrew-autoupdate.out

I guess you could also use TouchID: https://github.com/jorgelbg/pinentry-touchid

@swissbuechi
Copy link
Contributor

I wonder if pinentry could be used via SUDO_ASKPASS? I believe it doesn't require a terminal for password input as it uses its own gui prompt. This is what the gpgagent daemon uses (or can be setup to use).

Yes, it works and is in my opinion the most secure and user-friendly solution.

Setup

Dependency

brew install pinentry-mac

Create Password Script

nano $HOME/getpass.sh
getpass.sh:

#!/bin/bash
PW="$(printf "%s\n" "SETOK OK" "SETCANCEL Cancel" "SETDESC homebrew-autoupdate needs your admin password to complete the task" "SETPROMPT Enter Password:$
echo "$PW"

Invoke Password Script when homebrew-autoupdate runs

sudo nano "/Users/$(whoami)/Library/Application Support/com.github.domt4.homebrew-autoupdate/brew_autoupdate"
add: export SUDO_ASKPASS=${HOME}/getpass.sh before the last line.

Test

Test Password Dialog

export SUDO_ASKPASS=${HOME}/getpass.sh
sudo -i -A
Screenshot 2023-10-25 at 09 33 18

Test homebrew-autoupdate

launchctl start com.github.domt4.homebrew-autoupdate
tail -f ~/Library/Logs/com.github.domt4.homebrew-autoupdate/com.github.domt4.homebrew-autoupdate.out

I guess you could also use TouchID: https://github.com/jorgelbg/pinentry-touchid

It would be awesome if we could use the touch ID.
But I don't think it's as simple as using pinetry-mac.
From where would pinetry-touchid receive the sudo password?
Maybe you could manually store the password in the keyring and access the secret via pinetry-touchid.
Also it would not work for older macs without touch ID.

@swissbuechi
Copy link
Contributor

The argument --sudo from PR #110 did solve this issue.

@DomT4
I believe you can now close?

@toobuntu
Copy link
Contributor

The argument --sudo from PR #110 did solve this issue.

@swissbuechi
Thank you for this very useful addition to Homebrew Autoupdate!

Out of curiosity, why do you invoke a subshell and then echo the password, when it works as well to not do that?

@swissbuechi
Copy link
Contributor

swissbuechi commented Nov 12, 2023

@toobuntu

Thank you for this very useful addition to Homebrew Autoupdate!

I'm glad you like it 👍🏻

Out of curiosity, why do you invoke a subshell and then echo the password, when it works as well to not do that?

The `brew autoupdate start --sudo` command does generate the content of a script, that will invoke pinentry and echo out the pw. The command will then set the `SUDO_ASKPASS` environment variable to the path of this script. Every command which supports `SUDO_ASKPASS` will now invoke this script automatically.

EDIT:

@toobuntu was right, I did not understand his initial question about invoking a subshell, he already fixed it in PR: #128

@swissbuechi
Copy link
Contributor

@DomT4 I think this issue could now be closed.

@DomT4 DomT4 closed this as completed Dec 29, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 2, 2024
@DomT4 DomT4 unpinned this issue Feb 16, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests