[BACK]Return to security CVS log [TXT][DIR] Up to [local] / src / etc

Annotation of src/etc/security, Revision 1.85

1.1       deraadt     1: #
1.85    ! schwarze    2: #      $OpenBSD: security,v 1.84 2009/05/14 21:24:33 schwarze Exp $
1.13      millert     3: #      from: @(#)security      8.1 (Berkeley) 6/9/93
1.1       deraadt     4: #
1.13      millert     5:
1.55      millert     6: PATH=/bin:/usr/bin:/sbin:/usr/sbin
1.1       deraadt     7:
                      8: umask 077
                      9:
1.60      avsm       10: DIR=`mktemp -d /tmp/_secure.XXXXXXXXXX` || exit 1
1.7       deraadt    11: TMP1=$DIR/_secure2
                     12: TMP2=$DIR/_secure3
                     13: LIST=$DIR/_secure5
1.8       deraadt    14:
1.25      deraadt    15: trap 'rm -rf $DIR; exit 1' 0 1 2 3 13 15
1.1       deraadt    16:
                     17: # Check the master password file syntax.
                     18: MP=/etc/master.passwd
1.84      schwarze   19: next_part "Checking the ${MP} file:"
1.1       deraadt    20: awk -F: '{
                     21:        if ($0 ~ /^[     ]*$/) {
                     22:                printf("Line %d is a blank line.\n", NR);
                     23:                next;
                     24:        }
                     25:        if (NF != 10)
1.32      espie      26:                printf("Line %d has the wrong number of fields:\n%s\n", NR, $0);
1.15      millert    27:        if ($1 ~ /^[+-]/)
1.2       deraadt    28:                next;
                     29:        if ($1 == "")
1.32      espie      30:                printf("Line %d has an empty login field:\n%s\n", NR, $0);
1.59      grange     31:        else if ($1 !~ /^[A-Za-z0-9_][A-Za-z0-9_\-\.]*\$?$/)
1.1       deraadt    32:                printf("Login %s has non-alphanumeric characters.\n", $1);
1.48      brad       33:        if (length($1) > 31)
                     34:                printf("Login %s has more than 31 characters.\n", $1);
1.1       deraadt    35:        if ($2 == "")
                     36:                printf("Login %s has no password.\n", $1);
1.23      deraadt    37:        if ($2 != "" && length($2) != 13 && ($10 ~ /.*sh$/ || $10 == "") &&
1.70      david      38:           ($2 !~ /^\$[0-9a-f]+\$/) && ($2 != "skey")) {
1.51      millert    39:                if (system("test -s /etc/skey/"$1"") == 0)
                     40:                        printf("Login %s is off but still has a valid shell and an entry in /etc/skey.\n", $1);
1.23      deraadt    41:                if (system("test -d "$9" -a ! -r "$9"") == 0)
1.40      hugh       42:                        printf("Login %s is off but still has valid shell and home directory is unreadable\n\t by root; cannot check for existence of alternate access files.\n", $1);
1.23      deraadt    43:                else if (system("for file in .ssh .rhosts .shosts .klogin; do if test -e "$9"/$file; then if ((ls -ld "$9"/$file | cut -b 2-10 | grep -q r) && (test ! -O "$9"/$file)) ; then exit 1; fi; fi; done"))
                     44:                         printf("Login %s is off but still has a valid shell and alternate access files in\n\t home directory are still readable.\n",$1);
                     45:        }
1.9       deraadt    46:        if ($3 == 0 && $1 != "root")
1.36      aaron      47:                printf("Login %s has a user ID of 0.\n", $1);
1.1       deraadt    48:        if ($3 < 0)
1.36      aaron      49:                printf("Login %s has a negative user ID.\n", $1);
1.1       deraadt    50:        if ($4 < 0)
1.36      aaron      51:                printf("Login %s has a negative group ID.\n", $1);
1.64      millert    52:        if (int($7) != 0 && system("test "$7" -lt `date +%s`") == 0)
1.53      pvalchev   53:                printf("Login %s has expired.\n", $1);
1.84      schwarze   54: }' < $MP
1.1       deraadt    55:
1.84      schwarze   56: next_part "${MP} has duplicate user names."
                     57: awk -F: '{ print $1 }' $MP | sort | uniq -d | column
1.1       deraadt    58:
1.84      schwarze   59: next_part "${MP} has duplicate user IDs."
1.47      millert    60: awk -F: '/^[^\+]/ { print $1 " " $3 }' $MP | sort -n +1 | tee $TMP1 |
1.1       deraadt    61: uniq -d -f 1 | awk '{ print $2 }' > $TMP2
                     62: if [ -s $TMP2 ] ; then
