When migrating users, an initial password should be provided. The user is then typically e-mailed or told of their new password via a phone call. The user will then be prompted to change their password when logging in (that is, if the security password policy rules are enforced). Password changes can also occur through ad-hoc requests which will require resetting the user account passwords, be it locally or remotely. Going through these password changes takes time and is very repetitive. However, using the AIX utility chpasswd (which is also shipped with Linux variants), these tasks can be carried out and repeated with ease.
Choosing a good password is, however, another matter. It is easy when changing or resetting several passwords at once to use dictionary words or even the users name, but, this is not good password policy. A password should be fairly easy enough to remember but not hard enough that the user has to write it down to remember it. Some people suggest using random passwords for ordinary user accounts is good security policy. I suggest that it is only good policy if the user can remember their own password. If the user writes their password down on a sticky note, they will very likely leave it where they can easily retrieve it, like underneath their desktop or in their desk draw. Ultimately, this might be an easy place for a suspecting intruder to find the user's password.
A good tool to use for generating pronounceable and non-pronounceable passwords, be it from a system administrator's perspective or from a user who wants to generate their own password, is the utility application called pwgen. Pwgen can generate one or multiple passwords, and you can specify different password lengths, which can include using a capital or numeric digit.
In this article, I will demonstrate the use of chpasswd and pwgen, and how they can be used interactively, or in batch, when dealing with password changes. I first came into contact with chpassswd when migrating users into an LDAP environment a few years back. Now it is my tool of choice for changing passwords, non-interactively, local or remote accounts. To see where to download pwgen be it binary or source see the Resources section.
With chpasswd, you can change a single or many account passwords in one hit. This means no more re-typing the password as you would normally do on the command line. Though chpasswd can be used interactively, I suggest using it in non-interactive mode. Use chpasswd since it is a quick way to change passwords.
The format to use chpasswd is:
chpasswd -f <pwdadm flags> -c |
Where:
-f pwdadm flags can be parsed
-c clears the password flags
The user and password are read from the standard input in the format:
user_name:user_password |
Imagine we have just created three users accounts with the following names: alpha, bravo and charlie
No password has been set on these accounts yet, you can tell this by interrogating the /etc/passwd file and the pwdadm command:
# tail /etc/passwd alpha:*:209:1:alpha.apps:/home/alpha:/usr/bin/ksh bravo:*:210:1:bravo.suppt:/home/bravo:/usr/bin/ksh charlie:*:211:1:charlie.suppt:/home/charlie:/usr/bin/ksh |
Notice that the passwd file that the second column has a '*', this informs us that no password has yet been set. This can also be confirmed by querying one of the users with the pwdadm command:
# pwdadm -q alpha alpha: |
No output has been produced, as no password has been set. If there was, then the 'lastupdate' field would be populated with a UTC timestamp in seconds when it was set.
Using chpasswd, I will demonstrate two ways these users will have there initial passwords set. In the following example, I am echoing from the command line the username of alpha with the password of mypasswd then piping through to chpasswd:
echo "alpha:mypasswd" | chpasswd |
The login and password details can also be contained in a string and piped through to chpasswd, like so:
# detail="charlie:charpw" echo $detail | chpasswd |
Now querying user alpha via pwdadm we can see that the flags value ADMCHG has been set, which is the chpasswd default setting when resetting passwords:
# pwdadm -q alpha
alpha:
lastupdate = 1265765265
flags = ADMCHG
|
The ADMCHG indicates that next time the user alpha attempts to login using their initial password (mypasswd) that has been set, user alpha will be forced to change their password. This also applies to attempts on other accounts that have their ADMCHG flags set.
Passwords can also be changed, where the details are held in a file. For example consider the following contents of the file pass:
# cat pass bravo:bravpass charlie:charpass |
In the previous file called pass, user bravo will have their password changed to bravpass and user charlie will have there password changed to charpass. To execute the password changes, simply cat the file and pipe it through to chpasswd, like so:
# cat pass | chpasswd |
A file can also be redirected into chpasswd for processing. In this example, I'll specify that the users bravo and charlie will not have to change their password by specifying the 'c-' option (clear password flags) like so:
# chpasswd -c < pass |
Using pwdadm to query the user charlie , the following is produced:
# pwdadm -q charlie
charlie:
lastupdate = 1265853052
|
Notice the use of the clear flags option in the chpasswd command; it has cleared all flags value in that field.
To determine when a password was last set or changed, as indicated in the last update value in pwdadm output. The UTC time stamp in seconds will need to be converted into a more meaningful current date time stamp.
Both of the following commands return the last update of a password change or initial set (if present). In this example, we are interrogating user alpha's last password update:
# lssec -f /etc/security/passwd -s alpha -a lastupdate
alpha lastupdate=1265940457
# pwdadm -q alpha
alpha:
lastupdate = 1265940457
flags = ADMCHG |
You can use perl or gawk to convert the UTC into the current time stamp, both of the following examples achieve the same result:
# perl -e 'use POSIX;print ctime(1265940457)'
Thu Feb 11 20:07:37 2010
# gawk 'BEGIN {print strftime("%c",1265940457)}'
Thu Feb 11 20:07:37 GMT 2010 |
The current pwgen version is 2.0.6 if you download the source. The binary version is at 2.0.5. In this demonstration I'll be using the source.
Once downloaded, unzip it and compile it:
# gunzip pwgen-2.06.tar.gz # tar -xvf pwgen-2.06.tar # cd pwgen-2.06 #./configure # make # make install |
The pwgen binary will be installed in /usr/local/bin.
Pwgen generates passwords that can be random (hard to remember) or easy on the brain (not to hard to remember). The utility can be used both interactively or in batch mode for scripts.
By default, pwgen prints a screen full of passwords to the standard output. Generally you would not want this; however, this could be useful if you or a user wishes to choose a password for a one-time use that is entered manually. When generating passwords, pwgen will try and mix it up with a number and capital by default.
The format is:
pwgen <options> <password_length> <number_of_passwords> |
Common options are:
| -1 | print passwords one per line |
| -c | must include a capital letter |
| -n | must include a number |
| -s | random password |
To print a single password of 8 character length:
# pwgen 8 1 eej3eeZu |
To print three passwords of 7 character length forcing the use of a capital letter use:
# pwgen -c 7 3 |
To print 10 passwords of 8 character length forcing the use of a capital letter and number use:
# pwgen -c -n 8 10 zum5Shei Choo6Eih Ub5uagei Ooxu6ohs Eix9xeip iV4yoeph Io3aeGhe taiTh6ia cuere1AW phai9Pai |
Pwgen will determine if you are executing the utility via a tty or not. If not, it will only generate one password by default, if no options are passed. This makes it easier for scripting, when you need to store values in a variable, like so:
# pass=$(pwgen) # echo $pass ohtherah |
If you prefer, you can use the back-ticks for command substitution. It achieves the same result:
pass=`pwgen`
# echo $pass
oowahxei
|
Of course, we can include as many passwords as we like. In the following example, three passwords are generated:
# pass=$(pwgen -c -n 8 3) # echo $pass EluBie0z thohku0W Ail3fu3z |
To print a truly random password of eight characters use:
# pwgen -s 8 1 9bTzZxt9 |
A note of caution should be considered when using the random option (as in the previous example). These can be extremely hard to remember and, if assigned to a user, they could write down the password. In my experience, random generated passwords should only be used for application owner accounts.
Now that we have seen the tools pwgen and chpasswd in action, we can start setting initial passwords for users. Clearly this will have to be carried out via a script, such as Listing 1. First, determine a list of users you want to set the passwords for; this list could be contained in a file (although in this demonstration the users are contained in the string $list which contains three users). For each of these users, a password of eight character length will be generated using the command when each user is processed through the loop:
pwgen 8 1 |
An initial check is carried out making sure the user account is present on the AIX host. If it is, then the user name and generated password is appended to the file passfile in the format for chpasswd to process. Once all the users have been processed, the file is piped through chpasswd. If a user is not present in /etc/passwd then no user/password entry will be present in passfile for that user.
Listing 1. setpass
#!/bin/sh
# setpass
passfile=/home/dxtans/passfile
>$passfile
list="alpha bravo charlie"
for user in $list
do
if ! grep -w ^$user /etc/passwd > /dev/null
then
echo "user NOT present: $user"
else
echo "user present: $user"
pass=$(pwgen 8 1)
echo "$user:$pass">>$passfile
fi
done
cat $passfile | chpasswd
|
After running the script setpass, the file passfile is generated with the following contents, prior to processing through chpasswd:
# cat passfile alpha:jiebuzio bravo:oegaeyay charlie:ooweipoa |
In the next example (see Listing 2), a user called foxtrot is created with a initial password and login attribute changes. The create_user script demonstrates one way this can be done using pwgen for setting the password. In this example, a password is set for 8 characters containing at least one capital and one number:
pwgen -c -n 8 1 |
First, the user foxtrot is created with the su set to false. The password is then set on the account clearing all password restrict flags for the user (that means user foxtrot will not be prompted to change their password upon login). The gecos field is then set, expanding the variable $user to become foxtrot, and "apps" is then appended to the expanded variable. The maxage is set to five weeks, user foxtrot will be forced to change the password five weeks after the last password change or password set. User foxtrot cannot change that password until after one week , as dictated by the minage=1. Finally, the group memberships are set with the primary group being staff (which is the AIX default).
Listing 2. create_user
#!/bin/sh
# create_user
user="foxtrot"
pass=$(pwgen -c -n 8 1)
echo "the passwd for $user is: $pass"
echo "creating user $user..creating password"
mkuser su=false $user
if [ $? = 0 ]
then
echo "$user:$pass" | chpasswd -c
else
echo "error: unable to create user $user"
exit 1
fi
echo "changing $user attributes..."
chuser gecos="${user}.apps" $user
chuser maxage=5 $user
chuser minage=1 $user
|
In the previous example when executing the script create_user, the output is:
# create_user the passwd for foxtrot is: oiN2hi9r creating user foxtrot..creating password changing foxtrot attributes... |
We can tell that the password flags have been cleared, by using the pwdadm command, as described earlier:
# pwdadm -q foxtrot
foxtrot:
lastupdate = 1266174412
|
Changing the root password at frequent intervals is an audit requirement. The best way to do this, in my opinion, is to ssh out to each host as root and then change the password once connected on that host. Please note however, this is one password you do not want to forget. So it maybe advantageous to either first generate the password with pwgen locally, hard code it in the script, and then delete the password from the script after it has been rolled out and after the password has been secured in a physical place, like a safe. Do not forget to inform the other system administrators of the new password.
A good practice is to have all the hosts you want to connect to remotely contained a file. Using this approach means the file can then be read by other scripts, thus stopping typos by manually putting them in your scripts. A typical file containing the hosts could be in the following format:
# cat all_hosts host1 host2 host3 host.. |
Listing 3 shows one easy way this could be done. The password has already been generated with pwgen and the password is 'tu8ahLae'. For each host we connect to, as read in the all_hosts file, the here document method is used. This means all commands that are contained between the words 'mayday' are read as standard input on the remote host. The string root:tu8ahLae is piped through to chpasswd, like so:
echo "root:tu8ahLae" | chpasswd |
Listing 3. chpw_root
#!/bin/sh
cat all_hosts | while read host
do
echo "[$host]″
ssh -T -t -l root $host<<'mayday'
hostname
echo "root:tu8ahLae" | chpasswd
if [ $? != 0 ]
then
echo " password of root change failed $host"
else
echo " password of root change OK"
fi
mayday
done
|
The chpw_root script assumes the ssh keys have been exchanged from the remote hosts to the host where the script resides.
The script contained in Listing 2 creates a user with the initial password set, though the method of informing the user of their new password is a manual one. As this often involves copying and pasting the authentication details into an e-mail and then mailing the user or telephoning the details. A more automotive method could be to e-mail the user directly from the script. To do this, a process must be in place where the user and e-mail address can be associated. One option that could be considered is to use a file containing users Ids with their respective e-mail addresses. Another option could be to have their e-mail address in their gecos field in the /etc/password file in the form: <first_name>.<last_name>@<domain>,
dxtans:!:203:1:david.tansley@btinternet.com:/home/dxtans:/usr/bin/ksh |
This scenario, however, opens the doors for typos especially if you have many AIX boxes, so it should only be considered if you administer a few boxes.
The other alternative (which I believe is a quicker method to set-up and requires zero amendments to the /etc/passwd file) is to have a global lookup file. This file could contain a list of all login-able users and their respective e-mail addresses, like so:
# cat email_lookup alpha alpha.apps@mycompany.com bravo bravo.suppt@mycompany.com charlie charlie.suppt@mycompany.com … |
This global file email_lookup containing all the user names and e-mail accounts could then be pushed out to all the boxes. Having one global file to update means less of a headache, just remember to update it when you add or delete a user, then push it out to all boxes again via scp. It does not matter if a user is not present on a remote box where the email_lookup file is present, because the lookup for that user will not take place, if changing passwords, as the user does not exist.
The script contained in Listing 4 uses the previous email_lookup file to find the user name and their respective e-mail address and notify the user of their account changes. It reads the user and password from the file passfile, (generated earlier in this demonstration) it then checks this is a valid account by checking /etc/passwd. If all is OK, then the e-mail address is extracted for that given user from the email_lookup file. The script assumes that the chpasswd has already been run, and the login and password details are present in the file passfile as presented earlier. Ideally the script should also contain the chpasswd and pwgen routines to change passwords in a single hit as demonstrated in this article. For now, the script contained in Listing 4 should give you some ideas on how to automatically notify users via e-mail once their password has been reset or changed.
Listing 4. email_user
#!/bin/sh
passfile=/home/dxtans/passfile
email_lookup=/home/dxtans/email_lookup
IFS=":"
cat $passfile | while read user pass
do
if grep -w ^$user /etc/passwd >/dev/null
then
echo "$user - found"
email_name=$(grep -w ^$user $email_lookup | awk '{print $2}')
if [ "$email_name" = "" ]
then
echo "lookup failed for this user:$user"
fi
mail -s "`hostname` account change" $email_name<<mayday
your account: $user
new password: $pass
mayday
else
echo "$user - NOT found"
fi
done
|
Using pwgen along with chpasswd allows the system administrator to automate the task of setting user passwords. The passwords generated from pwgen are not easily predictable words, thus ensuring good security practice for password changes. I have also suggested two ways a user could be notified of password changes.
Learn
- Pwgen project can be found at sourceforge
Get products and technologies
- Download the binary and source, version 2.05
Discuss
- Follow developerWorks on Twitter.
- Get involved in the My developerWorks community.
-
Participate in the AIX and UNIX forums:
- AIX Forum
- AIX Forum for developers
- Cluster Systems Management
- IBM Support Assistant Forum
- Performance Tools Forum
- Virtualization Forum
- More AIX and UNIX Forums





