How to get password from shell script without echo

Keywords: shell Linux Cygwin Unix

I have a script that automates processes that need access to password protected systems. Access the system through a command-line program that accepts the user password as a parameter.

I want to prompt the user to type their password, assign it to a shell variable, and then use that variable to build the command line of the accessor (which, of course, produces the stream output that I'll work with).

I'm a fairly competent shell programmer in Bourne / Bash, but I don't know how to accept user input without it echoing to the terminal (or possibly with the '*' character).

Can I help you?

#1 building

One liner:

read -s -p "Password: " password

Under Linux (and cygwin), this form applies to bash and sh. But it may not be the standard Unix sh.

For more information and options, type help read in bash.

$ help read
read: read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
Read a line from the standard input and split it into fields.
  ...
  -p prompt output the string PROMPT without a trailing newline before
            attempting to read
  ...
  -s                do not echo input coming from a terminal

#2 building

The option read for this - s is not defined in the POSIX standard. Please see http://pubs.opengroup.org/onlinepubs/9699919799/utilities/read.html . I wanted something suitable for any POSIX shell, so I wrote a small function that uses stty to disable echo.

#!/bin/sh

# Read secret string
read_secret()
{
    # Disable echo.
    stty -echo

    # Set up trap to ensure echo is enabled before exiting if the script
    # is terminated while echo is disabled.
    trap 'stty echo' EXIT

    # Read secret.
    read "$@"

    # Enable echo.
    stty echo
    trap - EXIT

    # Print a newline because the newline entered by the user after
    # entering the passcode is not echoed. This ensures that the
    # next line of output begins at a new line.
    echo
}

This function behaves very similar to the read command. The following is a simple use of read, followed by a similar use of read'u secret. The input to read ﹣ secret appears empty because it is not echoed to the terminal.

[susam@cube ~]$ read a b c
foo \bar baz \qux
[susam@cube ~]$ echo a=$a b=$b c=$c
a=foo b=bar c=baz qux
[susam@cube ~]$ unset a b c
[susam@cube ~]$ read_secret a b c

[susam@cube ~]$ echo a=$a b=$b c=$c
a=foo b=bar c=baz qux
[susam@cube ~]$ unset a b c

This is another use of the - r option to keep the backslash in the input. This is valid because the read? Secret function defined above passes all the parameters it receives to the read command.

[susam@cube ~]$ read -r a b c
foo \bar baz \qux
[susam@cube ~]$ echo a=$a b=$b c=$c
a=foo b=\bar c=baz \qux
[susam@cube ~]$ unset a b c
[susam@cube ~]$ read_secret -r a b c

[susam@cube ~]$ echo a=$a b=$b c=$c
a=foo b=\bar c=baz \qux
[susam@cube ~]$ unset a b c

Finally, this is an example of how to use the read? Secret function to read a password POSIX compliant.

printf "Password: "
read_secret password
# Do something with $password here ...

#3 building

First, if someone wants to store any password in a file, I'll make sure it's hashed. This is not the best security, but at least it won't be plain text.

  1. First, create the password and hash it:

    echo "password123" | md5sum | cut -d '-' -f 1 > /tmp/secret
  2. Now, create your program to use the hash. In this case, the applet receives the user's input password without echo, and then converts it to a hash to compare it with the stored hash. If it matches the stored hash, access is granted:

    #!/bin/bash PASSWORD_FILE="/tmp/secret" MD5_HASH=$(cat /tmp/secret) PASSWORD_WRONG=1 while [ $PASSWORD_WRONG -eq 1 ] do echo "Enter your password:" read -s ENTERED_PASSWORD if [ "$MD5_HASH" != "$(echo $ENTERED_PASSWORD | md5sum | cut -d '-' -f 1)" ]; then echo "Access Deniend: Incorrenct password!. Try again" else echo "Access Granted" PASSWORD_WRONG=0 fi done

#4 building

Use stty Turn echo off and then back on.

#5 building

POSIX compliant answer. Note that / bin/sh is used instead of / bin/bash. (it does work with bash, but it doesn't need bash.)

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

Posted by trampolinejoe on Mon, 17 Feb 2020 03:23:02 -0800