1.70      david      63:        while read uid; do
                     64:                grep -w $uid $TMP1
                     65:        done < $TMP2 | column
1.1       deraadt    66: fi
                     67:
                     68: # Backup the master password file; a special case, the normal backup
                     69: # mechanisms also print out file differences and we don't want to do
                     70: # that because this file has encrypted passwords in it.
1.2       deraadt    71: if [ ! -d /var/backups ] ; then
                     72:        mkdir /var/backups
1.31      deraadt    73:        chmod 700 /var/backups
1.2       deraadt    74: fi
1.1       deraadt    75: CUR=/var/backups/`basename $MP`.current
                     76: BACK=/var/backups/`basename $MP`.backup
                     77: if [ -s $CUR ] ; then
                     78:        if cmp -s $CUR $MP; then
                     79:                :
                     80:        else
                     81:                cp -p $CUR $BACK
                     82:                cp -p $MP $CUR
1.56      millert    83:                chown root:wheel $CUR
1.1       deraadt    84:        fi
                     85: else
                     86:        cp -p $MP $CUR
1.56      millert    87:        chown root:wheel $CUR
1.1       deraadt    88: fi
                     89:
                     90: # Check the group file syntax.
                     91: GRP=/etc/group
1.84      schwarze   92: next_part "Checking the ${GRP} file:"
1.1       deraadt    93: awk -F: '{
                     94:        if ($0 ~ /^[     ]*$/) {
                     95:                printf("Line %d is a blank line.\n", NR);
                     96:                next;
                     97:        }
1.2       deraadt    98:        if ($1 ~ /^[+-].*$/)
                     99:                next;
1.1       deraadt   100:        if (NF != 4)
1.32      espie     101:                printf("Line %d has the wrong number of fields:\n%s\n", NR, $0);
1.65      sturm     102:        if ($1 !~ /^[A-Za-z0-9_][A-Za-z0-9_\-\.]*$/)
1.1       deraadt   103:                printf("Group %s has non-alphanumeric characters.\n", $1);
1.48      brad      104:        if (length($1) > 31)
                    105:                printf("Group %s has more than 31 characters.\n", $1);
1.83      schwarze  106:        if ($3 !~ /^[0-9]*$/)
                    107:                printf("Group %s has an invalid group ID.\n", $1);
1.84      schwarze  108: }' < $GRP
1.1       deraadt   109:
1.84      schwarze  110: next_part "${GRP} has duplicate group names."
                    111: awk -F: '{ print $1 }' $GRP | sort | uniq -d | column
1.1       deraadt   112:
                    113: # Check for root paths, umask values in startup files.
                    114: # The check for the root paths is problematical -- it's likely to fail
                    115: # in other environments.  Once the shells have been modified to warn
                    116: # of '.' in the path, the path tests should go away.
                    117: rhome=/root
                    118: umaskset=no
                    119: list="/etc/csh.cshrc /etc/csh.login ${rhome}/.cshrc ${rhome}/.login"
1.84      schwarze  120: next_part "Checking root csh paths, umask values:\n${list}"
1.1       deraadt   121: for i in $list ; do
1.15      millert   122:        if [ -s $i ] ; then
1.75      david     123:                if egrep -aq '[[:space:]]*umask[[:space:]]' $i ; then
1.63      millert   124:                        umaskset=yes
                    125:                fi
1.61      millert   126:                awk '{
                    127:                    if ($1 == "umask") {
1.62      millert   128:                         if ($2 % 100 / 10 ~ /^[0145]/)
1.61      millert   129:                            print "Root umask is group writable";
                    130:                         if ($2 % 10 ~ /^[0145]/)
                    131:                            print "Root umask is other writable";
                    132:                    }
1.84      schwarze  133:                }' < $i
1.21      deraadt   134:                SAVE_PATH=$PATH
                    135:                unset PATH
1.1       deraadt   136:                /bin/csh -f -s << end-of-csh > /dev/null 2>&1
                    137:                        source $i
1.29      marc      138:                        if (\$?path) then
                    139:                                /bin/ls -ldgT \$path > $TMP1
                    140:                        else
                    141:                                cat /dev/null > $TMP1
                    142:                        endif
1.1       deraadt   143: end-of-csh
1.21      deraadt   144:                PATH=$SAVE_PATH
1.1       deraadt   145:                awk '{
                    146:                        if ($10 ~ /^\.$/) {
                    147:                                print "The root path includes .";
                    148:                                next;
                    149:                        }
                    150:                     }
                    151:                     $1 ~ /^d....w/ \
