Source code pulled from OpenBSD for OpenNTPD. The place to contribute to this code is via the OpenBSD CVS tree.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

681 lines
18 KiB

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