When a user logs in, and their password is about to expire, they are presented with a warning. However, unless the user is observant, they will generally ignore this warning and wait until the actual password expires before changing it. If this is the case, you can be sure that some users will lock up their account trying their old password beyond what the loginretries allows. This means a call to the support desk to unlock the account, before they can change their password. Being proactive, you can determine when the password is due to expire and send a warning email to the user. They are more likely to pay attention to an email than a message on a screen once logged in. For local authentication, the attributes are present using the pwdadm andlsuser command to determine the next password change or the password expiry of that user.
As demonstrated earlier in this article, the expiry of a password is governed by the maxage attribute. For example:
maxage=0 means never to expire
maxage=2 means will expire in two weeks.
AIX (UNIX® and Linux®) stores the time in the epoch format in seconds, so first you must determine how many seconds in a week, as this is how maxage measures the time between password expiry, that is in week numbers.
There are 86400 seconds in a day, so multiplying that by seven comes in at 604800. So there are 604800 seconds in a week.
The next command you need to look at is the pwdadm, which in turn queries the file /etc/security/passwd. This file holds the values in seconds when a user last changed their password. Interrogating the file or using the pwdadm command will return the same result. For this demonstration, let us query the user spoll:
# grep -p "spoll:" /etc/security/passwd
spoll:
password = EvqNjMMwJzXnc
lastupdate = 1274003127
flags = ADMCHG
# pwdadm -q spoll
spoll:
lastupdate = 1274003127
flags = ADMCHG
You can see the lastupdate value in seconds from the above output. In other words, the last time the password was changed:
1274003127
Next, using the lsuser or interrogating the file with /etc/security/user, you can determine the number of weeks before the user spoll password will expire:
# grep -p "spoll:" /etc/security/user
spoll:
admin = false
maxage = 4
# lsuser -a maxage spoll
spoll maxage=4
You can see from the above output that the number of weeks before password expiry is 4.
The next task is then to multiply the number of seconds in a week by the number of weeks before the user spoll password is due to expire. In this case, it is 4:
604800 * 4
# expr 604800 \* 4
2419200
Next, you need to add the maxage value in seconds (604800 * 4) to the last time the password was changed:
2419200 + 1274003127
# expr 2419200 + 1274003127
1276422327
You can now convert that number of seconds from UNIX epoch into a more meaningful current time presentation. You can use different tools, but for this demonstration you'll use gawk with the strftime function:
# gawk 'BEGIN {print strftime("%c",'1276422327')}'
Sun Jun 13 10:45:27 BST 2010
The above calculation gives the time of the next password expiry.
So, you now know that user spoll's password was last changed on ( from the pwdadm command):
# gawk 'BEGIN {print strftime("%c",'1274003127')}'
Sun May 16 10:45:27 BST 2010
And that it will expire on:
Sun Jun 13 10:45:27 BST 2010
Now you have the building blocks to determine when a password expires. It is a straight forward process to loop through all users and produce a report. Producing a report, especially when being audited, saves you time from the consuming task of extracting individual information. Once the report is produced you can print it or email it to the security administrators for review. I state this from experience, an auditor likes nothing better than a report detailing all the attributes you are required to produce, rather than ad-hoc screen shots. The report also serves as a reminder to system administrators to make sure their password policy is implemented as a standard across all servers. Viewing the report, you can spot any inconsistencies on the password policy between different users.
Ideally, a report should cover at least the following password attributes for each user:
maxage
pwdadm flags set
last password change date
next password change date
Listing 4 contains a script that will generate such a report on login password attributes. When this script is executed, a report is generated on the user's password attributes. The output taken from my system is contained in Listing 3. Looking more closely at Listing 3, it contains 5 columns:
User: The actual user
Change weeks: Weeks before the next password change (maxage value)
Last change password: Date of last password change
Flags: Any pwdadm flags set
Next change password: Date of the next due password change
Listing 3. next_pwch command
# next_pwch1
user change last change flags next change
weeks password password
root 0 Sun Feb 21 09:44:59 GMT 2010
daemon 0 password never set
charlie 0 Sun Feb 28 16:35:36 GMT 2010
kilo 5 Mon May 17 09:38:57 BST 2010 NOCHECK Mon Jun 21 09:38:57 BST 2010
xray 0 Sun Feb 28 16:42:20 GMT 2010
jane 0 password never set
plutt 1 Sat Apr 24 20:21:17 BST 2010 Sat May 1 20:21:17 BST 2010
spoll 4 Sun May 16 10:45:27 BST 2010 Sun Jun 13 10:45:27 BST 2010
foxtrot 5 Sat Feb 20 19:25:48 GMT 2010 ADMCHG Sat Mar 27 19:25:48 GMT 2010
From the users on my system as contained in Listing 3. I can determine from the report the following:
User daemon and jane have never had their initial password set.
User root, charlie and xray do not have an entry for next password change; this is due to the maxage=0 on the accounts (password never to expire).
User kilo will not be forced to adhere to password rules, as denoted by the pwdadm NOCHECK flags.
The pwdadm ADMCHG flags have been set on user foxtrot's account. This means he will be forced to change his password upon next login.
The script could easily be amended to include other user attributes like rlogin, login, su values.
Listing 4. next_pwch
!/bin/sh
# next_pwch
# display date of next passwd change
# maxage value is in number of weeks
# secs in a day is:86400 ..so
secs_in_week=604800
log=/home/naeem/next_pwch.log
>$log
myhost=`hostname`
mydate=`date +"%d-%m-%y"`
echo " Date: $mydate" >>$log
echo "Local Password Expiry $myhost">>$log
list=$(lsuser -a registry ALL|grep -w files| awk '{print $1}')
echo "user change last change flags next change"
echo " weeks password password"
for user in $list
do
wks_before_ch=$(lsuser -a maxage $user | awk -F '=' '{print $2}')
if [ "$wks_before_ch" = "" ]
then
# krb5 / ldap /limbo"
expire="??"
else
expire=$wks_before_ch
fi
last_ch_pw=$(pwdadm -q $user | grep last | awk '{print $3}')
# echo "last pw change : $last_ch_pw"
if [ "$last_ch_pw" = "" ]
then
passset="password never set"
else
last_ch_pw_conv=$(gawk 'BEGIN {print strftime("%c",'$last_ch_pw')}')
last_pw_ch=$last_ch_pw_conv
passset=$last_pw_ch
total_secs=$(expr $secs_in_week \* $wks_before_ch)
#echo "total secs: $total_secs"
# weeks + last pw change
date_to_ch=`expr $total_secs + $last_ch_pw`
pw_flags=$(pwdadm -q $user | grep flags | awk '{print $3}')
pw_flags=$pw_flags
# now convert to normal
next_pw_ch=$(gawk 'BEGIN {print strftime("%c",'$date_to_ch')}')
fi
#echo "..$user..$wks_before_ch..$passset"
if [ "$wks_before_ch" = "0" ]
then
next_pw_ch=""
else
next_pw_ch=$next_pw_ch
fi
if [ "$passset" = "password never set" ]
then
#echo "..$user.."
next_pw_ch=""
fi
printf "%-8s %-2s %-28s %-10s%-28s\n"
"$user" "$expire" "$passset" "$pw_flags" "$next_pw_ch"
done