1.70      david     152:        { print "Root path directory " $10 " is group writable." } \
1.1       deraadt   153:                     $1 ~ /^d.......w/ \
1.70      david     154:        { print "Root path directory " $10 " is other writable." }' \
1.84      schwarze  155:                < $TMP1
1.1       deraadt   156:        fi
                    157: done
1.84      schwarze  158: if [ $umaskset = "no" ] ; then
                    159:        echo "\nRoot csh startup files do not set the umask."
1.1       deraadt   160: fi
                    161:
1.29      marc      162: > $TMP2
1.1       deraadt   163: rhome=/root
                    164: umaskset=no
1.20      millert   165: list="/etc/profile ${rhome}/.profile"
1.84      schwarze  166: next_part "Checking root sh paths, umask values:\n${list}"
1.1       deraadt   167: for i in $list; do
1.15      millert   168:        if [ -s $i ] ; then
1.75      david     169:                if egrep -a umask $i > /dev/null ; then
1.1       deraadt   170:                        umaskset=yes
                    171:                fi
1.75      david     172:                egrep -a umask $i |
1.1       deraadt   173:                awk '$2 % 100 < 20 \
1.54      henning   174:                        { print "Root umask is group writable" } \
1.1       deraadt   175:                     $2 % 10 < 2 \
1.84      schwarze  176:                        { print "Root umask is other writable" }'
1.21      deraadt   177:                SAVE_PATH=$PATH
1.29      marc      178:                SAVE_ENV=$ENV
                    179:                unset PATH ENV
1.1       deraadt   180:                /bin/sh << end-of-sh > /dev/null 2>&1
                    181:                        . $i
