LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - General (http://www.linuxquestions.org/questions/linux-general-1/)
-   -   How to get a list of users with their password status (expired, account locked...)? (http://www.linuxquestions.org/questions/linux-general-1/how-to-get-a-list-of-users-with-their-password-status-expired-account-locked-294627/)

ricky_ds 02-25-2005 03:12 AM

How to get a list of users with their password status (expired, account locked...)?
 
At my company we are migrating from SCO UNIX to RHEL and one of the tasks we often had to do on SCO is get a list of all users whose password has expired and of those, who didn't react, whose account is now locked.

I can imagine this could be done by analyzing the contents of /etc/passwd and /etc/shadow but before going this way, I'd like to know if
1) there is another simpler way to do it
2) if not, then if somebody already has a similar script to share?

Thanks a lot in advance

homey 02-25-2005 08:34 AM

You're right, the information is in /etc/passwd and /etc/shadow.
Here is a script to get the information, haven't seen a script yet that totally breaks it down by field but I'm sure it can be done.
Code:

#!/bin/bash

cat /etc/passwd | grep /home | awk -F: '{print$1}' |\
while read uname ; do
  name=`cat /etc/shadow | grep $uname`
  echo $name
done

This is from Redhat.com explaining the fields of /etc/shadow
Code:


The /etc/shadow file is readable only by the root user, and contains password and optional password aging information. As in the /etc/passwd file, each user's information is on a separate line. Each of these lines is a nine field, colon delimited list including the following information:

      Username The name the user types when logging into the system. This allows the login application to retrieve the user's password (and related information).

      Encrypted password The 13 to 24 character password. The password is encrypted using either the crypt library function, or the md5 hash algorithm. In this field, values other than a validly-formatted encrypted or hashed password are used to control user logins and to show the password status. For example, if the value is ! or * the account is locked, and the user is not allowed to log in. If the value is !! a password has never been set before (and the user, not having set a password, will not be able to log in).

      Date password last changed The number of days since January 1, 1970 (also called the epoch) that the password was last changed. This information is used for the following password aging fields.

      Number of days before password can be changed The minimum number of days that must pass before the password can be changed.

      Number of days before password change is required The number of days that must pass before the password must be changed.

      Number of days warning before password change The number of days before password expiration during which the user is warned of the impending expiration.

      Number of days before the account is disabled The number of days after a password expires before the account will be disabled.

      Date since the account has been disabled The date (stored as the number of days since the epoch) since the user account has been disabled.

      A reserved field A field that is ignored in Red Hat Linux.

Here is an example line from /etc/shadow:

juan:$1$.QKDPc5E$SWlkjRWexrXYgc98F.:11956:0:90:5:30:12197:

This line shows the following information for user juan:

      The password was last changed September 25, 2002

      There is no minimum amount of time required before the password can be changed

      The password must be changed every 90 days

      The user will get a warning five days before the password must be changed.

      The account will be disabled 30 days after the password expires if no login attempt is made

      The account will expire on May 24, 2003

For more information on the /etc/shadow file, type man 5 shadow.


homey 02-25-2005 01:30 PM

Something like this may get you started...
Code:

#!/bin/bash

cat /etc/passwd |grep /home | awk -F: '{print$1}' |\
while read name ; do

uname=`cat /etc/shadow | grep $name | awk -F":" '{print}'`

a=`echo -e $uname | awk -F: '{print$3}'`
b=`echo -e $uname | awk -F: '{print$4}'`
c=`echo -e $uname | awk -F: '{print$5}'`
d=`echo -e $uname | awk -F: '{print$6}'`
e=`echo -e $uname | awk -F: '{print$7}'`
f=`echo -e $uname | awk -F: '{print$8}'`

now=$(( ($(date +%s) / 86400) ))
pass=$(( $now - $a ))
last=`date +%B" "%d" "%Y -d "-$pass day"`

if test  "$f" != "" ; then
  next=$(( $f - $now ))
  exp=`date +%B" "%d" "%Y -d "$next day"`
else
  exp=`echo N/A` 
fi

echo
echo "Information for $name"
echo "Password last changed: $last"
echo "Minumum password age: $b"
echo "Maximum password age: $c"
echo "Password warning age: $d"
echo "The account will be disabled [ $e days ] after"
echo "the password expires if no login attempt is made: "
echo "The account will expire on: $exp"
echo

done


ricky_ds 02-28-2005 08:36 AM

Quote:

Originally posted by homey
Something like this may get you started...
Thanks, that was really helpful. Here's my current version. It might be useful for others:
Code:

#!/bin/bash

