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
-
Armbian 24.11 Released with Expanded Hardware Support
If you've been waiting for Armbian to support OrangePi 5 Max and Radxa ROCK 5B+, the wait is over.
-
SUSE Renames Several Products for Better Name Recognition
SUSE has been a very powerful player in the European market, but it knows it must branch out to gain serious traction. Will a name change do the trick?
-
ESET Discovers New Linux Malware
WolfsBane is an all-in-one malware that has hit the Linux operating system and includes a dropper, a launcher, and a backdoor.
-
New Linux Kernel Patch Allows Forcing a CPU Mitigation
Even when CPU mitigations can consume precious CPU cycles, it might not be a bad idea to allow users to enable them, even if your machine isn't vulnerable.
-
Red Hat Enterprise Linux 9.5 Released
Notify your friends, loved ones, and colleagues that the latest version of RHEL is available with plenty of enhancements.
-
Linux Sees Massive Performance Increase from a Single Line of Code
With one line of code, Intel was able to increase the performance of the Linux kernel by 4,000 percent.
-
Fedora KDE Approved as an Official Spin
If you prefer the Plasma desktop environment and the Fedora distribution, you're in luck because there's now an official spin that is listed on the same level as the Fedora Workstation edition.
-
New Steam Client Ups the Ante for Linux
The latest release from Steam has some pretty cool tricks up its sleeve.
-
Gnome OS Transitioning Toward a General-Purpose Distro
If you're looking for the perfectly vanilla take on the Gnome desktop, Gnome OS might be for you.
-
Fedora 41 Released with New Features
If you're a Fedora fan or just looking for a Linux distribution to help you migrate from Windows, Fedora 41 might be just the ticket.