1.29      marc      182:                        if [ X"\$PATH" != "X" ]; then
                    183:                                list=\`echo \$PATH | /usr/bin/sed -e 's/:/ /g'\`
                    184:                                /bin/ls -ldgT \$list > $TMP1
                    185:                        else
                    186:                                > $TMP1
                    187:                        fi
                    188:                        echo \$ENV >> $TMP2
1.1       deraadt   189: end-of-sh
1.21      deraadt   190:                PATH=$SAVE_PATH
1.29      marc      191:                ENV=$SAVE_ENV
1.1       deraadt   192:                awk '{
                    193:                        if ($10 ~ /^\.$/) {
                    194:                                print "The root path includes .";
                    195:                                next;
                    196:                        }
                    197:                     }
                    198:                     $1 ~ /^d....w/ \
1.70      david     199:        { print "Root path directory " $10 " is group writable." } \
1.1       deraadt   200:                     $1 ~ /^d.......w/ \
1.70      david     201:        { print "Root path directory " $10 " is other writable." }' \
1.84      schwarze  202:                < $TMP1
1.1       deraadt   203:
                    204:        fi
                    205: done
1.84      schwarze  206: if [ $umaskset = "no" ] ; then
                    207:        echo "\nRoot sh startup files do not set the umask."
1.1       deraadt   208: fi
                    209:
1.27      marc      210: # A good .kshrc will not have a umask or path, that being set in .profile
                    211: # check anyway.
                    212: rhome=/root
1.29      marc      213: list="/etc/ksh.kshrc `cat $TMP2`"
1.84      schwarze  214: next_part "Checking root ksh paths, umask values:\n${list}"
1.29      marc      215: (cd $rhome
                    216:  for i in $list; do
1.27      marc      217:        if [ -s $i ] ; then
1.75      david     218:                egrep -a umask $i |
1.27      marc      219:                awk '$2 % 100 < 20 \
1.54      henning   220:                        { print "Root umask is group writable" } \
1.27      marc      221:                     $2 % 10 < 2 \
1.84      schwarze  222:                        { print "Root umask is other writable" }'
1.75      david     223:                if egrep -a PATH= $i > /dev/null ; then
1.27      marc      224:                        SAVE_PATH=$PATH
                    225:                        unset PATH
                    226:                        /bin/ksh << end-of-sh > /dev/null 2>&1
                    227:                                . $i
1.29      marc      228:                                if [ X"\$PATH" != "X" ]; then
                    229:                                        list=\`echo \$PATH | /usr/bin/sed -e 's/:/ /g'\`
                    230:                                        /bin/ls -ldgT \$list > $TMP1
                    231:                                else
                    232:                                        > $TMP1
                    233:                                fi
1.27      marc      234: end-of-sh
                    235:                        PATH=$SAVE_PATH
                    236:                        awk '{
                    237:                                if ($10 ~ /^\.$/) {
                    238:                                        print "The root path includes .";
                    239:                                        next;
                    240:                                }
                    241:                            }
                    242:                            $1 ~ /^d....w/ \
1.54      henning   243:                { print "Root path directory " $10 " is group writable." } \
1.27      marc      244:                            $1 ~ /^d.......w/ \
1.54      henning   245:                { print "Root path directory " $10 " is other writable." }' \
1.84      schwarze  246:                        < $TMP1
1.27      marc      247:                fi
                    248:
                    249:        fi
1.29      marc      250:  done
                    251: )
1.27      marc      252:
1.84      schwarze  253: next_part "Checking configuration files:"
1.1       deraadt   254: # Root and uucp should both be in /etc/ftpusers.
                    255: if egrep root /etc/ftpusers > /dev/null ; then
                    256:        :
                    257: else
1.84      schwarze  258:        echo "Root not listed in /etc/ftpusers file."
1.1       deraadt   259: fi
                    260: if egrep uucp /etc/ftpusers > /dev/null ; then
                    261:        :
                    262: else
1.84      schwarze  263:        echo "Uucp not listed in /etc/ftpusers file."
1.1       deraadt   264: fi
                    265:
1.35      millert   266: # Uudecode should not be in the /etc/mail/aliases file.
                    267: if egrep 'uudecode|decode' /etc/mail/aliases; then
1.84      schwarze  268:        echo "There is an entry for uudecode in the /etc/mail/aliases file."
1.1       deraadt   269: fi
1.80      sthen     270:
                    271: # hostname.if files may contain secrets and should not be
                    272: # world-readable.
                    273:
                    274: for f in /etc/hostname.* ; do
1.81      sthen     275:        if [ ! -e $f ]; then
                    276:                continue
                    277:        fi
                    278:        if [ "$(stat -Lf "%SLp" $f)" != "---" ]; then
1.84      schwarze  279:                echo "$f is world readable."
1.80      sthen     280:        fi
                    281: done
1.1       deraadt   282:
                    283: # Files that should not have + signs.
1.2       deraadt   284: list="/etc/hosts.equiv /etc/shosts.equiv /etc/hosts.lpd"
1.1       deraadt   285: for f in $list ; do
1.6       millert   286:        if [ -s $f ] ; then
1.2       deraadt   287:                awk '{
1.13      millert   288:                        if ($0 ~ /^\+@.*$/)
1.2       deraadt   289:                                next;
1.13      millert   290:                        if ($0 ~ /^\+.*$/)
1.84      schwarze  291:                                printf("Plus sign in %s file.\n", FILENAME);
1.2       deraadt   292:                }' $f
1.1       deraadt   293:        fi
                    294: done
                    295:
1.13      millert   296: # Check for special users with .rhosts/.shosts files.  Only root
                    297: # should have .rhosts/.shosts files.  Also, .rhosts/.shosts
                    298: # files should not have plus signs.
1.84      schwarze  299: next_part "Checking for special users with .rhosts/.shosts files."
1.14      millert   300: awk -F: '$1 != "root" && $1 !~ /^[+-]/ && \
1.1       deraadt   301:        ($3 < 100 || $1 == "ftp" || $1 == "uucp") \
                    302:                { print $1 " " $6 }' /etc/passwd |
                    303: while read uid homedir; do
1.2       deraadt   304:        for j in .rhosts .shosts; do
1.14      millert   305:                # Root owned .rhosts/.shosts files are ok.
1.15      millert   306:                if [ -s ${homedir}/$j -a ! -O ${homedir}/$j ] ; then
1.2       deraadt   307:                        rhost=`ls -ldgT ${homedir}/$j`
1.41      millert   308:                        echo "${uid}: ${rhost}"
1.2       deraadt   309:                fi
                    310:        done
1.84      schwarze  311: done
1.1       deraadt   312:
1.84      schwarze  313: next_part "Checking .rhosts/.shosts files syntax."
1.14      millert   314: awk -F: '/^[^+-]/ { print $1 " " $6 }' /etc/passwd | \
1.1       deraadt   315: while read uid homedir; do
1.2       deraadt   316:        for j in .rhosts .shosts; do
1.13      millert   317:                if [ -s ${homedir}/$j ] ; then
1.2       deraadt   318:                        awk '{
                    319:                                if ($0 ~ /^+@.*$/ )
                    320:                                        next;
1.4       deraadt   321:                                if ($0 ~ /^\+[  ]*$/ )
1.2       deraadt   322:                                        printf("%s has + sign in it.\n",
1.13      millert   323:                                                FILENAME);
1.2       deraadt   324:                        }' ${homedir}/$j
                    325:                fi
                    326:        done
1.84      schwarze  327: done
1.1       deraadt   328:
                    329: # Check home directories.  Directories should not be owned by someone else
                    330: # or writeable.
1.84      schwarze  331: next_part "Checking home directories."
1.14      millert   332: awk -F: '/^[^+-]/ { print $1 " " $6 }' /etc/passwd | \
1.1       deraadt   333: while read uid homedir; do
                    334:        if [ -d ${homedir}/ ] ; then
                    335:                file=`ls -ldgT ${homedir}`
1.41      millert   336:                echo "${uid} ${file}"
1.1       deraadt   337:        fi
                    338: done |
                    339: awk '$1 != $4 && $4 != "root" \
                    340:        { print "user " $1 " home directory is owned by " $4 }
                    341:      $2 ~ /^-....w/ \
1.54      henning   342:        { print "user " $1 " home directory is group writable" }
1.1       deraadt   343:      $2 ~ /^-.......w/ \
1.84      schwarze  344:        { print "user " $1 " home directory is other writable" }'
1.1       deraadt   345:
                    346: # Files that should not be owned by someone else or readable.
1.43      todd      347: list=".netrc .rhosts .gnupg/secring.gpg .gnupg/random_seed \
1.45      millert   348:        .pgp/secring.pgp .shosts .ssh/identity .ssh/id_dsa .ssh/id_rsa"
1.84      schwarze  349: next_part "Checking dot files."
1.14      millert   350: awk -F: '/^[^+-]/ { print $1 " " $6 }' /etc/passwd | \
1.1       deraadt   351: while read uid homedir; do
                    352:        for f in $list ; do
                    353:                file=${homedir}/${f}
                    354:                if [ -f $file ] ; then
1.41      millert   355:                        echo "${uid} ${f} `ls -ldgT ${file}`"
1.1       deraadt   356:                fi
                    357:        done
                    358: done |
                    359: awk '$1 != $5 && $5 != "root" \
                    360:        { print "user " $1 " " $2 " file is owned by " $5 }
1.13      millert   361:      $3 ~ /^-...r/ \
                    362:        { print "user " $1 " " $2 " file is group readable" }
1.1       deraadt   363:      $3 ~ /^-......r/ \
                    364:        { print "user " $1 " " $2 " file is other readable" }
                    365:      $3 ~ /^-....w/ \
1.54      henning   366:        { print "user " $1 " " $2 " file is group writable" }
1.1       deraadt   367:      $3 ~ /^-.......w/ \
1.84      schwarze  368:        { print "user " $1 " " $2 " file is other writable" }'
1.1       deraadt   369:
                    370: # Files that should not be owned by someone else or writeable.
1.28      todd      371: list=".bashrc .bash_profile .bash_login .bash_logout .cshrc \
                    372:       .emacs .exrc .forward .fvwmrc .inputrc .klogin .kshrc .login \
                    373:       .logout .nexrc .profile .screenrc .ssh .ssh/config \
1.45      millert   374:       .ssh/authorized_keys .ssh/authorized_keys2 .ssh/environment \
                    375:       .ssh/known_hosts .ssh/rc .tcshrc .twmrc .xsession .xinitrc \
                    376:       .Xdefaults .Xauthority"
1.14      millert   377: awk -F: '/^[^+-]/ { print $1 " " $6 }' /etc/passwd | \
1.1       deraadt   378: while read uid homedir; do
                    379:        for f in $list ; do
                    380:                file=${homedir}/${f}
                    381:                if [ -f $file ] ; then
1.41      millert   382:                        echo "${uid} ${f} `ls -ldgT ${file}`"
1.1       deraadt   383:                fi
                    384:        done
                    385: done |
                    386: awk '$1 != $5 && $5 != "root" \
                    387:        { print "user " $1 " " $2 " file is owned by " $5 }
                    388:      $3 ~ /^-....w/ \
1.54      henning   389:        { print "user " $1 " " $2 " file is group writable" }
1.1       deraadt   390:      $3 ~ /^-.......w/ \
1.84      schwarze  391:        { print "user " $1 " " $2 " file is other writable" }'
1.1       deraadt   392:
                    393: # Mailboxes should be owned by user and unreadable.
1.84      schwarze  394: next_part "Checking mailbox ownership."
1.1       deraadt   395: ls -l /var/mail | sed 1d | \
                    396: awk '$3 != $9 \
                    397:        { print "user " $9 " mailbox is owned by " $3 }
                    398:      $1 != "-rw-------" \
1.84      schwarze  399:        { print "user " $9 " mailbox is " $1 ", group " $4 }'
1.1       deraadt   400:
1.13      millert   401: # File systems should not be globally exported.
1.84      schwarze  402: next_part "Checking for globally exported file systems."
1.13      millert   403: if [ -s /etc/exports ] ; then
                    404:        awk '{
1.19      flipk     405:                if (($1 ~ /^#/) || ($1 ~ /^$/))
1.1       deraadt   406:                        next;
1.13      millert   407:                readonly = 0;
                    408:                for (i = 2; i <= NF; ++i) {
1.19      flipk     409:                        if ($i ~ /^-ro$/)
1.13      millert   410:                                readonly = 1;
1.71      otto      411:                        else if ($i !~ /^-/ || $i ~ /^-network/)
1.13      millert   412:                                next;
                    413:                }
                    414:                if (readonly)
                    415:                        print "File system " $1 " globally exported, read-only."
                    416:                else
                    417:                        print "File system " $1 " globally exported, read-write."
1.84      schwarze  418:        }' < /etc/exports
1.1       deraadt   419: fi
                    420:
1.5       deraadt   421: # Display any changes in setuid/setgid files and devices.
1.84      schwarze  422: next_part "Setuid/device find errors:"
                    423: find / \( ! -fstype local \
1.72      deraadt   424:        -o -fstype procfs -o -fstype afs -o -fstype xfs \) -a -prune -o \
1.13      millert   425:        -type f -a \( -perm -u+s -o -perm -g+s \) -print0 -o \
1.30      millert   426:        ! -type d -a ! -type f -a ! -type l -a ! -type s -a ! -type p \
1.84      schwarze  427:        -print0 | xargs -0 ls -ldgT | sort +9 > $LIST
1.1       deraadt   428:
1.12      millert   429: # Display any changes in the setuid/setgid file list.
1.84      schwarze  430: next_part "Checking setuid/setgid files and devices:"
1.66      otto      431: FIELDS1=1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,0
                    432: FIELDS2=2.1,2.2,2.3,2.4,2.5,2.6,2.7,2.8,2.9,0
                    433: egrep -av '^[bc]' $LIST | join -o $FIELDS2 -110 -210 -v2 /dev/null - > $TMP1
1.1       deraadt   434: if [ -s $TMP1 ] ; then
                    435:        # Check to make sure uudecode isn't setuid.
1.66      otto      436:        if grep -aw uudecode $TMP1 > /dev/null ; then
1.84      schwarze  437:                echo "Uudecode is setuid."
1.1       deraadt   438:        fi
                    439:
                    440:        CUR=/var/backups/setuid.current
                    441:        BACK=/var/backups/setuid.backup
                    442:
                    443:        if [ -s $CUR ] ; then
                    444:                if cmp -s $CUR $TMP1 ; then
                    445:                        :
                    446:                else
1.84      schwarze  447:                        next_part "Setuid additions:"
                    448:                        join -o $FIELDS2 -110 -210 -v2 $CUR $TMP1 | \
                    449:                                tee $TMP2 | column -t
                    450:
                    451:                        next_part "Setuid deletions:"
                    452:                        join -o $FIELDS1 -110 -210 -v1 $CUR $TMP1 | \
                    453:                                tee -a $TMP2 | column -t
1.1       deraadt   454:
1.84      schwarze  455:                        next_part "Setuid changes:"
1.13      millert   456:                        sort +9 $TMP2 $CUR $TMP1 | \
1.84      schwarze  457:                            sed -e 's/[  ][      ]*/ /g' | uniq -u | column -t
1.1       deraadt   458:
                    459:                        cp $CUR $BACK
                    460:                        cp $TMP1 $CUR
                    461:                fi
                    462:        else
1.85    ! schwarze  463:                next_part "Setuid additions:"
1.1       deraadt   464:                column -t $TMP1
                    465:                cp $TMP1 $CUR
                    466:        fi
                    467: fi
                    468:
                    469: # Check for block and character disk devices that are readable or writeable
                    470: # or not owned by root.operator.
1.84      schwarze  471: next_part "Checking disk ownership and permissions."
1.1       deraadt   472: >$TMP1
1.13      millert   473: DISKLIST="ccd dk fd hd hk hp jb kra ra rb rd rl rx rz sd up vnd wd xd"
1.1       deraadt   474: for i in $DISKLIST; do
1.33      millert   475:        egrep "^b.*/${i}[0-9][0-9]*[B-H]?[a-p]$"  $LIST >> $TMP1
                    476:        egrep "^c.*/r${i}[0-9][0-9]*[B-H]?[a-p]$"  $LIST >> $TMP1
1.1       deraadt   477: done
                    478:
                    479: awk '$3 != "root" || $4 != "operator" || $1 !~ /.rw-r-----/ \
                    480:        { printf("Disk %s is user %s, group %s, permissions %s.\n", \
1.84      schwarze  481:            $11, $3, $4, $1); }' < $TMP1
1.1       deraadt   482:
1.66      otto      483: FIELDS1=1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,1.10,0
                    484: FIELDS2=2.1,2.2,2.3,2.4,2.5,2.6,2.7,2.8,2.9,2.10,0
1.1       deraadt   485: # Display any changes in the device file list.
1.66      otto      486: egrep -a '^[bc]' $LIST | sort +10 | \
                    487:     join -o $FIELDS2 -111 -211 -v2 /dev/null - > $TMP1
1.1       deraadt   488: if [ -s $TMP1 ] ; then
                    489:        CUR=/var/backups/device.current
                    490:        BACK=/var/backups/device.backup
                    491:
                    492:        if [ -s $CUR ] ; then
                    493:                if cmp -s $CUR $TMP1 ; then
                    494:                        :
                    495:                else
1.84      schwarze  496:                        next_part "Device additions:"
                    497:                        join -o $FIELDS2 -111 -211 -v2 $CUR $TMP1 | \
                    498:                                tee $TMP2 | column -t
                    499:
                    500:                        next_part "Device deletions:"
                    501:                        join -o $FIELDS1 -111 -211 -v1 $CUR $TMP1 | \
                    502:                                tee -a $TMP2 | column -t
1.1       deraadt   503:
                    504:                        # Report any block device change.  Ignore character
                    505:                        # devices, only the name is significant.
1.84      schwarze  506:                        next_part "Block device changes:"
1.1       deraadt   507:                        cat $TMP2 $CUR $TMP1 | \
                    508:                        sed -e '/^c/d' | \
                    509:                        sort +10 | \
                    510:                        sed -e 's/[      ][      ]*/ /g' | \
1.84      schwarze  511:                        uniq -u | \
                    512:                        column -t
1.1       deraadt   513:
                    514:                        cp $CUR $BACK
                    515:                        cp $TMP1 $CUR
                    516:                fi
                    517:        else
1.85    ! schwarze  518:                next_part "Device additions:"
1.1       deraadt   519:                column -t $TMP1
                    520:                cp $TMP1 $CUR
                    521:        fi
                    522: fi
                    523:
                    524: # Check special files.
                    525: # Check system binaries.
                    526: #
                    527: # Create the mtree tree specifications using:
                    528: #
1.69      jmc       529: #      mtree -cx -p DIR -K md5digest,type >/etc/mtree/DIR.secure
                    530: #      chown root:wheel /etc/mtree/DIR.secure
                    531: #      chmod 600 /etc/mtree/DIR.secure
1.1       deraadt   532: #
                    533: # Note, this is not complete protection against Trojan horsed binaries, as
                    534: # the hacker can modify the tree specification to match the replaced binary.
                    535: # For details on really protecting yourself against modified binaries, see
                    536: # the mtree(8) manual page.
1.84      schwarze  537: next_part "Checking special files and directories.
                    538: Output format is:\n\tfilename:\n\t\tcriteria (shouldbe, reallyis)"
1.13      millert   539: if [ -d /etc/mtree ] ; then
1.2       deraadt   540:        cd /etc/mtree
1.84      schwarze  541:        mtree -e -l -p / -f /etc/mtree/special
1.1       deraadt   542:        for file in *.secure; do
1.2       deraadt   543:                [ $file = '*.secure' ] && continue
1.1       deraadt   544:                tree=`sed -n -e '3s/.* //p' -e 3q $file`
1.84      schwarze  545:                next_part "Checking system binaries in ${tree}:"
                    546:                mtree -f $file -p $tree
1.1       deraadt   547:        done
1.2       deraadt   548: else
                    549:        echo /etc/mtree is missing
1.1       deraadt   550: fi
                    551:
                    552: # List of files that get backed up and checked for any modifications.  Each
                    553: # file is expected to have two backups, /var/backups/file.{current,backup}.
                    554: # Any changes cause the files to rotate.
1.37      todd      555: _fnchg() {
                    556:        echo "$1" | sed 's/^\///;s/\//_/g'
                    557: }
1.1       deraadt   558: if [ -s /etc/changelist ] ; then
1.46      millert   559:        for file in `egrep -v "^(#|\+|$MP)" /etc/changelist`; do
1.37      todd      560:                CUR=/var/backups/$(_fnchg  "$file").current
                    561:                BACK=/var/backups/$(_fnchg "$file").backup
1.84      schwarze  562:                next_part "======\n${file} diffs (-OLD  +NEW)\n======"
1.37      todd      563:                if [ -s $file -a ! -d $file ] ; then
1.1       deraadt   564:                        if [ -s $CUR ] ; then
1.84      schwarze  565:                                diff -ua $CUR $file
                    566:                                if [ -s $PARTOUT ] ; then
1.1       deraadt   567:                                        cp -p $CUR $BACK
                    568:                                        cp -p $file $CUR
1.56      millert   569:                                        chown root:wheel $CUR $BACK
1.1       deraadt   570:                                fi
                    571:                        else
1.77      dlg       572:                                diff -u /dev/null $file
1.1       deraadt   573:                                cp -p $file $CUR
1.56      millert   574:                                chown root:wheel $CUR
1.46      millert   575:                        fi
                    576:                fi
1.77      dlg       577:                if [ ! -s $file -a -s $CUR ]; then
                    578:                        diff -u $CUR /dev/null
                    579:                        cp -p $CUR $BACK
                    580:                        rm -f $CUR
                    581:                        chown root:wheel $BACK
                    582:                fi
1.46      millert   583:        done
                    584:        for file in `egrep "^\+" /etc/changelist`; do
                    585:                file="${file#+}"
                    586:                CUR=/var/backups/$(_fnchg  "$file").current.md5
                    587:                BACK=/var/backups/$(_fnchg "$file").backup.md5
                    588:                if [ -s $file -a ! -d $file ] ; then
                    589:                        MD5_NEW=`md5 $file | sed 's/^.* //'`
                    590:                        if [ -s $CUR ] ; then
                    591:                                MD5_OLD="`cat $CUR`"
                    592:                                if [ "$MD5_NEW" != "$MD5_OLD" ]; then
1.85    ! schwarze  593:                next_part "======\n${file} MD5 checksums\n======"
1.46      millert   594:                                        echo "OLD: $MD5_OLD"
                    595:                                        echo "NEW: $MD5_NEW"
                    596:                                        cp -p $CUR $BACK
                    597:                                        echo $MD5_NEW > $CUR
1.56      millert   598:                                        chown root:wheel $CUR $BACK
1.46      millert   599:                                        chmod 600 $CUR
                    600:                                fi
                    601:                        else
1.85    ! schwarze  602:                next_part "======\n${file} new MD5 checksum\n======"
1.77      dlg       603:                                echo "NEW: $MD5_NEW"
1.46      millert   604:                                echo $MD5_NEW > $CUR
1.56      millert   605:                                chown root:wheel $CUR
1.46      millert   606:                                chmod 600 $CUR
1.1       deraadt   607:                        fi
1.77      dlg       608:                fi
                    609:                if [ ! -s $file -a -s $CUR ]; then
                    610:                        MD5_OLD="`cat $CUR`"
1.85    ! schwarze  611:                next_part "======\n${file} removed MD5 checksum\n======"
1.77      dlg       612:                        echo "OLD: $MD5_OLD"
                    613:                        cp -p $CUR $BACK
                    614:                        rm $CUR
                    615:                        chown root:wheel $BACK
1.1       deraadt   616:                fi
                    617:        done
                    618: fi
1.67      millert   619:
                    620: # Make backups of the labels for any mounted disks and produce diffs
                    621: # when they change.
                    622: for d in `df -ln | sed -n 's:^/dev/\([a-z]*[0-9]*\)[a-p].*$:\1:p' | sort -u`; do
                    623:        file=/var/backups/disklabel.$d
                    624:        CUR=$file.current
                    625:        BACK=$file.backup
1.84      schwarze  626:        next_part "======\n${d} diffs (-OLD  +NEW)\n======"
1.68      millert   627:        if disklabel $d > $file 2>&1 ; then
1.67      millert   628:                if [ -s $CUR ] ; then
1.84      schwarze  629:                        diff -u $CUR $file
                    630:                        if [ -s $PARTOUT ] ; then
1.67      millert   631:                                cp -p $CUR $BACK
                    632:                                cp -p $file $CUR
                    633:                                chown root:wheel $CUR $BACK
                    634:                        fi
                    635:                else
                    636:                        cp -p $file $CUR
                    637:                        chown root:wheel $CUR
                    638:                fi
                    639:        fi
                    640:        rm -f $file
                    641: done
1.79      sthen     642:
                    643: # Backup the list of installed packages and produce diffs when it changes.
1.84      schwarze  644: next_part "======\nPackage list changes (-OLD  +NEW)\n======"
1.79      sthen     645: file=/var/backups/pkglist
                    646: CUR=$file.current
                    647: BACK=$file.backup
                    648: if pkg_info > $file 2>&1 ; then
                    649:        if [ -s $CUR ] ; then
1.84      schwarze  650:                diff -u $CUR $file
                    651:                if [ -s $PARTOUT ] ; then
1.79      sthen     652:                        cp -p $CUR $BACK
                    653:                        cp -p $file $CUR
                    654:                        chown root:wheel $CUR $BACK
                    655:                fi
                    656:        else
                    657:                cp -p $file $CUR
                    658:                chown root:wheel $CUR
                    659:        fi
                    660: fi
                    661: rm -f $file