Bash Tips: Passing Passwords
By
Bash offers any number of simplifications, especially when it comes to pesky individual steps in installation routines for larger software packages. Some caution is advisable, though, if you need to handle database and application passwords, which can easily be compromised.
From the administrator’s point of view, installing web applications always follows the same pattern: download and unpack the package, prepare the database, then introduce the two components to one another, typically in the form of a configuration file. To discover what entries you need – in what syntax and in which file – you traditionally read the README, but the installation can be faster for an administrator (and often less prone to error) if the developers include a shell script that takes the administrator by the hand and guides them through the settings.
This is the approach that the community surrounding Magento, a popular eCommence platform for PHP, takes. The website provides an installer in the form of a Bash script. The script (see an excerpt in Listing 1) follows a simple pattern; it queries whether the required MySQL database exists, asks for various connection information for the database, then downloads the required packages with wget. It then sets up a couple of permissions and feeds a schema to the database so you can launch the web application.
Listing 1: Magento Installer
01 #!/bin/bash 02 03 clear 04 05 echo "To install Magento, you will need a blank database ready with a user assigned to it." 06 07 echo -n "Database Host (usually localhost): " 08 read dbhost 09 10 echo -n "Database Name: " 11 read dbname 12 13 echo -n "Database User: " 14 read dbuser 15 16 echo -n "Database Password: " 17 read dbpass 18 19 echo -n "Store URL: " 20 read url 21 22 echo -n "Admin Username: " 23 read adminuser 24 25 echo -n "Admin Password: " 26 read adminpass 27 [...] 28 echo "Downloading and extracting packages ..." 29 30 wget http://www.magentocommerce.com/downloads/assets/1.4.1.1/magento-1.4.1.1.tar.gz 31 wget http://www.magentocommerce.com/downloads/assets/1.2.0/magento-sample-data-1.2.0.tar.gz 32 tar -zxvf magento-1.4.1.1.tar.gz 33 tar -zxvf magento-sample-data-1.2.0.tar.gz 34 [...] 35 echo "Importing sample products ..." 36 mysql -h $dbhost -u $dbuser -p$dbpass $dbname < data.sql 37 [...] 38 echo "Installing Magento ..." 39 40 php-cli -f install.php -- \ 41 --license_agreement_accepted "yes" \ 42 --db_host "$dbhost" \ 43 --db_name "$dbname" \ 44 --db_user "$dbuser" \ 45 --db_pass "$dbpass" \ 46 [...] 47 echo "Finished installing Magento"
Visible Secrets
Security-conscious administrators will have noticed a couple of details. In line 16, the script uses echo -n "password: **" to create a prompt that doesn’t cause a line break. The -n option keeps the cursor to the right of the output. The script then prompts for the database password. Some lines farther down, this pattern is repeated for the administrator account.
If you work in an open plan office or suspect that somebody is shoulder surfing, you will not be very happy to see the password entry echoed onto the screen. The Bash read command normally repeats all of your input on the standard output.
At this point, it could be useful to think about how these characters actually get where they are. If a user is sitting directly in front of the computer, the physical keyboard passes the key presses to the kernel. The kernel passes them to an X server, assuming an X11 interface is running, and the X server converts them into X events and sends them to the correct window; this will be a terminal emulation such as xterm or konsole.
Inside the terminal program you will typically have a shell like Bash running. The two programs are connected by a pipe that presents a pseudo-terminal device such as /dev/pts/0 on the terminal side and the standard input on the shell side. If a Bash user needs a file for this, they can use /proc/self/fd/0. Two other pipes, numbered 1 and 2, combine the two sides for the standard output and the standard error output in the same way (see Figure 1).
The terminal program is also responsible for showing the keys you press in the terminal, not in the shell. To try this out, you can issue the command
stty -echo
in the shell. The command then uses ioctl() to send a change to the terminal driver, which will not display any keys you press from now on. However, the shell will continue to process commands and create the normal output. To restore the normal state, you just need to enter the complementary command:
stty echo
Curious Eyes
This means you can disable the echo in shell scripts and then reenable it after entering the password. To avoid the need to use this external command, Bash also has a built-in function that works in a similar way. The -s option in read also tells the shell to suppress the echo.
Bash has another couple of useful options here: for example, the -n <number> key defines the number of characters that read should read. You don’t even need a newline for this, which the shell always otherwise requires to terminate input. If you use a combination of read -n1 x, Bash will wait for a single key press and store this in the variable x.
Sometimes – in wild arcade shooters, for example – programmers only want to wait a limited time for input. The option for handling this is -t <seconds>. After the specified time, Bash processes the subsequent command. Then you need to check the exit status of the command with $? to discover whether or not you have any input. Listing 2 implements proof of concept in the form of a small race into space in retro design. The user can guide a small spaceship through an asteroid belt using the G and H keys, leaving a tail of exhaust gas in its wake.
Listing 2: Space Race in Bash
01 #!/bin/bash 02 03 pos=40 04 width=80 05 06 while true; do 07 read -t1 -s -n1 x 08 case "$x" in 09 g) pos=$(($pos - 1)) ;; 10 h) pos=$(($pos + 1)) ;; 11 esac 12 for ((i=0; i < $width; i++)) 13 do 14 if [ $i -eq $pos ]; then 15 echo -n 'V' 16 elif [ $(($RANDOM % 9)) -eq 0 ]; then 17 echo -n '*' 18 else 19 echo -n ' ' 20 fi 21 done 22 echo 23 done
The Magento installer, now improved by adding read -s, has another problem. In line 36 of Listing 1, the script calls MySQL to initialize the database and uses the -p$dbpass option to pass the password it queried previously into the database. Other users logged in to the same computer at run time can see these details in the clear in the process list by typing ps auxwww.
This explains why passwords should be banned from command-line arguments. An alternative when handing over data would be to use environmental variables, but you can access these in the same way with ps aueww. Absurdly, many programs implement this insecure method of launching MySQL via the MYSQL_PWD environmental variable. The best way to transfer a cleartext password will thus be in the configuration files, which the software reads, or, alternatively, with the use of pipes, such as standard input. Purists would comment that unencrypted passwords should never be stored in the clear and point instead to hashes or tokens, in the style of Kerberos. However, you might find it difficult to implement this with Bash alone.
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
Gnome 48 Debuts New Audio Player
To date, the audio player found within the Gnome desktop has been meh at best, but with the upcoming release that all changes.
-
Plasma 6.3 Ready for Public Beta Testing
Plasma 6.3 will ship with KDE Gear 24.12.1 and KDE Frameworks 6.10, along with some new and exciting features.
-
Budgie 10.10 Scheduled for Q1 2025 with a Surprising Desktop Update
If Budgie is your desktop environment of choice, 2025 is going to be a great year for you.
-
Firefox 134 Offers Improvements for Linux Version
Fans of Linux and Firefox rejoice, as there's a new version available that includes some handy updates.
-
Serpent OS Arrives with a New Alpha Release
After months of silence, Ikey Doherty has released a new alpha for his Serpent OS.
-
HashiCorp Cofounder Unveils Ghostty, a Linux Terminal App
Ghostty is a new Linux terminal app that's fast, feature-rich, and offers a platform-native GUI while remaining cross-platform.
-
Fedora Asahi Remix 41 Available for Apple Silicon
If you have an Apple Silicon Mac and you're hoping to install Fedora, you're in luck because the latest release supports the M1 and M2 chips.
-
Systemd Fixes Bug While Facing New Challenger in GNU Shepherd
The systemd developers have fixed a really nasty bug amid the release of the new GNU Shepherd init system.
-
AlmaLinux 10.0 Beta Released
The AlmaLinux OS Foundation has announced the availability of AlmaLinux 10.0 Beta ("Purple Lion") for all supported devices with significant changes.
-
Gnome 47.2 Now Available
Gnome 47.2 is now available for general use but don't expect much in the way of newness, as this is all about improvements and bug fixes.