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