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