DomT4 / homebrew-autoupdate

:tropical_drink: An easy, convenient way to automatically update Homebrew.
BSD 2-Clause "Simplified" License
995 stars 55 forks source link

Handling Casks #40

Closed DomT4 closed 8 months ago

DomT4 commented 3 years ago

Issue:

Potential Fix:

Problems with Fix:

Hacky Temporary Workaround

Related Issues:

whazor commented 3 years ago

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

whazor commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

@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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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. https://github.com/milanvarady/Applite/issues/5#issuecomment-1692672608

swissbuechi commented 10 months ago

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 commented 10 months ago

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 commented 10 months ago

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 commented 10 months ago

The argument --sudo from PR https://github.com/Homebrew/homebrew-autoupdate/pull/110 did solve this issue.

@DomT4 I believe you can now close?

toobuntu commented 10 months ago

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 commented 10 months ago

@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: https://github.com/Homebrew/homebrew-autoupdate/pull/128

swissbuechi commented 8 months ago

@DomT4 I think this issue could now be closed.