22

When I want to ask for a password in a bash script, I do that :

read -s

...but when I run bash in POSIX mode, with sh, the -s option is rejected:

$ read -s
sh: 1: read: Illegal option -s

How do I securely ask for an input with a POSIX-compliant command ?

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
Hey
  • 681

2 Answers2

30
read_password() {
  REPLY="$(
    # always read from the tty even when redirected:
    exec < /dev/tty || exit # || exit only needed for bash

    # save current tty settings:
    tty_settings=$(stty -g) || exit

    # schedule restore of the settings on exit of that subshell
    # or on receiving SIGINT or SIGTERM:
    trap 'stty "$tty_settings"' EXIT INT TERM

    # disable terminal local echo
    stty -echo || exit

    # prompt on tty
    printf "Password: " > /dev/tty

    # read password as one line, record exit status
    IFS= read -r password; ret=$?

    # display a newline to visually acknowledge the entered password
    echo > /dev/tty

    # return the password for $REPLY
    printf '%s\n' "$password"
    exit "$ret"
  )"
}

Note that for those shells (ksh88, mksh and most other pdksh-derived shells) where printf is not builtin, the password would appear in clear in the ps output (for a few microseconds) or may show up in some audit logs if all command invocations with their parameters are audited. In those shells however, you can replace it with print -r -- "$password".

In any case echo is generally not an option.

Another POSIX-compliant one that doesn't involve revealing the password in the ps output (but might end up having it written onto permanent storage) is:

cat << EOF
$password
EOF

Also note that zsh's IFS= read -rs 'pass?Password: ' or bash's IFS= read -rsp 'Password: ' pass issue the Password: prompt on stderr. So with those, you might want to add a 2> /dev/tty to make sure the prompt goes to the controlling terminal.

In any case, make sure you don't forget the IFS= and -r.

26

read -s is not in POSIX. If you want to be POSIX-compliant use the stty -echo. stty and its echo parameter are defined in POSIX.

#!/bin/bash
stty -echo
printf "Password: "
read PASSWORD
stty echo
printf "\n"

This will work on all shells that conform to POSIX.

Source

serenesat
  • 1,326
  • 8
    to highlight a point from the answer in @arkadiusz-drabczyk's comment, it'd be a good idea to trap all the signals you can in order to turn stty echo back on -- in case the user gets confused and hits control-C during the read PASSWORD section. – Jeff Schaller Aug 13 '15 at 12:36
  • read the linked answer or see Stephane's answer in this thread – Jeff Schaller Aug 13 '15 at 15:00
  • 2
    You shouldn't turn on echoing unconditionally, you should save and restore the old setting. Many people work in Emacs shell buffers, and this normally has echoing disabled because Emacs is doing the echoing itself. The other answer shows how to do this. – Barmar Aug 19 '15 at 19:37