formatDate() {
  date +%d"."%m"."%Y -d " $1 day"
}
padr() {
  string="$1................................................"
  echo "$string" | cut -c1-$2
}
length() {
  length=`echo "$@" | wc -c | cut -c1-8`
  length=$(( $length -1 ))
  echo $length
}
padl() {
  string="................................................$1"
  length=`length "$string"`
  echo "$string" | cut -c`expr $length - $2`-$length
}

if [ "$#" = "0" ]; then
  echo
  echo "List of user accounts with password information"
  echo "==============================================="
  echo `date`
  echo
  echo "Legend: M=Minimum password age    W=Warning in days before exp"
  echo "        Dis=Account Disabled"
  echo "------------------------------------------------------------------------------------------"
  echo "Username  |Full name                |UID  |LastChange|M|Max  |W|Passwd Exp|Dis |Acct Exp  "
  echo "----------|-------------------------|-----|----------|-|-----|-|----------|----|----------"
fi

sort /etc/passwd |grep ":/home/" | awk -F":" '{print}' |\
while read line ; do
  name=`echo -e $line | awk -F: '{print$1}'`
  uname=`cat /etc/shadow | grep -r "^$name:" | awk -F":" '{print}'`
  thisuser=`echo -e $uname | awk -F: '{print$1}'`

  if [ "$#" = "1" ] && [ "$1" = "$thisuser" ] || [ "$#" = "0" ]; then

    a=`echo -e $uname | awk -F: '{print$3}'`
    b=`echo -e $uname | awk -F: '{print$4}'`
    c=`echo -e $uname | awk -F: '{print$5}'`
    d=`echo -e $uname | awk -F: '{print$6}'`
    e=`echo -e $uname | awk -F: '{print$7}'`
    f=`echo -e $uname | awk -F: '{print$8}'`

    uid=`echo -e $line | awk -F: '{print$3}'`
    fullname=`echo -e $line | awk -F: '{print$5}'`

    now=$(( ($(date +%s) / 86400) ))
    pass=$(( $now - $a ))
    last=`formatDate -$pass`

    if test  "$f" != "" ; then
      next=$(( $f - $now ))
      exp=`formatDate $next`
    else
      exp=`echo NEVER`
    fi

    pexpt=$(( $a + $c ))
    pexpt=$(( $pexpt - $now ))
    pexp=`formatDate $pexpt`

    if [ "$#" = "1" ]; then
      echo
      echo "===Information for user $name==="
      echo "Full name: $fullname"
      echo "User ID: $uid"
      echo "Password last changed: $last"
      echo "Minumum password age: $b"
      echo "Maximum password age: $c"
      echo "Password warning age: $d"
      echo "Password expires on: $pexp"
      if test "$e" != "" ; then
        echo "The account will be disabled *$e* days after expiration"
      fi
      echo "The account expires on: $exp"
      echo
    else
      name=`padr $name 10`
      c=`padl $c 4`
      if test "$e" = "" ; then
        e="."
      fi
      e=`padl $e 3`
      exp=`padl $exp 9`
      fullname=`padr "$fullname" 25`
      uid=`padl $uid 4`
      echo "$name|$fullname|$uid|$last|$b|$c|$d|$pexp|$e|$exp"
    fi
  fi

done

This allows you to get a tabular display of all users (if launched without argument) and a verbose line-by-line list for a specific user if the username is given as a first argument. Feedback and improvements welcome.

homey 02-28-2005 09:28 AM

Cool! Here is the output which looks good except for this part...
date: invalid date ` 99996 day'
Code:

List of user accounts with password information
===============================================
Mon Feb 28 09:23:58 EST 2005

Legend: M=Minimum password age    W=Warning in days before exp
        Dis=Account Disabled
------------------------------------------------------------------------------------------
Username  |Full name                |UID  |LastChange|M|Max  |W|Passwd Exp|Dis |Acct Exp
----------|-------------------------|-----|----------|-|-----|-|----------|----|----------
date: invalid date ` 99996 day'
joe....|.........................|..501|01.03.2005|0|99999|7||....|.....NEVER
date: invalid date ` 99960 day'
jane....|.........................|..500|01.03.2005|0|99999|7||....|.....NEVER


ricky_ds 02-28-2005 09:52 AM

Can you try this on your shell? This worked fine for me. I don't know why it would return an invalid date on your system?!

Code:

# date +%d"."%m"."%Y -d " 99996 day"
10.12.2278


homey 02-28-2005 10:53 AM

I'm using FC3 if that matters.
# date +%d"."%m"."%Y -d " 99996 day"
date: invalid date ` 99996 day'


All times are GMT -5. The time now is 03:20 PM.