#!/bin/sh
#
#     tiger - A UN*X security checking system
#     Copyright (C) 1993 Douglas Lee Schales, David K. Hess, David R. Safford
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2, or (at your option)
#    any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#     Please see the file `COPYING' for the complete copyright notice.
#
# Linux/2/gen_passwd_sets - 06/14/93
# Linux/2/gen_passwd_sets - 12/20/2001 - jfs
#      changed by jfs to provide support for both shadow and unshadowed
#      added SunOS gen_passwd_sets so that it works with nsswitch.conf if available
# Linux/2/gen_passwd_sets - 04/12/2003 - jfs
#      small change to that outfile gets created when the script is called
# Linux/2/gen_passwd_sets - 06/21/2003 - jfs
#      applied patch from Ryan Bradetich to identify which cryptographic
#      is used in the passwd format and simplify MD5 hashes check
# Linux/2/gen_passwd_sets - 11/18/2003 - jfs
#      Fixed call to YPCAT (only do it if it has been found). Thanks to
#      Dale Martin for the patch.
# Linux/2/gen_passwd_sets - 01/15/2004 - jfs 
#      YPCAT call to avoid errors in hosts that are not properly configured.
#      (i.e. nsswitch.conf is defined to use NIS but there's no NIS host)
#      Also, redirect error of ypcat's which to /dev/null since it's not
#      a requirement of the script (others are) and many systems do not 
#      include it, specially in Debian (Debian bug #225910)
# Linux/2/gen_passwd_sets - 06/17/2004 - jfs 
#      Change to do proper extraction of users from passwd and shadow files
#      avoiding conflicts when sorting lines with and without alphabetical
#      characters (which might make some lines be swapped and some users 
#      not be accounted for properly)
#      NOTE: This should be done in other systems too
# Linux/2/gen_passwd_sets - 06/27/2004 - jfs 
#      Fixed location of sort call which made duplicates appear, also
#      define CAT if not defined (for local testing)
# Linux/2/gen_passwd_sets - 05/14/2005 - jfs 
#      Add LDAP password support with patch provided by Micha Kersloot
#      (Debian bug #307505)
# Linux/2/gen_passwd_sets - 08/4/2005 - jfs 
#      Generate LDAP source file if using LDAP passwords
# Linux/2/gen_passwd_sets - 02/26/2011 - jfs 
#      Apply patch by Timo Lindfors to add support for SHA-512 passwords
#      (This is the default used in Debian GNU/Linux squeeze and later releases)
#      Corresponds to patch #7186
#
#-----------------------------------------------------------------------------
#

# If run directly do this, just in case:
[ -z "$SORT" ] && SORT=`which sort`
[ -z "$JOIN" ] && JOIN=`which join`
[ -z "$GREP" ] && GREP=`which grep`
[ -z "$AWK" ] && AWK=`which awk`
[ -z "$CAT" ] && CAT=`which cat`
[ -z "$RM" ] && RM=`which rm`
[ -z "$CP" ] && CP=`which cp`
[ -z "$YPCAT" ] && YPCAT=`which ypcat 2>/dev/null`
[ -z "$GETENT" ] && GETENT=`which getent 2>/dev/null`
[ -z "$WORKDIR" ] && WORKDIR=/tmp

local=0
for parm
do
  case "$parm" in
    -p) passwordflag=Y;;
    -l) local=1;;
    *)	outfile="$parm";;
  esac
done

[ -z "$outfile" ] && {
	echo "ERROR: Missing argument (outfile)"
	exit 1
}
# Empty the outfile
# This will prevent errors due to the file not existing
# if this script FAILs
> $outfile

zappasswd()
{
  IFS=:
  while read user passwd rest
  do
    case $passwd in
# Normal UNIX passwds (13 chars)
      [a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./])
	     passwd="crypt3"
	   ;;
# For MD5 passwds (34 chars) starting with $1$ (Linux)
      \$1\$[a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./]\$[a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./])
	     passwd="md5"
	   ;;
# For SHA512 passwds (98 chars) starting with $6$ (Linux)
      \$6\$[a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./][a-zA-Z0-9\./])
	     passwd="sha512"
	   ;;
      " ") passwd=""
	   ;;
	*|!!)
	     passwd="*"
	   ;;
    esac
    echo "$user:$passwd:$rest" 
  done
}

