Listing 4: chkaging script
#!/bin/sh
#
# chkaging
#
# Report current password aging settings from the
# /etc/passwd file. If -a is used, translates an
# aging value into a set of weeks numbers. If -d
# is used, translates a set of weeks number into an
# aging value.
#
# Each aging value is formed from a set of base-64
# numbers representing:
#
# 1. the number of weeks maximum before a password
# change is forced by the system,
# 2. the number of weeks minimum before a new
# password may be changed by the user, and
# 3. the number of weeks elapsed since week 0, 1970,
# when the password was last changed.
#
# The base-64 numbers are formed from the set of
# alphanumeric characters and two punctuation marks.
# The aging value follows the password, separated by a
# comma. If the comma isn't there, aging is
# deactiviated for that account. The weeks elapsed
# string may be missing, which corresponds to 0 weeks
# elapsed. That should force the password to change
# with the next login. According to passwd(4), the ..
# (00) should always force a new password on the next
# login.
#
# Copyright 1994, Lawrence S Reznick
# HISTORY
#
# 94Apr19 LSR
# The base-64 digits are output in reverse place-value
# order. That is, if the digits should have been Hm
# (H in the 64s place and m in the 1s place), the
# password aging system will output it as mH.
# Corrected the weeknum() & code_val() functions to
# handle it that way.
#
# Also, the NOW_WEEKS value is off because a 365-day
# year is really 52 weeks plus 1 day. expr doesn't
# work with floating point, so the simplest solution
# is to add 1 day for every 7 years since the epoch.
PW_FILE=/etc/passwd # Point to passwd file
#
# NOW_WEEKS holds the number of weeks elapsed since
# 1970: aging epoch
#
#NOW_WEEKS=`expr \( \`date '+%Y'\` - 1970 \) \* 52 + \`date '+%U'\``
NOW_WEEKS=`expr \`date '+%Y'\` - 1970`
NOW_WEEKS=`expr $NOW_WEEKS \* 52 + \`date '+%U'\` + \( $NOW_WEEKS / 7 \)`
#
# Given an encoded aging weeks value, return the
# numeric equivalent
#
DIGITS="./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz&q
ot;
weeknum ()
{
echo $1 |
awk '{
# for (i = 1; i <= length; i++) {
i = length;
do {
sum *= 64;
sum += index(digits, substr($0, i, 1)) - 1;
} while (--i);
}
END {
print sum;
}' digits=$DIGITS
}
#
# Given a comma-separated number list (max,min,elapsed),
# output aging code
#
code_val ()
{
echo $1 |
awk -F, '
$1 < 0 || $1 >= length(digits) {
print "Max out of range! 0 <= Max < ", length(digits);
exit;
}
$2 < 0 || $2 >= length(digits) {
print "Min out of range! 0 <= Min < ", length(digits);
exit;
}
{
code = substr(digits, $1 + 1, 1);
code = code substr(digits, $2 + 1, 1);
elapsed = $3;
do {
quot = int(elapsed / 64);
remn = elapsed % 64;
# base64 = substr(digits, remn + 1, 1) base64;
base64 = base64 substr(digits, remn + 1, 1);
elapsed = quot;
} while (elapsed >= 64);
# base64 = substr(digits, quot + 1, 1) base64;
base64 = base64 substr(digits, quot + 1, 1);
code = code base64;
print code;
}
' digits=$DIGITS
}
#
# Given a full aging value (no comma), display its
# numeric values
#
aging_val ()
{
code = $1
if [ `expr length $code` -eq 2 ]
then
code=${code}..
else if [ `expr length $code` -lt 3 ]
then
echo Invalid aging code \"$code\"
return
fi
fi
MAX=`expr $code : '\(.\)'` # Grab max weeks
MIN=`expr $code : '.\(.\)'` # Grab min weeks
ELAPSED=`expr $code : '..\(.*\)'` # Grab weeks since epoch
echo "aging set to `weeknum $MAX` weeks max, \c"
echo "`weeknum $MIN` weeks min, \c"
echo "last changed `expr $NOW_WEEKS - \`weeknum $ELAPSED\`` weeks ago."
}
#
# Collect the 1st 2 fields of the password file & parse
# the aging info
#
show_aging ()
{
INFO=`
cut -f1-2 -d: $PW_FILE | # Extract name & passwd fields
egrep -v '\*'` # Ignore disabled accounts
for n in $INFO
do
# echo "`echo $n | cut -d: -f1`\t\c"
oIFS="$IFS"
IFS="," # Use field sep to parse aging
set $n # $2 has the aging field value
IFS="$oIFS"
if [ -z "$2" ]
then
# echo aging inactive!
NOAGING="$NOAGING `echo $n | cut -d: -f1`"
else
echo "`echo $n | cut -d: -f1`\t\c"
aging_val $2
fi
done
if [ -n "$NOAGING" ]
then
echo "\rAging inactive ($PWFILE order):"
echo $NOAGING | tr ' ' '\012' | pr -t -6
fi
}
#
# Main processing
#
if [ $# -eq 0 ] # Default execution
then
show_aging # Show passwd file's aging settings
exit 0
fi
case $1 in
-a) # Turn aging value into weeks number
shift # Skip to the aging value
for v
do
echo $v = `aging_val $v`
done
;;
-d) # Turn weeks numbers into aging value
shift # Skip to the week number sets
for v
do
echo $v = `code_val $v`
done
;;
*) # Tell how program works
echo "Usage:\t`basename $0` [-a aging_codes] [-d week_nums]\n"
echo "No arg:\tTells aging settings for "$PW_FILE" file."
echo "-a arg:\tTurns aging codes into week numbers."
echo "-d arg:\tTurns max,min,elapsed num sets into aging codes."
;;
esac
exit 0
|