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