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.

683 lines
18 KiB

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