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