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