xref: /netbsd-src/etc/security (revision b2f03d66fa0b190f219b8b07d774d1ad307eae3e)
161f28255Scgd#!/bin/sh -
261f28255Scgd#
3*b2f03d66She#	$NetBSD: security,v 1.132 2024/07/21 14:56:16 he Exp $
491778fe0Scgd#	from: @(#)security	8.1 (Berkeley) 6/9/93
561f28255Scgd#
661f28255Scgd
791778fe0ScgdPATH=/sbin:/usr/sbin:/bin:/usr/bin
861f28255Scgd
93c8a1444Sjmmvrcvar_manpage='security.conf(5)'
103c8a1444Sjmmv
118f59ce8eSlukemif [ -f /etc/rc.subr ]; then
128f59ce8eSlukem	. /etc/rc.subr
138f59ce8eSlukemelse
148f59ce8eSlukem	echo "Can't read /etc/rc.subr; aborting."
158f59ce8eSlukem	exit 1;
168f59ce8eSlukemfi
178f59ce8eSlukem
1891778fe0Scgdumask 077
19350cdd6aScjsTZ=UTC; export TZ
2061f28255Scgd
21a9efb638Smrgif [ -s /etc/security.conf ]; then
22a9efb638Smrg	. /etc/security.conf
23a9efb638Smrgfi
241410cf30Sagcif [ -s /etc/pkgpath.conf ]; then
251410cf30Sagc	. /etc/pkgpath.conf
261410cf30Sagcfi
271c2ae9dcScgd
2896a1608eSlukem# Set reasonable defaults (if they're not set in security.conf)
2996a1608eSlukem#
3096a1608eSlukembackup_dir=${backup_dir:-/var/backups}
3196a1608eSlukemmax_loginlen=${max_loginlen:-8}
3296a1608eSlukemmax_grouplen=${max_grouplen:-8}
33dc76b0b0Sprlw1pkg_admin=${pkg_admin:-/usr/sbin/pkg_admin}
3467b08a07Sadrianppkg_info=${pkg_info:-/usr/sbin/pkg_info}
3596a1608eSlukem
3696a1608eSlukem# Other configurable variables
3796a1608eSlukem#
3896a1608eSlukemspecial_files="/etc/mtree/special /etc/mtree/special.local"
3996a1608eSlukemMP=/etc/master.passwd
4096a1608eSlukemCHANGELIST=""
4196a1608eSlukemwork_dir=$backup_dir/work
4296a1608eSlukem
4396a1608eSlukemif [ ! -d "$work_dir" ]; then
4496a1608eSlukem	mkdir -p "$work_dir"
4596a1608eSlukemfi
4696a1608eSlukem
47d405da7fSmarttiSECUREDIR=$(mktemp -d -t _securedir) || exit 1
48a9efb638Smrg
4996a1608eSlukemtrap "/bin/rm -rf $SECUREDIR ; exit 0" EXIT INT QUIT PIPE
50684e89f3Slukem
51684e89f3Slukemif ! cd "$SECUREDIR"; then
52684e89f3Slukem	echo "Can not cd to $SECUREDIR".
53a9efb638Smrg	exit 1
54a9efb638Smrgfi
55a9efb638Smrg
56610ee5bdSlukemERR=err.$$
57610ee5bdSlukemTMP1=tmp1.$$
58610ee5bdSlukemTMP2=tmp2.$$
59610ee5bdSlukemMPBYUID=mpbyuid.$$
60610ee5bdSlukemMPBYPATH=mpbypath.$$
61610ee5bdSlukemLIST=list.$$
62610ee5bdSlukemOUTPUT=output.$$
63610ee5bdSlukemLABELS=labels.$$
64a4e58525ShaadLVM_LABELS=lvm.$$
65610ee5bdSlukemPKGS=pkgs.$$
66610ee5bdSlukemCHANGEFILES=changefiles.$$
67610ee5bdSlukemSPECIALSPEC=specialspec.$$
68a9efb638Smrg
6953cb2117Sjmmvif [ -n "${pkgdb_dir}" ]; then
7053cb2117Sjmmv	echo "WARNING: Setting pkgdb_dir in security.conf(5) is deprecated"
7153cb2117Sjmmv	echo "WARNING: Please define PKG_DBDIR in pkg_install.conf(5) instead"
7253cb2117Sjmmv	_compat_K_flag="-K ${pkgdb_dir}"
7353cb2117Sjmmvfi
7453cb2117Sjmmv
7553cb2117Sjmmvhave_pkgs() {
7653cb2117Sjmmv	$pkg_info ${_compat_K_flag} -q -E '*'
7753cb2117Sjmmv}
7853cb2117Sjmmv
7996a1608eSlukem# migrate_file old new
8096a1608eSlukem#	Determine if the "${old}" path name needs to be migrated to the
8196a1608eSlukem#	"${new}" path. Also checks if "${old}.current" needs migrating,
8296a1608eSlukem#	and if so, migrate it and possibly "${old}.current,v" and
8396a1608eSlukem#	"${old}.backup".
8496a1608eSlukem#
8596a1608eSlukemmigrate_file()
8696a1608eSlukem{
8796a1608eSlukem	_old=$1
8896a1608eSlukem	_new=$2
899ae2b31fSkre	if [ -z "$_old" ] || [ -z "$_new" ]; then
9096a1608eSlukem		err 3 "USAGE: migrate_file old new"
9196a1608eSlukem	fi
9296a1608eSlukem	if [ ! -d "${_new%/*}" ]; then
9396a1608eSlukem		mkdir -p "${_new%/*}"
9496a1608eSlukem	fi
959ae2b31fSkre	if [ -f "${_old}" ] && ! [ -f "${_new}" ]; then
9696a1608eSlukem		echo "==> migrating ${_old}"
9796a1608eSlukem		echo "           to ${_new}"
9896a1608eSlukem		mv "${_old}" "${_new}"
9996a1608eSlukem	fi
1009ae2b31fSkre	if [ -f "${_old}.current" ] && ! [ -f "${_new}.current" ]; then
10196a1608eSlukem		echo "==> migrating ${_old}.current"
10296a1608eSlukem		echo "           to ${_new}.current"
10396a1608eSlukem		mv "${_old}.current" "${_new}.current"
1049ae2b31fSkre		if [ -f "${_old}.current,v" ] &&
1059ae2b31fSkre		 ! [ -f "${_new}.current,v" ]; then
10696a1608eSlukem			echo "==> migrating ${_old}.current,v"
10796a1608eSlukem			echo "           to ${_new}.current,v"
10896a1608eSlukem			mv "${_old}.current,v" "${_new}.current,v"
10996a1608eSlukem		fi
1109ae2b31fSkre		if [ -f "${_old}.backup" ] && ! [ -f "${_new}.backup" ]; then
11196a1608eSlukem			echo "==> migrating ${_old}.backup"
11296a1608eSlukem			echo "           to ${_new}.backup"
11396a1608eSlukem			mv "${_old}.backup" "${_new}.backup"
11496a1608eSlukem		fi
11596a1608eSlukem	fi
11696a1608eSlukem}
117a9efb638Smrg
11896a1608eSlukem
11996a1608eSlukem# backup_and_diff file printdiff
12096a1608eSlukem#	Determine if file needs backing up, and if so, do it.
12196a1608eSlukem#	If printdiff is yes, display the diffs, otherwise
12296a1608eSlukem#	just print a message saying "[changes omitted]".
12396a1608eSlukem#
12496a1608eSlukembackup_and_diff()
12596a1608eSlukem{
12696a1608eSlukem	_file=$1
12796a1608eSlukem	_printdiff=$2
1289ae2b31fSkre	if [ -z "$_file" ] || [ -z "$_printdiff" ]; then
12996a1608eSlukem		err 3 "USAGE: backup_and_diff file printdiff"
13096a1608eSlukem	fi
13196a1608eSlukem	! checkyesno _printdiff
13296a1608eSlukem	_printdiff=$?
13396a1608eSlukem
13496a1608eSlukem	_old=$backup_dir/${_file##*/}
13596a1608eSlukem	case "$_file" in
13696a1608eSlukem	$work_dir/*)
13796a1608eSlukem		_new=$_file
13896a1608eSlukem		migrate_file "$backup_dir/$_old" "$_new"
13996a1608eSlukem		migrate_file "$_old" "$_new"
14096a1608eSlukem		;;
14196a1608eSlukem	*)
14296a1608eSlukem		_new=$backup_dir/$_file
14396a1608eSlukem		migrate_file "$_old" "$_new"
14496a1608eSlukem		;;
14596a1608eSlukem	esac
14696a1608eSlukem	CUR=${_new}.current
14796a1608eSlukem	BACK=${_new}.backup
14896a1608eSlukem	if [ -f $_file ]; then
14996a1608eSlukem		if [ -f $CUR ] ; then
15096a1608eSlukem			if [ "$_printdiff" -ne 0 ]; then
1511d79603cSjhawk				diff ${diff_options} $CUR $_file > $OUTPUT
15296a1608eSlukem			else
15396a1608eSlukem				if ! cmp -s $CUR $_file; then
15496a1608eSlukem					echo "[changes omitted]"
15596a1608eSlukem				fi > $OUTPUT
15696a1608eSlukem			fi
15796a1608eSlukem			if [ -s $OUTPUT ] ; then
15896a1608eSlukem				printf \
15996a1608eSlukem			"\n======\n%s diffs (OLD < > NEW)\n======\n" $_file
16096a1608eSlukem				cat $OUTPUT
16196a1608eSlukem				backup_file update $_file $CUR $BACK
16296a1608eSlukem			fi
16396a1608eSlukem		else
16496a1608eSlukem			printf "\n======\n%s added\n======\n" $_file
16596a1608eSlukem			if [ "$_printdiff" -ne 0 ]; then
1661d79603cSjhawk				diff ${diff_options} /dev/null $_file
16796a1608eSlukem			else
16896a1608eSlukem				echo "[changes omitted]"
16996a1608eSlukem			fi
17096a1608eSlukem			backup_file add $_file $CUR $BACK
17196a1608eSlukem		fi
17296a1608eSlukem	else
17396a1608eSlukem		if [ -f $CUR ]; then
17496a1608eSlukem			printf "\n======\n%s removed\n======\n" $_file
17596a1608eSlukem			if [ "$_printdiff" -ne 0 ]; then
1761d79603cSjhawk				diff ${diff_options} $CUR /dev/null
17796a1608eSlukem			else
17896a1608eSlukem				echo "[changes omitted]"
17996a1608eSlukem			fi
18096a1608eSlukem			backup_file remove $_file $CUR $BACK
18196a1608eSlukem		fi
18296a1608eSlukem	fi
18396a1608eSlukem}
18496a1608eSlukem
18596a1608eSlukem
18696a1608eSlukem# These are used several times.
18796a1608eSlukem#
188610ee5bdSlukemawk -F: '!/^\+/ { print $1 " " $3 }' $MP | sort -k2n > $MPBYUID
18990ec96dfSlukemawk -F: '{ print $1 " " $9 }' $MP | sort -k2 > $MPBYPATH
190610ee5bdSlukemfor file in $special_files; do
191610ee5bdSlukem	[ -s $file ] && cat $file
192610ee5bdSlukemdone | mtree -CM -k all > $SPECIALSPEC || exit 1
1931c2ae9dcScgd
19496a1608eSlukem
195cba96d16Sriastradh# Check for enough entropy.
196cba96d16Sriastradh#
197cba96d16Sriastradhif checkyesno check_entropy; then
1981095510aSmartin	if [ "$(sysctl -n kern.entropy.needed)" != 0 ]; then
199cba96d16Sriastradh		printf '\n'
200cba96d16Sriastradh		printf 'Entropy:\n'
201cba96d16Sriastradh		printf 'System may need more entropy for cryptography.\n'
202cba96d16Sriastradh		printf 'See the entropy(7) man page for details.\n'
203cba96d16Sriastradh	fi
204cba96d16Sriastradhfi
205cba96d16Sriastradh
206cba96d16Sriastradh
20791778fe0Scgd# Check the master password file syntax.
2083a3b03bdSlukem#
2098f59ce8eSlukemif checkyesno check_passwd; then
210ea872628Sjhawk	# XXX: the sense of permit_star is reversed; the code works as
211ea872628Sjhawk	# implemented, but usage needs to be negated.
2121a4c8c02Sjhawk	checkyesno check_passwd_permit_star && permit_star=0 || permit_star=1
2138e401e6cSjdolecek	checkyesno check_passwd_permit_nonalpha \
2148e401e6cSjdolecek		 && permit_nonalpha=1 || permit_nonalpha=0
2158e401e6cSjdolecek
2161a4c8c02Sjhawk	awk -v "len=$max_loginlen" \
2171a4c8c02Sjhawk	    -v "nowarn_shells_list=$check_passwd_nowarn_shells" \
2181a4c8c02Sjhawk	    -v "nowarn_users_list=$check_passwd_nowarn_users" \
2198e401e6cSjdolecek	    -v "permit_star=$permit_star" \
2208e401e6cSjdolecek	    -v "permit_nonalpha=$permit_nonalpha" \
2218e401e6cSjdolecek	'
222fb34424eSlukem	BEGIN {
223fb34424eSlukem		while ( getline < "/etc/shells" > 0 ) {
2248b10c79fShubertf			if ($0 ~ /^\#/ || $0 ~ /^$/ )
225fb34424eSlukem				continue;
226fb34424eSlukem			shells[$1]++;
227fb34424eSlukem		}
2281a4c8c02Sjhawk		split(nowarn_shells_list, a);
2291a4c8c02Sjhawk		for (i in a) nowarn_shells[a[i]]++;
2301a4c8c02Sjhawk		split(nowarn_users_list, a);
2311a4c8c02Sjhawk		for (i in a) nowarn_users[a[i]]++;
2321a4c8c02Sjhawk		uid0_users_list="root toor"
2331a4c8c02Sjhawk		split(uid0_users_list, a);
2341a4c8c02Sjhawk		for (i in a) uid0_users[a[i]]++;
235fb34424eSlukem		FS=":";
236fb34424eSlukem	}
237fb34424eSlukem
238fb34424eSlukem	{
23991778fe0Scgd		if ($0 ~ /^[	 ]*$/) {
240fb34424eSlukem			printf "Line %d is a blank line.\n", NR;
24191778fe0Scgd			next;
24291778fe0Scgd		}
243d08cb6cfSdholland
244d08cb6cfSdholland		# NIS compat entry?
245d08cb6cfSdholland		compatline = $1 ~ "^[\\+-]";
246d08cb6cfSdholland		if (compatline) {
247d08cb6cfSdholland			if ($1 == "+" && NF == 1) {
248d08cb6cfSdholland				next;
249d08cb6cfSdholland			}
250d08cb6cfSdholland			sub("^.", "", $1);
251d08cb6cfSdholland		}
252d08cb6cfSdholland		if (NF != 10)
253fb34424eSlukem			printf "Line %d has the wrong number of fields.\n", NR;
254d08cb6cfSdholland		if (compatline)  {
255d08cb6cfSdholland			if ($3 == 0)
2561a4c8c02Sjhawk			    printf "Line %d includes entries with uid 0.\n",
2571a4c8c02Sjhawk			        NR;
258d08cb6cfSdholland			if ($1 == "")
259dade5b29Sabs			    next;
260dade5b29Sabs		}
2618e401e6cSjdolecek		if (!permit_nonalpha &&
262271ad04cSpeter		    $1 !~ /^[_A-Za-z0-9]([-A-Za-z0-9_.]*[A-Za-z0-9])*$/)
263fb34424eSlukem			printf "Login %s has non-alphanumeric characters.\n",
264fb34424eSlukem			    $1;
265dade5b29Sabs		if (length($1) > len)
2661a4c8c02Sjhawk			printf "Login %s has more than "len" characters.\n",
2671a4c8c02Sjhawk			    $1;
268d08cb6cfSdholland		if ($2 == "" && !compatline && !nowarn_users[$1])
269fb34424eSlukem			    printf "Login %s has no password.\n", $1;
2701a4c8c02Sjhawk		if (!nowarn_shells[$10] && !nowarn_users[$1]) {
271247041e3Sperry		    if (length($2) != 13 &&
272247041e3Sperry		    	length($2) != 20 &&
27374377e4aSitojun		    	$2 !~ /^\$1/ &&
27474377e4aSitojun		    	$2 !~ /^\$2/ &&
27564b4f9dcSjmcneill			$2 !~ /^\$sha1/ &&
2768e79eccaSnia			$2 !~ /^\$argon2(i|d|id)/ &&
277247041e3Sperry		    	$2 != "" &&
2781a4c8c02Sjhawk			(permit_star || $2 != "*") &&
279247041e3Sperry		    	$2 !~ /^\*[A-z-]+$/ &&
280247041e3Sperry			$1 != "toor") {
281fb34424eSlukem		    	    if ($10 == "" || shells[$10])
2821a4c8c02Sjhawk				printf "Login %s is off but still has "\
2831a4c8c02Sjhawk				  "a valid shell (%s)\n", $1, $10;
284d08cb6cfSdholland		    } else if (compatline && $10 == "") {
285d08cb6cfSdholland			    # nothing
286fb34424eSlukem		    } else if (! shells[$10])
2871a4c8c02Sjhawk		    	    printf "Login %s does not have a valid "\
2881a4c8c02Sjhawk			    "shell (%s)\n", $1, $10;
2891a4c8c02Sjhawk		}
2901a4c8c02Sjhawk		if ($3 == 0 && !uid0_users[$1] && !nowarn_users[$1])
291fb34424eSlukem			printf "Login %s has a user id of 0.\n", $1;
292d08cb6cfSdholland		if ($3 != "" && $3 < 0)
293fb34424eSlukem			printf "Login %s has a negative user id.\n", $1;
294d08cb6cfSdholland		if ($4 != "" && $4 < 0)
295fb34424eSlukem			printf "Login %s has a negative group id.\n", $1;
29691778fe0Scgd	}' < $MP > $OUTPUT
29791778fe0Scgd	if [ -s $OUTPUT ] ; then
29891778fe0Scgd		printf "\nChecking the $MP file:\n"
29991778fe0Scgd		cat $OUTPUT
30061f28255Scgd	fi
30161f28255Scgd
30291778fe0Scgd	awk -F: '{ print $1 }' $MP | sort | uniq -d > $OUTPUT
30391778fe0Scgd	if [ -s $OUTPUT ] ; then
30491778fe0Scgd		printf "\n$MP has duplicate user names.\n"
30591778fe0Scgd		column $OUTPUT
30691778fe0Scgd	fi
30791778fe0Scgd
308c6302b74Sspz	awk -v "permit_dups_list=$check_passwd_permit_dups" \
309c6302b74Sspz	'
310c6302b74Sspz	BEGIN {
311c6302b74Sspz		split(permit_dups_list, a);
312c6302b74Sspz		for (i in a) permit_dups[a[i]]++;
313c6302b74Sspz	}
314c6302b74Sspz	{
315c6302b74Sspz		if (!permit_dups[$1])
316c6302b74Sspz			print $2;
317c6302b74Sspz	}' < $MPBYUID | uniq -d > $TMP2
31891778fe0Scgd	if [ -s $TMP2 ] ; then
319c6302b74Sspz		printf "\n$MP has duplicate user ids.\n"
32091778fe0Scgd		while read uid; do
321f09b5e36Slukem			grep -w $uid $MPBYUID
32291778fe0Scgd		done < $TMP2 | column
32391778fe0Scgd	fi
324a9efb638Smrgfi
32591778fe0Scgd
32691778fe0Scgd# Check the group file syntax.
3273a3b03bdSlukem#
3288f59ce8eSlukemif checkyesno check_group; then
32991778fe0Scgd	GRP=/etc/group
3304ceebb11Sjdolecek	awk -F: -v "len=$max_grouplen" '{
33191778fe0Scgd		if ($0 ~ /^[	 ]*$/) {
332fb34424eSlukem			printf "Line %d is a blank line.\n", NR;
33391778fe0Scgd			next;
33491778fe0Scgd		}
335dade5b29Sabs		if (NF != 4 && ($1 != "+" || NF != 1))
336fb34424eSlukem			printf "Line %d has the wrong number of fields.\n", NR;
337dade5b29Sabs		if ($1 == "+" )  {
338dade5b29Sabs			next;
339dade5b29Sabs		}
340271ad04cSpeter		if ($1 !~ /^[_A-Za-z0-9]([-A-Za-z0-9_.]*[A-Za-z0-9])*$/)
341fb34424eSlukem			printf "Group %s has non-alphanumeric characters.\n",
342fb34424eSlukem			    $1;
3434ceebb11Sjdolecek		if (length($1) > len)
3444ceebb11Sjdolecek			printf "Group %s has more than "len" characters.\n", $1;
34591778fe0Scgd		if ($3 !~ /[0-9]*/)
346fb34424eSlukem			printf "Login %s has a negative group id.\n", $1;
34791778fe0Scgd	}' < $GRP > $OUTPUT
34891778fe0Scgd	if [ -s $OUTPUT ] ; then
34991778fe0Scgd		printf "\nChecking the $GRP file:\n"
35091778fe0Scgd		cat $OUTPUT
35191778fe0Scgd	fi
35291778fe0Scgd
35391778fe0Scgd	awk -F: '{ print $1 }' $GRP | sort | uniq -d > $OUTPUT
3540d7af235Sspz	dupgroups=""
3550d7af235Sspz	for group in $(cat $OUTPUT) ; do
3568ce568ceSapb		gcount=$(awk -F: "/$group/ { print \$1,\$3 }" $GRP |
3578ce568ceSapb			sort -u | wc -l)
3580d7af235Sspz		if [ $gcount -gt 1 ]; then
3590d7af235Sspz			dupgroups="$dupgroups $group"
3600d7af235Sspz		fi
3610d7af235Sspz	done
362*b2f03d66She	if [ ! -z "$dupgroups" ] ; then
36391778fe0Scgd		printf "\n$GRP has duplicate group names.\n"
3640d7af235Sspz		printf "$dupgroups\n"
36591778fe0Scgd	fi
366a9efb638Smrgfi
36791778fe0Scgd
36891778fe0Scgd# Check for root paths, umask values in startup files.
36991778fe0Scgd# The check for the root paths is problematical -- it's likely to fail
37091778fe0Scgd# in other environments.  Once the shells have been modified to warn
37191778fe0Scgd# of '.' in the path, the path tests should go away.
3723a3b03bdSlukem#
3738f59ce8eSlukemif checkyesno check_rootdotfiles; then
37496a1608eSlukem	rhome=~root
37591778fe0Scgd	umaskset=no
37691778fe0Scgd	list="/etc/csh.cshrc /etc/csh.login ${rhome}/.cshrc ${rhome}/.login"
37791778fe0Scgd	for i in $list ; do
37891778fe0Scgd		if [ -f $i ] ; then
37996a1608eSlukem			if egrep '^[ \t]*umask[ \t]+[0-7]+' $i > /dev/null ;
38096a1608eSlukem			then
38191778fe0Scgd				umaskset=yes
38291778fe0Scgd			fi
383f263bbb1Slukem			# Double check the umask value itself; ensure that
38496a1608eSlukem			# both the group and other write bits are set.
38596a1608eSlukem			#
3869928e1feSsommerfeld			egrep '^[ \t]*umask[ \t]+[0-7]+' $i |
387f263bbb1Slukem			awk '{
38896a1608eSlukem				if ($2 ~ /^.$/ || $2 ~! /[^2367].$/) {
3891035faffSwiz					print "\tRoot umask is group writable"
390f263bbb1Slukem				}
39196a1608eSlukem				if ($2 ~ /[^2367]$/) {
3921035faffSwiz					print "\tRoot umask is other writable"
393f263bbb1Slukem			    	}
39496a1608eSlukem			    }' | sort -u
3950f26a045Slukem			SAVE_PATH=$PATH
3960f26a045Slukem			unset PATH
39791778fe0Scgd			/bin/csh -f -s << end-of-csh > /dev/null 2>&1
39891778fe0Scgd				source $i
39991778fe0Scgd				/bin/ls -ldgT \$path > $TMP1
40091778fe0Scgdend-of-csh
401bc451d09Satatat			export PATH=$SAVE_PATH
40291778fe0Scgd			awk '{
40391778fe0Scgd				if ($10 ~ /^\.$/) {
40489fa41e9Slukem					print "\tThe root path includes .";
40591778fe0Scgd					next;
40691778fe0Scgd				}
40791778fe0Scgd			     }
40891778fe0Scgd			     $1 ~ /^d....w/ \
4091035faffSwiz		{ print "\tRoot path directory " $10 " is group writable." } \
41091778fe0Scgd			     $1 ~ /^d.......w/ \
4111035faffSwiz		{ print "\tRoot path directory " $10 " is other writable." }' \
41296a1608eSlukem			< $TMP1
41391778fe0Scgd		fi
41496a1608eSlukem	done > $OUTPUT
415d65b3b7aSkre	if [ $umaskset = no ] || [ -s $OUTPUT ] ; then
41689fa41e9Slukem		printf "\nChecking root csh paths, umask values:\n$list\n\n"
41791778fe0Scgd		if [ -s $OUTPUT ]; then
41891778fe0Scgd			cat $OUTPUT
41991778fe0Scgd		fi
4209ae2b31fSkre		if [ $umaskset = no ] ; then
42189fa41e9Slukem		    printf "\tRoot csh startup files do not set the umask.\n"
42291778fe0Scgd		fi
42391778fe0Scgd	fi
42491778fe0Scgd
42591778fe0Scgd	umaskset=no
426d0b6172bSlukem	list="/etc/profile ${rhome}/.profile"
42791778fe0Scgd	for i in $list; do
42891778fe0Scgd		if [ -f $i ] ; then
42991778fe0Scgd			if egrep umask $i > /dev/null ; then
43091778fe0Scgd				umaskset=yes
43191778fe0Scgd			fi
43291778fe0Scgd			egrep umask $i |
43396a1608eSlukem			awk '$2 ~ /^.$/ || $2 ~ /[^2367].$/ \
4341035faffSwiz				{ print "\tRoot umask is group writable" } \
43596a1608eSlukem			     $2 ~ /[^2367]$/ \
4361035faffSwiz				{ print "\tRoot umask is other writable" }'
4370f26a045Slukem			SAVE_PATH=$PATH
4380f26a045Slukem			unset PATH
43991778fe0Scgd			/bin/sh << end-of-sh > /dev/null 2>&1
44091778fe0Scgd				. $i
4416f0af47aSchristos				list=\$(echo \$PATH | /usr/bin/sed -e \
4426f0af47aSchristos				    's/^:/.:/;s/:$/:./;s/::/:.:/g;s/:/ /g')
44391778fe0Scgd				/bin/ls -ldgT \$list > $TMP1
44491778fe0Scgdend-of-sh
445bc451d09Satatat			export PATH=$SAVE_PATH
44691778fe0Scgd			awk '{
44791778fe0Scgd				if ($10 ~ /^\.$/) {
44889fa41e9Slukem					print "\tThe root path includes .";
44991778fe0Scgd					next;
45091778fe0Scgd				}
45191778fe0Scgd			     }
45291778fe0Scgd			     $1 ~ /^d....w/ \
4531035faffSwiz		{ print "\tRoot path directory " $10 " is group writable." } \
45491778fe0Scgd			     $1 ~ /^d.......w/ \
4551035faffSwiz		{ print "\tRoot path directory " $10 " is other writable." }' \
45696a1608eSlukem			< $TMP1
45791778fe0Scgd
45891778fe0Scgd		fi
45996a1608eSlukem	done > $OUTPUT
4609ae2b31fSkre	if [ $umaskset = no ] || [ -s $OUTPUT ] ; then
46191778fe0Scgd		printf "\nChecking root sh paths, umask values:\n$list\n"
46291778fe0Scgd		if [ -s $OUTPUT ]; then
46391778fe0Scgd			cat $OUTPUT
46491778fe0Scgd		fi
4659ae2b31fSkre		if [ $umaskset = no ] ; then
46689fa41e9Slukem			printf "\tRoot sh startup files do not set the umask.\n"
46791778fe0Scgd		fi
46891778fe0Scgd	fi
469a9efb638Smrgfi
47091778fe0Scgd
47191778fe0Scgd# Root and uucp should both be in /etc/ftpusers.
4723a3b03bdSlukem#
4738f59ce8eSlukemif checkyesno check_ftpusers; then
4744f848eeeSchristos	list="uucp "$(awk '$2 == 0 { print $1 }' $MPBYUID)
47589fa41e9Slukem	for i in $list; do
47690ec96dfSlukem		if /usr/libexec/ftpd -C $i ; then
47796a1608eSlukem			printf "\t$i is not denied\n"
47891778fe0Scgd		fi
47996a1608eSlukem	done > $OUTPUT
480f09b5e36Slukem	if [ -s $OUTPUT ]; then
481f09b5e36Slukem		printf "\nChecking the /etc/ftpusers configuration:\n"
482f09b5e36Slukem		cat $OUTPUT
483f09b5e36Slukem	fi
484a9efb638Smrgfi
48591778fe0Scgd
48613c8f7a2Sitojun# Uudecode should not be in the /etc/mail/aliases file.
4873a3b03bdSlukem#
4888f59ce8eSlukemif checkyesno check_aliases; then
48913c8f7a2Sitojun	for f in /etc/mail/aliases /etc/aliases; do
49013c8f7a2Sitojun		if [ -f $f ] && egrep '^[^#]*(uudecode|decode).*\|' $f; then
49113c8f7a2Sitojun			printf "\nEntry for uudecode in $f file.\n"
49291778fe0Scgd		fi
49313c8f7a2Sitojun	done
494a9efb638Smrgfi
49591778fe0Scgd
49691778fe0Scgd# Files that should not have + signs.
4973a3b03bdSlukem#
4988f59ce8eSlukemif checkyesno check_rhosts; then
49991778fe0Scgd	list="/etc/hosts.equiv /etc/hosts.lpd"
50091778fe0Scgd	for f in $list ; do
5011377ee09Spk		if [ -f $f ] && egrep '\+' $f > /dev/null ; then
50291778fe0Scgd			printf "\nPlus sign in $f file.\n"
50391778fe0Scgd		fi
50491778fe0Scgd	done
50591778fe0Scgd
50691778fe0Scgd	# Check for special users with .rhosts files.  Only root and toor should
5075b5eddafSmikel	# have .rhosts files.  Also, .rhosts files should not have plus signs.
50891778fe0Scgd	awk -F: '$1 != "root" && $1 != "toor" && \
50991778fe0Scgd		($3 < 100 || $1 == "ftp" || $1 == "uucp") \
510df1a64b9Smycroft			{ print $1 " " $9 }' $MP |
5114a0848acSmycroft	sort -k2 |
51291778fe0Scgd	while read uid homedir; do
51391778fe0Scgd		if [ -f ${homedir}/.rhosts ] ; then
5144f848eeeSchristos			rhost=$(ls -ldgT ${homedir}/.rhosts)
515b4266bbcSchristos			printf -- "$uid: $rhost\n"
51691778fe0Scgd		fi
51791778fe0Scgd	done > $OUTPUT
51891778fe0Scgd	if [ -s $OUTPUT ] ; then
51991778fe0Scgd		printf "\nChecking for special users with .rhosts files.\n"
52091778fe0Scgd		cat $OUTPUT
52191778fe0Scgd	fi
52291778fe0Scgd
52391778fe0Scgd	while read uid homedir; do
5249ae2b31fSkre		if [ -f ${homedir}/.rhosts ] &&
5259ae2b31fSkre		   [ -r ${homedir}/.rhosts ] &&
5269ae2b31fSkre		   cat -f ${homedir}/.rhosts | egrep '\+' > /dev/null
5279ae2b31fSkre		then
528b4266bbcSchristos			printf -- "$uid: + in .rhosts file.\n"
52991778fe0Scgd		fi
53090ec96dfSlukem	done < $MPBYPATH > $OUTPUT
53191778fe0Scgd	if [ -s $OUTPUT ] ; then
53291778fe0Scgd		printf "\nChecking .rhosts files syntax.\n"
53391778fe0Scgd		cat $OUTPUT
53491778fe0Scgd	fi
535a9efb638Smrgfi
53691778fe0Scgd
53791778fe0Scgd# Check home directories.  Directories should not be owned by someone else
5381035faffSwiz# or writable.
5393a3b03bdSlukem#
5408f59ce8eSlukemif checkyesno check_homes; then
541ea872628Sjhawk	checkyesno check_homes_permit_usergroups && \
542ea872628Sjhawk		permit_usergroups=1 || permit_usergroups=0
54391778fe0Scgd	while read uid homedir; do
54491778fe0Scgd		if [ -d ${homedir}/ ] ; then
5454f848eeeSchristos			file=$(ls -ldgT ${homedir})
546b4266bbcSchristos			printf -- "$uid $file\n"
54791778fe0Scgd		fi
54890ec96dfSlukem	done < $MPBYPATH |
549acaf72ecSspz	awk -v "usergroups=$permit_usergroups" \
550acaf72ecSspz	    -v "permit_owners_list=$check_homes_permit_other_owner"  '
551acaf72ecSspz	     BEGIN {
552acaf72ecSspz		split(permit_owners_list, a);
553acaf72ecSspz		for (i in a) permit_owners[a[i]]++;
554acaf72ecSspz	     }
555acaf72ecSspz	     $1 != $4 && $4 != "root" && !permit_owners[$1] \
55691778fe0Scgd		{ print "user " $1 " home directory is owned by " $4 }
557f2e95068Sjnemeth	     $2 ~ /^d....w/ && (!usergroups || $5 != $1) \
5581035faffSwiz		{ print "user " $1 " home directory is group writable" }
559f2e95068Sjnemeth	     $2 ~ /^d.......w/ \
5601035faffSwiz		{ print "user " $1 " home directory is other writable" }' \
56189fa41e9Slukem	    > $OUTPUT
56291778fe0Scgd	if [ -s $OUTPUT ] ; then
56391778fe0Scgd		printf "\nChecking home directories.\n"
56491778fe0Scgd		cat $OUTPUT
56591778fe0Scgd	fi
56691778fe0Scgd
56791778fe0Scgd	# Files that should not be owned by someone else or readable.
56896a1608eSlukem	list=".Xauthority .netrc .ssh/id_dsa .ssh/id_rsa .ssh/identity"
56991778fe0Scgd	while read uid homedir; do
57091778fe0Scgd		for f in $list ; do
57191778fe0Scgd			file=${homedir}/${f}
57291778fe0Scgd			if [ -f $file ] ; then
5734f848eeeSchristos				printf -- "$uid $f $(ls -ldgT $file)\n"
57491778fe0Scgd			fi
57591778fe0Scgd		done
57690ec96dfSlukem	done < $MPBYPATH |
577acaf72ecSspz	awk -v "usergroups=$permit_usergroups" \
578acaf72ecSspz	    -v "permit_owners_list=$check_homes_permit_other_owner"  '
579acaf72ecSspz	     BEGIN {
580acaf72ecSspz		split(permit_owners_list, a);
581acaf72ecSspz		for (i in a) permit_owners[a[i]]++;
582acaf72ecSspz	     }
583acaf72ecSspz	     $1 != $5 && $5 != "root" && !permit_owners[$1] \
58491778fe0Scgd		{ print "user " $1 " " $2 " file is owned by " $5 }
585ea872628Sjhawk	     $3 ~ /^-...r/ && (!usergroups || $6 != $1) \
58691778fe0Scgd		{ print "user " $1 " " $2 " file is group readable" }
58791778fe0Scgd	     $3 ~ /^-......r/ \
58891778fe0Scgd		{ print "user " $1 " " $2 " file is other readable" }
589ea872628Sjhawk	     $3 ~ /^-....w/ && (!usergroups || $6 != $1) \
5901035faffSwiz		{ print "user " $1 " " $2 " file is group writable" }
59191778fe0Scgd	     $3 ~ /^-.......w/ \
5921035faffSwiz		{ print "user " $1 " " $2 " file is other writable" }' \
59389fa41e9Slukem	    > $OUTPUT
59491778fe0Scgd
5951035faffSwiz	# Files that should not be owned by someone else or writable.
5964a0848acSmycroft	list=".bash_history .bash_login .bash_logout .bash_profile .bashrc \
5978efcaddaSelric	      .cshrc .emacs .exrc .forward .history .k5login .klogin .login \
5988efcaddaSelric	      .logout .profile .qmail .rc_history .rhosts .shosts ssh .tcshrc \
5998efcaddaSelric	      .twmrc .xinitrc .xsession .ssh/authorized_keys \
6008efcaddaSelric	      .ssh/authorized_keys2 .ssh/config .ssh/id_dsa.pub \
6018efcaddaSelric	      .ssh/id_rsa.pub .ssh/identity.pub .ssh/known_hosts \
6028efcaddaSelric	      .ssh/known_hosts2"
60391778fe0Scgd	while read uid homedir; do
60491778fe0Scgd		for f in $list ; do
60591778fe0Scgd			file=${homedir}/${f}
60691778fe0Scgd			if [ -f $file ] ; then
6074f848eeeSchristos				printf -- "$uid $f $(ls -ldgT $file)\n"
60891778fe0Scgd			fi
60991778fe0Scgd		done
61090ec96dfSlukem	done < $MPBYPATH |
611acaf72ecSspz	awk -v "usergroups=$permit_usergroups" \
612acaf72ecSspz	    -v "permit_owners_list=$check_homes_permit_other_owner"  '
613acaf72ecSspz	     BEGIN {
614acaf72ecSspz		split(permit_owners_list, a);
615acaf72ecSspz		for (i in a) permit_owners[a[i]]++;
616acaf72ecSspz	     }
617acaf72ecSspz	     $1 != $5 && $5 != "root" && !permit_owners[$1] \
61891778fe0Scgd		{ print "user " $1 " " $2 " file is owned by " $5 }
619ea872628Sjhawk	     $3 ~ /^-....w/ && (!usergroups || $6 != $1) \
6201035faffSwiz		{ print "user " $1 " " $2 " file is group writable" }
62191778fe0Scgd	     $3 ~ /^-.......w/ \
6221035faffSwiz		{ print "user " $1 " " $2 " file is other writable" }' \
62389fa41e9Slukem	    >> $OUTPUT
62491778fe0Scgd	if [ -s $OUTPUT ] ; then
62591778fe0Scgd		printf "\nChecking dot files.\n"
62691778fe0Scgd		cat $OUTPUT
62791778fe0Scgd	fi
628a9efb638Smrgfi
62991778fe0Scgd
63091778fe0Scgd# Mailboxes should be owned by user and unreadable.
6313a3b03bdSlukem#
6328f59ce8eSlukemif checkyesno check_varmail; then
63334604558Sjhawk	ls -lA /var/mail | \
634f263bbb1Slukem	awk '	NR == 1 { next; }
63534604558Sjhawk		$9 ~ /^\./ {next; }
636f263bbb1Slukem	    	$3 != $9 {
637f263bbb1Slukem			print "user " $9 " mailbox is owned by " $3
638f263bbb1Slukem		}
639f263bbb1Slukem		$1 != "-rw-------" {
640f263bbb1Slukem			print "user " $9 " mailbox is " $1 ", group " $4
641f263bbb1Slukem		}' > $OUTPUT
64291778fe0Scgd	if [ -s $OUTPUT ] ; then
64391778fe0Scgd		printf "\nChecking mailbox ownership.\n"
64491778fe0Scgd		cat $OUTPUT
64591778fe0Scgd	fi
646a9efb638Smrgfi
64791778fe0Scgd
6483a3b03bdSlukem# NFS exports shouldn't be globally exported
6493a3b03bdSlukem#
6503a3b03bdSlukemif checkyesno check_nfs && [ -f /etc/exports ]; then
65191778fe0Scgd	awk '{
652b07aea8eSlukem		# ignore comments and blank lines
6538b10c79fShubertf		if ($0 ~ /^\#/ || $0 ~ /^$/ )
654b07aea8eSlukem			next;
655820a3576Stron		# manage line continuation
656820a3576Stron		while ($NF ~ /^\\$/) {
657820a3576Stron			$NF = "";
658820a3576Stron			line = $0 "";
659820a3576Stron			getline;
660820a3576Stron			$0 = line $0 "";
661820a3576Stron		}
662b07aea8eSlukem
663820a3576Stron		delete dir;
664820a3576Stron		readonly = ndir = 0;
665820a3576Stron		for (i = 1; i <= NF; ++i) {
666820a3576Stron			if ($i ~ /^\//) dir[ndir++] = $i;
667820a3576Stron			else if ($i ~ /^-/) {
668820a3576Stron				if ($i ~ /^-(ro|o)$/) readonly = 1;
669820a3576Stron				if ($i ~ /^-network/) next;
670820a3576Stron			}
671820a3576Stron			else next;
67291778fe0Scgd		}
67391778fe0Scgd		if (readonly)
674820a3576Stron			for (item in dir)
675820a3576Stron				rodir[nrodir++] = dir[item];
67691778fe0Scgd		else
677820a3576Stron			for (item in dir)
678820a3576Stron				rwdir[nrwdir++] = dir[item];
679820a3576Stron
680820a3576Stron	}
681820a3576Stron
682820a3576Stron	END {
683820a3576Stron		if (nrodir) {
684820a3576Stron			printf("Globally exported file system%s, read-only:\n",
685820a3576Stron				nrodir > 1 ? "s" : "");
686820a3576Stron			for (item in rodir)
687820a3576Stron				printf("\t%s\n", rodir[item]);
688820a3576Stron		}
689820a3576Stron		if (nrwdir) {
690820a3576Stron			printf("Globally exported file system%s, read-write:\n",
691820a3576Stron				nrwdir > 1 ? "s" : "");
692820a3576Stron			for (item in rwdir)
693820a3576Stron				printf("\t%s\n", rwdir[item]);
694820a3576Stron		}
69591778fe0Scgd	}' < /etc/exports > $OUTPUT
69691778fe0Scgd	if [ -s $OUTPUT ] ; then
69791778fe0Scgd		printf "\nChecking for globally exported file systems.\n"
69891778fe0Scgd		cat $OUTPUT
69991778fe0Scgd	fi
7001377ee09Spkfi
70191778fe0Scgd
70291778fe0Scgd# Display any changes in setuid files and devices.
7033a3b03bdSlukem#
7048f59ce8eSlukemif checkyesno check_devices; then
705f09b5e36Slukem	> $ERR
7067da8bb10Serh	(
7076d23caf2Slukem
7086d23caf2Slukem	# Convert check_devices_ignore_fstypes="foo !bar bax"
7096d23caf2Slukem	#    into "-fstype foo -o ! -fstype bar -o -fstype bax"
7106d23caf2Slukem	# and check_devices_ignore_paths="/foo !/bar /bax"
7116d23caf2Slukem	#    into " -path /foo -o ! -path /bar -o -path /bax"
7126d23caf2Slukem	#
7136d23caf2Slukem	ignexpr=$(\
7146d23caf2Slukem	    echo $check_devices_ignore_fstypes | \
7156d23caf2Slukem		sed -e's/\(!*\)\([^[:space:]]\{1,\}\)/-o \1 -fstype \2/g' ; \
7166d23caf2Slukem	    echo $check_devices_ignore_paths | \
7176d23caf2Slukem		sed -e's/\(!*\)\([^[:space:]]\{1,\}\)/-o \1 -path \2/g' \
7186d23caf2Slukem	)
7196d23caf2Slukem
7206d23caf2Slukem	# Massage the expression into ( $ignexpr ) -a -prune -o
7216d23caf2Slukem	if [ -n "${ignexpr}" ]; then
7226d23caf2Slukem		ignexpr=$(\
7236d23caf2Slukem			echo $ignexpr | \
7246d23caf2Slukem			    sed -e 's/^-o /( /' \
7256d23caf2Slukem				-e 's/$/ ) -a -prune -o/' \
7266d23caf2Slukem		)
7276d23caf2Slukem	fi
7286d23caf2Slukem
7296d23caf2Slukem	find / $ignexpr \
730d8dcc658Smycroft	    \( \( -perm -u+s -a ! -type d \) -o \
731d8dcc658Smycroft	       \( -perm -g+s -a ! -type d \) -o \
732ff2ea5d1Slukem	       -type b -o -type c \) -print0 | \
7336d23caf2Slukem	xargs -0 ls -ldgTq | sort +9 > $LIST
7346d23caf2Slukem
7356d23caf2Slukem	) 2> $OUTPUT
73691778fe0Scgd
73791778fe0Scgd	# Display any errors that occurred during system file walk.
73891778fe0Scgd	if [ -s $OUTPUT ] ; then
739f09b5e36Slukem		printf "Setuid/device find errors:\n" >> $ERR
740f09b5e36Slukem		cat $OUTPUT >> $ERR
741f09b5e36Slukem		printf "\n" >> $ERR
74291778fe0Scgd	fi
74391778fe0Scgd
74491778fe0Scgd	# Display any changes in the setuid file list.
74591778fe0Scgd	egrep -v '^[bc]' $LIST > $TMP1
74691778fe0Scgd	if [ -s $TMP1 ] ; then
74791778fe0Scgd		# Check to make sure uudecode isn't setuid.
74891778fe0Scgd		if grep -w uudecode $TMP1 > /dev/null ; then
749f09b5e36Slukem			printf "\nUudecode is setuid.\n" >> $ERR
75091778fe0Scgd		fi
75191778fe0Scgd
75296a1608eSlukem		file=$work_dir/setuid
75396a1608eSlukem		migrate_file "$backup_dir/setuid" "$file"
75496a1608eSlukem		CUR=${file}.current
75596a1608eSlukem		BACK=${file}.backup
75691778fe0Scgd		if [ -s $CUR ] ; then
75791778fe0Scgd			if cmp -s $CUR $TMP1 ; then
75891778fe0Scgd				:
75991778fe0Scgd			else
76091778fe0Scgd				> $TMP2
76191778fe0Scgd				join -110 -210 -v2 $CUR $TMP1 > $OUTPUT
76291778fe0Scgd				if [ -s $OUTPUT ] ; then
763f09b5e36Slukem					printf "Setuid additions:\n" >> $ERR
764f09b5e36Slukem					tee -a $TMP2 < $OUTPUT >> $ERR
765f09b5e36Slukem					printf "\n" >> $ERR
76691778fe0Scgd				fi
76791778fe0Scgd
76891778fe0Scgd				join -110 -210 -v1 $CUR $TMP1 > $OUTPUT
76991778fe0Scgd				if [ -s $OUTPUT ] ; then
770f09b5e36Slukem					printf "Setuid deletions:\n" >> $ERR
771f09b5e36Slukem					tee -a $TMP2 < $OUTPUT >> $ERR
772f09b5e36Slukem					printf "\n" >> $ERR
77391778fe0Scgd				fi
77491778fe0Scgd
775df1a64b9Smycroft				sort -k10 $TMP2 $CUR $TMP1 | \
77689fa41e9Slukem				    sed -e 's/[	 ][	 ]*/ /g' | \
77789fa41e9Slukem				    uniq -u > $OUTPUT
77891778fe0Scgd				if [ -s $OUTPUT ] ; then
779f09b5e36Slukem					printf "Setuid changes:\n" >> $ERR
780f09b5e36Slukem					column -t $OUTPUT >> $ERR
781f09b5e36Slukem					printf "\n" >> $ERR
78291778fe0Scgd				fi
78391778fe0Scgd
7842811b170Satatat				backup_file update $TMP1 $CUR $BACK
78591778fe0Scgd			fi
78691778fe0Scgd		else
787f09b5e36Slukem			printf "Setuid additions:\n" >> $ERR
788f09b5e36Slukem			column -t $TMP1 >> $ERR
789f09b5e36Slukem			printf "\n" >> $ERR
7902811b170Satatat			backup_file add $TMP1 $CUR $BACK
79191778fe0Scgd		fi
79291778fe0Scgd	fi
79391778fe0Scgd
79489fa41e9Slukem	# Check for block and character disk devices that are readable or
7951035faffSwiz	# writable or not owned by root.operator.
79691778fe0Scgd	>$TMP1
7975a212acfSlukem	DISKLIST="ccd ch hk hp ld md ra raid rb rd rl rx \
798e60403a3Ssimonb	    sd se ss uk up vnd wd xd xy"
79989fa41e9Slukem#	DISKLIST="$DISKLIST ct mt st wt"
80091778fe0Scgd	for i in $DISKLIST; do
801a9efb638Smrg		egrep "^b.*/${i}[0-9][0-9]*[a-p]$"  $LIST >> $TMP1
802a9efb638Smrg		egrep "^c.*/r${i}[0-9][0-9]*[a-p]$"  $LIST >> $TMP1
80391778fe0Scgd	done
80491778fe0Scgd
80591778fe0Scgd	awk '$3 != "root" || $4 != "operator" || $1 !~ /.rw-r-----/ \
806fb34424eSlukem		{ printf "Disk %s is user %s, group %s, permissions %s.\n", \
807fb34424eSlukem		    $11, $3, $4, $1; }' < $TMP1 > $OUTPUT
80891778fe0Scgd	if [ -s $OUTPUT ] ; then
809f09b5e36Slukem		printf "\nChecking disk ownership and permissions.\n" >> $ERR
810f09b5e36Slukem		cat $OUTPUT >> $ERR
811f09b5e36Slukem		printf "\n" >> $ERR
81291778fe0Scgd	fi
81391778fe0Scgd
81491778fe0Scgd	# Display any changes in the device file list.
815df1a64b9Smycroft	egrep '^[bc]' $LIST | sort -k11 > $TMP1
81691778fe0Scgd	if [ -s $TMP1 ] ; then
81796a1608eSlukem		file=$work_dir/device
81896a1608eSlukem		migrate_file "$backup_dir/device" "$file"
81996a1608eSlukem		CUR=${file}.current
82096a1608eSlukem		BACK=${file}.backup
82191778fe0Scgd
82291778fe0Scgd		if [ -s $CUR ] ; then
82391778fe0Scgd			if cmp -s $CUR $TMP1 ; then
82491778fe0Scgd				:
82591778fe0Scgd			else
82691778fe0Scgd				> $TMP2
82791778fe0Scgd				join -111 -211 -v2 $CUR $TMP1 > $OUTPUT
82891778fe0Scgd				if [ -s $OUTPUT ] ; then
829f09b5e36Slukem					printf "Device additions:\n" >> $ERR
830f09b5e36Slukem					tee -a $TMP2 < $OUTPUT >> $ERR
831f09b5e36Slukem					printf "\n" >> $ERR
83291778fe0Scgd				fi
83391778fe0Scgd
83491778fe0Scgd				join -111 -211 -v1 $CUR $TMP1 > $OUTPUT
83591778fe0Scgd				if [ -s $OUTPUT ] ; then
836f09b5e36Slukem					printf "Device deletions:\n" >> $ERR
837f09b5e36Slukem					tee -a $TMP2 < $OUTPUT >> $ERR
838f09b5e36Slukem					printf "\n" >> $ERR
83991778fe0Scgd				fi
84091778fe0Scgd
84189fa41e9Slukem				# Report any block device change. Ignore
84289fa41e9Slukem				# character devices, only the name is
84389fa41e9Slukem				# significant.
84491778fe0Scgd				cat $TMP2 $CUR $TMP1 | \
84591778fe0Scgd				    sed -e '/^c/d' | \
846df1a64b9Smycroft				    sort -k11 | \
84791778fe0Scgd				    sed -e 's/[	 ][	 ]*/ /g' | \
84891778fe0Scgd				    uniq -u > $OUTPUT
84991778fe0Scgd				if [ -s $OUTPUT ] ; then
850f09b5e36Slukem					printf "Block device changes:\n" >> $ERR
851f09b5e36Slukem					column -t $OUTPUT >> $ERR
852f09b5e36Slukem					printf "\n" >> $ERR
85391778fe0Scgd				fi
85491778fe0Scgd
8552811b170Satatat				backup_file update $TMP1 $CUR $BACK
85691778fe0Scgd			fi
85791778fe0Scgd		else
858f09b5e36Slukem			printf "Device additions:\n" >> $ERR
859f09b5e36Slukem			column -t $TMP1 >> $ERR
860f09b5e36Slukem			printf "\n" >> $ERR
8612811b170Satatat			backup_file add $TMP1 $CUR $BACK >> $ERR
86291778fe0Scgd		fi
86391778fe0Scgd	fi
864f09b5e36Slukem	if [ -s $ERR ] ; then
865f09b5e36Slukem		printf "\nChecking setuid files and devices:\n"
866f09b5e36Slukem		cat $ERR
867f09b5e36Slukem		printf "\n"
868f09b5e36Slukem	fi
869a9efb638Smrgfi
87091778fe0Scgd
87191778fe0Scgd# Check special files.
87291778fe0Scgd# Check system binaries.
87391778fe0Scgd#
87491778fe0Scgd# Create the mtree tree specifications using:
87596a1608eSlukem#	mtree -cx -pDIR -kmd5,uid,gid,mode,nlink,size,link,time > DIR.secure
876357a0baaSkleink#	chown root:wheel DIR.secure
87796a1608eSlukem#	chmod u+r,go= DIR.secure
87891778fe0Scgd#
87991778fe0Scgd# Note, this is not complete protection against Trojan horsed binaries, as
88091778fe0Scgd# the hacker can modify the tree specification to match the replaced binary.
88191778fe0Scgd# For details on really protecting yourself against modified binaries, see
88291778fe0Scgd# the mtree(8) manual page.
8833a3b03bdSlukem#
8848f59ce8eSlukemif checkyesno check_mtree; then
885687107d3Sjhawk	if checkyesno check_mtree_follow_symlinks; then
886687107d3Sjhawk		check_mtree_flags="-L"
887687107d3Sjhawk	else
888687107d3Sjhawk		check_mtree_flags=""
889687107d3Sjhawk	fi
890610ee5bdSlukem	mtree -e -l -p / $check_mtree_flags -f $SPECIALSPEC 3>&1 >$OUTPUT 2>&3 |
8916a6c54a1Sjhawk		grep -v '^mtree: dev/tty: Device not configured$' >&2
89291778fe0Scgd	if [ -s $OUTPUT ]; then
89391778fe0Scgd		printf "\nChecking special files and directories.\n"
89491778fe0Scgd		cat $OUTPUT
89591778fe0Scgd	fi
89691778fe0Scgd
8975b5eddafSmikel	for file in /etc/mtree/*.secure; do
8985b5eddafSmikel		[ $file = '/etc/mtree/*.secure' ] && continue
8994f848eeeSchristos		tree=$(sed -n -e '3s/.* //p' -e 3q $file)
900687107d3Sjhawk		mtree $check_mtree_flags -f $file -p $tree > $TMP1
90191778fe0Scgd		if [ -s $TMP1 ]; then
90296a1608eSlukem			printf "\nChecking $tree:\n"
90396a1608eSlukem			cat $TMP1
90491778fe0Scgd		fi
90596a1608eSlukem	done > $OUTPUT
90691778fe0Scgd	if [ -s $OUTPUT ]; then
90791778fe0Scgd		printf "\nChecking system binaries:\n"
90891778fe0Scgd		cat $OUTPUT
90991778fe0Scgd	fi
91091778fe0Scgdfi
91191778fe0Scgd
9123a3b03bdSlukem# Backup disklabels of available disks
9133a3b03bdSlukem#
9143a3b03bdSlukemif checkyesno check_disklabels; then
91596a1608eSlukem		# migrate old disklabels
9164f848eeeSchristos	for file in $(ls -1d $backup_dir/$backup_dir/disklabel.* \
9174f848eeeSchristos	    $backup_dir/disklabel.* 2>/dev/null); do
91896a1608eSlukem		migrate_file "$file" "$work_dir/${file##*/}"
91996a1608eSlukem	done
92096a1608eSlukem
9218ce568ceSapb		# generate list of old disklabels, fdisks & wedges,
9228ce568ceSapb		# and remove them
9238ce568ceSapb	ls -1d $work_dir/disklabel.* $work_dir/fdisk.* $work_dir/wedges.* \
9248ce568ceSapb	    2>/dev/null |
9252811b170Satatat	    egrep -v '\.(backup|current)(,v)?$' > $LABELS
9263a3b03bdSlukem	xargs rm < $LABELS
9273a3b03bdSlukem
9282f6dbbcfSmlelstv	disks="$(/sbin/sysctl -n hw.iostatnames)"
9293c3f7bb8Schristos
9303c3f7bb8Schristos		# generate disklabels of all disks excluding:	cd fd md dk st
9313c3f7bb8Schristos		# nfs and "device" (the header of iostat)
9323a3b03bdSlukem	for i in $disks; do
9333c3f7bb8Schristos		case $i in
9342f6dbbcfSmlelstv		[cfm]d[0-9]*|dk[0-9]*|st[0-9]*|nfs[0-9]*)
9353c3f7bb8Schristos			;;
9363c3f7bb8Schristos		*)
9376b45f4edSpgoyette			if disklabel $i > /dev/null 2>&1; then
9383c3f7bb8Schristos				disklabel $i > "$work_dir/disklabel.$i"
9393c3f7bb8Schristos			fi
9403c3f7bb8Schristos			;;
9413c3f7bb8Schristos		esac
9423a3b03bdSlukem	done
9433a3b03bdSlukem
94496a1608eSlukem		# if fdisk is available, generate fdisks for:	ed ld sd wd
94596a1608eSlukem	if [ -x /sbin/fdisk ]; then
94696a1608eSlukem		for i in $disks; do
9473c3f7bb8Schristos			case $i in
9483c3f7bb8Schristos			[elsw]d[0-9]*)
9493c3f7bb8Schristos				/sbin/fdisk $i > "$work_dir/fdisk.$i" \
9503c3f7bb8Schristos				    2>/dev/null
9513c3f7bb8Schristos				;;
9523c3f7bb8Schristos			esac
95396a1608eSlukem		done
95496a1608eSlukem	fi
95596a1608eSlukem
9568ce568ceSapb		# if dkctl is available, generate dkctl listwedges
9578ce568ceSapb		# for:	ed ld sd wd cgd ofdisk ra rl raid
958b21dec17Stron	if [ -x /sbin/dkctl ]; then
959b21dec17Stron		for i in $disks; do
9603c3f7bb8Schristos			case $i in
9613c3f7bb8Schristos			[elsw]d[0-9]*|cgd[0-9]*|ofdisk[0-9]*|r[al][0-9]*|raid[0-9]*)
9622f6dbbcfSmlelstv				if /sbin/dkctl $i listwedges |
9632f6dbbcfSmlelstv				     grep -qe '[0-9] wedges:'; then
9648ce568ceSapb					/sbin/dkctl $i listwedges \
9658ce568ceSapb					    > "$work_dir/wedges.$i" 2>/dev/null
9663c3f7bb8Schristos				fi
9673c3f7bb8Schristos				;;
9683c3f7bb8Schristos			esac
969b21dec17Stron		done
970b21dec17Stron	fi
971b21dec17Stron
97225e09ac3Sriastradh		# if raidctl is available, generate raidctls for:	raid
97325e09ac3Sriastradh	if [ -x /sbin/raidctl ]; then
97425e09ac3Sriastradh		disks=$(iostat -x | awk 'NR > 1 && $1 ~ /^raid/ { print $1; }')
97525e09ac3Sriastradh		for i in $disks; do
97625e09ac3Sriastradh			/sbin/raidctl -G $i > "$work_dir/raidconf.$i" \
97725e09ac3Sriastradh				2>/dev/null
97825e09ac3Sriastradh		done
97925e09ac3Sriastradh	fi
98025e09ac3Sriastradh
981b21dec17Stron		# append list of new disklabels, fdisks and wedges
9828ce568ceSapb	ls -1d $work_dir/disklabel.* $work_dir/fdisk.* $work_dir/wedges.* \
98325e09ac3Sriastradh	    $work_dir/raidconf.* 2>/dev/null |
9842811b170Satatat	    egrep -v '\.(backup|current)(,v)?$' >> $LABELS
98592025001Satatat	CHANGELIST="$LABELS $CHANGELIST"
98692025001Satatatfi
98792025001Satatat
988a4e58525Shaadif checkyesno check_lvm; then
989b249d4b6Suebayasi		# generate list of existing LVM elements Physical Volumes,
990b249d4b6Suebayasi		# Volume Groups and Logical Volumes.
991a4e58525Shaad	if [ -x /sbin/lvm ]; then
992a4e58525Shaad		lvm pvdisplay -m >"$work_dir/lvm.pv" 2>/dev/null
993a4e58525Shaad		lvm vgdisplay -m >"$work_dir/lvm.vg" 2>/dev/null
994a4e58525Shaad		lvm lvdisplay -m >"$work_dir/lvm.lv" 2>/dev/null
995a4e58525Shaad	fi
996a4e58525Shaad	ls -1d $work_dir/lvm.* 2>/dev/null |
997a4e58525Shaad	    egrep -v '\.(backup|current)(,v)?$'>> $LVM_LABELS
998a4e58525Shaad	CHANGELIST="$CHANGELIST $LVM_LABELS"
999a4e58525Shaadfi
1000a4e58525Shaad
100192025001Satatat# Check for changes in the list of installed pkgs
100292025001Satatat#
100353cb2117Sjmmvif checkyesno check_pkgs && have_pkgs; then
100496a1608eSlukem	pkgs=$work_dir/pkgs
100596a1608eSlukem	migrate_file "$backup_dir/pkgs" "$pkgs"
10061410cf30Sagc	pkg_dbdir=$(${pkg_admin} config-var PKG_DBDIR)
1007d5fdd803Swiz	: ${pkg_dbdir:=/usr/pkg/pkgdb}
100853cb2117Sjmmv	(	cd $pkg_dbdir
100967b08a07Sadrianp		$pkg_info | sort
101092025001Satatat		echo ""
101192025001Satatat		find . \( -name +REQUIRED_BY -o -name +CONTENTS \) -print0 |
101211336572Slukem			xargs -0 ls -ldgTq | sort -t. +1 | sed -e 's, \./, ,'
101392025001Satatat	 ) > $pkgs
101496a1608eSlukem	echo "$pkgs" > $PKGS
101592025001Satatat	CHANGELIST="$PKGS $CHANGELIST"
10163a3b03bdSlukemfi
10173a3b03bdSlukem
101896a1608eSlukem# List of files that get backed up and checked for any modifications.
101991778fe0Scgd# Any changes cause the files to rotate.
10203a3b03bdSlukem#
102196a1608eSlukemif checkyesno check_changelist ; then
1022610ee5bdSlukem	mtree -D -k type -f $SPECIALSPEC -E exclude |
1023610ee5bdSlukem	    sed '/^type=file/!d ; s/type=file \.//' | unvis > $CHANGEFILES
102496a1608eSlukem
10251dfde696Slukem	(
10266c2d977eSlukem		# Add other files which might dynamically exist:
102796a1608eSlukem		#	/etc/ifconfig.*
102896a1608eSlukem		#	/etc/raid*.conf
10296c2d977eSlukem		#	/etc/rc.d/*
103096a1608eSlukem		#	/etc/rc.conf.d/*
10316c2d977eSlukem		#
10321dfde696Slukem		echo "/etc/ifconfig.*"
10331dfde696Slukem		echo "/etc/raid*.conf"
10341dfde696Slukem		echo "/etc/rc.d/*"
10351dfde696Slukem		echo "/etc/rc.conf.d/*"
1036a4e58525Shaad		echo "/etc/lvm/backup/*"
1037a4e58525Shaad		echo "/etc/lvm/archive/*"
103896a1608eSlukem
10396c2d977eSlukem		# Add /etc/changelist
10406c2d977eSlukem		#
10416c2d977eSlukem		if [ -s /etc/changelist ]; then
10421dfde696Slukem			grep -v '^#' /etc/changelist
10436c2d977eSlukem		fi
10441dfde696Slukem	) | while read file; do
10451dfde696Slukem		case "$file" in
10461dfde696Slukem		*[\*\?\[]*)	# If changelist line is a glob ...
10471dfde696Slukem				# ... expand possible backup files
10481dfde696Slukem				#
1049c3e808d5Suwe			ls -1d $backup_dir/${file}.current 2>/dev/null \
10501dfde696Slukem			    | sed "s,^$backup_dir/,, ; s,\.current$,,"
10516c2d977eSlukem
10521dfde696Slukem				# ... expand possible files
10531dfde696Slukem				#
1054c3e808d5Suwe			ls -1d $file 2>/dev/null
10551dfde696Slukem			;;
10561dfde696Slukem		*)
10571dfde696Slukem				# Otherwise, just print the filename
10581dfde696Slukem			echo $file
10591dfde696Slukem			;;
10601dfde696Slukem		esac
10611dfde696Slukem	done >> $CHANGEFILES
106296a1608eSlukem	CHANGELIST="$CHANGEFILES $CHANGELIST"
10633a3b03bdSlukemfi
10643a3b03bdSlukem
1065c91905c4Sriastradh# Save entropy to ${random_file} if defined, like
1066c91905c4Sriastradh# /etc/rc.d/random_seed.
1067c91905c4Sriastradh#
1068c91905c4Sriastradhif [ -n "${random_file:-}" ]; then
1069c91905c4Sriastradh	rndctl -S "$random_file"
1070c91905c4Sriastradhfi
1071c91905c4Sriastradh
107296a1608eSlukem# Special case backups, including the master password file and
107396a1608eSlukem# ssh private host keys. The normal backup mechanisms for
107496a1608eSlukem# $check_changelist (see below) also print out the actual file
107596a1608eSlukem# differences and we don't want to do that for these files
107696a1608eSlukem#
107796a1608eSlukemecho $MP > $TMP1			# always add /etc/master.passwd
1078610ee5bdSlukemmtree -D -k type -f $SPECIALSPEC -I nodiff |
1079610ee5bdSlukem    sed '/^type=file/!d ; s/type=file \.//' | unvis >> $TMP1
1080949fa9aeSlukemgrep -v '^$' $TMP1 | sort -u > $TMP2
10816c2d977eSlukem
108274cf1ec6Slukemwhile read file; do
108396a1608eSlukem	backup_and_diff "$file" no
108474cf1ec6Slukemdone < $TMP2
108596a1608eSlukem
108696a1608eSlukem
10873a3b03bdSlukemif [ -n "$CHANGELIST" ]; then
1088949fa9aeSlukem	grep -h -v '^$' $CHANGELIST | sort -u > $TMP1
10896c2d977eSlukem	comm -23 $TMP1 $TMP2 | while read file; do
109096a1608eSlukem		backup_and_diff "$file" yes
109191778fe0Scgd	done
109291778fe0Scgdfi
1093065c791dSfair
109453cb2117Sjmmvif have_pkgs; then
1095497b5f80Sjmmv	if checkyesno check_pkg_vulnerabilities; then
10961410cf30Sagc		${pkg_admin} ${_compat_K_flag} audit >${OUTPUT} 2>&1
1097497b5f80Sjmmv		if [ -s ${OUTPUT} ]; then
1098497b5f80Sjmmv			printf "\nInstalled vulnerable packages:\n"
1099497b5f80Sjmmv			cat ${OUTPUT}
1100497b5f80Sjmmv		fi
1101497b5f80Sjmmv	fi
1102497b5f80Sjmmv
1103497b5f80Sjmmv	if checkyesno check_pkg_signatures; then
11041410cf30Sagc		${pkg_admin} ${_compat_K_flag} check >${OUTPUT} 2>&1
1105497b5f80Sjmmv		if [ $? -ne 0 ]; then
1106497b5f80Sjmmv			printf "\nFiles with invalid signatures:\n"
1107497b5f80Sjmmv			cat ${OUTPUT}
1108497b5f80Sjmmv		fi
1109497b5f80Sjmmv	fi
1110497b5f80Sjmmvfi
1111497b5f80Sjmmv
1112fb3a33ffSadif [ -f /etc/security.local ]; then
11134d554522Skim	. /etc/security.local > $OUTPUT 2>&1
11146a61a211Sjhawk	if [ -s $OUTPUT ] ; then
11156a61a211Sjhawk		printf "\nRunning /etc/security.local:\n"
11166a61a211Sjhawk		cat $OUTPUT
11176a61a211Sjhawk	fi
1118fb3a33ffSadfi
1119