Home | History | Annotate | Line # | Download | only in etc
security revision 1.56
      1   1.1       cgd #!/bin/sh -
      2   1.1       cgd #
      3  1.56     lukem #	$NetBSD: security,v 1.56 2001/06/18 10:54:02 lukem Exp $
      4   1.9       cgd #	from: @(#)security	8.1 (Berkeley) 6/9/93
      5   1.1       cgd #
      6   1.1       cgd 
      7   1.9       cgd PATH=/sbin:/usr/sbin:/bin:/usr/bin
      8   1.1       cgd 
      9  1.31     lukem if [ -f /etc/rc.subr ]; then
     10  1.31     lukem 	. /etc/rc.subr
     11  1.31     lukem else
     12  1.31     lukem 	echo "Can't read /etc/rc.subr; aborting."
     13  1.31     lukem 	exit 1;
     14  1.31     lukem fi
     15  1.31     lukem 
     16   1.9       cgd umask 077
     17   1.1       cgd 
     18  1.15       mrg if [ -s /etc/security.conf ]; then
     19  1.15       mrg 	. /etc/security.conf
     20  1.15       mrg fi
     21  1.15       mrg 
     22  1.56     lukem SECUREDIR=`mktemp -d /tmp/_securedir.XXXXXX` || exit 1
     23  1.56     lukem 
     24  1.56     lukem trap "/bin/rm -rf $SECUREDIR ; exit 0" EXIT INT QUIT
     25  1.15       mrg 
     26  1.56     lukem if ! cd "$SECUREDIR"; then
     27  1.56     lukem 	echo "Can not cd to $SECUREDIR".
     28  1.15       mrg 	exit 1
     29  1.15       mrg fi
     30  1.15       mrg 
     31  1.34       abs if [ -z "$max_loginlen" ];then
     32  1.56     lukem 	max_loginlen=8
     33  1.34       abs fi
     34  1.34       abs 
     35  1.49  jdolecek if [ -z "$max_grouplen" ]; then
     36  1.56     lukem 	max_grouplen=8
     37  1.49  jdolecek fi
     38  1.49  jdolecek 
     39  1.15       mrg ERR=secure1.$$
     40  1.15       mrg TMP1=secure2.$$
     41  1.15       mrg TMP2=secure3.$$
     42  1.28     lukem MPBYUID=secure4.$$
     43  1.29     lukem MPBYPATH=secure5.$$
     44  1.27     lukem LIST=secure6.$$
     45  1.27     lukem OUTPUT=secure7.$$
     46  1.32     lukem LABELS=secure8.$$
     47  1.15       mrg 
     48  1.48       abs # Handle backup_dir not being set in .conf file
     49  1.48       abs backup_dir=${backup_dir:-/var/backups}
     50  1.48       abs 
     51  1.15       mrg MP=/etc/master.passwd
     52   1.9       cgd 
     53  1.27     lukem # these is used several times.
     54  1.34       abs awk -F: '!/^+/ { print $1 " " $3 }' $MP | sort -k2n > $MPBYUID
     55  1.29     lukem awk -F: '{ print $1 " " $9 }' $MP | sort -k2 > $MPBYPATH
     56   1.9       cgd 
     57   1.9       cgd # Check the master password file syntax.
     58  1.32     lukem #
     59  1.31     lukem if checkyesno check_passwd; then
     60  1.34       abs 	awk -v "len=$max_loginlen" '
     61  1.25     lukem 	BEGIN {
     62  1.25     lukem 		while ( getline < "/etc/shells" > 0 ) {
     63  1.39   hubertf 			if ($0 ~ /^\#/ || $0 ~ /^$/ )
     64  1.25     lukem 				continue;
     65  1.25     lukem 			shells[$1]++;
     66  1.25     lukem 		}
     67  1.25     lukem 		FS=":";
     68  1.25     lukem 	}
     69  1.25     lukem 
     70  1.25     lukem 	{
     71  1.15       mrg 		if ($0 ~ /^[	 ]*$/) {
     72  1.25     lukem 			printf "Line %d is a blank line.\n", NR;
     73  1.15       mrg 			next;
     74  1.15       mrg 		}
     75  1.34       abs 		if (NF != 10 && ($1 != "+" || NF != 1))
     76  1.25     lukem 			printf "Line %d has the wrong number of fields.\n", NR;
     77  1.34       abs 		if ($1 == "+" )  {
     78  1.34       abs 			if (NF != 1 && $3 == 0)
     79  1.34       abs 			    printf "Line %d includes entries with uid 0.\n", NR;
     80  1.34       abs 			next;
     81  1.34       abs 		}
     82  1.53    atatat 		if ($1 !~ /^[A-Za-z0-9]([-A-Za-z0-9]*[A-Za-z0-9])*$/)
     83  1.25     lukem 			printf "Login %s has non-alphanumeric characters.\n",
     84  1.25     lukem 			    $1;
     85  1.34       abs 		if (length($1) > len)
     86  1.34       abs 			printf "Login %s has more than "len" characters.\n", $1;
     87  1.15       mrg 		if ($2 == "")
     88  1.25     lukem 			printf "Login %s has no password.\n", $1;
     89  1.50    atatat 		if (length($2) != 13 && length($2) != 20 && length($2) != 34 && $2 != "") {
     90  1.25     lukem 			if ($10 == "" || shells[$10])
     91  1.27     lukem 		    printf "Login %s is off but still has a valid shell (%s)\n",
     92  1.25     lukem 				    $1, $10;
     93  1.25     lukem 		} else if (! shells[$10])
     94  1.25     lukem 			printf "Login %s does not have a valid shell (%s)\n",
     95  1.25     lukem 			    $1, $10;
     96  1.15       mrg 		if ($3 == 0 && $1 != "root" && $1 != "toor")
     97  1.25     lukem 			printf "Login %s has a user id of 0.\n", $1;
     98  1.15       mrg 		if ($3 < 0)
     99  1.25     lukem 			printf "Login %s has a negative user id.\n", $1;
    100  1.15       mrg 		if ($4 < 0)
    101  1.25     lukem 			printf "Login %s has a negative group id.\n", $1;
    102  1.15       mrg 	}' < $MP > $OUTPUT
    103  1.15       mrg 	if [ -s $OUTPUT ] ; then
    104  1.15       mrg 		printf "\nChecking the $MP file:\n"
    105  1.15       mrg 		cat $OUTPUT
    106  1.15       mrg 	fi
    107  1.15       mrg 
    108  1.15       mrg 	awk -F: '{ print $1 }' $MP | sort | uniq -d > $OUTPUT
    109  1.15       mrg 	if [ -s $OUTPUT ] ; then
    110  1.15       mrg 		printf "\n$MP has duplicate user names.\n"
    111  1.15       mrg 		column $OUTPUT
    112  1.15       mrg 	fi
    113  1.15       mrg 
    114  1.37  wrstuden # To not exclude 'toor', a standard duplicate root account, from the duplicate
    115  1.37  wrstuden # account test, uncomment the line below (without egrep in it)and comment
    116  1.37  wrstuden # out the line (with egrep in it) below it.
    117  1.37  wrstuden #
    118  1.37  wrstuden #	< $MPBYUID uniq -d -f 1 | awk '{ print $2 }' > $TMP2
    119  1.36  wrstuden 	< $MPBYUID egrep -v '^toor ' | uniq -d -f 1 | awk '{ print $2 }' > $TMP2
    120  1.15       mrg 	if [ -s $TMP2 ] ; then
    121  1.15       mrg 		printf "\n$MP has duplicate user id's.\n"
    122  1.15       mrg 		while read uid; do
    123  1.28     lukem 			grep -w $uid $MPBYUID
    124  1.15       mrg 		done < $TMP2 | column
    125  1.15       mrg 	fi
    126   1.9       cgd fi
    127   1.9       cgd 
    128   1.9       cgd # Backup the master password file; a special case, the normal backup
    129   1.9       cgd # mechanisms also print out file differences and we don't want to do
    130   1.9       cgd # that because this file has encrypted passwords in it.
    131  1.32     lukem #
    132  1.48       abs CUR=$backup_dir/${MP##*/}.current
    133  1.48       abs BACK=$backup_dir/${MP##*/}.backup
    134   1.9       cgd if [ -s $CUR ] ; then
    135   1.9       cgd 	if cmp -s $CUR $MP; then
    136   1.9       cgd 		:
    137   1.9       cgd 	else
    138  1.52    atatat 		backup_file update $MP $CUR $BACK
    139   1.9       cgd 	fi
    140   1.9       cgd else
    141  1.52    atatat 	backup_file add $MP $CUR $BACK
    142   1.9       cgd fi
    143   1.9       cgd 
    144   1.9       cgd # Check the group file syntax.
    145  1.32     lukem #
    146  1.31     lukem if checkyesno check_group; then
    147  1.15       mrg 	GRP=/etc/group
    148  1.49  jdolecek 	awk -F: -v "len=$max_grouplen" '{
    149  1.15       mrg 		if ($0 ~ /^[	 ]*$/) {
    150  1.25     lukem 			printf "Line %d is a blank line.\n", NR;
    151  1.15       mrg 			next;
    152  1.15       mrg 		}
    153  1.34       abs 		if (NF != 4 && ($1 != "+" || NF != 1))
    154  1.25     lukem 			printf "Line %d has the wrong number of fields.\n", NR;
    155  1.34       abs 		if ($1 == "+" )  {
    156  1.34       abs 			next;
    157  1.34       abs 		}
    158  1.53    atatat 		if ($1 !~ /^[A-Za-z0-9]([-A-Za-z0-9]*[A-Za-z0-9])*$/)
    159  1.25     lukem 			printf "Group %s has non-alphanumeric characters.\n",
    160  1.25     lukem 			    $1;
    161  1.49  jdolecek 		if (length($1) > len)
    162  1.49  jdolecek 			printf "Group %s has more than "len" characters.\n", $1;
    163  1.15       mrg 		if ($3 !~ /[0-9]*/)
    164  1.25     lukem 			printf "Login %s has a negative group id.\n", $1;
    165  1.15       mrg 	}' < $GRP > $OUTPUT
    166  1.15       mrg 	if [ -s $OUTPUT ] ; then
    167  1.15       mrg 		printf "\nChecking the $GRP file:\n"
    168  1.15       mrg 		cat $OUTPUT
    169  1.15       mrg 	fi
    170  1.15       mrg 
    171  1.15       mrg 	awk -F: '{ print $1 }' $GRP | sort | uniq -d > $OUTPUT
    172  1.15       mrg 	if [ -s $OUTPUT ] ; then
    173  1.15       mrg 		printf "\n$GRP has duplicate group names.\n"
    174  1.15       mrg 		column $OUTPUT
    175  1.15       mrg 	fi
    176   1.9       cgd fi
    177   1.9       cgd 
    178   1.9       cgd # Check for root paths, umask values in startup files.
    179   1.9       cgd # The check for the root paths is problematical -- it's likely to fail
    180   1.9       cgd # in other environments.  Once the shells have been modified to warn
    181   1.9       cgd # of '.' in the path, the path tests should go away.
    182  1.32     lukem #
    183  1.31     lukem if checkyesno check_rootdotfiles; then
    184  1.28     lukem 	> $OUTPUT
    185  1.15       mrg 	rhome=`csh -fc "echo ~root"`
    186  1.15       mrg 	umaskset=no
    187  1.15       mrg 	list="/etc/csh.cshrc /etc/csh.login ${rhome}/.cshrc ${rhome}/.login"
    188  1.15       mrg 	for i in $list ; do
    189  1.15       mrg 		if [ -f $i ] ; then
    190  1.45  sommerfe 			if egrep '^[ \t]*umask[ \t]+[0-7]+' $i > /dev/null ; then
    191  1.15       mrg 				umaskset=yes
    192  1.15       mrg 			fi
    193  1.45  sommerfe 			# double check the umask value itself; ensure that both the
    194  1.45  sommerfe 			# 020 and 002 bits are set.
    195  1.45  sommerfe 			# we handle this in decimal initially to extract the digits,
    196  1.45  sommerfe 			# and then extract the `2' bit of each digit.
    197  1.45  sommerfe 			# this is made especially painful because 
    198  1.45  sommerfe 			# bitwise operations were left out of awk.
    199  1.45  sommerfe 			egrep '^[ \t]*umask[ \t]+[0-7]+' $i |
    200  1.45  sommerfe 			awk '{ g= ($2 % 100) - ($2 % 10);
    201  1.45  sommerfe 			       g /= 10;
    202  1.45  sommerfe 			       g = g % 4;
    203  1.45  sommerfe 			       g -= g % 2;
    204  1.45  sommerfe 			       if (g != 2) { print "\tRoot umask is group writeable" }
    205  1.45  sommerfe 			       o = ($2 % 10);
    206  1.45  sommerfe 			       o = o % 4;
    207  1.45  sommerfe 			       o -= o % 2;
    208  1.45  sommerfe 			       if (o != 2) { print "\tRoot umask is other writeable" } }' |
    209  1.45  sommerfe 			    sort -u >> $OUTPUT
    210  1.26     lukem 			SAVE_PATH=$PATH
    211  1.26     lukem 			unset PATH
    212  1.15       mrg 			/bin/csh -f -s << end-of-csh > /dev/null 2>&1
    213  1.15       mrg 				source $i
    214  1.15       mrg 				/bin/ls -ldgT \$path > $TMP1
    215   1.9       cgd end-of-csh
    216  1.26     lukem 			PATH=$SAVE_PATH
    217  1.15       mrg 			awk '{
    218  1.15       mrg 				if ($10 ~ /^\.$/) {
    219  1.27     lukem 					print "\tThe root path includes .";
    220  1.15       mrg 					next;
    221  1.15       mrg 				}
    222  1.15       mrg 			     }
    223  1.15       mrg 			     $1 ~ /^d....w/ \
    224  1.27     lukem 		{ print "\tRoot path directory " $10 " is group writeable." } \
    225  1.15       mrg 			     $1 ~ /^d.......w/ \
    226  1.27     lukem 		{ print "\tRoot path directory " $10 " is other writeable." }' \
    227  1.15       mrg 			< $TMP1 >> $OUTPUT
    228  1.15       mrg 		fi
    229  1.15       mrg 	done
    230  1.15       mrg 	if [ $umaskset = "no" -o -s $OUTPUT ] ; then
    231  1.27     lukem 		printf "\nChecking root csh paths, umask values:\n$list\n\n"
    232  1.15       mrg 		if [ -s $OUTPUT ]; then
    233  1.15       mrg 			cat $OUTPUT
    234  1.15       mrg 		fi
    235  1.15       mrg 		if [ $umaskset = "no" ] ; then
    236  1.27     lukem 		    printf "\tRoot csh startup files do not set the umask.\n"
    237  1.15       mrg 		fi
    238   1.9       cgd 	fi
    239   1.9       cgd 
    240  1.28     lukem 	> $OUTPUT
    241  1.15       mrg 	rhome=/root
    242  1.15       mrg 	umaskset=no
    243  1.23     lukem 	list="/etc/profile ${rhome}/.profile"
    244  1.15       mrg 	for i in $list; do
    245  1.15       mrg 		if [ -f $i ] ; then
    246  1.15       mrg 			if egrep umask $i > /dev/null ; then
    247  1.15       mrg 				umaskset=yes
    248  1.15       mrg 			fi
    249  1.15       mrg 			egrep umask $i |
    250  1.15       mrg 			awk '$2 % 100 < 20 \
    251  1.27     lukem 				{ print "\tRoot umask is group writeable" } \
    252  1.15       mrg 			     $2 % 10 < 2 \
    253  1.27     lukem 				{ print "\tRoot umask is other writeable" }' \
    254  1.27     lukem 			    >> $OUTPUT
    255  1.26     lukem 			SAVE_PATH=$PATH
    256  1.26     lukem 			unset PATH
    257  1.15       mrg 			/bin/sh << end-of-sh > /dev/null 2>&1
    258  1.15       mrg 				. $i
    259  1.26     lukem 				list=\`echo \$PATH | /usr/bin/sed -e \
    260  1.26     lukem 				    's/^:/.:/;s/:$/:./;s/::/:.:/g;s/:/ /g'\`
    261  1.15       mrg 				/bin/ls -ldgT \$list > $TMP1
    262   1.9       cgd end-of-sh
    263  1.26     lukem 			PATH=$SAVE_PATH
    264  1.15       mrg 			awk '{
    265  1.15       mrg 				if ($10 ~ /^\.$/) {
    266  1.27     lukem 					print "\tThe root path includes .";
    267  1.15       mrg 					next;
    268  1.15       mrg 				}
    269  1.15       mrg 			     }
    270  1.15       mrg 			     $1 ~ /^d....w/ \
    271  1.27     lukem 		{ print "\tRoot path directory " $10 " is group writeable." } \
    272  1.15       mrg 			     $1 ~ /^d.......w/ \
    273  1.27     lukem 		{ print "\tRoot path directory " $10 " is other writeable." }' \
    274  1.15       mrg 			< $TMP1 >> $OUTPUT
    275   1.9       cgd 
    276  1.15       mrg 		fi
    277  1.15       mrg 	done
    278  1.15       mrg 	if [ $umaskset = "no" -o -s $OUTPUT ] ; then
    279  1.15       mrg 		printf "\nChecking root sh paths, umask values:\n$list\n"
    280  1.15       mrg 		if [ -s $OUTPUT ]; then
    281  1.15       mrg 			cat $OUTPUT
    282  1.15       mrg 		fi
    283  1.15       mrg 		if [ $umaskset = "no" ] ; then
    284  1.27     lukem 			printf "\tRoot sh startup files do not set the umask.\n"
    285  1.15       mrg 		fi
    286   1.9       cgd 	fi
    287   1.9       cgd fi
    288   1.9       cgd 
    289   1.9       cgd # Root and uucp should both be in /etc/ftpusers.
    290  1.32     lukem #
    291  1.31     lukem if checkyesno check_ftpusers; then
    292  1.28     lukem 	> $OUTPUT
    293  1.28     lukem 	list="uucp "`awk '$2 == 0 { print $1 }' $MPBYUID`
    294  1.27     lukem 	for i in $list; do
    295  1.29     lukem 		if /usr/libexec/ftpd -C $i ; then
    296  1.29     lukem 			printf "\t$i is not denied\n" >> $OUTPUT
    297  1.27     lukem 		fi
    298  1.27     lukem 	done
    299  1.28     lukem 	if [ -s $OUTPUT ]; then
    300  1.28     lukem 		printf "\nChecking the /etc/ftpusers configuration:\n"
    301  1.28     lukem 		cat $OUTPUT
    302  1.28     lukem 	fi
    303   1.9       cgd fi
    304   1.9       cgd 
    305  1.43    itojun # Uudecode should not be in the /etc/mail/aliases file.
    306  1.32     lukem #
    307  1.31     lukem if checkyesno check_aliases; then
    308  1.43    itojun 	for f in /etc/mail/aliases /etc/aliases; do
    309  1.43    itojun 		if [ -f $f ] && egrep '^[^#]*(uudecode|decode).*\|' $f; then
    310  1.43    itojun 			printf "\nEntry for uudecode in $f file.\n"
    311  1.43    itojun 		fi
    312  1.43    itojun 	done
    313   1.9       cgd fi
    314   1.9       cgd 
    315   1.9       cgd # Files that should not have + signs.
    316  1.32     lukem #
    317  1.31     lukem if checkyesno check_rhosts; then
    318  1.15       mrg 	list="/etc/hosts.equiv /etc/hosts.lpd"
    319  1.15       mrg 	for f in $list ; do
    320  1.15       mrg 		if [ -f $f ] && egrep '\+' $f > /dev/null ; then
    321  1.15       mrg 			printf "\nPlus sign in $f file.\n"
    322  1.15       mrg 		fi
    323  1.15       mrg 	done
    324  1.15       mrg 
    325  1.15       mrg 	# Check for special users with .rhosts files.  Only root and toor should
    326  1.16     mikel 	# have .rhosts files.  Also, .rhosts files should not have plus signs.
    327  1.15       mrg 	awk -F: '$1 != "root" && $1 != "toor" && \
    328  1.15       mrg 		($3 < 100 || $1 == "ftp" || $1 == "uucp") \
    329  1.20   mycroft 			{ print $1 " " $9 }' $MP |
    330  1.19   mycroft 	sort -k2 |
    331  1.15       mrg 	while read uid homedir; do
    332  1.15       mrg 		if [ -f ${homedir}/.rhosts ] ; then
    333  1.15       mrg 			rhost=`ls -ldgT ${homedir}/.rhosts`
    334  1.46  christos 			printf -- "$uid: $rhost\n"
    335  1.15       mrg 		fi
    336  1.15       mrg 	done > $OUTPUT
    337  1.15       mrg 	if [ -s $OUTPUT ] ; then
    338  1.15       mrg 		printf "\nChecking for special users with .rhosts files.\n"
    339  1.15       mrg 		cat $OUTPUT
    340  1.15       mrg 	fi
    341  1.15       mrg 
    342  1.15       mrg 	while read uid homedir; do
    343  1.35      fair 		if [ -f ${homedir}/.rhosts -a -r ${homedir}/.rhosts ] && \
    344  1.41  christos 		    cat -f ${homedir}/.rhosts | egrep '\+' > /dev/null ; then
    345  1.46  christos 			printf -- "$uid: + in .rhosts file.\n"
    346  1.15       mrg 		fi
    347  1.29     lukem 	done < $MPBYPATH > $OUTPUT
    348  1.15       mrg 	if [ -s $OUTPUT ] ; then
    349  1.15       mrg 		printf "\nChecking .rhosts files syntax.\n"
    350  1.15       mrg 		cat $OUTPUT
    351  1.15       mrg 	fi
    352   1.9       cgd fi
    353   1.9       cgd 
    354   1.9       cgd # Check home directories.  Directories should not be owned by someone else
    355   1.9       cgd # or writeable.
    356  1.32     lukem #
    357  1.31     lukem if checkyesno check_homes; then
    358  1.15       mrg 	while read uid homedir; do
    359  1.15       mrg 		if [ -d ${homedir}/ ] ; then
    360  1.15       mrg 			file=`ls -ldgT ${homedir}`
    361  1.46  christos 			printf -- "$uid $file\n"
    362   1.9       cgd 		fi
    363  1.29     lukem 	done < $MPBYPATH |
    364  1.15       mrg 	awk '$1 != $4 && $4 != "root" \
    365  1.15       mrg 		{ print "user " $1 " home directory is owned by " $4 }
    366  1.15       mrg 	     $2 ~ /^-....w/ \
    367  1.15       mrg 		{ print "user " $1 " home directory is group writeable" }
    368  1.15       mrg 	     $2 ~ /^-.......w/ \
    369  1.27     lukem 		{ print "user " $1 " home directory is other writeable" }' \
    370  1.27     lukem 	    > $OUTPUT
    371  1.15       mrg 	if [ -s $OUTPUT ] ; then
    372  1.15       mrg 		printf "\nChecking home directories.\n"
    373  1.15       mrg 		cat $OUTPUT
    374  1.15       mrg 	fi
    375  1.15       mrg 
    376  1.15       mrg 	# Files that should not be owned by someone else or readable.
    377  1.27     lukem 	list=".Xauthority .netrc"
    378  1.15       mrg 	while read uid homedir; do
    379  1.15       mrg 		for f in $list ; do
    380  1.15       mrg 			file=${homedir}/${f}
    381  1.15       mrg 			if [ -f $file ] ; then
    382  1.46  christos 				printf -- "$uid $f `ls -ldgT $file`\n"
    383  1.15       mrg 			fi
    384  1.15       mrg 		done
    385  1.29     lukem 	done < $MPBYPATH |
    386  1.15       mrg 	awk '$1 != $5 && $5 != "root" \
    387  1.15       mrg 		{ print "user " $1 " " $2 " file is owned by " $5 }
    388  1.15       mrg 	     $3 ~ /^-...r/ \
    389  1.15       mrg 		{ print "user " $1 " " $2 " file is group readable" }
    390  1.15       mrg 	     $3 ~ /^-......r/ \
    391  1.15       mrg 		{ print "user " $1 " " $2 " file is other readable" }
    392  1.15       mrg 	     $3 ~ /^-....w/ \
    393  1.15       mrg 		{ print "user " $1 " " $2 " file is group writeable" }
    394  1.15       mrg 	     $3 ~ /^-.......w/ \
    395  1.27     lukem 		{ print "user " $1 " " $2 " file is other writeable" }' \
    396  1.27     lukem 	    > $OUTPUT
    397  1.15       mrg 
    398  1.15       mrg 	# Files that should not be owned by someone else or writeable.
    399  1.19   mycroft 	list=".bash_history .bash_login .bash_logout .bash_profile .bashrc \
    400  1.19   mycroft 	      .cshrc .emacs .exrc .forward .history .klogin .login .logout \
    401  1.27     lukem 	      .profile .qmail .rc_history .rhosts .tcshrc .twmrc .xinitrc \
    402  1.27     lukem 	      .xsession"
    403  1.15       mrg 	while read uid homedir; do
    404  1.15       mrg 		for f in $list ; do
    405  1.15       mrg 			file=${homedir}/${f}
    406  1.15       mrg 			if [ -f $file ] ; then
    407  1.46  christos 				printf -- "$uid $f `ls -ldgT $file`\n"
    408  1.15       mrg 			fi
    409  1.15       mrg 		done
    410  1.29     lukem 	done < $MPBYPATH |
    411  1.15       mrg 	awk '$1 != $5 && $5 != "root" \
    412  1.15       mrg 		{ print "user " $1 " " $2 " file is owned by " $5 }
    413  1.15       mrg 	     $3 ~ /^-....w/ \
    414  1.15       mrg 		{ print "user " $1 " " $2 " file is group writeable" }
    415  1.15       mrg 	     $3 ~ /^-.......w/ \
    416  1.27     lukem 		{ print "user " $1 " " $2 " file is other writeable" }' \
    417  1.27     lukem 	    >> $OUTPUT
    418  1.15       mrg 	if [ -s $OUTPUT ] ; then
    419  1.15       mrg 		printf "\nChecking dot files.\n"
    420  1.15       mrg 		cat $OUTPUT
    421  1.15       mrg 	fi
    422   1.9       cgd fi
    423   1.9       cgd 
    424   1.9       cgd # Mailboxes should be owned by user and unreadable.
    425  1.32     lukem #
    426  1.31     lukem if checkyesno check_varmail; then
    427  1.15       mrg 	ls -l /var/mail | sed 1d | \
    428  1.15       mrg 	awk '$3 != $9 \
    429  1.15       mrg 		{ print "user " $9 " mailbox is owned by " $3 }
    430  1.15       mrg 	     $1 != "-rw-------" \
    431  1.15       mrg 		{ print "user " $9 " mailbox is " $1 ", group " $4 }' > $OUTPUT
    432  1.15       mrg 	if [ -s $OUTPUT ] ; then
    433  1.15       mrg 		printf "\nChecking mailbox ownership.\n"
    434  1.15       mrg 		cat $OUTPUT
    435  1.15       mrg 	fi
    436  1.15       mrg fi
    437  1.15       mrg 
    438  1.32     lukem # NFS exports shouldn't be globally exported
    439  1.32     lukem #
    440  1.32     lukem if checkyesno check_nfs && [ -f /etc/exports ]; then
    441  1.32     lukem 	awk '{
    442  1.22     lukem 		# ignore comments and blank lines
    443  1.39   hubertf 		if ($0 ~ /^\#/ || $0 ~ /^$/ )
    444  1.22     lukem 			next;
    445  1.22     lukem 
    446  1.15       mrg 		readonly = 0;
    447  1.15       mrg 		for (i = 2; i <= NF; ++i) {
    448  1.15       mrg 			if ($i ~ /-ro/)
    449  1.15       mrg 				readonly = 1;
    450  1.15       mrg 			else if ($i !~ /^-/)
    451  1.15       mrg 				next;
    452  1.15       mrg 		}
    453  1.15       mrg 		if (readonly)
    454  1.15       mrg 			print "File system " $1 " globally exported, read-only."
    455  1.15       mrg 		else
    456  1.15       mrg 			print "File system " $1 " globally exported, read-write."
    457  1.32     lukem 	}' < /etc/exports > $OUTPUT
    458  1.32     lukem 	if [ -s $OUTPUT ] ; then
    459  1.15       mrg 		printf "\nChecking for globally exported file systems.\n"
    460  1.15       mrg 		cat $OUTPUT
    461  1.15       mrg 	fi
    462   1.9       cgd fi
    463   1.9       cgd 
    464   1.9       cgd # Display any changes in setuid files and devices.
    465  1.32     lukem #
    466  1.31     lukem if checkyesno check_devices; then
    467  1.28     lukem 	> $ERR
    468  1.15       mrg 	(find / \( ! -fstype local -o -fstype fdesc -o -fstype kernfs \
    469  1.15       mrg 			-o -fstype procfs \) -a -prune -o \
    470  1.21   mycroft 	    \( \( -perm -u+s -a ! -type d \) -o \
    471  1.21   mycroft 	       \( -perm -g+s -a ! -type d \) -o \
    472  1.24     lukem 	       -type b -o -type c \) -print0 | \
    473  1.24     lukem 	xargs -0 ls -ldgTq | sort +9 > $LIST) 2> $OUTPUT
    474  1.15       mrg 
    475  1.15       mrg 	# Display any errors that occurred during system file walk.
    476  1.15       mrg 	if [ -s $OUTPUT ] ; then
    477  1.28     lukem 		printf "Setuid/device find errors:\n" >> $ERR
    478  1.28     lukem 		cat $OUTPUT >> $ERR
    479  1.28     lukem 		printf "\n" >> $ERR
    480  1.15       mrg 	fi
    481  1.15       mrg 
    482  1.15       mrg 	# Display any changes in the setuid file list.
    483  1.15       mrg 	egrep -v '^[bc]' $LIST > $TMP1
    484  1.15       mrg 	if [ -s $TMP1 ] ; then
    485  1.15       mrg 		# Check to make sure uudecode isn't setuid.
    486  1.15       mrg 		if grep -w uudecode $TMP1 > /dev/null ; then
    487  1.28     lukem 			printf "\nUudecode is setuid.\n" >> $ERR
    488  1.15       mrg 		fi
    489  1.15       mrg 
    490  1.48       abs 		CUR=$backup_dir/setuid.current
    491  1.48       abs 		BACK=$backup_dir/setuid.backup
    492   1.9       cgd 
    493  1.15       mrg 		if [ -s $CUR ] ; then
    494  1.15       mrg 			if cmp -s $CUR $TMP1 ; then
    495  1.15       mrg 				:
    496  1.15       mrg 			else
    497  1.15       mrg 				> $TMP2
    498  1.15       mrg 				join -110 -210 -v2 $CUR $TMP1 > $OUTPUT
    499  1.15       mrg 				if [ -s $OUTPUT ] ; then
    500  1.28     lukem 					printf "Setuid additions:\n" >> $ERR
    501  1.28     lukem 					tee -a $TMP2 < $OUTPUT >> $ERR
    502  1.28     lukem 					printf "\n" >> $ERR
    503  1.15       mrg 				fi
    504  1.15       mrg 
    505  1.15       mrg 				join -110 -210 -v1 $CUR $TMP1 > $OUTPUT
    506  1.15       mrg 				if [ -s $OUTPUT ] ; then
    507  1.28     lukem 					printf "Setuid deletions:\n" >> $ERR
    508  1.28     lukem 					tee -a $TMP2 < $OUTPUT >> $ERR
    509  1.28     lukem 					printf "\n" >> $ERR
    510  1.15       mrg 				fi
    511  1.15       mrg 
    512  1.20   mycroft 				sort -k10 $TMP2 $CUR $TMP1 | \
    513  1.27     lukem 				    sed -e 's/[	 ][	 ]*/ /g' | \
    514  1.27     lukem 				    uniq -u > $OUTPUT
    515  1.15       mrg 				if [ -s $OUTPUT ] ; then
    516  1.28     lukem 					printf "Setuid changes:\n" >> $ERR
    517  1.28     lukem 					column -t $OUTPUT >> $ERR
    518  1.28     lukem 					printf "\n" >> $ERR
    519  1.15       mrg 				fi
    520   1.9       cgd 
    521  1.52    atatat 				backup_file update $TMP1 $CUR $BACK
    522   1.9       cgd 			fi
    523  1.15       mrg 		else
    524  1.28     lukem 			printf "Setuid additions:\n" >> $ERR
    525  1.28     lukem 			column -t $TMP1 >> $ERR
    526  1.28     lukem 			printf "\n" >> $ERR
    527  1.52    atatat 			backup_file add $TMP1 $CUR $BACK
    528   1.9       cgd 		fi
    529  1.15       mrg 	fi
    530  1.15       mrg 
    531  1.27     lukem 	# Check for block and character disk devices that are readable or
    532  1.27     lukem 	# writeable or not owned by root.operator.
    533  1.15       mrg 	>$TMP1
    534  1.27     lukem 	DISKLIST="acd ccd cd ch fd hk hp mcd md ra rb rd rl rx rz \
    535  1.27     lukem 	    sd se ss tz uk up vnd wd xd xy"
    536  1.27     lukem #	DISKLIST="$DISKLIST ct mt st wt"
    537  1.15       mrg 	for i in $DISKLIST; do
    538  1.15       mrg 		egrep "^b.*/${i}[0-9][0-9]*[a-p]$"  $LIST >> $TMP1
    539  1.15       mrg 		egrep "^c.*/r${i}[0-9][0-9]*[a-p]$"  $LIST >> $TMP1
    540  1.15       mrg 	done
    541  1.15       mrg 
    542  1.15       mrg 	awk '$3 != "root" || $4 != "operator" || $1 !~ /.rw-r-----/ \
    543  1.25     lukem 		{ printf "Disk %s is user %s, group %s, permissions %s.\n", \
    544  1.25     lukem 		    $11, $3, $4, $1; }' < $TMP1 > $OUTPUT
    545  1.15       mrg 	if [ -s $OUTPUT ] ; then
    546  1.28     lukem 		printf "\nChecking disk ownership and permissions.\n" >> $ERR
    547  1.28     lukem 		cat $OUTPUT >> $ERR
    548  1.28     lukem 		printf "\n" >> $ERR
    549   1.9       cgd 	fi
    550   1.9       cgd 
    551  1.15       mrg 	# Display any changes in the device file list.
    552  1.20   mycroft 	egrep '^[bc]' $LIST | sort -k11 > $TMP1
    553  1.15       mrg 	if [ -s $TMP1 ] ; then
    554  1.48       abs 		CUR=$backup_dir/device.current
    555  1.48       abs 		BACK=$backup_dir/device.backup
    556  1.15       mrg 
    557  1.15       mrg 		if [ -s $CUR ] ; then
    558  1.15       mrg 			if cmp -s $CUR $TMP1 ; then
    559  1.15       mrg 				:
    560  1.15       mrg 			else
    561  1.15       mrg 				> $TMP2
    562  1.15       mrg 				join -111 -211 -v2 $CUR $TMP1 > $OUTPUT
    563  1.15       mrg 				if [ -s $OUTPUT ] ; then
    564  1.28     lukem 					printf "Device additions:\n" >> $ERR
    565  1.28     lukem 					tee -a $TMP2 < $OUTPUT >> $ERR
    566  1.28     lukem 					printf "\n" >> $ERR
    567  1.15       mrg 				fi
    568  1.15       mrg 
    569  1.15       mrg 				join -111 -211 -v1 $CUR $TMP1 > $OUTPUT
    570  1.15       mrg 				if [ -s $OUTPUT ] ; then
    571  1.28     lukem 					printf "Device deletions:\n" >> $ERR
    572  1.28     lukem 					tee -a $TMP2 < $OUTPUT >> $ERR
    573  1.28     lukem 					printf "\n" >> $ERR
    574  1.15       mrg 				fi
    575  1.15       mrg 
    576  1.27     lukem 				# Report any block device change. Ignore
    577  1.27     lukem 				# character devices, only the name is
    578  1.27     lukem 				# significant.
    579  1.15       mrg 				cat $TMP2 $CUR $TMP1 | \
    580  1.27     lukem 				    sed -e '/^c/d' | \
    581  1.27     lukem 				    sort -k11 | \
    582  1.27     lukem 				    sed -e 's/[	 ][	 ]*/ /g' | \
    583  1.27     lukem 				    uniq -u > $OUTPUT
    584  1.15       mrg 				if [ -s $OUTPUT ] ; then
    585  1.28     lukem 					printf "Block device changes:\n" >> $ERR
    586  1.28     lukem 					column -t $OUTPUT >> $ERR
    587  1.28     lukem 					printf "\n" >> $ERR
    588  1.15       mrg 				fi
    589   1.9       cgd 
    590  1.52    atatat 				backup_file update $TMP1 $CUR $BACK
    591   1.9       cgd 			fi
    592  1.15       mrg 		else
    593  1.28     lukem 			printf "Device additions:\n" >> $ERR
    594  1.28     lukem 			column -t $TMP1 >> $ERR
    595  1.28     lukem 			printf "\n" >> $ERR
    596  1.52    atatat 			backup_file add $TMP1 $CUR $BACK >> $ERR
    597   1.9       cgd 		fi
    598  1.28     lukem 	fi
    599  1.28     lukem 	if [ -s $ERR ] ; then
    600  1.28     lukem 		printf "\nChecking setuid files and devices:\n"
    601  1.28     lukem 		cat $ERR
    602  1.28     lukem 		printf "\n"
    603   1.9       cgd 	fi
    604   1.9       cgd fi
    605   1.9       cgd 
    606   1.9       cgd # Check special files.
    607   1.9       cgd # Check system binaries.
    608   1.9       cgd #
    609   1.9       cgd # Create the mtree tree specifications using:
    610   1.9       cgd #
    611   1.9       cgd #	mtree -cx -pDIR -kcksum,gid,mode,nlink,size,link,time,uid > DIR.secure
    612  1.38    kleink #	chown root:wheel DIR.secure
    613  1.16     mikel #	chmod 600 DIR.secure
    614   1.9       cgd #
    615   1.9       cgd # Note, this is not complete protection against Trojan horsed binaries, as
    616   1.9       cgd # the hacker can modify the tree specification to match the replaced binary.
    617   1.9       cgd # For details on really protecting yourself against modified binaries, see
    618   1.9       cgd # the mtree(8) manual page.
    619  1.32     lukem #
    620  1.31     lukem if checkyesno check_mtree; then
    621   1.9       cgd 	mtree -e -p / -f /etc/mtree/special > $OUTPUT
    622  1.15       mrg 	if [ -s $OUTPUT ]; then
    623   1.9       cgd 		printf "\nChecking special files and directories.\n"
    624   1.9       cgd 		cat $OUTPUT
    625   1.9       cgd 	fi
    626   1.9       cgd 
    627   1.9       cgd 	> $OUTPUT
    628  1.16     mikel 	for file in /etc/mtree/*.secure; do
    629  1.16     mikel 		[ $file = '/etc/mtree/*.secure' ] && continue
    630   1.9       cgd 		tree=`sed -n -e '3s/.* //p' -e 3q $file`
    631   1.9       cgd 		mtree -f $file -p $tree > $TMP1
    632   1.9       cgd 		if [ -s $TMP1 ]; then
    633   1.9       cgd 			printf "\nChecking $tree:\n" >> $OUTPUT
    634   1.9       cgd 			cat $TMP1 >> $OUTPUT
    635   1.9       cgd 		fi
    636   1.9       cgd 	done
    637  1.15       mrg 	if [ -s $OUTPUT ]; then
    638   1.9       cgd 		printf "\nChecking system binaries:\n"
    639   1.9       cgd 		cat $OUTPUT
    640   1.9       cgd 	fi
    641   1.9       cgd fi
    642   1.9       cgd 
    643  1.32     lukem CHANGELIST=""
    644  1.32     lukem 
    645  1.32     lukem # Backup disklabels of available disks
    646  1.32     lukem #
    647  1.32     lukem if checkyesno check_disklabels; then
    648  1.32     lukem 		# generate list of old disklabels and remove them
    649  1.48       abs 	ls -1d $backup_dir/disklabel.* 2>/dev/null |
    650  1.52    atatat 	    egrep -v '\.(backup|current)(,v)?$' > $LABELS
    651  1.32     lukem 	xargs rm < $LABELS
    652  1.32     lukem 
    653  1.40     perry 	disks=`iostat -x | sed 1d | awk '$1 !~ /^[cfm]d/ { print $1; }'`
    654  1.32     lukem 	for i in $disks; do
    655  1.48       abs 		dlf="$backup_dir/disklabel.$i"
    656  1.32     lukem 		disklabel $i > $dlf 2>/dev/null
    657  1.32     lukem 	done
    658  1.32     lukem 
    659  1.32     lukem 		# append list of new disklabels, sort list
    660  1.48       abs 	ls -1d $backup_dir/disklabel.* 2>/dev/null |
    661  1.52    atatat 	    egrep -v '\.(backup|current)(,v)?$' >> $LABELS
    662  1.32     lukem 	sort -u -o $LABELS $LABELS
    663  1.32     lukem 	CHANGELIST=$LABELS
    664  1.32     lukem fi
    665  1.32     lukem 
    666   1.9       cgd # List of files that get backed up and checked for any modifications.  Each
    667  1.48       abs # file is expected to have two backups, $backup_dir/file.{current,backup}.
    668   1.9       cgd # Any changes cause the files to rotate.
    669  1.32     lukem #
    670  1.31     lukem if checkyesno check_changelist && [ -s /etc/changelist ] ; then
    671  1.32     lukem 	CHANGELIST="/etc/changelist $CHANGELIST"
    672  1.32     lukem fi
    673  1.32     lukem 
    674  1.32     lukem if [ -n "$CHANGELIST" ]; then
    675  1.32     lukem 	for file in `egrep -hv "^#|$MP" $CHANGELIST`; do
    676  1.54    atatat 		# old changelist backup names
    677  1.54    atatat 		OCUR=$backup_dir/${file##*/}.current
    678  1.54    atatat 		OBACK=$backup_dir/${file##*/}.backup
    679  1.54    atatat 		# new changelist backup names
    680  1.54    atatat 		CUR=$backup_dir$file.current
    681  1.54    atatat 		BACK=$backup_dir$file.backup
    682  1.54    atatat 		# roll over old backups
    683  1.54    atatat 		if [ ! -d ${CUR%/*} ]; then
    684  1.54    atatat 			mkdir -p ${CUR%/*}
    685  1.54    atatat 		fi
    686  1.54    atatat 		if [ -f $OCUR -a ! -f $CUR ]; then
    687  1.54    atatat 			mv $OCUR $CUR
    688  1.54    atatat 		fi
    689  1.54    atatat 		if [ -f $OCUR,v -a ! -f $CUR,v ]; then
    690  1.54    atatat 			mv $OCUR,v $CUR,v
    691  1.54    atatat 		fi
    692  1.54    atatat 		if [ -f $OBACK -a ! -f $BACK ]; then
    693  1.54    atatat 			mv $OBACK $BACK
    694  1.54    atatat 		fi
    695  1.54    atatat 		# and down to work
    696  1.30   mycroft 		if [ -f $file ]; then
    697  1.30   mycroft 			if [ -f $CUR ] ; then
    698   1.9       cgd 				diff $CUR $file > $OUTPUT
    699   1.9       cgd 				if [ -s $OUTPUT ] ; then
    700   1.9       cgd 		printf "\n======\n%s diffs (OLD < > NEW)\n======\n" $file
    701   1.9       cgd 					cat $OUTPUT
    702  1.52    atatat 					backup_file update $file $CUR $BACK
    703   1.9       cgd 				fi
    704   1.9       cgd 			else
    705  1.30   mycroft 		printf "\n======\n%s added\n======\n" $file
    706  1.30   mycroft 				diff /dev/null $file
    707  1.52    atatat 				backup_file add $file $CUR $BACK
    708  1.30   mycroft 			fi
    709  1.30   mycroft 		else
    710  1.30   mycroft 			if [ -f $CUR ]; then
    711  1.30   mycroft 		printf "\n======\n%s removed\n======\n" $file
    712  1.30   mycroft 				diff $CUR /dev/null
    713  1.52    atatat 				backup_file remove $file $CUR $BACK
    714   1.9       cgd 			fi
    715   1.9       cgd 		fi
    716   1.9       cgd 	done
    717  1.44        ad fi
    718  1.44        ad 
    719  1.44        ad if [ -f /etc/security.local ]; then
    720  1.44        ad 	echo ""
    721  1.44        ad 	echo "Running /etc/security.local:"
    722  1.44        ad 	. /etc/security.local
    723   1.9       cgd fi
    724