Annotation of src/etc/security, Revision 1.82
1.1 cgd 1: #!/bin/sh -
2: #
1.82 ! jhawk 3: # $NetBSD: security,v 1.81 2003/02/13 01:55:10 jhawk Exp $
1.9 cgd 4: # from: @(#)security 8.1 (Berkeley) 6/9/93
1.1 cgd 5: #
6:
1.9 cgd 7: PATH=/sbin:/usr/sbin:/bin:/usr/bin
1.1 cgd 8:
1.31 lukem 9: if [ -f /etc/rc.subr ]; then
10: . /etc/rc.subr
11: else
12: echo "Can't read /etc/rc.subr; aborting."
13: exit 1;
14: fi
15:
1.9 cgd 16: umask 077
1.64 cjs 17: TZ=UTC; export TZ
1.1 cgd 18:
1.15 mrg 19: if [ -s /etc/security.conf ]; then
20: . /etc/security.conf
21: fi
22:
1.67 lukem 23: # Set reasonable defaults (if they're not set in security.conf)
24: #
25: backup_dir=${backup_dir:-/var/backups}
26: pkgdb_dir=${pkgdb_dir:-/var/db/pkg}
27: max_loginlen=${max_loginlen:-8}
28: max_grouplen=${max_grouplen:-8}
29:
30: # Other configurable variables
31: #
32: special_files="/etc/mtree/special /etc/mtree/special.local"
33: MP=/etc/master.passwd
34: CHANGELIST=""
35: work_dir=$backup_dir/work
36:
37: if [ ! -d "$work_dir" ]; then
38: mkdir -p "$work_dir"
39: fi
40:
1.56 lukem 41: SECUREDIR=`mktemp -d /tmp/_securedir.XXXXXX` || exit 1
42:
1.67 lukem 43: trap "/bin/rm -rf $SECUREDIR ; exit 0" EXIT INT QUIT PIPE
1.15 mrg 44:
1.56 lukem 45: if ! cd "$SECUREDIR"; then
46: echo "Can not cd to $SECUREDIR".
1.15 mrg 47: exit 1
48: fi
49:
50: ERR=secure1.$$
51: TMP1=secure2.$$
52: TMP2=secure3.$$
1.28 lukem 53: MPBYUID=secure4.$$
1.29 lukem 54: MPBYPATH=secure5.$$
1.27 lukem 55: LIST=secure6.$$
56: OUTPUT=secure7.$$
1.32 lukem 57: LABELS=secure8.$$
1.62 atatat 58: PKGS=secure9.$$
1.67 lukem 59: CHANGEFILES=secure10.$$
60:
1.15 mrg 61:
1.67 lukem 62: # migrate_file old new
63: # Determine if the "${old}" path name needs to be migrated to the
64: # "${new}" path. Also checks if "${old}.current" needs migrating,
65: # and if so, migrate it and possibly "${old}.current,v" and
66: # "${old}.backup".
67: #
68: migrate_file()
69: {
70: _old=$1
71: _new=$2
72: if [ -z "$_old" -o -z "$_new" ]; then
73: err 3 "USAGE: migrate_file old new"
74: fi
75: if [ ! -d "${_new%/*}" ]; then
76: mkdir -p "${_new%/*}"
77: fi
78: if [ -f "${_old}" -a ! -f "${_new}" ]; then
79: echo "==> migrating ${_old}"
80: echo " to ${_new}"
81: mv "${_old}" "${_new}"
82: fi
83: if [ -f "${_old}.current" -a ! -f "${_new}.current" ]; then
84: echo "==> migrating ${_old}.current"
85: echo " to ${_new}.current"
86: mv "${_old}.current" "${_new}.current"
87: if [ -f "${_old}.current,v" -a ! -f "${_new}.current,v" ]; then
88: echo "==> migrating ${_old}.current,v"
89: echo " to ${_new}.current,v"
90: mv "${_old}.current,v" "${_new}.current,v"
91: fi
92: if [ -f "${_old}.backup" -a ! -f "${_new}.backup" ]; then
93: echo "==> migrating ${_old}.backup"
94: echo " to ${_new}.backup"
95: mv "${_old}.backup" "${_new}.backup"
96: fi
97: fi
98: }
99:
100:
101: # backup_and_diff file printdiff
102: # Determine if file needs backing up, and if so, do it.
103: # If printdiff is yes, display the diffs, otherwise
104: # just print a message saying "[changes omitted]".
105: #
106: backup_and_diff()
107: {
108: _file=$1
109: _printdiff=$2
110: if [ -z "$_file" -o -z "$_printdiff" ]; then
111: err 3 "USAGE: backup_and_diff file printdiff"
112: fi
113: ! checkyesno _printdiff
114: _printdiff=$?
115:
116: _old=$backup_dir/${_file##*/}
117: case "$_file" in
118: $work_dir/*)
119: _new=$_file
120: migrate_file "$backup_dir/$_old" "$_new"
121: migrate_file "$_old" "$_new"
122: ;;
123: *)
124: _new=$backup_dir/$_file
125: migrate_file "$_old" "$_new"
126: ;;
127: esac
128: CUR=${_new}.current
129: BACK=${_new}.backup
130: if [ -f $_file ]; then
131: if [ -f $CUR ] ; then
132: if [ "$_printdiff" -ne 0 ]; then
133: diff $CUR $_file > $OUTPUT
134: else
135: if ! cmp -s $CUR $_file; then
136: echo "[changes omitted]"
137: fi > $OUTPUT
138: fi
139: if [ -s $OUTPUT ] ; then
140: printf \
141: "\n======\n%s diffs (OLD < > NEW)\n======\n" $_file
142: cat $OUTPUT
143: backup_file update $_file $CUR $BACK
144: fi
145: else
146: printf "\n======\n%s added\n======\n" $_file
147: if [ "$_printdiff" -ne 0 ]; then
148: diff /dev/null $_file
149: else
150: echo "[changes omitted]"
151: fi
152: backup_file add $_file $CUR $BACK
153: fi
154: else
155: if [ -f $CUR ]; then
156: printf "\n======\n%s removed\n======\n" $_file
157: if [ "$_printdiff" -ne 0 ]; then
158: diff $CUR /dev/null
159: else
160: echo "[changes omitted]"
161: fi
162: backup_file remove $_file $CUR $BACK
163: fi
164: fi
165: }
1.48 abs 166:
1.9 cgd 167:
1.67 lukem 168: # These are used several times.
169: #
1.34 abs 170: awk -F: '!/^+/ { print $1 " " $3 }' $MP | sort -k2n > $MPBYUID
1.29 lukem 171: awk -F: '{ print $1 " " $9 }' $MP | sort -k2 > $MPBYPATH
1.9 cgd 172:
1.67 lukem 173:
1.9 cgd 174: # Check the master password file syntax.
1.32 lukem 175: #
1.31 lukem 176: if checkyesno check_passwd; then
1.81 jhawk 177: checkyesno check_passwd_permit_star && permit_star=0 || permit_star=1
178: awk -v "len=$max_loginlen" \
179: -v "nowarn_shells_list=$check_passwd_nowarn_shells" \
180: -v "nowarn_users_list=$check_passwd_nowarn_users" \
181: -v "permit_star=$permit_star" '
1.25 lukem 182: BEGIN {
183: while ( getline < "/etc/shells" > 0 ) {
1.39 hubertf 184: if ($0 ~ /^\#/ || $0 ~ /^$/ )
1.25 lukem 185: continue;
186: shells[$1]++;
187: }
1.81 jhawk 188: split(nowarn_shells_list, a);
189: for (i in a) nowarn_shells[a[i]]++;
190: split(nowarn_users_list, a);
191: for (i in a) nowarn_users[a[i]]++;
192: uid0_users_list="root toor"
193: split(uid0_users_list, a);
194: for (i in a) uid0_users[a[i]]++;
1.25 lukem 195: FS=":";
196: }
197:
198: {
1.15 mrg 199: if ($0 ~ /^[ ]*$/) {
1.25 lukem 200: printf "Line %d is a blank line.\n", NR;
1.15 mrg 201: next;
202: }
1.34 abs 203: if (NF != 10 && ($1 != "+" || NF != 1))
1.25 lukem 204: printf "Line %d has the wrong number of fields.\n", NR;
1.34 abs 205: if ($1 == "+" ) {
206: if (NF != 1 && $3 == 0)
1.81 jhawk 207: printf "Line %d includes entries with uid 0.\n",
208: NR;
1.34 abs 209: next;
210: }
1.53 atatat 211: if ($1 !~ /^[A-Za-z0-9]([-A-Za-z0-9]*[A-Za-z0-9])*$/)
1.25 lukem 212: printf "Login %s has non-alphanumeric characters.\n",
213: $1;
1.34 abs 214: if (length($1) > len)
1.81 jhawk 215: printf "Login %s has more than "len" characters.\n",
216: $1;
217: if ($2 == "" && !nowarn_users[$1])
218: printf "Login %s has no password.\n", $1;
219: if (!nowarn_shells[$10] && !nowarn_users[$1]) {
220: if (length($2) != 13 &&
221: length($2) != 20 &&
222: $2 !~ /^\$1/ &&
223: $2 !~ /^\$2/ &&
224: $2 != "" &&
225: (permit_star || $2 != "*") &&
226: $2 !~ /^\*[A-z-]+$/ &&
227: $1 != "toor") {
228: if ($10 == "" || shells[$10])
229: printf "Login %s is off but still has "\
230: "a valid shell (%s)\n", $1, $10;
231: } else if (! shells[$10])
232: printf "Login %s does not have a valid "\
233: "shell (%s)\n", $1, $10;
234: }
235: if ($3 == 0 && !uid0_users[$1] && !nowarn_users[$1])
1.25 lukem 236: printf "Login %s has a user id of 0.\n", $1;
1.15 mrg 237: if ($3 < 0)
1.25 lukem 238: printf "Login %s has a negative user id.\n", $1;
1.15 mrg 239: if ($4 < 0)
1.25 lukem 240: printf "Login %s has a negative group id.\n", $1;
1.15 mrg 241: }' < $MP > $OUTPUT
242: if [ -s $OUTPUT ] ; then
243: printf "\nChecking the $MP file:\n"
244: cat $OUTPUT
245: fi
246:
247: awk -F: '{ print $1 }' $MP | sort | uniq -d > $OUTPUT
248: if [ -s $OUTPUT ] ; then
249: printf "\n$MP has duplicate user names.\n"
250: column $OUTPUT
251: fi
252:
1.37 wrstuden 253: # To not exclude 'toor', a standard duplicate root account, from the duplicate
254: # account test, uncomment the line below (without egrep in it)and comment
255: # out the line (with egrep in it) below it.
256: #
257: # < $MPBYUID uniq -d -f 1 | awk '{ print $2 }' > $TMP2
1.36 wrstuden 258: < $MPBYUID egrep -v '^toor ' | uniq -d -f 1 | awk '{ print $2 }' > $TMP2
1.15 mrg 259: if [ -s $TMP2 ] ; then
260: printf "\n$MP has duplicate user id's.\n"
261: while read uid; do
1.28 lukem 262: grep -w $uid $MPBYUID
1.15 mrg 263: done < $TMP2 | column
264: fi
1.9 cgd 265: fi
266:
267: # Check the group file syntax.
1.32 lukem 268: #
1.31 lukem 269: if checkyesno check_group; then
1.15 mrg 270: GRP=/etc/group
1.49 jdolecek 271: awk -F: -v "len=$max_grouplen" '{
1.15 mrg 272: if ($0 ~ /^[ ]*$/) {
1.25 lukem 273: printf "Line %d is a blank line.\n", NR;
1.15 mrg 274: next;
275: }
1.34 abs 276: if (NF != 4 && ($1 != "+" || NF != 1))
1.25 lukem 277: printf "Line %d has the wrong number of fields.\n", NR;
1.34 abs 278: if ($1 == "+" ) {
279: next;
280: }
1.53 atatat 281: if ($1 !~ /^[A-Za-z0-9]([-A-Za-z0-9]*[A-Za-z0-9])*$/)
1.25 lukem 282: printf "Group %s has non-alphanumeric characters.\n",
283: $1;
1.49 jdolecek 284: if (length($1) > len)
285: printf "Group %s has more than "len" characters.\n", $1;
1.15 mrg 286: if ($3 !~ /[0-9]*/)
1.25 lukem 287: printf "Login %s has a negative group id.\n", $1;
1.15 mrg 288: }' < $GRP > $OUTPUT
289: if [ -s $OUTPUT ] ; then
290: printf "\nChecking the $GRP file:\n"
291: cat $OUTPUT
292: fi
293:
294: awk -F: '{ print $1 }' $GRP | sort | uniq -d > $OUTPUT
295: if [ -s $OUTPUT ] ; then
296: printf "\n$GRP has duplicate group names.\n"
297: column $OUTPUT
298: fi
1.9 cgd 299: fi
300:
301: # Check for root paths, umask values in startup files.
302: # The check for the root paths is problematical -- it's likely to fail
303: # in other environments. Once the shells have been modified to warn
304: # of '.' in the path, the path tests should go away.
1.32 lukem 305: #
1.31 lukem 306: if checkyesno check_rootdotfiles; then
1.67 lukem 307: rhome=~root
1.15 mrg 308: umaskset=no
309: list="/etc/csh.cshrc /etc/csh.login ${rhome}/.cshrc ${rhome}/.login"
310: for i in $list ; do
311: if [ -f $i ] ; then
1.67 lukem 312: if egrep '^[ \t]*umask[ \t]+[0-7]+' $i > /dev/null ;
313: then
1.15 mrg 314: umaskset=yes
315: fi
1.63 lukem 316: # Double check the umask value itself; ensure that
1.67 lukem 317: # both the group and other write bits are set.
318: #
1.45 sommerfe 319: egrep '^[ \t]*umask[ \t]+[0-7]+' $i |
1.63 lukem 320: awk '{
1.67 lukem 321: if ($2 ~ /^.$/ || $2 ~! /[^2367].$/) {
1.80 wiz 322: print "\tRoot umask is group writable"
1.63 lukem 323: }
1.67 lukem 324: if ($2 ~ /[^2367]$/) {
1.80 wiz 325: print "\tRoot umask is other writable"
1.63 lukem 326: }
1.67 lukem 327: }' | sort -u
1.26 lukem 328: SAVE_PATH=$PATH
329: unset PATH
1.15 mrg 330: /bin/csh -f -s << end-of-csh > /dev/null 2>&1
331: source $i
332: /bin/ls -ldgT \$path > $TMP1
1.9 cgd 333: end-of-csh
1.76 atatat 334: export PATH=$SAVE_PATH
1.15 mrg 335: awk '{
336: if ($10 ~ /^\.$/) {
1.27 lukem 337: print "\tThe root path includes .";
1.15 mrg 338: next;
339: }
340: }
341: $1 ~ /^d....w/ \
1.80 wiz 342: { print "\tRoot path directory " $10 " is group writable." } \
1.15 mrg 343: $1 ~ /^d.......w/ \
1.80 wiz 344: { print "\tRoot path directory " $10 " is other writable." }' \
1.67 lukem 345: < $TMP1
1.15 mrg 346: fi
1.67 lukem 347: done > $OUTPUT
1.15 mrg 348: if [ $umaskset = "no" -o -s $OUTPUT ] ; then
1.27 lukem 349: printf "\nChecking root csh paths, umask values:\n$list\n\n"
1.15 mrg 350: if [ -s $OUTPUT ]; then
351: cat $OUTPUT
352: fi
353: if [ $umaskset = "no" ] ; then
1.27 lukem 354: printf "\tRoot csh startup files do not set the umask.\n"
1.15 mrg 355: fi
1.9 cgd 356: fi
357:
1.15 mrg 358: umaskset=no
1.23 lukem 359: list="/etc/profile ${rhome}/.profile"
1.15 mrg 360: for i in $list; do
361: if [ -f $i ] ; then
362: if egrep umask $i > /dev/null ; then
363: umaskset=yes
364: fi
365: egrep umask $i |
1.67 lukem 366: awk '$2 ~ /^.$/ || $2 ~ /[^2367].$/ \
1.80 wiz 367: { print "\tRoot umask is group writable" } \
1.67 lukem 368: $2 ~ /[^2367]$/ \
1.80 wiz 369: { print "\tRoot umask is other writable" }'
1.26 lukem 370: SAVE_PATH=$PATH
371: unset PATH
1.15 mrg 372: /bin/sh << end-of-sh > /dev/null 2>&1
373: . $i
1.26 lukem 374: list=\`echo \$PATH | /usr/bin/sed -e \
375: 's/^:/.:/;s/:$/:./;s/::/:.:/g;s/:/ /g'\`
1.15 mrg 376: /bin/ls -ldgT \$list > $TMP1
1.9 cgd 377: end-of-sh
1.76 atatat 378: export PATH=$SAVE_PATH
1.15 mrg 379: awk '{
380: if ($10 ~ /^\.$/) {
1.27 lukem 381: print "\tThe root path includes .";
1.15 mrg 382: next;
383: }
384: }
385: $1 ~ /^d....w/ \
1.80 wiz 386: { print "\tRoot path directory " $10 " is group writable." } \
1.15 mrg 387: $1 ~ /^d.......w/ \
1.80 wiz 388: { print "\tRoot path directory " $10 " is other writable." }' \
1.67 lukem 389: < $TMP1
1.9 cgd 390:
1.15 mrg 391: fi
1.67 lukem 392: done > $OUTPUT
1.15 mrg 393: if [ $umaskset = "no" -o -s $OUTPUT ] ; then
394: printf "\nChecking root sh paths, umask values:\n$list\n"
395: if [ -s $OUTPUT ]; then
396: cat $OUTPUT
397: fi
398: if [ $umaskset = "no" ] ; then
1.27 lukem 399: printf "\tRoot sh startup files do not set the umask.\n"
1.15 mrg 400: fi
1.9 cgd 401: fi
402: fi
403:
404: # Root and uucp should both be in /etc/ftpusers.
1.32 lukem 405: #
1.31 lukem 406: if checkyesno check_ftpusers; then
1.28 lukem 407: list="uucp "`awk '$2 == 0 { print $1 }' $MPBYUID`
1.27 lukem 408: for i in $list; do
1.29 lukem 409: if /usr/libexec/ftpd -C $i ; then
1.67 lukem 410: printf "\t$i is not denied\n"
1.27 lukem 411: fi
1.67 lukem 412: done > $OUTPUT
1.28 lukem 413: if [ -s $OUTPUT ]; then
414: printf "\nChecking the /etc/ftpusers configuration:\n"
415: cat $OUTPUT
416: fi
1.9 cgd 417: fi
418:
1.43 itojun 419: # Uudecode should not be in the /etc/mail/aliases file.
1.32 lukem 420: #
1.31 lukem 421: if checkyesno check_aliases; then
1.43 itojun 422: for f in /etc/mail/aliases /etc/aliases; do
423: if [ -f $f ] && egrep '^[^#]*(uudecode|decode).*\|' $f; then
424: printf "\nEntry for uudecode in $f file.\n"
425: fi
426: done
1.9 cgd 427: fi
428:
429: # Files that should not have + signs.
1.32 lukem 430: #
1.31 lukem 431: if checkyesno check_rhosts; then
1.15 mrg 432: list="/etc/hosts.equiv /etc/hosts.lpd"
433: for f in $list ; do
434: if [ -f $f ] && egrep '\+' $f > /dev/null ; then
435: printf "\nPlus sign in $f file.\n"
436: fi
437: done
438:
439: # Check for special users with .rhosts files. Only root and toor should
1.16 mikel 440: # have .rhosts files. Also, .rhosts files should not have plus signs.
1.15 mrg 441: awk -F: '$1 != "root" && $1 != "toor" && \
442: ($3 < 100 || $1 == "ftp" || $1 == "uucp") \
1.20 mycroft 443: { print $1 " " $9 }' $MP |
1.19 mycroft 444: sort -k2 |
1.15 mrg 445: while read uid homedir; do
446: if [ -f ${homedir}/.rhosts ] ; then
447: rhost=`ls -ldgT ${homedir}/.rhosts`
1.46 christos 448: printf -- "$uid: $rhost\n"
1.15 mrg 449: fi
450: done > $OUTPUT
451: if [ -s $OUTPUT ] ; then
452: printf "\nChecking for special users with .rhosts files.\n"
453: cat $OUTPUT
454: fi
455:
456: while read uid homedir; do
1.35 fair 457: if [ -f ${homedir}/.rhosts -a -r ${homedir}/.rhosts ] && \
1.41 christos 458: cat -f ${homedir}/.rhosts | egrep '\+' > /dev/null ; then
1.46 christos 459: printf -- "$uid: + in .rhosts file.\n"
1.15 mrg 460: fi
1.29 lukem 461: done < $MPBYPATH > $OUTPUT
1.15 mrg 462: if [ -s $OUTPUT ] ; then
463: printf "\nChecking .rhosts files syntax.\n"
464: cat $OUTPUT
465: fi
1.9 cgd 466: fi
467:
468: # Check home directories. Directories should not be owned by someone else
1.80 wiz 469: # or writable.
1.32 lukem 470: #
1.31 lukem 471: if checkyesno check_homes; then
1.15 mrg 472: while read uid homedir; do
473: if [ -d ${homedir}/ ] ; then
474: file=`ls -ldgT ${homedir}`
1.46 christos 475: printf -- "$uid $file\n"
1.9 cgd 476: fi
1.29 lukem 477: done < $MPBYPATH |
1.15 mrg 478: awk '$1 != $4 && $4 != "root" \
479: { print "user " $1 " home directory is owned by " $4 }
480: $2 ~ /^-....w/ \
1.80 wiz 481: { print "user " $1 " home directory is group writable" }
1.15 mrg 482: $2 ~ /^-.......w/ \
1.80 wiz 483: { print "user " $1 " home directory is other writable" }' \
1.27 lukem 484: > $OUTPUT
1.15 mrg 485: if [ -s $OUTPUT ] ; then
486: printf "\nChecking home directories.\n"
487: cat $OUTPUT
488: fi
489:
490: # Files that should not be owned by someone else or readable.
1.67 lukem 491: list=".Xauthority .netrc .ssh/id_dsa .ssh/id_rsa .ssh/identity"
1.15 mrg 492: while read uid homedir; do
493: for f in $list ; do
494: file=${homedir}/${f}
495: if [ -f $file ] ; then
1.46 christos 496: printf -- "$uid $f `ls -ldgT $file`\n"
1.15 mrg 497: fi
498: done
1.29 lukem 499: done < $MPBYPATH |
1.15 mrg 500: awk '$1 != $5 && $5 != "root" \
501: { print "user " $1 " " $2 " file is owned by " $5 }
502: $3 ~ /^-...r/ \
503: { print "user " $1 " " $2 " file is group readable" }
504: $3 ~ /^-......r/ \
505: { print "user " $1 " " $2 " file is other readable" }
506: $3 ~ /^-....w/ \
1.80 wiz 507: { print "user " $1 " " $2 " file is group writable" }
1.15 mrg 508: $3 ~ /^-.......w/ \
1.80 wiz 509: { print "user " $1 " " $2 " file is other writable" }' \
1.27 lukem 510: > $OUTPUT
1.15 mrg 511:
1.80 wiz 512: # Files that should not be owned by someone else or writable.
1.19 mycroft 513: list=".bash_history .bash_login .bash_logout .bash_profile .bashrc \
1.79 elric 514: .cshrc .emacs .exrc .forward .history .k5login .klogin .login \
515: .logout .profile .qmail .rc_history .rhosts .shosts ssh .tcshrc \
516: .twmrc .xinitrc .xsession .ssh/authorized_keys \
517: .ssh/authorized_keys2 .ssh/config .ssh/id_dsa.pub \
518: .ssh/id_rsa.pub .ssh/identity.pub .ssh/known_hosts \
519: .ssh/known_hosts2"
1.15 mrg 520: while read uid homedir; do
521: for f in $list ; do
522: file=${homedir}/${f}
523: if [ -f $file ] ; then
1.46 christos 524: printf -- "$uid $f `ls -ldgT $file`\n"
1.15 mrg 525: fi
526: done
1.29 lukem 527: done < $MPBYPATH |
1.15 mrg 528: awk '$1 != $5 && $5 != "root" \
529: { print "user " $1 " " $2 " file is owned by " $5 }
530: $3 ~ /^-....w/ \
1.80 wiz 531: { print "user " $1 " " $2 " file is group writable" }
1.15 mrg 532: $3 ~ /^-.......w/ \
1.80 wiz 533: { print "user " $1 " " $2 " file is other writable" }' \
1.27 lukem 534: >> $OUTPUT
1.15 mrg 535: if [ -s $OUTPUT ] ; then
536: printf "\nChecking dot files.\n"
537: cat $OUTPUT
538: fi
1.9 cgd 539: fi
540:
541: # Mailboxes should be owned by user and unreadable.
1.32 lukem 542: #
1.31 lukem 543: if checkyesno check_varmail; then
1.63 lukem 544: ls -l /var/mail | \
545: awk ' NR == 1 { next; }
546: $3 != $9 {
547: print "user " $9 " mailbox is owned by " $3
548: }
549: $1 != "-rw-------" {
550: print "user " $9 " mailbox is " $1 ", group " $4
551: }' > $OUTPUT
1.15 mrg 552: if [ -s $OUTPUT ] ; then
553: printf "\nChecking mailbox ownership.\n"
554: cat $OUTPUT
555: fi
556: fi
557:
1.32 lukem 558: # NFS exports shouldn't be globally exported
559: #
560: if checkyesno check_nfs && [ -f /etc/exports ]; then
561: awk '{
1.22 lukem 562: # ignore comments and blank lines
1.39 hubertf 563: if ($0 ~ /^\#/ || $0 ~ /^$/ )
1.22 lukem 564: next;
565:
1.15 mrg 566: readonly = 0;
567: for (i = 2; i <= NF; ++i) {
568: if ($i ~ /-ro/)
569: readonly = 1;
570: else if ($i !~ /^-/)
571: next;
572: }
573: if (readonly)
574: print "File system " $1 " globally exported, read-only."
575: else
576: print "File system " $1 " globally exported, read-write."
1.32 lukem 577: }' < /etc/exports > $OUTPUT
578: if [ -s $OUTPUT ] ; then
1.15 mrg 579: printf "\nChecking for globally exported file systems.\n"
580: cat $OUTPUT
581: fi
1.9 cgd 582: fi
583:
584: # Display any changes in setuid files and devices.
1.32 lukem 585: #
1.31 lukem 586: if checkyesno check_devices; then
1.28 lukem 587: > $ERR
1.15 mrg 588: (find / \( ! -fstype local -o -fstype fdesc -o -fstype kernfs \
1.74 lukem 589: -o -fstype null \
1.15 mrg 590: -o -fstype procfs \) -a -prune -o \
1.21 mycroft 591: \( \( -perm -u+s -a ! -type d \) -o \
592: \( -perm -g+s -a ! -type d \) -o \
1.24 lukem 593: -type b -o -type c \) -print0 | \
594: xargs -0 ls -ldgTq | sort +9 > $LIST) 2> $OUTPUT
1.15 mrg 595:
596: # Display any errors that occurred during system file walk.
597: if [ -s $OUTPUT ] ; then
1.28 lukem 598: printf "Setuid/device find errors:\n" >> $ERR
599: cat $OUTPUT >> $ERR
600: printf "\n" >> $ERR
1.15 mrg 601: fi
602:
603: # Display any changes in the setuid file list.
604: egrep -v '^[bc]' $LIST > $TMP1
605: if [ -s $TMP1 ] ; then
606: # Check to make sure uudecode isn't setuid.
607: if grep -w uudecode $TMP1 > /dev/null ; then
1.28 lukem 608: printf "\nUudecode is setuid.\n" >> $ERR
1.15 mrg 609: fi
610:
1.67 lukem 611: file=$work_dir/setuid
612: migrate_file "$backup_dir/setuid" "$file"
613: CUR=${file}.current
614: BACK=${file}.backup
1.15 mrg 615: if [ -s $CUR ] ; then
616: if cmp -s $CUR $TMP1 ; then
617: :
618: else
619: > $TMP2
620: join -110 -210 -v2 $CUR $TMP1 > $OUTPUT
621: if [ -s $OUTPUT ] ; then
1.28 lukem 622: printf "Setuid additions:\n" >> $ERR
623: tee -a $TMP2 < $OUTPUT >> $ERR
624: printf "\n" >> $ERR
1.15 mrg 625: fi
626:
627: join -110 -210 -v1 $CUR $TMP1 > $OUTPUT
628: if [ -s $OUTPUT ] ; then
1.28 lukem 629: printf "Setuid deletions:\n" >> $ERR
630: tee -a $TMP2 < $OUTPUT >> $ERR
631: printf "\n" >> $ERR
1.15 mrg 632: fi
633:
1.20 mycroft 634: sort -k10 $TMP2 $CUR $TMP1 | \
1.27 lukem 635: sed -e 's/[ ][ ]*/ /g' | \
636: uniq -u > $OUTPUT
1.15 mrg 637: if [ -s $OUTPUT ] ; then
1.28 lukem 638: printf "Setuid changes:\n" >> $ERR
639: column -t $OUTPUT >> $ERR
640: printf "\n" >> $ERR
1.15 mrg 641: fi
1.9 cgd 642:
1.52 atatat 643: backup_file update $TMP1 $CUR $BACK
1.9 cgd 644: fi
1.15 mrg 645: else
1.28 lukem 646: printf "Setuid additions:\n" >> $ERR
647: column -t $TMP1 >> $ERR
648: printf "\n" >> $ERR
1.52 atatat 649: backup_file add $TMP1 $CUR $BACK
1.9 cgd 650: fi
1.15 mrg 651: fi
652:
1.27 lukem 653: # Check for block and character disk devices that are readable or
1.80 wiz 654: # writable or not owned by root.operator.
1.15 mrg 655: >$TMP1
1.61 lukem 656: DISKLIST="ccd ch hk hp ld md ra raid rb rd rl rx \
1.57 simonb 657: sd se ss uk up vnd wd xd xy"
1.27 lukem 658: # DISKLIST="$DISKLIST ct mt st wt"
1.15 mrg 659: for i in $DISKLIST; do
660: egrep "^b.*/${i}[0-9][0-9]*[a-p]$" $LIST >> $TMP1
661: egrep "^c.*/r${i}[0-9][0-9]*[a-p]$" $LIST >> $TMP1
662: done
663:
664: awk '$3 != "root" || $4 != "operator" || $1 !~ /.rw-r-----/ \
1.25 lukem 665: { printf "Disk %s is user %s, group %s, permissions %s.\n", \
666: $11, $3, $4, $1; }' < $TMP1 > $OUTPUT
1.15 mrg 667: if [ -s $OUTPUT ] ; then
1.28 lukem 668: printf "\nChecking disk ownership and permissions.\n" >> $ERR
669: cat $OUTPUT >> $ERR
670: printf "\n" >> $ERR
1.9 cgd 671: fi
672:
1.15 mrg 673: # Display any changes in the device file list.
1.20 mycroft 674: egrep '^[bc]' $LIST | sort -k11 > $TMP1
1.15 mrg 675: if [ -s $TMP1 ] ; then
1.67 lukem 676: file=$work_dir/device
677: migrate_file "$backup_dir/device" "$file"
678: CUR=${file}.current
679: BACK=${file}.backup
1.15 mrg 680:
681: if [ -s $CUR ] ; then
682: if cmp -s $CUR $TMP1 ; then
683: :
684: else
685: > $TMP2
686: join -111 -211 -v2 $CUR $TMP1 > $OUTPUT
687: if [ -s $OUTPUT ] ; then
1.28 lukem 688: printf "Device additions:\n" >> $ERR
689: tee -a $TMP2 < $OUTPUT >> $ERR
690: printf "\n" >> $ERR
1.15 mrg 691: fi
692:
693: join -111 -211 -v1 $CUR $TMP1 > $OUTPUT
694: if [ -s $OUTPUT ] ; then
1.28 lukem 695: printf "Device deletions:\n" >> $ERR
696: tee -a $TMP2 < $OUTPUT >> $ERR
697: printf "\n" >> $ERR
1.15 mrg 698: fi
699:
1.27 lukem 700: # Report any block device change. Ignore
701: # character devices, only the name is
702: # significant.
1.15 mrg 703: cat $TMP2 $CUR $TMP1 | \
1.27 lukem 704: sed -e '/^c/d' | \
705: sort -k11 | \
706: sed -e 's/[ ][ ]*/ /g' | \
707: uniq -u > $OUTPUT
1.15 mrg 708: if [ -s $OUTPUT ] ; then
1.28 lukem 709: printf "Block device changes:\n" >> $ERR
710: column -t $OUTPUT >> $ERR
711: printf "\n" >> $ERR
1.15 mrg 712: fi
1.9 cgd 713:
1.52 atatat 714: backup_file update $TMP1 $CUR $BACK
1.9 cgd 715: fi
1.15 mrg 716: else
1.28 lukem 717: printf "Device additions:\n" >> $ERR
718: column -t $TMP1 >> $ERR
719: printf "\n" >> $ERR
1.52 atatat 720: backup_file add $TMP1 $CUR $BACK >> $ERR
1.9 cgd 721: fi
1.28 lukem 722: fi
723: if [ -s $ERR ] ; then
724: printf "\nChecking setuid files and devices:\n"
725: cat $ERR
726: printf "\n"
1.9 cgd 727: fi
728: fi
729:
730: # Check special files.
731: # Check system binaries.
732: #
733: # Create the mtree tree specifications using:
1.67 lukem 734: # mtree -cx -pDIR -kmd5,uid,gid,mode,nlink,size,link,time > DIR.secure
1.38 kleink 735: # chown root:wheel DIR.secure
1.67 lukem 736: # chmod u+r,go= DIR.secure
1.9 cgd 737: #
738: # Note, this is not complete protection against Trojan horsed binaries, as
739: # the hacker can modify the tree specification to match the replaced binary.
740: # For details on really protecting yourself against modified binaries, see
741: # the mtree(8) manual page.
1.32 lukem 742: #
1.31 lukem 743: if checkyesno check_mtree; then
1.82 ! jhawk 744: if checkyesno check_mtree_follow_symlinks; then
! 745: check_mtree_flags="-L"
! 746: else
! 747: check_mtree_flags=""
! 748: fi
1.67 lukem 749: for file in $special_files; do
750: [ ! -s $file ] && continue
1.82 ! jhawk 751: mtree -e -l -p / $check_mtree_flags -f $file
1.67 lukem 752: done > $OUTPUT
1.15 mrg 753: if [ -s $OUTPUT ]; then
1.9 cgd 754: printf "\nChecking special files and directories.\n"
755: cat $OUTPUT
756: fi
757:
1.16 mikel 758: for file in /etc/mtree/*.secure; do
759: [ $file = '/etc/mtree/*.secure' ] && continue
1.9 cgd 760: tree=`sed -n -e '3s/.* //p' -e 3q $file`
1.82 ! jhawk 761: mtree $check_mtree_flags -f $file -p $tree > $TMP1
1.9 cgd 762: if [ -s $TMP1 ]; then
1.67 lukem 763: printf "\nChecking $tree:\n"
764: cat $TMP1
1.9 cgd 765: fi
1.67 lukem 766: done > $OUTPUT
1.15 mrg 767: if [ -s $OUTPUT ]; then
1.9 cgd 768: printf "\nChecking system binaries:\n"
769: cat $OUTPUT
770: fi
771: fi
772:
1.32 lukem 773: # Backup disklabels of available disks
774: #
775: if checkyesno check_disklabels; then
1.67 lukem 776: # migrate old disklabels
777: for file in `ls -1d $backup_dir/$backup_dir/disklabel.* \
778: $backup_dir/disklabel.* 2>/dev/null`; do
779: migrate_file "$file" "$work_dir/${file##*/}"
780: done
781:
782: # generate list of old disklabels & fdisks and remove them
783: ls -1d $work_dir/disklabel.* $work_dir/fdisk.* 2>/dev/null |
1.52 atatat 784: egrep -v '\.(backup|current)(,v)?$' > $LABELS
1.32 lukem 785: xargs rm < $LABELS
786:
1.67 lukem 787: # generate disklabels of all disks excluding: cd fd md
1.63 lukem 788: disks=`iostat -x | awk 'NR > 1 && $1 !~ /^[cfm]d/ { print $1; }'`
1.32 lukem 789: for i in $disks; do
1.67 lukem 790: disklabel $i > "$work_dir/disklabel.$i" 2>/dev/null
1.32 lukem 791: done
792:
1.67 lukem 793: # if fdisk is available, generate fdisks for: ed ld sd wd
794: if [ -x /sbin/fdisk ]; then
795: disks=`iostat -x| awk 'NR > 1 && $1 ~ /^[elsw]d/ { print $1; }'`
796: for i in $disks; do
797: /sbin/fdisk $i > "$work_dir/fdisk.$i" 2>/dev/null
798: done
799: fi
800:
801: # append list of new disklabels and fdisks
802: ls -1d $work_dir/disklabel.* $work_dir/fdisk.* 2>/dev/null |
1.52 atatat 803: egrep -v '\.(backup|current)(,v)?$' >> $LABELS
1.62 atatat 804: CHANGELIST="$LABELS $CHANGELIST"
805: fi
806:
807: # Check for changes in the list of installed pkgs
808: #
1.65 lukem 809: if checkyesno check_pkgs && [ -d $pkgdb_dir ]; then
1.67 lukem 810: pkgs=$work_dir/pkgs
811: migrate_file "$backup_dir/pkgs" "$pkgs"
1.65 lukem 812: ( cd $pkgdb_dir
1.62 atatat 813: pkg_info | sort
814: echo ""
815: find . \( -name +REQUIRED_BY -o -name +CONTENTS \) -print0 |
1.72 lukem 816: xargs -0 ls -ldgTq | sort -t. +1 | sed -e 's, \./, ,'
1.62 atatat 817: ) > $pkgs
1.67 lukem 818: echo "$pkgs" > $PKGS
1.62 atatat 819: CHANGELIST="$PKGS $CHANGELIST"
1.32 lukem 820: fi
821:
1.67 lukem 822: # List of files that get backed up and checked for any modifications.
1.9 cgd 823: # Any changes cause the files to rotate.
1.32 lukem 824: #
1.67 lukem 825: if checkyesno check_changelist ; then
826: for file in $special_files; do
827: [ ! -s $file ] && continue
828: mtree -D -k type -f $file -E exclude |
829: sed '/^type=file/!d ; s/type=file \.//'
830: done > $CHANGEFILES
831:
1.75 lukem 832: (
1.68 lukem 833: # Add other files which might dynamically exist:
1.67 lukem 834: # /etc/ifconfig.*
835: # /etc/raid*.conf
1.68 lukem 836: # /etc/rc.d/*
1.67 lukem 837: # /etc/rc.conf.d/*
1.68 lukem 838: #
1.75 lukem 839: echo "/etc/ifconfig.*"
840: echo "/etc/raid*.conf"
841: echo "/etc/rc.d/*"
842: echo "/etc/rc.conf.d/*"
1.67 lukem 843:
1.68 lukem 844: # Add /etc/changelist
845: #
1.75 lukem 846: if [ -s /etc/changelist ]; then
847: grep -v '^#' /etc/changelist
848: fi
849: ) | while read file; do
850: case "$file" in
851: *[\*\?\[]*) # If changelist line is a glob ...
852: # ... expand possible backup files
853: #
854: ls -1d $(echo $backup_dir/${file}.current) 2>/dev/null \
855: | sed "s,^$backup_dir/,, ; s,\.current$,,"
856:
857: # ... expand possible files
858: #
859: ls -1d $(echo $file) 2>/dev/null
860: ;;
861: *)
862: # Otherwise, just print the filename
863: echo $file
864: ;;
865: esac
866: done >> $CHANGEFILES
1.67 lukem 867: CHANGELIST="$CHANGEFILES $CHANGELIST"
868: fi
869:
870: # Special case backups, including the master password file and
871: # ssh private host keys. The normal backup mechanisms for
872: # $check_changelist (see below) also print out the actual file
873: # differences and we don't want to do that for these files
874: #
875: echo $MP > $TMP1 # always add /etc/master.passwd
876: for file in $special_files; do
877: [ ! -s $file ] && continue
1.70 lukem 878: mtree -D -k type -f $file -I nodiff |
1.67 lukem 879: sed '/^type=file/!d ; s/type=file \.//'
880: done >> $TMP1
1.73 lukem 881: grep -v '^$' $TMP1 | sort -u > $TMP2
1.68 lukem 882:
1.69 lukem 883: while read file; do
1.67 lukem 884: backup_and_diff "$file" no
1.69 lukem 885: done < $TMP2
1.67 lukem 886:
1.32 lukem 887:
888: if [ -n "$CHANGELIST" ]; then
1.73 lukem 889: grep -h -v '^$' $CHANGELIST | sort -u > $TMP1
1.68 lukem 890: comm -23 $TMP1 $TMP2 | while read file; do
1.67 lukem 891: backup_and_diff "$file" yes
1.9 cgd 892: done
1.44 ad 893: fi
894:
895: if [ -f /etc/security.local ]; then
896: echo ""
897: echo "Running /etc/security.local:"
898: . /etc/security.local
1.9 cgd 899: fi
CVSweb <webmaster@jp.NetBSD.org>