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