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

Annotation of src/etc/security, Revision 1.83

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