xref: /original-bsd/etc/security (revision de0b4677)
1341415c8Sbostic#!/bin/sh -
2341415c8Sbostic#
3*de0b4677Sbostic#	@(#)security	8.1 (Berkeley) 06/09/93
4341415c8Sbostic#
5e4e6515bSbostic
6efff9fd4SbosticPATH=/sbin:/usr/sbin:/bin:/usr/bin
7341415c8Sbostic
82e01ce9eSbosticumask 077
99f40dbdcSbostic
106c152fbeSbosticERR=/tmp/_secure1.$$
116c152fbeSbosticTMP1=/tmp/_secure2.$$
126c152fbeSbosticTMP2=/tmp/_secure3.$$
132e01ce9eSbosticTMP3=/tmp/_secure4.$$
142e01ce9eSbosticLIST=/tmp/_secure5.$$
152e01ce9eSbosticOUTPUT=/tmp/_secure6.$$
16efff9fd4Sbostic
172e01ce9eSbostictrap 'rm -f $ERR $TMP1 $TMP2 $TMP3 $LIST $OUTPUT' 0
18efff9fd4Sbostic
198f0ba418Sbostic# Check the master password file syntax.
202e01ce9eSbosticMP=/etc/master.passwd
212e01ce9eSbosticawk -F: '{
222e01ce9eSbostic	if ($0 ~ /^[	 ]*$/) {
232e01ce9eSbostic		printf("Line %d is a blank line.\n", NR);
242e01ce9eSbostic		next;
252e01ce9eSbostic	}
262e01ce9eSbostic	if (NF != 10)
272e01ce9eSbostic		printf("Line %d has the wrong number of fields.\n", NR);
28c7ce5722Sbostic	if ($1 !~ /^[A-Za-z0-9]*$/)
298b53557dSbostic		printf("Login %s has non-alphanumeric characters.\n", $1);
302e01ce9eSbostic	if (length($1) > 8)
312e01ce9eSbostic		printf("Login %s has more than 8 characters.\n", $1);
322e01ce9eSbostic	if ($2 == "")
332e01ce9eSbostic		printf("Login %s has no password.\n", $1);
342e01ce9eSbostic	if (length($2) != 13 && ($10 ~ /.*sh$/ || $10 == ""))
352e01ce9eSbostic		printf("Login %s is off but still has a valid shell.\n", $1);
362e01ce9eSbostic	if ($3 == 0 && $1 != "root" && $1 != "toor")
372e01ce9eSbostic		printf("Login %s has a user id of 0.\n", $1);
382e01ce9eSbostic	if ($3 < 0)
392e01ce9eSbostic		printf("Login %s has a negative user id.\n", $1);
402e01ce9eSbostic	if ($4 < 0)
41c7ce5722Sbostic		printf("Login %s has a negative group id.\n", $1);
422e01ce9eSbostic}' < $MP > $OUTPUT
432e01ce9eSbosticif [ -s $OUTPUT ] ; then
442e01ce9eSbostic	printf "\nChecking the $MP file:\n"
452e01ce9eSbostic	cat $OUTPUT
462e01ce9eSbosticfi
47fe22c88eSbostic
482e01ce9eSbosticawk -F: '{ print $1 }' $MP | sort | uniq -d > $OUTPUT
492e01ce9eSbosticif [ -s $OUTPUT ] ; then
502e01ce9eSbostic	printf "\n$MP has duplicate user names.\n"
512e01ce9eSbostic	column $OUTPUT
522e01ce9eSbosticfi
53f4e62e4fSbostic
542e01ce9eSbosticawk -F: '{ print $1 " " $3 }' $MP | sort -n +1 | tee $TMP1 |
552e01ce9eSbosticuniq -d -f 1 | awk '{ print $2 }' > $TMP2
562e01ce9eSbosticif [ -s $TMP2 ] ; then
572e01ce9eSbostic	printf "\n$MP has duplicate user id's.\n"
582e01ce9eSbostic        while read uid; do
592e01ce9eSbostic                grep -w $uid $TMP1
602e01ce9eSbostic        done < $TMP2 | column
612e01ce9eSbosticfi
622e01ce9eSbostic
6317aa77b0Sbostic# Backup the master password file; a special case, the normal backup
6417aa77b0Sbostic# mechanisms also print out file differences and we don't want to do
6517aa77b0Sbostic# that because this file has encrypted passwords in it.
6617aa77b0SbosticCUR=/var/backups/`basename $MP`.current
6717aa77b0SbosticBACK=/var/backups/`basename $MP`.backup
6817aa77b0Sbosticif [ -s $CUR ] ; then
6917aa77b0Sbostic	if cmp -s $CUR $MP; then
7017aa77b0Sbostic		:
7117aa77b0Sbostic	else
7217aa77b0Sbostic		cp -p $CUR $BACK
7317aa77b0Sbostic		cp -p $MP $CUR
7417aa77b0Sbostic		chown root.wheel $CUR
7517aa77b0Sbostic	fi
7617aa77b0Sbosticelse
7717aa77b0Sbostic	cp -p $MP $CUR
7817aa77b0Sbostic	chown root.wheel $CUR
7917aa77b0Sbosticfi
8017aa77b0Sbostic
812e01ce9eSbostic# Check the group file syntax.
822e01ce9eSbosticGRP=/etc/group
832e01ce9eSbosticawk -F: '{
842e01ce9eSbostic	if ($0 ~ /^[	 ]*$/) {
852e01ce9eSbostic		printf("Line %d is a blank line.\n", NR);
862e01ce9eSbostic		next;
872e01ce9eSbostic	}
882e01ce9eSbostic	if (NF != 4)
892e01ce9eSbostic		printf("Line %d has the wrong number of fields.\n", NR);
90f5577ccbSbostic	if ($1 !~ /^[A-za-z0-9]*$/)
918b53557dSbostic		printf("Group %s has non-alphanumeric characters.\n", $1);
922e01ce9eSbostic	if (length($1) > 8)
932e01ce9eSbostic		printf("Group %s has more than 8 characters.\n", $1);
942e01ce9eSbostic	if ($3 !~ /[0-9]*/)
95c7ce5722Sbostic		printf("Login %s has a negative group id.\n", $1);
962e01ce9eSbostic}' < $GRP > $OUTPUT
972e01ce9eSbosticif [ -s $OUTPUT ] ; then
982e01ce9eSbostic	printf "\nChecking the $GRP file:\n"
992e01ce9eSbostic	cat $OUTPUT
1002e01ce9eSbosticfi
1012e01ce9eSbostic
1022e01ce9eSbosticawk -F: '{ print $1 }' $GRP | sort | uniq -d > $OUTPUT
1032e01ce9eSbosticif [ -s $OUTPUT ] ; then
1042e01ce9eSbostic	printf "\n$GRP has duplicate group names.\n"
1052e01ce9eSbostic	column $OUTPUT
1062e01ce9eSbosticfi
1072e01ce9eSbostic
1082e01ce9eSbostic# Check for root paths, umask values in startup files.
1098f0ba418Sbostic# The check for the root paths is problematical -- it's likely to fail
1108f0ba418Sbostic# in other environments.  Once the shells have been modified to warn
1118f0ba418Sbostic# of '.' in the path, the path tests should go away.
1122e01ce9eSbostic> $OUTPUT
1132e01ce9eSbosticrhome=/root
1142e01ce9eSbosticumaskset=no
1152e01ce9eSbosticlist="/etc/csh.cshrc /etc/csh.login ${rhome}/.cshrc ${rhome}/.login"
1162e01ce9eSbosticfor i in $list ; do
1172e01ce9eSbostic	if [ -f $i ] ; then
1182e01ce9eSbostic		if egrep umask $i > /dev/null ; then
1192e01ce9eSbostic			umaskset=yes
1202e01ce9eSbostic		fi
1212e01ce9eSbostic		egrep umask $i |
1222e01ce9eSbostic		awk '$2 % 100 < 20 \
1232e01ce9eSbostic			{ print "Root umask is group writeable" }
1242e01ce9eSbostic		     $2 % 10 < 2 \
1252e01ce9eSbostic			{ print "Root umask is other writeable" }' >> $OUTPUT
1262e01ce9eSbostic		/bin/csh -f -s << end-of-csh > /dev/null 2>&1
1272e01ce9eSbostic			unset path
1282e01ce9eSbostic			source $i
1292e01ce9eSbostic			/bin/ls -ldgT \$path > $TMP1
1302e01ce9eSbosticend-of-csh
1312e01ce9eSbostic		awk '{
132f5577ccbSbostic			if ($10 ~ /^\.$/) {
1332e01ce9eSbostic				print "The root path includes .";
1342e01ce9eSbostic				next;
1352e01ce9eSbostic			}
1362e01ce9eSbostic		     }
1372e01ce9eSbostic		     $1 ~ /^d....w/ \
1382e01ce9eSbostic        { print "Root path directory " $10 " is group writeable." } \
1392e01ce9eSbostic		     $1 ~ /^d.......w/ \
1402e01ce9eSbostic        { print "Root path directory " $10 " is other writeable." }' \
1412e01ce9eSbostic		< $TMP1 >> $OUTPUT
1422e01ce9eSbostic	fi
1432e01ce9eSbosticdone
1442e01ce9eSbosticif [ $umaskset = "no" -o -s $OUTPUT ] ; then
1452e01ce9eSbostic	printf "\nChecking root csh paths, umask values:\n$list\n"
1462e01ce9eSbostic	if [ -s $OUTPUT ]; then
1472e01ce9eSbostic		cat $OUTPUT
1482e01ce9eSbostic	fi
1492e01ce9eSbostic	if [ $umaskset = "no" ] ; then
1502e01ce9eSbostic		printf "\nRoot csh startup files do not set the umask.\n"
1512e01ce9eSbostic	fi
1522e01ce9eSbosticfi
1532e01ce9eSbostic
1542e01ce9eSbostic> $OUTPUT
1552e01ce9eSbosticrhome=/root
1562e01ce9eSbosticumaskset=no
1572e01ce9eSbosticlist="${rhome}/.profile"
1582e01ce9eSbosticfor i in $list; do
1592e01ce9eSbostic	if [ -f $i ] ; then
1602e01ce9eSbostic		if egrep umask $i > /dev/null ; then
1612e01ce9eSbostic			umaskset=yes
1622e01ce9eSbostic		fi
1632e01ce9eSbostic		egrep umask $i |
1642e01ce9eSbostic		awk '$2 % 100 < 20 \
1652e01ce9eSbostic			{ print "Root umask is group writeable" } \
1662e01ce9eSbostic		     $2 % 10 < 2 \
1672e01ce9eSbostic			{ print "Root umask is other writeable" }' >> $OUTPUT
1682e01ce9eSbostic		/bin/sh << end-of-sh > /dev/null 2>&1
1692e01ce9eSbostic			PATH=
1702e01ce9eSbostic			. $i
1712e01ce9eSbostic			list=\`echo \$PATH | /usr/bin/sed -e 's/:/ /g'\`
1722e01ce9eSbostic			/bin/ls -ldgT \$list > $TMP1
1732e01ce9eSbosticend-of-sh
1742e01ce9eSbostic		awk '{
175f5577ccbSbostic			if ($10 ~ /^\.$/) {
1762e01ce9eSbostic				print "The root path includes .";
1772e01ce9eSbostic				next;
1782e01ce9eSbostic			}
1792e01ce9eSbostic		     }
1802e01ce9eSbostic		     $1 ~ /^d....w/ \
1812e01ce9eSbostic        { print "Root path directory " $10 " is group writeable." } \
1822e01ce9eSbostic		     $1 ~ /^d.......w/ \
1832e01ce9eSbostic        { print "Root path directory " $10 " is other writeable." }' \
1842e01ce9eSbostic		< $TMP1 >> $OUTPUT
1852e01ce9eSbostic
1862e01ce9eSbostic	fi
1872e01ce9eSbosticdone
1882e01ce9eSbosticif [ $umaskset = "no" -o -s $OUTPUT ] ; then
1892e01ce9eSbostic	printf "\nChecking root sh paths, umask values:\n$list\n"
1902e01ce9eSbostic	if [ -s $OUTPUT ]; then
1912e01ce9eSbostic		cat $OUTPUT
1922e01ce9eSbostic	fi
1932e01ce9eSbostic	if [ $umaskset = "no" ] ; then
1942e01ce9eSbostic		printf "\nRoot sh startup files do not set the umask.\n"
1952e01ce9eSbostic	fi
1962e01ce9eSbosticfi
1972e01ce9eSbostic
1982e01ce9eSbostic# Root and uucp should both be in /etc/ftpusers.
1992e01ce9eSbosticif egrep root /etc/ftpusers > /dev/null ; then
2002e01ce9eSbostic	:
2012e01ce9eSbosticelse
2022e01ce9eSbostic	printf "\nRoot not listed in /etc/ftpusers file.\n"
2032e01ce9eSbosticfi
2042e01ce9eSbosticif egrep uucp /etc/ftpusers > /dev/null ; then
2052e01ce9eSbostic	:
2062e01ce9eSbosticelse
2072e01ce9eSbostic	printf "\nUucp not listed in /etc/ftpusers file.\n"
2082e01ce9eSbosticfi
2092e01ce9eSbostic
2108f0ba418Sbostic# Uudecode should not be in the /etc/aliases file.
2117fc7eaa2Sbosticif egrep 'uudecode|decode' /etc/aliases; then
2122e01ce9eSbostic	printf "\nThere is an entry for uudecode in the /etc/aliases file.\n"
2132e01ce9eSbosticfi
2142e01ce9eSbostic
215e4bdd3a8Sbostic# Files that should not have + signs.
216353a346cSbosticlist="/etc/hosts.equiv /etc/hosts.lpd"
217353a346cSbosticfor f in $list ; do
218e4bdd3a8Sbostic	if egrep '\+' $f > /dev/null ; then
219e4bdd3a8Sbostic		printf "\nPlus sign in $f file.\n"
2202e01ce9eSbostic	fi
221353a346cSbosticdone
222f4e62e4fSbostic
223e4e6515bSbostic# Check for special users with .rhosts files.  Only root and toor should
224e4bdd3a8Sbostic# have a .rhosts files.  Also, .rhosts files should not plus signs.
2252e01ce9eSbosticawk -F: '$1 != "root" && $1 != "toor" && \
2262e01ce9eSbostic	($3 < 100 || $1 == "ftp" || $1 == "uucp") \
2272e01ce9eSbostic		{ print $1 " " $6 }' /etc/passwd |
228f4e62e4fSbosticwhile read uid homedir; do
229f4e62e4fSbostic	if [ -f ${homedir}/.rhosts ] ; then
230e4e6515bSbostic		rhost=`ls -ldgT ${homedir}/.rhosts`
2312e01ce9eSbostic		printf "$uid: $rhost\n"
232f4e62e4fSbostic	fi
2332e01ce9eSbosticdone > $OUTPUT
2342e01ce9eSbosticif [ -s $OUTPUT ] ; then
2352e01ce9eSbostic	printf "\nChecking for special users with .rhosts files.\n"
2362e01ce9eSbostic	cat $OUTPUT
2372e01ce9eSbosticfi
238f4e62e4fSbostic
2392e01ce9eSbosticawk -F: '{ print $1 " " $6 }' /etc/passwd | \
2402e01ce9eSbosticwhile read uid homedir; do
2412e01ce9eSbostic	if [ -f ${homedir}/.rhosts ] && \
242e4bdd3a8Sbostic	    egrep '\+' ${homedir}/.rhosts > /dev/null ; then
243e4bdd3a8Sbostic		printf "$uid: + in .rhosts file.\n"
2442e01ce9eSbostic	fi
2452e01ce9eSbosticdone > $OUTPUT
2462e01ce9eSbosticif [ -s $OUTPUT ] ; then
2472e01ce9eSbostic	printf "\nChecking .rhosts files syntax.\n"
2482e01ce9eSbostic	cat $OUTPUT
2492e01ce9eSbosticfi
2502e01ce9eSbostic
2518f0ba418Sbostic# Check home directories.  Directories should not be owned by someone else
2528f0ba418Sbostic# or writeable.
2532e01ce9eSbosticawk -F: '{ print $1 " " $6 }' /etc/passwd | \
254e4e6515bSbosticwhile read uid homedir; do
255e4e6515bSbostic	if [ -d ${homedir}/ ] ; then
256e4e6515bSbostic		file=`ls -ldgT ${homedir}`
2572e01ce9eSbostic		printf "$uid $file\n"
258e4e6515bSbostic	fi
2592e01ce9eSbosticdone |
2602e01ce9eSbosticawk '$1 != $4 && $4 != "root" \
2612e01ce9eSbostic	{ print "user " $1 " home directory is owned by " $4 }
2622e01ce9eSbostic     $2 ~ /^-....w/ \
2632e01ce9eSbostic	{ print "user " $1 " home directory is group writeable" }
2642e01ce9eSbostic     $2 ~ /^-.......w/ \
2652e01ce9eSbostic	{ print "user " $1 " home directory is other writeable" }' > $OUTPUT
2662e01ce9eSbosticif [ -s $OUTPUT ] ; then
2672e01ce9eSbostic	printf "\nChecking home directories.\n"
2682e01ce9eSbostic	cat $OUTPUT
2692e01ce9eSbosticfi
270e4e6515bSbostic
271f4e62e4fSbostic# Files that should not be owned by someone else or readable.
2722e01ce9eSbosticlist=".netrc .rhosts"
2732e01ce9eSbosticawk -F: '{ print $1 " " $6 }' /etc/passwd | \
274f4e62e4fSbosticwhile read uid homedir; do
2752e01ce9eSbostic	for f in $list ; do
2762e01ce9eSbostic		file=${homedir}/${f}
2772e01ce9eSbostic		if [ -f $file ] ; then
2782e01ce9eSbostic			printf "$uid $f `ls -ldgT $file`\n"
279f4e62e4fSbostic		fi
2802e01ce9eSbostic	done
2812e01ce9eSbosticdone |
2822e01ce9eSbosticawk '$1 != $5 && $5 != "root" \
2832e01ce9eSbostic	{ print "user " $1 " " $2 " file is owned by " $5 }
2842e01ce9eSbostic     $3 ~ /^-...r/ \
2852e01ce9eSbostic	{ print "user " $1 " " $2 " file is group readable" }
2862e01ce9eSbostic     $3 ~ /^-......r/ \
2872e01ce9eSbostic	{ print "user " $1 " " $2 " file is other readable" }
2882e01ce9eSbostic     $3 ~ /^-....w/ \
2892e01ce9eSbostic	{ print "user " $1 " " $2 " file is group writeable" }
2902e01ce9eSbostic     $3 ~ /^-.......w/ \
2912e01ce9eSbostic	{ print "user " $1 " " $2 " file is other writeable" }' > $OUTPUT
292f4e62e4fSbostic
293f4e62e4fSbostic# Files that should not be owned by someone else or writeable.
2942e01ce9eSbosticlist=".bashrc .cshrc .emacsrc .exrc .forward .klogin .login .logout \
2952e01ce9eSbostic      .profile .tcshrc"
2962e01ce9eSbosticawk -F: '{ print $1 " " $6 }' /etc/passwd | \
297f4e62e4fSbosticwhile read uid homedir; do
2982e01ce9eSbostic	for f in $list ; do
2992e01ce9eSbostic		file=${homedir}/${f}
3002e01ce9eSbostic		if [ -f $file ] ; then
3012e01ce9eSbostic			printf "$uid $f `ls -ldgT $file`\n"
302f4e62e4fSbostic		fi
3032e01ce9eSbostic	done
3042e01ce9eSbosticdone |
3052e01ce9eSbosticawk '$1 != $5 && $5 != "root" \
3062e01ce9eSbostic	{ print "user " $1 " " $2 " file is owned by " $5 }
3072e01ce9eSbostic     $3 ~ /^-....w/ \
3082e01ce9eSbostic	{ print "user " $1 " " $2 " file is group writeable" }
3092e01ce9eSbostic     $3 ~ /^-.......w/ \
3102e01ce9eSbostic	{ print "user " $1 " " $2 " file is other writeable" }' >> $OUTPUT
3112e01ce9eSbosticif [ -s $OUTPUT ] ; then
3122e01ce9eSbostic	printf "\nChecking dot files.\n"
3132e01ce9eSbostic	cat $OUTPUT
314f4e62e4fSbosticfi
315f4e62e4fSbostic
3168f0ba418Sbostic# Mailboxes should be owned by user and unreadable.
3172e01ce9eSbosticls -l /var/mail | sed 1d | \
3182e01ce9eSbosticawk '$3 != $9 \
3192e01ce9eSbostic	{ print "user " $9 " mailbox is owned by " $3 }
3202e01ce9eSbostic     $1 != "-rw-------" \
3212e01ce9eSbostic	{ print "user " $9 " mailbox is " $1 ", group " $4 }' > $OUTPUT
3222e01ce9eSbosticif [ -s $OUTPUT ] ; then
3232e01ce9eSbostic	printf "\nChecking mailbox ownership.\n"
3242e01ce9eSbostic	cat $OUTPUT
325f4e62e4fSbosticfi
326fe22c88eSbostic
3278f0ba418Sbostic# File systems should not be globally exported.
328e4e6515bSbosticawk '{
329e4e6515bSbostic	readonly = 0;
330e4e6515bSbostic	for (i = 2; i <= NF; ++i) {
331e4e6515bSbostic		if ($i ~ /-ro/)
332e4e6515bSbostic			readonly = 1;
333e4e6515bSbostic		else if ($i !~ /^-/)
334e4e6515bSbostic			next;
335e4e6515bSbostic	}
336e4e6515bSbostic	if (readonly)
337e4e6515bSbostic		print "File system " $1 " globally exported, read-only."
338e4e6515bSbostic	else
339e4e6515bSbostic		print "File system " $1 " globally exported, read-write."
3402e01ce9eSbostic}' < /etc/exports > $OUTPUT
3412e01ce9eSbosticif [ -s $OUTPUT ] ; then
3422e01ce9eSbostic	printf "\nChecking for globally exported file systems.\n"
3432e01ce9eSbostic	cat $OUTPUT
3442e01ce9eSbosticfi
345e4e6515bSbostic
3468f0ba418Sbostic# Display any changes in setuid files and devices.
3472e01ce9eSbosticprintf "\nChecking setuid files and devices:\n"
3482e01ce9eSbostic(find / ! -fstype local -a -prune -o \
3492e01ce9eSbostic    \( -perm -u+s -o -perm -g+s -o ! -type d -a ! -type f -a ! -type l -a \
3502e01ce9eSbostic       ! -type s \) | \
3512e01ce9eSbosticsort | sed -e 's/^/ls -ldgT /' | sh > $LIST) 2> $OUTPUT
352341415c8Sbostic
3536c152fbeSbostic# Display any errors that occurred during system file walk.
3542e01ce9eSbosticif [ -s $OUTPUT ] ; then
3552e01ce9eSbostic	printf "Setuid/device find errors:\n"
3562e01ce9eSbostic	cat $OUTPUT
3572e01ce9eSbostic	printf "\n"
358341415c8Sbosticfi
3599f40dbdcSbostic
3606c152fbeSbostic# Display any changes in the setuid file list.
3612e01ce9eSbosticegrep -v '^[bc]' $LIST > $TMP1
3622e01ce9eSbosticif [ -s $TMP1 ] ; then
3632e01ce9eSbostic	# Check to make sure uudecode isn't setuid.
3642e01ce9eSbostic	if grep -w uudecode $TMP1 > /dev/null ; then
3652e01ce9eSbostic		printf "\nUudecode is setuid.\n"
3662e01ce9eSbostic	fi
3672e01ce9eSbostic
3682e01ce9eSbostic	CUR=/var/backups/setuid.current
3692e01ce9eSbostic	BACK=/var/backups/setuid.backup
370fe22c88eSbostic
3716c152fbeSbostic	if [ -s $CUR ] ; then
3722e01ce9eSbostic		if cmp -s $CUR $TMP1 ; then
373fe22c88eSbostic			:
374fe22c88eSbostic		else
3752e01ce9eSbostic			> $TMP2
3762e01ce9eSbostic			join -110 -210 -v2 $CUR $TMP1 > $OUTPUT
3772e01ce9eSbostic			if [ -s $OUTPUT ] ; then
3782e01ce9eSbostic				printf "Setuid additions:\n"
3792e01ce9eSbostic				tee -a $TMP2 < $OUTPUT
3802e01ce9eSbostic				printf "\n"
3819f40dbdcSbostic			fi
382341415c8Sbostic
3832e01ce9eSbostic			join -110 -210 -v1 $CUR $TMP1 > $OUTPUT
3842e01ce9eSbostic			if [ -s $OUTPUT ] ; then
3852e01ce9eSbostic				printf "Setuid deletions:\n"
3862e01ce9eSbostic				tee -a $TMP2 < $OUTPUT
3872e01ce9eSbostic				printf "\n"
388fe22c88eSbostic			fi
389fe22c88eSbostic
3902e01ce9eSbostic			sort +9 $TMP2 $CUR $TMP1 | \
3912e01ce9eSbostic			    sed -e 's/[	 ][	 ]*/ /g' | uniq -u > $OUTPUT
3922e01ce9eSbostic			if [ -s $OUTPUT ] ; then
3932e01ce9eSbostic				printf "Setuid changes:\n"
3942e01ce9eSbostic				column -t $OUTPUT
3952e01ce9eSbostic				printf "\n"
396fe22c88eSbostic			fi
397fe22c88eSbostic
3982e01ce9eSbostic			cp $CUR $BACK
3992e01ce9eSbostic			cp $TMP1 $CUR
400fe22c88eSbostic		fi
401fe22c88eSbostic	else
4022e01ce9eSbostic		printf "Setuid additions:\n"
4038d53afbfSbostic		column -t $TMP1
4042e01ce9eSbostic		printf "\n"
4052e01ce9eSbostic		cp $TMP1 $CUR
406fe22c88eSbostic	fi
407fe22c88eSbosticfi
408fe22c88eSbostic
4098f0ba418Sbostic# Check for block and character disk devices that are readable or writeable
4108d53afbfSbostic# or not owned by root.operator.
411cc8fcf7bSbostic>$TMP1
412cc8fcf7bSbosticDISKLIST="dk fd hd hk hp jb kra ra rb rd rl rx rz sd up wd"
413cc8fcf7bSbosticfor i in $DISKLIST; do
414cc8fcf7bSbostic	egrep "^b.*/${i}[0-9][0-9]*[a-h]$"  $LIST >> $TMP1
415cc8fcf7bSbostic	egrep "^c.*/r${i}[0-9][0-9]*[a-h]$"  $LIST >> $TMP1
416cc8fcf7bSbosticdone
417e4e6515bSbostic
4188d53afbfSbosticawk '$3 != "root" || $4 != "operator" || $1 !~ /.rw-r-----/ \
4198d53afbfSbostic	{ printf("Disk %s is user %s, group %s, permissions %s.\n", \
4208d53afbfSbostic	    $11, $3, $4, $1); }' < $TMP1 > $OUTPUT
4212e01ce9eSbosticif [ -s $OUTPUT ] ; then
4222e01ce9eSbostic	printf "\nChecking disk ownership and permissions.\n"
4232e01ce9eSbostic	cat $OUTPUT
4242e01ce9eSbostic	printf "\n"
4252e01ce9eSbosticfi
426e4e6515bSbostic
4276c152fbeSbostic# Display any changes in the device file list.
4288f0ba418Sbosticegrep '^[bc]' $LIST | sort +10 > $TMP1
4292e01ce9eSbosticif [ -s $TMP1 ] ; then
4302e01ce9eSbostic	CUR=/var/backups/device.current
4312e01ce9eSbostic	BACK=/var/backups/device.backup
4326c152fbeSbostic
4336c152fbeSbostic	if [ -s $CUR ] ; then
4342e01ce9eSbostic		if cmp -s $CUR $TMP1 ; then
4356c152fbeSbostic			:
4366c152fbeSbostic		else
4372e01ce9eSbostic			> $TMP2
4382e01ce9eSbostic			join -111 -211 -v2 $CUR $TMP1 > $OUTPUT
4392e01ce9eSbostic			if [ -s $OUTPUT ] ; then
4402e01ce9eSbostic				printf "Device additions:\n"
4412e01ce9eSbostic				tee -a $TMP2 < $OUTPUT
4422e01ce9eSbostic				printf "\n"
4436c152fbeSbostic			fi
4446c152fbeSbostic
4452e01ce9eSbostic			join -111 -211 -v1 $CUR $TMP1 > $OUTPUT
4462e01ce9eSbostic			if [ -s $OUTPUT ] ; then
4472e01ce9eSbostic				printf "Device deletions:\n"
4482e01ce9eSbostic				tee -a $TMP2 < $OUTPUT
4492e01ce9eSbostic				printf "\n"
4506c152fbeSbostic			fi
4516c152fbeSbostic
4528d53afbfSbostic			# Report any block device change.  Ignore character
4538d53afbfSbostic			# devices, only the name is significant.
4548d53afbfSbostic			cat $TMP2 $CUR $TMP1 | \
4558d53afbfSbostic			sed -e '/^c/d' | \
4568d53afbfSbostic			sort +10 | \
4572e01ce9eSbostic			sed -e 's/[	 ][	 ]*/ /g' | \
4588d53afbfSbostic			uniq -u > $OUTPUT
4592e01ce9eSbostic			if [ -s $OUTPUT ] ; then
4608d53afbfSbostic				printf "Block device changes:\n"
4612e01ce9eSbostic				column -t $OUTPUT
4622e01ce9eSbostic				printf "\n"
4636c152fbeSbostic			fi
4646c152fbeSbostic
4652e01ce9eSbostic			cp $CUR $BACK
4662e01ce9eSbostic			cp $TMP1 $CUR
4676c152fbeSbostic		fi
4686c152fbeSbostic	else
4692e01ce9eSbostic		printf "Device additions:\n"
4708d53afbfSbostic		column -t $TMP1
4712e01ce9eSbostic		printf "\n"
4722e01ce9eSbostic		cp $TMP1 $CUR
4736c152fbeSbostic	fi
4746c152fbeSbosticfi
4756c152fbeSbostic
476bfcfc884Sbostic# Check special files.
477bfcfc884Sbostic# Check system binaries.
478bfcfc884Sbostic#
479efff9fd4Sbostic# Create the mtree tree specifications using:
480efff9fd4Sbostic#
4812e01ce9eSbostic#	mtree -cx -pDIR -kcksum,gid,mode,nlink,size,link,time,uid > DIR.secure
4822e01ce9eSbostic#	chown root.wheel DIR.SECURE
4832e01ce9eSbostic#	chmod 600 DIR.SECURE
484efff9fd4Sbostic#
485efff9fd4Sbostic# Note, this is not complete protection against Trojan horsed binaries, as
486efff9fd4Sbostic# the hacker can modify the tree specification to match the replaced binary.
487efff9fd4Sbostic# For details on really protecting yourself against modified binaries, see
488efff9fd4Sbostic# the mtree(8) manual page.
489efff9fd4Sbosticif cd /etc/mtree; then
4902e01ce9eSbostic	mtree -e -p / -f /etc/mtree/special > $OUTPUT
4912e01ce9eSbostic	if [ -s $OUTPUT ] ; then
4922e01ce9eSbostic		printf "\nChecking special files and directories.\n"
4932e01ce9eSbostic		cat $OUTPUT
4942e01ce9eSbostic	fi
4952e01ce9eSbostic
4962e01ce9eSbostic	> $OUTPUT
497efff9fd4Sbostic	for file in *.secure; do
498efff9fd4Sbostic		tree=`sed -n -e '3s/.* //p' -e 3q $file`
4992e01ce9eSbostic		mtree -f $file -p $tree > $TMP1
5002e01ce9eSbostic		if [ -s $TMP1 ]; then
5012e01ce9eSbostic			printf "\nChecking $tree:\n" >> $OUTPUT
5022e01ce9eSbostic			cat $TMP1 >> $OUTPUT
5032e01ce9eSbostic		fi
504efff9fd4Sbostic	done
5052e01ce9eSbostic	if [ -s $OUTPUT ] ; then
5062e01ce9eSbostic		printf "\nChecking system binaries:\n"
5072e01ce9eSbostic		cat $OUTPUT
5082e01ce9eSbostic	fi
509efff9fd4Sbosticfi
51017aa77b0Sbostic
51117aa77b0Sbostic# List of files that get backed up and checked for any modifications.  Each
51217aa77b0Sbostic# file is expected to have two backups, /var/backups/file.{current,backup}.
51317aa77b0Sbostic# Any changes cause the files to rotate.
51417aa77b0Sbosticif [ -s /etc/changelist ] ; then
51517aa77b0Sbostic	for file in `cat /etc/changelist`; do
51617aa77b0Sbostic		CUR=/var/backups/`basename $file`.current
51717aa77b0Sbostic		BACK=/var/backups/`basename $file`.backup
51817aa77b0Sbostic		if [ -s $file ]; then
51917aa77b0Sbostic			if [ -s $CUR ] ; then
52017aa77b0Sbostic				diff $CUR $file > $OUTPUT
52117aa77b0Sbostic				if [ -s $OUTPUT ] ; then
52217aa77b0Sbostic		printf "\n======\n%s diffs (OLD < > NEW)\n======\n" $file
52317aa77b0Sbostic					cat $OUTPUT
52417aa77b0Sbostic					cp -p $CUR $BACK
52517aa77b0Sbostic					cp -p $file $CUR
52617aa77b0Sbostic					chown root.wheel $CUR $BACK
52717aa77b0Sbostic				fi
52817aa77b0Sbostic			else
52917aa77b0Sbostic				cp -p $file $CUR
53017aa77b0Sbostic				chown root.wheel $CUR
53117aa77b0Sbostic			fi
53217aa77b0Sbostic		fi
53317aa77b0Sbostic	done
53417aa77b0Sbosticfi
535