if [ -f /etc/nsswitch.conf ]
then
    INPUTS=` $GREP '^passwd' /etc/nsswitch.conf | $AWK '{
	for(i=2;i<=NF;i++)
          print $i
      }' `
else
    INPUTS="compat"
fi

for source in $INPUTS
do
  case $source in
    files|compat)
	if [ -f /etc/shadow ] 
	    then
		if [ -r /etc/shadow ] 
		then
		$CAT /etc/passwd /etc/shadow | 
		$AWK -F : '{ print $1 } ' | $SORT -u >$WORKDIR/u.$$
		>$WORKDIR/p.$$
		>$WORKDIR/s.$$
		$CAT $WORKDIR/u.$$ |
		while read user; do
			$GREP "^$user:" /etc/passwd >>$WORKDIR/p.$$
			$GREP "^$user:" /etc/shadow >>$WORKDIR/s.$$
		done
		$JOIN -t: -e " " -o 2.1 1.2 2.3 2.4 2.5 2.6 2.7 $WORKDIR/s.$$ $WORKDIR/p.$$ |
		{
			if [ "$passwordflag" = 'Y' ]; then
			    $CAT
			else
			    zappasswd
			fi
		} > $WORKDIR/etc_passwd.$$
	   
		[ -s $WORKDIR/etc_passwd.$$ ] && {
		    echo "/etc/passwd" > $WORKDIR/etc_passwd.$$.src
		    echo $WORKDIR/etc_passwd.$$ >> $outfile
		}
		$RM $WORKDIR/u.$$
		$RM $WORKDIR/p.$$
		$RM $WORKDIR/s.$$
		else 
		      echo "--ERROR-- [run001e] The file /etc/shadow is available but not readable by the user running Tiger."
		fi

	    else
                $CAT /etc/passwd |
                {
                        if [ "$passwordflag" = 'Y' ]; then
                                $CAT
                        else
                                zappasswd
                        fi
                } > $WORKDIR/etc_passwd.$$
		echo "/etc/passwd" > $WORKDIR/etc_passwd.$$.src
		echo $WORKDIR/etc_passwd.$$ >> $outfile
	    fi
	   
	   [ "$source" = "files" ] && $GREP '^+' $WORKDIR/etc_passwd.$$ && {
	     echo "--WARN-- [miscxxxx] The '+' key in the /etc/passwd file should only be used in nsswitch 'compat' mode."
	   }

	    [ "$source" = "compat" ] && [ -n "$YPCAT" ] && {
		$YPCAT passwd > $WORKDIR/nis_passwd.$$ 2>/dev/null
		if [ $? -eq 0 ] ; then
		echo "NIS" > $WORKDIR/nis_passwd.$$.src
		echo $WORKDIR/nis_passwd.$$ >> $outfile
		else
		# Ypcat has not succeeded, remove the temporary file
		$RM $WORKDIR/nis_passwd.$$ 
		fi
	    }

	 ;;
    nis)   [ "$local" != 1 ] && [ -n "$YPCAT" ] && {
             $YPCAT passwd > $WORKDIR/nis_passwd.$$ 2>/dev/null
             $YPCAT passwd > $WORKDIR/nis_passwd.$$ 2>/dev/null
	     if [ $? -eq 0 ] ; then
	     echo "NIS" > $WORKDIR/nis_passwd.$$.src
	     echo $WORKDIR/nis_passwd.$$ >> $outfile
	     else
	     # Ypcat has not succeeded, remove the temporary file
	     $RM $WORKDIR/nis_passwd.$$ 
	     fi
	   }
	 ;;
    ldap) [ "$local" != 1 ] && [ -n "$GETENT" ]  && {
	    $GETENT passwd > $WORKDIR/ldap_passwd.$$ 2>/dev/null
	    if [ $? -eq 0 ] ; then
		    echo "LDAP" > $WORKDIR/ldap_passwd.$$.src
		    echo $WORKDIR/ldap_passwd.$$ >> $outfile
	    else
		    $RM $WORKDIR/ldap_passwd.$$
	    fi
          }
         ;;
# This is from SunOS, what should we do here for Linux? (if anything)
#    nisplus) [ "$local" != 1 ] && {
#               $NISCAT passwd.org_dir > $WORKDIR/nisplus_passwd.$$
#	       echo "NIS+" > $WORKDIR/nisplus_passwd.$$.src
#	       echo "$WORKDIR/nisplus_passwd.$$" >> $outfile
#	     }
#         ;;
    *)
         ;;
  esac
done


exit 0
