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

Annotation of src/etc/security, Revision 1.46

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