1. Overview

Creating new users to give access to the system is a routine task for Linux system administrators. The task may involve multiple commands, like the useradd and passwd commands, as well as other administrative commands that may be required for specific Linux installations. Most system administrators usually create a shell script to simplify the task.

In this tutorial, we will quickly show the challenge of using the passwd command inside a shell script. We’ll then look at three methods to solve the problem.

2. Preparing a Simple User Creation Script

Let’s begin by exploring a straightforward script for creating a user. Firstly, the script takes the username to create as the first parameter. Inside, it calls useradd and passwd commands:

#!/bin/sh
set -e

NEWUSR=$1
useradd -m -U $NEWUSR
passwd $NEWUSR

Next, let’s set the executable flag and test it out, assuming we have sudo access:

$ chmod +x newuser.sh
$ sudo ./newuser.sh testnewuser
Changing password for user testnewuser.
New password:

Finally, we’ll just enter a specific password twice when prompted. If everything is fine, we’ll get the success message:

passwd: all authentication tokens updated successfully.

3. Making the Script Non-interactive

What if we want to automate the creation of new users using other tools such as Jenkins? Then, we would need to make the script non-interactive. That is to say that we do not want to provide the passwords of the new users via the command prompt. Instead, we want to pass the password values directly to the passwd command.

There are many ways to generate a password. Here, let’s use a simple set of commands that gives us the first 8 characters of the MD5 sum of the current Unix timestamp to use as the password:

$ date | md5sum | cut -c1-8
720e6264

Next, we’ll use the piping technique to pass that value to the passwd command within the script:

#!/bin/sh
set -e

NEWUSR=$1
useradd -m -U $NEWUSR
PASSWD=$(date | md5sum | cut -c1-8)
echo $PASSWD | passwd $NEWUSR

Let’s test it:

$ sudo ./newuser.sh testnewuser2
Changing password for user testnewuser2.
New password: Retype new password: Password change aborted.
New password: Password change aborted.
New password: Password change aborted.
passwd: Have exhausted maximum number of retries for service

The script call failed. The pipe successfully passed the password to the passwd command, but it failed to handle the second prompt with the “Retype new password” instruction.

Next, let’s explore a few methods to solve this problem.

3.1. Using stdin Option

The first method to pipe the new password to the passwd command is by using the stdin option. First, we need to check if the passwd command of our Linux distro supports that option:

$ passwd --help | grep stdin
  --stdin                 read new tokens from stdin (root only)

Next, we’ll insert it into the script:

#!/bin/sh
set -e

NEWUSR=$1
useradd -m -U $NEWUSR
PASSWD=$(date | md5sum | cut -c1-8)
echo $PASSWD | passwd --stdin $NEWUSR

Finally, let’s test it out:

$ sudo ./newuser.sh testnewuser3
Changing password for user testnewuser3.
passwd: all authentication tokens updated successfully.

3.2. Using chpasswd

The second method we explore here is to pipe the new password to the chpasswd command instead. While passwd expects the default mode of input via the input prompts, chpasswd expects the password to be passed via STDIN by default.

Inside the script, we need to pipe both the username and the password separated by a “:” to the chpasswd command:

#!/bin/sh
set -e

NEWUSR=$1
useradd -m -U $NEWUSR
PASSWD=$(date | md5sum | cut -c1-8)
echo "$NEWUSR:$PASSWD" | chpasswd

Finally, let’s have a go at it:

$ sudo ./newuser.sh testnewuser4

Interestingly, chpasswd outputs no message when it is a success as it was designed to be used non-interactively.

3.3. Passing the Password Twice

This last method is considered hackish. Therefore, we should only choose this method if neither of the previous methods is available on our Linux installation.

This method involves crafting a string that contains the password twice using “\n” as the delimiter. For example, if the variable $PASSWD holds the value of the password, we craft a string that holds the value “$PASSWD\n$PASSWD“.

Just like the previous two methods, we pipe this string to the plain passwd command using the echo command:

#!/bin/sh
set -e

NEWUSR=$1
useradd -m -U $NEWUSR
PASSWD=$(date | md5sum | cut -c1-8)
echo -e "$PASSWD\n$PASSWD" | passwd $NEWUSR

However, this time we add the  -e option to the echo command to make the shell interpret the backslash-escaped “\n” character.

Testing the script shows two prompts that ask for the password twice, just like when we use the passwd command interactively. However, the prompts do not wait for inputs from us anymore:

$ sudo ./newuser.sh testnewuser5
Changing password for user testnewuser5.
New password: Retype new password: passwd: all authentication tokens updated successfully.

4. Conclusion

In this article, we’ve explored three methods to set a user’s password non-interactively inside a shell script. Two of those three methods use the passwd command, while the other uses an alternative chpasswd command.

Comments are closed on this article!