------------------------------------------------------------------------------- Password Reading and Handling For Terminal password reading scroll down to... "Plain TTY Prompted Password Reading" This includes a lot of information on using "systemd-ask-password" For Programs see below... "Password Reading from a Program" For development of a BASH password reading helper... https://antofthy.gitlab.io/info/crypto/passwd_askpass_stars.txt =============================================================================== GUI Password Reading Programs. Why re-invent the wheel. There are lots of programs that have already been written for getting password from users, and which then pipe the result to stdout, ready to feed into the program that needs it, or to be buffered in a variable. Examples include... /usr/libexec/openssh/x11-ssh-askpass Prompt /usr/libexec/openssh/ssh-askpass Prompt /usr/bin/ssh-askpass Prompt /usr/libexec/openssh/gnome-ssh-askpass Prompt /usr/lib/openssh/gnome-ssh-askpass Prompt /usr/lib64/seahorse/seahorse-ssh-askpass Prompt /usr/lib/git-core/git-gui--askpass Prompt zenity --title=Title --entry --text=Prompt --hide-text kdialog --title Title --password Prompt Xdialog --title Title --stdout --password --inputbox "Prompt" 0x0 yad --title Title --mouse --on-top \ --entry --hide-text --entry-label "Password:" # Note "pinentry" has a very weird interface, designed for program use... # BUT also has some good options for positioning of the window # Quite a few programs actually use it too! { echo "SETDESC Title" # Window Title echo "SETDESC title" # main descriptive text (above prompt) echo "SETPROMPT Password" # the prompt before input window echo "SETQUALITYBAR" # enable a passphrase quality bar echo "GETPIN" # Now DOIT } | pinentry | sed -n 's/^D //p' These programs can be used for general password entry, but often do not provide any configuration options to let you re-purpose them to your application. Many systems actually specify the password reading program to use in the SSH_ASSPASS environment variable (set during system login). This lets the user override the method by which passwords will be entered, and let them use other password entry systems, sources, and key rings. However only a programs needing passwords will make use that environment variable :-( Of course if X windows is not enabled you will need to fall back to some form of TTY method, or even a curses method such as "dialog" (see below). My views on the above list... YAD looks to be the cleanest and most configurable, especially with its general overall clean look and popup position. Then 'x11-ssh-askpass' which is a little more configurable (and even has a manpage!), than other 'askpass' type programs. Though I would include a little X windows resource modification to make it cleaner. title="Decrypt Data" prompt="Password" /usr/libexec/openssh/x11-ssh-askpass \ -xrm "*Dialog.title:$title" \ "$prompt" PinEntry is not bad, and is active development as part of GPG. However it has a VERY different application interface than most other password input helpers. And likes to grab the display. See "pinentry.txt" After that Zenity would be a good choice. And finally Xdialog is pretty 'ugly' looking, in its widget placement. ------------------------------------------------------------------------------- GUI Double Password Entry... When you are encrypting data, (essentially entering a new password) you want to read a password twice, and then allow the user to try again, or cancel, if the two passwords don't match. However very few GUI password helpers provides this capability! --- pinentry See "pinentry.txt" sed -n '/^ *|/!d; s///; s/^ //; p' <<<' | SETDESC New Password | SETREPEAT | GETPIN ' | pinentry-gtk | sed -n 's/^D //p' This will only return (outtputing a password) if the user enters the same password twice. If you don't get any output (the "sed" did not find 'D' output) the user pressed the "cancel" ('ERR' output), or helper was killed. --- zenity The "zenity" 'forms' allow you to input the password twice... However "zenity" does not check that the password is the same, it just outputs the input with the specified seperator (like a newline). For example this uses "readarray" to read the two output lines. into an array variable, then checks the two values matchs. readarray -t password < <( zenity --forms --text "Enter Password Twice" \ --add-password="Password" \ --add-password="Pwd Again" \ --separator=$'\n' ) # Check results... (( $? )) && echo Zenity Cancled [[ -z "$password" ]] && echo "Empty Password or Aborted" if [[ "$password" = "${password[1]}" ]] then echo Passwords Match else echo Passwords DO NOT Match fi printf "DEBUG:"; printf " '%s'" "${password[@]}"; printf "\n" --- XDialog result=$( Xdialog --title "$title" --stdout --password --password \ --2inputsbox "$*" 0x0 first: '' second: '' ) len=$(( ${#result} /2 )) if [[ "${result:0:len}" == "${result:len+1}" ]]; then echo "${result:0:len}"; exit 0 else exit 1 fi ------------------------------------------------------------------------------- TTY Curses input... This method generally takes over the whole TTY window (like text editors do). Which is typically very annoying for getting a password and generally not what is wanted. But if you do want to use this... dialog --stdout --insecure --title Password --passwordbox 'Prompt' 0 0 The --insecure will output stars for the typed characters The --stdout makes the result output to stdout instead of stderr. You can also add a --timeout before the 'box' option whiptail --title "@_" --passwordbox 'Password' 5 50 2>&1 >/dev/tty Very simular to dialog but with better clean up (use of alternate screen) Note the result is on stderr, while stdout is assumed to be the TTY. The stars are output by default, but no --timeout option available. The 'Prompt' option string is not displayed. ------------------------------------------------------------------------------- Plain TTY Prompted Password Reading... (Tools & Helpers) There is not a lot of easilly obtainable 'helper' programs for TTY password input. Almost every program rolls its own... ------ askpass_stars A shell script to try and read a password while outputting stars so that the user can see that what they are typing is being relieved. https://antofthy.gitlab.io/software/#askpass_stars This will use "system-ask-password" if available, but with a TTY bug fix for use with sudo. The script also makes use of kernel cache if wanted, in a way that allows you to use it while editting files, something direct use of "system-ask-password" does not provide. For the initial development notes of this script see https://antofthy.gitlab.io/info/crypto/passwd_askpass_stars.txt -------- httpd-ssl-pass-dialog /usr/libexec/httpd-ssl-pass-dialog 'site' 'type' /opt/rh/httpd*/root/usr/libexec/httpd-ssl-pass-dialog 'site' 'type' This is used by web server "mod_ssl' package to get a password to decode the private SSL keys, when an apache webserver is starting up. You do not however have good control of the prompt, and it is not always available. Given the arguments above the prompts (in bold) becomes... Enter SSL pass phrase for site (type) : Internally all it does is define a prompt and calls "systemd-ask-password" So don't bother, and just use "systemd-ask-password" directly (see next) ------ system-ask-password HIGHLY RECOMMENDED -- or it used to be! This is an excellent program with full prompt control. systemd-ask-password "Password:" It also has the ability to interact with other methods of password input, and can even cache passwords for re-use later. For more info, see 'caching' below. A later upgrade added some extras to the basic use above... + Initially types "(press TAB for no echo)", in the color grey on start. This is then removed when the user presses the first character (use stars). If 'no echo' mode is enabled then grey part is replaced with "(no echo)" + TAB at any time will remove any stars already output and turn on 'no echo'. Later TABs after this will be included in the final output! Of course this passwords containing tabs will now need to press tab once first, before pressing the TAB's in the password. + DELETE or BACKSPACE as first character also turns on 'no echo' mode. + It understands Backspace (^H), kill-line (^U) to edit the password. + Outputs an emoji padlock character, followed by a space before the prompt. Emoji characters do not work for many terminals (like XTerms), so comes out as a dotted box in my current unicode font. This is VERY annoying, and as output is direct to the TTY. Newer versons of the command can disable this using "--emoji=off". None of these 'features' can be turned off or disabled There is ano more options too... + A useful new feature is to not output the password (--no-output) at all. In this mode you would need to save the password in the cache, and retrieve it from that cache (see 'caching' below). + You can now use --echo to echo user output, so you could use it for normal prompted input. In this case the padlock emoji is also removed from prompt. BIGGER PROBLEM... If this program is used for "sudo -A" (eg: via the "SUDO_ASKPASS" environment variable) and the user interrupts it (by typing ^C) the program tends to leave the TTY in a bad state, requiring you to run "reset" to restore things. Later versions seems to have fixed this issue. Here is wrapper script to ensure there are no TTY problems... =======8<-------- #!/bin/sh # use the systemd to ask for a password with echoed 'stars' # Warning "sudo" with interrupt - can leave the TTY in a bad state! # Thus I save and restore the TTY settings stty_save=`stty -g` trap 'stty "$stty_save"' EXIT /bin/systemd-ask-password --timeout=0 "${1:-Password: }" exit $? =======8<-------- WARNING: If a password is piped in (no input TTY), it does NOT stop reading on a End-Of-Line, but instead waits for the pipe to close. That can be bad for "co-processing" situations. My "askpass_stars" script (v2 an on) solves this by avoiding "systemd-ask-password" when input is not from a TTY, using bash "read" instead. It also includes thw above wrapper to handle older versions of the program. See my "askpass_stars" script https://antofthy.gitlab.io/software/#askpass_stars --- NO TTY systemd-ask-password... This works but is trickier, and unfortunatally also reqires sudo privalages, which is a pain. The Man pages about its are also clear-as-mud. Initiate a NO-TTY password request... sudo systemd-ask-password --no-tty "Testing No-TTY Password" A wall request (via systemd service 'systemd-ask-password-wall.service' will be sent to all TTY's on the system asking you to enter a password. But it does not tell you how to do this, not even in the man pages. TO answer the system password request, type.... sudo systemd-tty-ask-password-agent No arguments or other options. However 'sudo' privalages are needed! The password will then be prompted for, and answer will be returned to calling process. A X windows popup ask-password-agent for this would be a VERY nice addition! But alas, you will need to DIY one, if wanted. --- Linux Password caching by "systemd-ask-password"... The "systemd-ask-password" program also has the ability to cache passwords into a user kernel keyring. This is different to the gnome keyring in that it is in kernel memory only, and will also 'timeout' after a defined period, making it a much better way of providing general password caching for a specific user. For more detail see... https://antofthy.gitlab.io/info/crypto/keyring_linux_kernal.txt The "systemd-ask-password" does not provides a 'retrieve only' mode for password handling, which is required if you want to use this for encrypting files with password caching. That is because you need to read the password twice when encrypting a file, but does not ask if a password is successfully retrievd. For details see.. https://antofthy.gitlab.io/info/crypto/passwd_caching.txt ASIDE: Password caching has been incorperated into version 3 of my "askpass_stars" helper script, with these options. This is a wrapper around "systemd-ask-password" if it is available on the system... https://antofthy.gitlab.io/software/#askpass_stars Password Caching has also been built into my "keepout" script... https://antofthy.gitlab.io/software/#keepout =============================================================================== Password Reading from a Program OR: How to allow use of a password helper, with fallback to direct TTY input... When you ask a password in a script you generally want to keep it as simple as posible (that is a simple a 'no-echo' TTY reader). Result is returned using a global variable to keep things simple. But you need to ensure that the variable used is not an environment variable (the reason it is unset). If you don't the password will become visible in the process table of any child process, such as the final "tty" or "stty" call, fleeting though those commands are. =======8<-------- read_noecho() { # A 'no-echo' TTY Reader (bourne sh) # Prepare Terminal if tty >/dev/null; then echo -n "$1 " >/dev/tty # output prompt stty_save=`stty -g` # save the terminal state trap 'stty "$stty_save"' EXIT # restore it on exit trap 'echo "===INTERUPT==="; exit 10' HUP INT QUIT ABRT TERM stty -echo # turn off echo fi # Do the password read unset passwd # ensure it is not an environment variable! read passwd # read password echo '' # echo the users return # Return TTY to normal, cancel exit trap if tty >/dev/null; then stty "$stty_save" trap - EXIT HUP INT QUIT TERM fi } read_noecho "Password:" =======8<-------- BASH makes this a lot simpler... A "-s" option that can be used to ensure no-echo regardless of any current 'stty' settings. You can add a "-p prompt" which will automatically be disabled if the input is not from a TTY. This means you don't need the 'stty' tests above. If using bash you should also ALWAYS add an "-r" option to ensure correct handling of a final backslash. This option is needed even when you are reading the input one character at a time. =======8<-------- read_noecho() { # A 'no-echo' TTY Password Reader (BASH) unset passwd # ensure it is not an environment variable! read -r -s -p "$1" passwd tty >/dev/null && echo '' } =======8<-------- =======8<-------- An alternative no-echo TTY reader using python read_noecho() { python3 -m getpass -c "print(getpass('$1 '))" } =======8<-------- Now that we have a 'fallback' password reader... We can wrap that with another function to use a password helper if the user has provided one (via $TTY_ASKPASS environment variable). Or optionally fall back to using the linux "systemd-ask-password" program, if available. This is Bourne shell version (with fallbacks to "read_noecho()" function above) =======8<-------- read_password() { # Read password from helper, or no-echo fallback unset passwd # ensure it is not an environment variable! if [ "X$TTY_ASKPASS" != 'X' ]; then # User defined password reader passwd=`$TTY_ASKPASS "$1"` elif [ -x /usr/bin/systemd-ask-password ]; then # Linux systemd password reader passwd=`/usr/bin/systemd-ask-password "$1"` else read_noecho "$1" fi # Final checks -- adjust to suit password standards of your application [ "X$passwd" = 'X' ] && Error "Zero length password not allowed." } =======8<-------- And this BASH version is not that much different... =======8<-------- read_password() { # Read password from helper, or no-echo fallback unset passwd # ensure it is not an environment variable! if [[ "$TTY_ASKPASS" ]]; then # User defined password reader passwd=$("$TTY_ASKPASS" "$1"