Home | History | Annotate | Line # | Download | only in etc
security revision 1.13
      1   1.1      cgd #!/bin/sh -
      2   1.1      cgd #
      3  1.13       pk #	$NetBSD: security,v 1.13 1996/01/14 00:58:25 pk 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.9      cgd umask 077
     10   1.1      cgd 
     11   1.9      cgd ERR=/tmp/_secure1.$$
     12   1.9      cgd TMP1=/tmp/_secure2.$$
     13   1.9      cgd TMP2=/tmp/_secure3.$$
     14   1.9      cgd TMP3=/tmp/_secure4.$$
     15   1.9      cgd LIST=/tmp/_secure5.$$
     16   1.9      cgd OUTPUT=/tmp/_secure6.$$
     17   1.9      cgd 
     18   1.9      cgd trap 'rm -f $ERR $TMP1 $TMP2 $TMP3 $LIST $OUTPUT' 0
     19   1.9      cgd 
     20   1.9      cgd # Check the master password file syntax.
     21   1.9      cgd MP=/etc/master.passwd
     22   1.9      cgd awk -F: '{
     23   1.9      cgd 	if ($0 ~ /^[	 ]*$/) {
     24   1.9      cgd 		printf("Line %d is a blank line.\n", NR);
     25   1.9      cgd 		next;
     26   1.9      cgd 	}
     27   1.9      cgd 	if (NF != 10)
     28   1.9      cgd 		printf("Line %d has the wrong number of fields.\n", NR);
     29   1.9      cgd 	if ($1 !~ /^[A-Za-z0-9]*$/)
     30   1.9      cgd 		printf("Login %s has non-alphanumeric characters.\n", $1);
     31   1.9      cgd 	if (length($1) > 8)
     32   1.9      cgd 		printf("Login %s has more than 8 characters.\n", $1);
     33   1.9      cgd 	if ($2 == "")
     34   1.9      cgd 		printf("Login %s has no password.\n", $1);
     35  1.13       pk 	if (length($2) != 13 && $2 != "" && ($10 ~ /.*sh$/ || $10 == ""))
     36   1.9      cgd 		printf("Login %s is off but still has a valid shell.\n", $1);
     37   1.9      cgd 	if ($3 == 0 && $1 != "root" && $1 != "toor")
     38   1.9      cgd 		printf("Login %s has a user id of 0.\n", $1);
     39   1.9      cgd 	if ($3 < 0)
     40   1.9      cgd 		printf("Login %s has a negative user id.\n", $1);
     41   1.9      cgd 	if ($4 < 0)
     42   1.9      cgd 		printf("Login %s has a negative group id.\n", $1);
     43   1.9      cgd }' < $MP > $OUTPUT
     44   1.9      cgd if [ -s $OUTPUT ] ; then
     45   1.9      cgd 	printf "\nChecking the $MP file:\n"
     46   1.9      cgd 	cat $OUTPUT
     47   1.9      cgd fi
     48   1.9      cgd 
     49   1.9      cgd awk -F: '{ print $1 }' $MP | sort | uniq -d > $OUTPUT
     50   1.9      cgd if [ -s $OUTPUT ] ; then
     51   1.9      cgd 	printf "\n$MP has duplicate user names.\n"
     52   1.9      cgd 	column $OUTPUT
     53   1.9      cgd fi
     54   1.9      cgd 
     55   1.9      cgd awk -F: '{ print $1 " " $3 }' $MP | sort -n +1 | tee $TMP1 |
     56   1.9      cgd uniq -d -f 1 | awk '{ print $2 }' > $TMP2
     57   1.9      cgd if [ -s $TMP2 ] ; then
     58   1.9      cgd 	printf "\n$MP has duplicate user id's.\n"
     59   1.9      cgd         while read uid; do
     60   1.9      cgd                 grep -w $uid $TMP1
     61   1.9      cgd         done < $TMP2 | column
     62   1.9      cgd fi
     63   1.9      cgd 
     64   1.9      cgd # Backup the master password file; a special case, the normal backup
     65   1.9      cgd # mechanisms also print out file differences and we don't want to do
     66   1.9      cgd # that because this file has encrypted passwords in it.
     67   1.9      cgd CUR=/var/backups/`basename $MP`.current
     68   1.9      cgd BACK=/var/backups/`basename $MP`.backup
     69   1.9      cgd if [ -s $CUR ] ; then
     70   1.9      cgd 	if cmp -s $CUR $MP; then
     71   1.9      cgd 		:
     72   1.9      cgd 	else
     73   1.9      cgd 		cp -p $CUR $BACK
     74   1.9      cgd 		cp -p $MP $CUR
     75   1.9      cgd 		chown root.wheel $CUR
     76   1.9      cgd 	fi
     77   1.9      cgd else
     78   1.9      cgd 	cp -p $MP $CUR
     79   1.9      cgd 	chown root.wheel $CUR
     80   1.9      cgd fi
     81   1.9      cgd 
     82   1.9      cgd # Check the group file syntax.
     83   1.9      cgd GRP=/etc/group
     84   1.9      cgd awk -F: '{
     85   1.9      cgd 	if ($0 ~ /^[	 ]*$/) {
     86   1.9      cgd 		printf("Line %d is a blank line.\n", NR);
     87   1.9      cgd 		next;
     88   1.9      cgd 	}
     89   1.9      cgd 	if (NF != 4)
     90   1.9      cgd 		printf("Line %d has the wrong number of fields.\n", NR);
     91   1.9      cgd 	if ($1 !~ /^[A-za-z0-9]*$/)
     92   1.9      cgd 		printf("Group %s has non-alphanumeric characters.\n", $1);
     93   1.9      cgd 	if (length($1) > 8)
     94   1.9      cgd 		printf("Group %s has more than 8 characters.\n", $1);
     95   1.9      cgd 	if ($3 !~ /[0-9]*/)
     96   1.9      cgd 		printf("Login %s has a negative group id.\n", $1);
     97   1.9      cgd }' < $GRP > $OUTPUT
     98   1.9      cgd if [ -s $OUTPUT ] ; then
     99   1.9      cgd 	printf "\nChecking the $GRP file:\n"
    100   1.9      cgd 	cat $OUTPUT
    101   1.9      cgd fi
    102   1.9      cgd 
    103   1.9      cgd awk -F: '{ print $1 }' $GRP | sort | uniq -d > $OUTPUT
    104   1.9      cgd if [ -s $OUTPUT ] ; then
    105   1.9      cgd 	printf "\n$GRP has duplicate group names.\n"
    106   1.9      cgd 	column $OUTPUT
    107   1.9      cgd fi
    108   1.9      cgd 
    109   1.9      cgd # Check for root paths, umask values in startup files.
    110   1.9      cgd # The check for the root paths is problematical -- it's likely to fail
    111   1.9      cgd # in other environments.  Once the shells have been modified to warn
    112   1.9      cgd # of '.' in the path, the path tests should go away.
    113   1.9      cgd > $OUTPUT
    114   1.9      cgd rhome=/root
    115   1.9      cgd umaskset=no
    116   1.9      cgd list="/etc/csh.cshrc /etc/csh.login ${rhome}/.cshrc ${rhome}/.login"
    117   1.9      cgd for i in $list ; do
    118   1.9      cgd 	if [ -f $i ] ; then
    119   1.9      cgd 		if egrep umask $i > /dev/null ; then
    120   1.9      cgd 			umaskset=yes
    121   1.9      cgd 		fi
    122   1.9      cgd 		egrep umask $i |
    123   1.9      cgd 		awk '$2 % 100 < 20 \
    124   1.9      cgd 			{ print "Root umask is group writeable" }
    125   1.9      cgd 		     $2 % 10 < 2 \
    126   1.9      cgd 			{ print "Root umask is other writeable" }' >> $OUTPUT
    127   1.9      cgd 		/bin/csh -f -s << end-of-csh > /dev/null 2>&1
    128   1.9      cgd 			unset path
    129   1.9      cgd 			source $i
    130   1.9      cgd 			/bin/ls -ldgT \$path > $TMP1
    131   1.9      cgd end-of-csh
    132   1.9      cgd 		awk '{
    133   1.9      cgd 			if ($10 ~ /^\.$/) {
    134   1.9      cgd 				print "The root path includes .";
    135   1.9      cgd 				next;
    136   1.9      cgd 			}
    137   1.9      cgd 		     }
    138   1.9      cgd 		     $1 ~ /^d....w/ \
    139   1.9      cgd         { print "Root path directory " $10 " is group writeable." } \
    140   1.9      cgd 		     $1 ~ /^d.......w/ \
    141   1.9      cgd         { print "Root path directory " $10 " is other writeable." }' \
    142   1.9      cgd 		< $TMP1 >> $OUTPUT
    143   1.9      cgd 	fi
    144   1.9      cgd done
    145   1.9      cgd if [ $umaskset = "no" -o -s $OUTPUT ] ; then
    146   1.9      cgd 	printf "\nChecking root csh paths, umask values:\n$list\n"
    147   1.9      cgd 	if [ -s $OUTPUT ]; then
    148   1.9      cgd 		cat $OUTPUT
    149   1.9      cgd 	fi
    150   1.9      cgd 	if [ $umaskset = "no" ] ; then
    151   1.9      cgd 		printf "\nRoot csh startup files do not set the umask.\n"
    152   1.9      cgd 	fi
    153   1.9      cgd fi
    154   1.9      cgd 
    155   1.9      cgd > $OUTPUT
    156   1.9      cgd rhome=/root
    157   1.9      cgd umaskset=no
    158   1.9      cgd list="${rhome}/.profile"
    159   1.9      cgd for i in $list; do
    160   1.9      cgd 	if [ -f $i ] ; then
    161   1.9      cgd 		if egrep umask $i > /dev/null ; then
    162   1.9      cgd 			umaskset=yes
    163   1.9      cgd 		fi
    164   1.9      cgd 		egrep umask $i |
    165   1.9      cgd 		awk '$2 % 100 < 20 \
    166   1.9      cgd 			{ print "Root umask is group writeable" } \
    167   1.9      cgd 		     $2 % 10 < 2 \
    168   1.9      cgd 			{ print "Root umask is other writeable" }' >> $OUTPUT
    169   1.9      cgd 		/bin/sh << end-of-sh > /dev/null 2>&1
    170   1.9      cgd 			PATH=
    171   1.9      cgd 			. $i
    172   1.9      cgd 			list=\`echo \$PATH | /usr/bin/sed -e 's/:/ /g'\`
    173   1.9      cgd 			/bin/ls -ldgT \$list > $TMP1
    174   1.9      cgd end-of-sh
    175   1.9      cgd 		awk '{
    176   1.9      cgd 			if ($10 ~ /^\.$/) {
    177   1.9      cgd 				print "The root path includes .";
    178   1.9      cgd 				next;
    179   1.9      cgd 			}
    180   1.9      cgd 		     }
    181   1.9      cgd 		     $1 ~ /^d....w/ \
    182   1.9      cgd         { print "Root path directory " $10 " is group writeable." } \
    183   1.9      cgd 		     $1 ~ /^d.......w/ \
    184   1.9      cgd         { print "Root path directory " $10 " is other writeable." }' \
    185   1.9      cgd 		< $TMP1 >> $OUTPUT
    186   1.9      cgd 
    187   1.9      cgd 	fi
    188   1.9      cgd done
    189   1.9      cgd if [ $umaskset = "no" -o -s $OUTPUT ] ; then
    190   1.9      cgd 	printf "\nChecking root sh paths, umask values:\n$list\n"
    191   1.9      cgd 	if [ -s $OUTPUT ]; then
    192   1.9      cgd 		cat $OUTPUT
    193   1.9      cgd 	fi
    194   1.9      cgd 	if [ $umaskset = "no" ] ; then
    195   1.9      cgd 		printf "\nRoot sh startup files do not set the umask.\n"
    196   1.9      cgd 	fi
    197   1.9      cgd fi
    198   1.9      cgd 
    199   1.9      cgd # Root and uucp should both be in /etc/ftpusers.
    200   1.9      cgd if egrep root /etc/ftpusers > /dev/null ; then
    201   1.9      cgd 	:
    202   1.9      cgd else
    203   1.9      cgd 	printf "\nRoot not listed in /etc/ftpusers file.\n"
    204   1.9      cgd fi
    205   1.9      cgd if egrep uucp /etc/ftpusers > /dev/null ; then
    206   1.9      cgd 	:
    207   1.9      cgd else
    208   1.9      cgd 	printf "\nUucp not listed in /etc/ftpusers file.\n"
    209   1.9      cgd fi
    210   1.9      cgd 
    211   1.9      cgd # Uudecode should not be in the /etc/aliases file.
    212   1.9      cgd if egrep 'uudecode|decode' /etc/aliases; then
    213   1.9      cgd 	printf "\nThere is an entry for uudecode in the /etc/aliases file.\n"
    214   1.9      cgd fi
    215   1.9      cgd 
    216   1.9      cgd # Files that should not have + signs.
    217   1.9      cgd list="/etc/hosts.equiv /etc/hosts.lpd"
    218   1.9      cgd for f in $list ; do
    219  1.13       pk 	if [ -f $f ] && egrep '\+' $f > /dev/null ; then
    220   1.9      cgd 		printf "\nPlus sign in $f file.\n"
    221   1.9      cgd 	fi
    222   1.9      cgd done
    223   1.9      cgd 
    224   1.9      cgd # Check for special users with .rhosts files.  Only root and toor should
    225   1.9      cgd # have a .rhosts files.  Also, .rhosts files should not plus signs.
    226   1.9      cgd awk -F: '$1 != "root" && $1 != "toor" && \
    227   1.9      cgd 	($3 < 100 || $1 == "ftp" || $1 == "uucp") \
    228   1.9      cgd 		{ print $1 " " $6 }' /etc/passwd |
    229   1.9      cgd while read uid homedir; do
    230   1.9      cgd 	if [ -f ${homedir}/.rhosts ] ; then
    231   1.9      cgd 		rhost=`ls -ldgT ${homedir}/.rhosts`
    232   1.9      cgd 		printf "$uid: $rhost\n"
    233   1.9      cgd 	fi
    234   1.9      cgd done > $OUTPUT
    235   1.9      cgd if [ -s $OUTPUT ] ; then
    236   1.9      cgd 	printf "\nChecking for special users with .rhosts files.\n"
    237   1.9      cgd 	cat $OUTPUT
    238   1.9      cgd fi
    239   1.9      cgd 
    240   1.9      cgd awk -F: '{ print $1 " " $6 }' /etc/passwd | \
    241   1.9      cgd while read uid homedir; do
    242   1.9      cgd 	if [ -f ${homedir}/.rhosts ] && \
    243   1.9      cgd 	    egrep '\+' ${homedir}/.rhosts > /dev/null ; then
    244   1.9      cgd 		printf "$uid: + in .rhosts file.\n"
    245   1.9      cgd 	fi
    246   1.9      cgd done > $OUTPUT
    247   1.9      cgd if [ -s $OUTPUT ] ; then
    248   1.9      cgd 	printf "\nChecking .rhosts files syntax.\n"
    249   1.9      cgd 	cat $OUTPUT
    250   1.9      cgd fi
    251   1.9      cgd 
    252   1.9      cgd # Check home directories.  Directories should not be owned by someone else
    253   1.9      cgd # or writeable.
    254   1.9      cgd awk -F: '{ print $1 " " $6 }' /etc/passwd | \
    255   1.9      cgd while read uid homedir; do
    256   1.9      cgd 	if [ -d ${homedir}/ ] ; then
    257   1.9      cgd 		file=`ls -ldgT ${homedir}`
    258   1.9      cgd 		printf "$uid $file\n"
    259   1.9      cgd 	fi
    260   1.9      cgd done |
    261   1.9      cgd awk '$1 != $4 && $4 != "root" \
    262   1.9      cgd 	{ print "user " $1 " home directory is owned by " $4 }
    263   1.9      cgd      $2 ~ /^-....w/ \
    264   1.9      cgd 	{ print "user " $1 " home directory is group writeable" }
    265   1.9      cgd      $2 ~ /^-.......w/ \
    266   1.9      cgd 	{ print "user " $1 " home directory is other writeable" }' > $OUTPUT
    267   1.9      cgd if [ -s $OUTPUT ] ; then
    268   1.9      cgd 	printf "\nChecking home directories.\n"
    269   1.9      cgd 	cat $OUTPUT
    270   1.9      cgd fi
    271   1.9      cgd 
    272   1.9      cgd # Files that should not be owned by someone else or readable.
    273   1.9      cgd list=".netrc .rhosts"
    274   1.9      cgd awk -F: '{ print $1 " " $6 }' /etc/passwd | \
    275   1.9      cgd while read uid homedir; do
    276   1.9      cgd 	for f in $list ; do
    277   1.9      cgd 		file=${homedir}/${f}
    278   1.9      cgd 		if [ -f $file ] ; then
    279   1.9      cgd 			printf "$uid $f `ls -ldgT $file`\n"
    280   1.9      cgd 		fi
    281   1.9      cgd 	done
    282   1.9      cgd done |
    283   1.9      cgd awk '$1 != $5 && $5 != "root" \
    284   1.9      cgd 	{ print "user " $1 " " $2 " file is owned by " $5 }
    285   1.9      cgd      $3 ~ /^-...r/ \
    286   1.9      cgd 	{ print "user " $1 " " $2 " file is group readable" }
    287   1.9      cgd      $3 ~ /^-......r/ \
    288   1.9      cgd 	{ print "user " $1 " " $2 " file is other readable" }
    289   1.9      cgd      $3 ~ /^-....w/ \
    290   1.9      cgd 	{ print "user " $1 " " $2 " file is group writeable" }
    291   1.9      cgd      $3 ~ /^-.......w/ \
    292   1.9      cgd 	{ print "user " $1 " " $2 " file is other writeable" }' > $OUTPUT
    293   1.9      cgd 
    294   1.9      cgd # Files that should not be owned by someone else or writeable.
    295  1.11      jtc list=".bashrc .cshrc .emacs .exrc .forward .klogin .login .logout \
    296   1.9      cgd       .profile .tcshrc"
    297   1.9      cgd awk -F: '{ print $1 " " $6 }' /etc/passwd | \
    298   1.9      cgd while read uid homedir; do
    299   1.9      cgd 	for f in $list ; do
    300   1.9      cgd 		file=${homedir}/${f}
    301   1.9      cgd 		if [ -f $file ] ; then
    302   1.9      cgd 			printf "$uid $f `ls -ldgT $file`\n"
    303   1.9      cgd 		fi
    304   1.9      cgd 	done
    305   1.9      cgd done |
    306   1.9      cgd awk '$1 != $5 && $5 != "root" \
    307   1.9      cgd 	{ print "user " $1 " " $2 " file is owned by " $5 }
    308   1.9      cgd      $3 ~ /^-....w/ \
    309   1.9      cgd 	{ print "user " $1 " " $2 " file is group writeable" }
    310   1.9      cgd      $3 ~ /^-.......w/ \
    311   1.9      cgd 	{ print "user " $1 " " $2 " file is other writeable" }' >> $OUTPUT
    312   1.9      cgd if [ -s $OUTPUT ] ; then
    313   1.9      cgd 	printf "\nChecking dot files.\n"
    314   1.9      cgd 	cat $OUTPUT
    315   1.9      cgd fi
    316   1.9      cgd 
    317   1.9      cgd # Mailboxes should be owned by user and unreadable.
    318   1.9      cgd ls -l /var/mail | sed 1d | \
    319   1.9      cgd awk '$3 != $9 \
    320   1.9      cgd 	{ print "user " $9 " mailbox is owned by " $3 }
    321   1.9      cgd      $1 != "-rw-------" \
    322   1.9      cgd 	{ print "user " $9 " mailbox is " $1 ", group " $4 }' > $OUTPUT
    323   1.9      cgd if [ -s $OUTPUT ] ; then
    324   1.9      cgd 	printf "\nChecking mailbox ownership.\n"
    325   1.9      cgd 	cat $OUTPUT
    326   1.9      cgd fi
    327   1.9      cgd 
    328  1.13       pk if [ -f /etc/exports ]; then
    329  1.13       pk     # File systems should not be globally exported.
    330  1.13       pk     awk '{
    331   1.9      cgd 	readonly = 0;
    332   1.9      cgd 	for (i = 2; i <= NF; ++i) {
    333   1.9      cgd 		if ($i ~ /-ro/)
    334   1.9      cgd 			readonly = 1;
    335   1.9      cgd 		else if ($i !~ /^-/)
    336   1.9      cgd 			next;
    337   1.9      cgd 	}
    338   1.9      cgd 	if (readonly)
    339   1.9      cgd 		print "File system " $1 " globally exported, read-only."
    340   1.9      cgd 	else
    341   1.9      cgd 		print "File system " $1 " globally exported, read-write."
    342  1.13       pk     }' < /etc/exports > $OUTPUT
    343  1.13       pk     if [ -s $OUTPUT ] ; then
    344   1.9      cgd 	printf "\nChecking for globally exported file systems.\n"
    345   1.9      cgd 	cat $OUTPUT
    346  1.13       pk     fi
    347   1.9      cgd fi
    348   1.9      cgd 
    349   1.9      cgd # Display any changes in setuid files and devices.
    350   1.9      cgd printf "\nChecking setuid files and devices:\n"
    351  1.10  mycroft (find / \( ! -fstype local -o -fstype fdesc -o -fstype kernfs \
    352  1.10  mycroft 		-o -fstype procfs \) -a -prune -o \
    353   1.9      cgd     \( -perm -u+s -o -perm -g+s -o ! -type d -a ! -type f -a ! -type l -a \
    354  1.13       pk        ! -type s \) -print | \
    355   1.9      cgd sort | sed -e 's/^/ls -ldgT /' | sh > $LIST) 2> $OUTPUT
    356   1.9      cgd 
    357   1.9      cgd # Display any errors that occurred during system file walk.
    358   1.9      cgd if [ -s $OUTPUT ] ; then
    359   1.9      cgd 	printf "Setuid/device find errors:\n"
    360   1.9      cgd 	cat $OUTPUT
    361   1.9      cgd 	printf "\n"
    362   1.9      cgd fi
    363   1.9      cgd 
    364   1.9      cgd # Display any changes in the setuid file list.
    365   1.9      cgd egrep -v '^[bc]' $LIST > $TMP1
    366   1.9      cgd if [ -s $TMP1 ] ; then
    367   1.9      cgd 	# Check to make sure uudecode isn't setuid.
    368   1.9      cgd 	if grep -w uudecode $TMP1 > /dev/null ; then
    369   1.9      cgd 		printf "\nUudecode is setuid.\n"
    370   1.9      cgd 	fi
    371   1.9      cgd 
    372   1.9      cgd 	CUR=/var/backups/setuid.current
    373   1.9      cgd 	BACK=/var/backups/setuid.backup
    374   1.9      cgd 
    375   1.9      cgd 	if [ -s $CUR ] ; then
    376   1.9      cgd 		if cmp -s $CUR $TMP1 ; then
    377   1.9      cgd 			:
    378   1.9      cgd 		else
    379   1.9      cgd 			> $TMP2
    380   1.9      cgd 			join -110 -210 -v2 $CUR $TMP1 > $OUTPUT
    381   1.9      cgd 			if [ -s $OUTPUT ] ; then
    382   1.9      cgd 				printf "Setuid additions:\n"
    383   1.9      cgd 				tee -a $TMP2 < $OUTPUT
    384   1.9      cgd 				printf "\n"
    385   1.9      cgd 			fi
    386   1.9      cgd 
    387   1.9      cgd 			join -110 -210 -v1 $CUR $TMP1 > $OUTPUT
    388   1.9      cgd 			if [ -s $OUTPUT ] ; then
    389   1.9      cgd 				printf "Setuid deletions:\n"
    390   1.9      cgd 				tee -a $TMP2 < $OUTPUT
    391   1.9      cgd 				printf "\n"
    392   1.9      cgd 			fi
    393   1.9      cgd 
    394   1.9      cgd 			sort +9 $TMP2 $CUR $TMP1 | \
    395   1.9      cgd 			    sed -e 's/[	 ][	 ]*/ /g' | uniq -u > $OUTPUT
    396   1.9      cgd 			if [ -s $OUTPUT ] ; then
    397   1.9      cgd 				printf "Setuid changes:\n"
    398   1.9      cgd 				column -t $OUTPUT
    399   1.9      cgd 				printf "\n"
    400   1.9      cgd 			fi
    401   1.9      cgd 
    402   1.9      cgd 			cp $CUR $BACK
    403   1.9      cgd 			cp $TMP1 $CUR
    404   1.9      cgd 		fi
    405   1.9      cgd 	else
    406   1.9      cgd 		printf "Setuid additions:\n"
    407   1.9      cgd 		column -t $TMP1
    408   1.9      cgd 		printf "\n"
    409   1.9      cgd 		cp $TMP1 $CUR
    410   1.9      cgd 	fi
    411   1.9      cgd fi
    412   1.9      cgd 
    413   1.9      cgd # Check for block and character disk devices that are readable or writeable
    414   1.9      cgd # or not owned by root.operator.
    415   1.9      cgd >$TMP1
    416   1.9      cgd DISKLIST="dk fd hd hk hp jb kra ra rb rd rl rx rz sd up wd"
    417   1.9      cgd for i in $DISKLIST; do
    418   1.9      cgd 	egrep "^b.*/${i}[0-9][0-9]*[a-h]$"  $LIST >> $TMP1
    419   1.9      cgd 	egrep "^c.*/r${i}[0-9][0-9]*[a-h]$"  $LIST >> $TMP1
    420   1.9      cgd done
    421   1.9      cgd 
    422   1.9      cgd awk '$3 != "root" || $4 != "operator" || $1 !~ /.rw-r-----/ \
    423   1.9      cgd 	{ printf("Disk %s is user %s, group %s, permissions %s.\n", \
    424   1.9      cgd 	    $11, $3, $4, $1); }' < $TMP1 > $OUTPUT
    425   1.9      cgd if [ -s $OUTPUT ] ; then
    426   1.9      cgd 	printf "\nChecking disk ownership and permissions.\n"
    427   1.9      cgd 	cat $OUTPUT
    428   1.9      cgd 	printf "\n"
    429   1.9      cgd fi
    430   1.9      cgd 
    431   1.9      cgd # Display any changes in the device file list.
    432   1.9      cgd egrep '^[bc]' $LIST | sort +10 > $TMP1
    433   1.9      cgd if [ -s $TMP1 ] ; then
    434   1.9      cgd 	CUR=/var/backups/device.current
    435   1.9      cgd 	BACK=/var/backups/device.backup
    436   1.9      cgd 
    437   1.9      cgd 	if [ -s $CUR ] ; then
    438   1.9      cgd 		if cmp -s $CUR $TMP1 ; then
    439   1.9      cgd 			:
    440   1.9      cgd 		else
    441   1.9      cgd 			> $TMP2
    442   1.9      cgd 			join -111 -211 -v2 $CUR $TMP1 > $OUTPUT
    443   1.9      cgd 			if [ -s $OUTPUT ] ; then
    444   1.9      cgd 				printf "Device additions:\n"
    445   1.9      cgd 				tee -a $TMP2 < $OUTPUT
    446   1.9      cgd 				printf "\n"
    447   1.9      cgd 			fi
    448   1.9      cgd 
    449   1.9      cgd 			join -111 -211 -v1 $CUR $TMP1 > $OUTPUT
    450   1.9      cgd 			if [ -s $OUTPUT ] ; then
    451   1.9      cgd 				printf "Device deletions:\n"
    452   1.9      cgd 				tee -a $TMP2 < $OUTPUT
    453   1.9      cgd 				printf "\n"
    454   1.9      cgd 			fi
    455   1.9      cgd 
    456   1.9      cgd 			# Report any block device change.  Ignore character
    457   1.9      cgd 			# devices, only the name is significant.
    458   1.9      cgd 			cat $TMP2 $CUR $TMP1 | \
    459   1.9      cgd 			sed -e '/^c/d' | \
    460   1.9      cgd 			sort +10 | \
    461   1.9      cgd 			sed -e 's/[	 ][	 ]*/ /g' | \
    462   1.9      cgd 			uniq -u > $OUTPUT
    463   1.9      cgd 			if [ -s $OUTPUT ] ; then
    464   1.9      cgd 				printf "Block device changes:\n"
    465   1.9      cgd 				column -t $OUTPUT
    466   1.9      cgd 				printf "\n"
    467   1.9      cgd 			fi
    468   1.9      cgd 
    469   1.9      cgd 			cp $CUR $BACK
    470   1.9      cgd 			cp $TMP1 $CUR
    471   1.9      cgd 		fi
    472   1.9      cgd 	else
    473   1.9      cgd 		printf "Device additions:\n"
    474   1.9      cgd 		column -t $TMP1
    475   1.9      cgd 		printf "\n"
    476   1.9      cgd 		cp $TMP1 $CUR
    477   1.9      cgd 	fi
    478   1.9      cgd fi
    479   1.9      cgd 
    480   1.9      cgd # Check special files.
    481   1.9      cgd # Check system binaries.
    482   1.9      cgd #
    483   1.9      cgd # Create the mtree tree specifications using:
    484   1.9      cgd #
    485   1.9      cgd #	mtree -cx -pDIR -kcksum,gid,mode,nlink,size,link,time,uid > DIR.secure
    486   1.9      cgd #	chown root.wheel DIR.SECURE
    487   1.9      cgd #	chmod 600 DIR.SECURE
    488   1.9      cgd #
    489   1.9      cgd # Note, this is not complete protection against Trojan horsed binaries, as
    490   1.9      cgd # the hacker can modify the tree specification to match the replaced binary.
    491   1.9      cgd # For details on really protecting yourself against modified binaries, see
    492   1.9      cgd # the mtree(8) manual page.
    493   1.9      cgd if cd /etc/mtree; then
    494   1.9      cgd 	mtree -e -p / -f /etc/mtree/special > $OUTPUT
    495   1.9      cgd 	if [ -s $OUTPUT ] ; then
    496   1.9      cgd 		printf "\nChecking special files and directories.\n"
    497   1.9      cgd 		cat $OUTPUT
    498   1.9      cgd 	fi
    499   1.9      cgd 
    500   1.9      cgd 	> $OUTPUT
    501   1.9      cgd 	for file in *.secure; do
    502  1.13       pk 		[ $file = '*.secure' ] && continue
    503   1.9      cgd 		tree=`sed -n -e '3s/.* //p' -e 3q $file`
    504   1.9      cgd 		mtree -f $file -p $tree > $TMP1
    505   1.9      cgd 		if [ -s $TMP1 ]; then
    506   1.9      cgd 			printf "\nChecking $tree:\n" >> $OUTPUT
    507   1.9      cgd 			cat $TMP1 >> $OUTPUT
    508   1.9      cgd 		fi
    509   1.9      cgd 	done
    510   1.9      cgd 	if [ -s $OUTPUT ] ; then
    511   1.9      cgd 		printf "\nChecking system binaries:\n"
    512   1.9      cgd 		cat $OUTPUT
    513   1.9      cgd 	fi
    514   1.9      cgd fi
    515   1.9      cgd 
    516   1.9      cgd # List of files that get backed up and checked for any modifications.  Each
    517   1.9      cgd # file is expected to have two backups, /var/backups/file.{current,backup}.
    518   1.9      cgd # Any changes cause the files to rotate.
    519   1.9      cgd if [ -s /etc/changelist ] ; then
    520   1.9      cgd 	for file in `cat /etc/changelist`; do
    521   1.9      cgd 		CUR=/var/backups/`basename $file`.current
    522   1.9      cgd 		BACK=/var/backups/`basename $file`.backup
    523   1.9      cgd 		if [ -s $file ]; then
    524   1.9      cgd 			if [ -s $CUR ] ; then
    525   1.9      cgd 				diff $CUR $file > $OUTPUT
    526   1.9      cgd 				if [ -s $OUTPUT ] ; then
    527   1.9      cgd 		printf "\n======\n%s diffs (OLD < > NEW)\n======\n" $file
    528   1.9      cgd 					cat $OUTPUT
    529   1.9      cgd 					cp -p $CUR $BACK
    530   1.9      cgd 					cp -p $file $CUR
    531   1.9      cgd 					chown root.wheel $CUR $BACK
    532   1.9      cgd 				fi
    533   1.9      cgd 			else
    534   1.9      cgd 				cp -p $file $CUR
    535   1.9      cgd 				chown root.wheel $CUR
    536   1.9      cgd 			fi
    537   1.9      cgd 		fi
    538   1.9      cgd 	done
    539   1.9      cgd fi
    540