security revision 1.64 1 1.1 cgd #!/bin/sh -
2 1.1 cgd #
3 1.64 cjs # $NetBSD: security,v 1.64 2001/10/03 07:04:32 cjs Exp $
4 1.9 cgd # from: @(#)security 8.1 (Berkeley) 6/9/93
5 1.1 cgd #
6 1.1 cgd
7 1.9 cgd PATH=/sbin:/usr/sbin:/bin:/usr/bin
8 1.1 cgd
9 1.31 lukem if [ -f /etc/rc.subr ]; then
10 1.31 lukem . /etc/rc.subr
11 1.31 lukem else
12 1.31 lukem echo "Can't read /etc/rc.subr; aborting."
13 1.31 lukem exit 1;
14 1.31 lukem fi
15 1.31 lukem
16 1.9 cgd umask 077
17 1.64 cjs TZ=UTC; export TZ
18 1.1 cgd
19 1.15 mrg if [ -s /etc/security.conf ]; then
20 1.15 mrg . /etc/security.conf
21 1.15 mrg fi
22 1.15 mrg
23 1.56 lukem SECUREDIR=`mktemp -d /tmp/_securedir.XXXXXX` || exit 1
24 1.56 lukem
25 1.56 lukem trap "/bin/rm -rf $SECUREDIR ; exit 0" EXIT INT QUIT
26 1.15 mrg
27 1.56 lukem if ! cd "$SECUREDIR"; then
28 1.56 lukem echo "Can not cd to $SECUREDIR".
29 1.15 mrg exit 1
30 1.15 mrg fi
31 1.15 mrg
32 1.34 abs if [ -z "$max_loginlen" ];then
33 1.56 lukem max_loginlen=8
34 1.34 abs fi
35 1.34 abs
36 1.49 jdolecek if [ -z "$max_grouplen" ]; then
37 1.56 lukem max_grouplen=8
38 1.49 jdolecek fi
39 1.49 jdolecek
40 1.15 mrg ERR=secure1.$$
41 1.15 mrg TMP1=secure2.$$
42 1.15 mrg TMP2=secure3.$$
43 1.28 lukem MPBYUID=secure4.$$
44 1.29 lukem MPBYPATH=secure5.$$
45 1.27 lukem LIST=secure6.$$
46 1.27 lukem OUTPUT=secure7.$$
47 1.32 lukem LABELS=secure8.$$
48 1.62 atatat PKGS=secure9.$$
49 1.15 mrg
50 1.48 abs # Handle backup_dir not being set in .conf file
51 1.48 abs backup_dir=${backup_dir:-/var/backups}
52 1.62 atatat CHANGELIST=""
53 1.62 atatat pkg_dbdir=${pkg_dbdir:-/var/db/pkg}
54 1.48 abs
55 1.15 mrg MP=/etc/master.passwd
56 1.9 cgd
57 1.27 lukem # these is used several times.
58 1.34 abs awk -F: '!/^+/ { print $1 " " $3 }' $MP | sort -k2n > $MPBYUID
59 1.29 lukem awk -F: '{ print $1 " " $9 }' $MP | sort -k2 > $MPBYPATH
60 1.9 cgd
61 1.9 cgd # Check the master password file syntax.
62 1.32 lukem #
63 1.31 lukem if checkyesno check_passwd; then
64 1.34 abs awk -v "len=$max_loginlen" '
65 1.25 lukem BEGIN {
66 1.25 lukem while ( getline < "/etc/shells" > 0 ) {
67 1.39 hubertf if ($0 ~ /^\#/ || $0 ~ /^$/ )
68 1.25 lukem continue;
69 1.25 lukem shells[$1]++;
70 1.25 lukem }
71 1.25 lukem FS=":";
72 1.25 lukem }
73 1.25 lukem
74 1.25 lukem {
75 1.15 mrg if ($0 ~ /^[ ]*$/) {
76 1.25 lukem printf "Line %d is a blank line.\n", NR;
77 1.15 mrg next;
78 1.15 mrg }
79 1.34 abs if (NF != 10 && ($1 != "+" || NF != 1))
80 1.25 lukem printf "Line %d has the wrong number of fields.\n", NR;
81 1.34 abs if ($1 == "+" ) {
82 1.34 abs if (NF != 1 && $3 == 0)
83 1.34 abs printf "Line %d includes entries with uid 0.\n", NR;
84 1.34 abs next;
85 1.34 abs }
86 1.53 atatat if ($1 !~ /^[A-Za-z0-9]([-A-Za-z0-9]*[A-Za-z0-9])*$/)
87 1.25 lukem printf "Login %s has non-alphanumeric characters.\n",
88 1.25 lukem $1;
89 1.34 abs if (length($1) > len)
90 1.34 abs printf "Login %s has more than "len" characters.\n", $1;
91 1.15 mrg if ($2 == "")
92 1.25 lukem printf "Login %s has no password.\n", $1;
93 1.59 perry if (length($2) != 13 &&
94 1.59 perry length($2) != 20 &&
95 1.59 perry length($2) != 34 &&
96 1.59 perry $2 != "" &&
97 1.59 perry $2 !~ /^\*[A-z-]+$/ &&
98 1.59 perry $1 != "toor") {
99 1.25 lukem if ($10 == "" || shells[$10])
100 1.27 lukem printf "Login %s is off but still has a valid shell (%s)\n",
101 1.25 lukem $1, $10;
102 1.25 lukem } else if (! shells[$10])
103 1.25 lukem printf "Login %s does not have a valid shell (%s)\n",
104 1.25 lukem $1, $10;
105 1.15 mrg if ($3 == 0 && $1 != "root" && $1 != "toor")
106 1.25 lukem printf "Login %s has a user id of 0.\n", $1;
107 1.15 mrg if ($3 < 0)
108 1.25 lukem printf "Login %s has a negative user id.\n", $1;
109 1.15 mrg if ($4 < 0)
110 1.25 lukem printf "Login %s has a negative group id.\n", $1;
111 1.15 mrg }' < $MP > $OUTPUT
112 1.15 mrg if [ -s $OUTPUT ] ; then
113 1.15 mrg printf "\nChecking the $MP file:\n"
114 1.15 mrg cat $OUTPUT
115 1.15 mrg fi
116 1.15 mrg
117 1.15 mrg awk -F: '{ print $1 }' $MP | sort | uniq -d > $OUTPUT
118 1.15 mrg if [ -s $OUTPUT ] ; then
119 1.15 mrg printf "\n$MP has duplicate user names.\n"
120 1.15 mrg column $OUTPUT
121 1.15 mrg fi
122 1.15 mrg
123 1.37 wrstuden # To not exclude 'toor', a standard duplicate root account, from the duplicate
124 1.37 wrstuden # account test, uncomment the line below (without egrep in it)and comment
125 1.37 wrstuden # out the line (with egrep in it) below it.
126 1.37 wrstuden #
127 1.37 wrstuden # < $MPBYUID uniq -d -f 1 | awk '{ print $2 }' > $TMP2
128 1.36 wrstuden < $MPBYUID egrep -v '^toor ' | uniq -d -f 1 | awk '{ print $2 }' > $TMP2
129 1.15 mrg if [ -s $TMP2 ] ; then
130 1.15 mrg printf "\n$MP has duplicate user id's.\n"
131 1.15 mrg while read uid; do
132 1.28 lukem grep -w $uid $MPBYUID
133 1.15 mrg done < $TMP2 | column
134 1.15 mrg fi
135 1.9 cgd fi
136 1.9 cgd
137 1.9 cgd # Backup the master password file; a special case, the normal backup
138 1.9 cgd # mechanisms also print out file differences and we don't want to do
139 1.9 cgd # that because this file has encrypted passwords in it.
140 1.32 lukem #
141 1.48 abs CUR=$backup_dir/${MP##*/}.current
142 1.48 abs BACK=$backup_dir/${MP##*/}.backup
143 1.9 cgd if [ -s $CUR ] ; then
144 1.9 cgd if cmp -s $CUR $MP; then
145 1.9 cgd :
146 1.9 cgd else
147 1.52 atatat backup_file update $MP $CUR $BACK
148 1.9 cgd fi
149 1.9 cgd else
150 1.52 atatat backup_file add $MP $CUR $BACK
151 1.9 cgd fi
152 1.9 cgd
153 1.9 cgd # Check the group file syntax.
154 1.32 lukem #
155 1.31 lukem if checkyesno check_group; then
156 1.15 mrg GRP=/etc/group
157 1.49 jdolecek awk -F: -v "len=$max_grouplen" '{
158 1.15 mrg if ($0 ~ /^[ ]*$/) {
159 1.25 lukem printf "Line %d is a blank line.\n", NR;
160 1.15 mrg next;
161 1.15 mrg }
162 1.34 abs if (NF != 4 && ($1 != "+" || NF != 1))
163 1.25 lukem printf "Line %d has the wrong number of fields.\n", NR;
164 1.34 abs if ($1 == "+" ) {
165 1.34 abs next;
166 1.34 abs }
167 1.53 atatat if ($1 !~ /^[A-Za-z0-9]([-A-Za-z0-9]*[A-Za-z0-9])*$/)
168 1.25 lukem printf "Group %s has non-alphanumeric characters.\n",
169 1.25 lukem $1;
170 1.49 jdolecek if (length($1) > len)
171 1.49 jdolecek printf "Group %s has more than "len" characters.\n", $1;
172 1.15 mrg if ($3 !~ /[0-9]*/)
173 1.25 lukem printf "Login %s has a negative group id.\n", $1;
174 1.15 mrg }' < $GRP > $OUTPUT
175 1.15 mrg if [ -s $OUTPUT ] ; then
176 1.15 mrg printf "\nChecking the $GRP file:\n"
177 1.15 mrg cat $OUTPUT
178 1.15 mrg fi
179 1.15 mrg
180 1.15 mrg awk -F: '{ print $1 }' $GRP | sort | uniq -d > $OUTPUT
181 1.15 mrg if [ -s $OUTPUT ] ; then
182 1.15 mrg printf "\n$GRP has duplicate group names.\n"
183 1.15 mrg column $OUTPUT
184 1.15 mrg fi
185 1.9 cgd fi
186 1.9 cgd
187 1.9 cgd # Check for root paths, umask values in startup files.
188 1.9 cgd # The check for the root paths is problematical -- it's likely to fail
189 1.9 cgd # in other environments. Once the shells have been modified to warn
190 1.9 cgd # of '.' in the path, the path tests should go away.
191 1.32 lukem #
192 1.31 lukem if checkyesno check_rootdotfiles; then
193 1.28 lukem > $OUTPUT
194 1.15 mrg rhome=`csh -fc "echo ~root"`
195 1.15 mrg umaskset=no
196 1.15 mrg list="/etc/csh.cshrc /etc/csh.login ${rhome}/.cshrc ${rhome}/.login"
197 1.15 mrg for i in $list ; do
198 1.15 mrg if [ -f $i ] ; then
199 1.45 sommerfe if egrep '^[ \t]*umask[ \t]+[0-7]+' $i > /dev/null ; then
200 1.15 mrg umaskset=yes
201 1.15 mrg fi
202 1.63 lukem # Double check the umask value itself; ensure that
203 1.63 lukem # both the 020 and 002 bits are set.
204 1.63 lukem # We handle this in decimal initially to extract the
205 1.63 lukem # digits, and then extract the `2' bit of each digit.
206 1.63 lukem # This is made especially painful because
207 1.45 sommerfe # bitwise operations were left out of awk.
208 1.45 sommerfe egrep '^[ \t]*umask[ \t]+[0-7]+' $i |
209 1.63 lukem awk '{
210 1.63 lukem g= ($2 % 100) - ($2 % 10);
211 1.63 lukem g /= 10;
212 1.63 lukem g = g % 4;
213 1.63 lukem g -= g % 2;
214 1.63 lukem if (g != 2) {
215 1.63 lukem print "\tRoot umask is group writeable"
216 1.63 lukem }
217 1.63 lukem o = ($2 % 10);
218 1.63 lukem o = o % 4;
219 1.63 lukem o -= o % 2;
220 1.63 lukem if (o != 2) {
221 1.63 lukem print "\tRoot umask is other writeable"
222 1.63 lukem }
223 1.63 lukem }' | sort -u >> $OUTPUT
224 1.26 lukem SAVE_PATH=$PATH
225 1.26 lukem unset PATH
226 1.15 mrg /bin/csh -f -s << end-of-csh > /dev/null 2>&1
227 1.15 mrg source $i
228 1.15 mrg /bin/ls -ldgT \$path > $TMP1
229 1.9 cgd end-of-csh
230 1.26 lukem PATH=$SAVE_PATH
231 1.15 mrg awk '{
232 1.15 mrg if ($10 ~ /^\.$/) {
233 1.27 lukem print "\tThe root path includes .";
234 1.15 mrg next;
235 1.15 mrg }
236 1.15 mrg }
237 1.15 mrg $1 ~ /^d....w/ \
238 1.27 lukem { print "\tRoot path directory " $10 " is group writeable." } \
239 1.15 mrg $1 ~ /^d.......w/ \
240 1.27 lukem { print "\tRoot path directory " $10 " is other writeable." }' \
241 1.15 mrg < $TMP1 >> $OUTPUT
242 1.15 mrg fi
243 1.15 mrg done
244 1.15 mrg if [ $umaskset = "no" -o -s $OUTPUT ] ; then
245 1.27 lukem printf "\nChecking root csh paths, umask values:\n$list\n\n"
246 1.15 mrg if [ -s $OUTPUT ]; then
247 1.15 mrg cat $OUTPUT
248 1.15 mrg fi
249 1.15 mrg if [ $umaskset = "no" ] ; then
250 1.27 lukem printf "\tRoot csh startup files do not set the umask.\n"
251 1.15 mrg fi
252 1.9 cgd fi
253 1.9 cgd
254 1.28 lukem > $OUTPUT
255 1.15 mrg rhome=/root
256 1.15 mrg umaskset=no
257 1.23 lukem list="/etc/profile ${rhome}/.profile"
258 1.15 mrg for i in $list; do
259 1.15 mrg if [ -f $i ] ; then
260 1.15 mrg if egrep umask $i > /dev/null ; then
261 1.15 mrg umaskset=yes
262 1.15 mrg fi
263 1.15 mrg egrep umask $i |
264 1.15 mrg awk '$2 % 100 < 20 \
265 1.27 lukem { print "\tRoot umask is group writeable" } \
266 1.15 mrg $2 % 10 < 2 \
267 1.27 lukem { print "\tRoot umask is other writeable" }' \
268 1.27 lukem >> $OUTPUT
269 1.26 lukem SAVE_PATH=$PATH
270 1.26 lukem unset PATH
271 1.15 mrg /bin/sh << end-of-sh > /dev/null 2>&1
272 1.15 mrg . $i
273 1.26 lukem list=\`echo \$PATH | /usr/bin/sed -e \
274 1.26 lukem 's/^:/.:/;s/:$/:./;s/::/:.:/g;s/:/ /g'\`
275 1.15 mrg /bin/ls -ldgT \$list > $TMP1
276 1.9 cgd end-of-sh
277 1.26 lukem PATH=$SAVE_PATH
278 1.15 mrg awk '{
279 1.15 mrg if ($10 ~ /^\.$/) {
280 1.27 lukem print "\tThe root path includes .";
281 1.15 mrg next;
282 1.15 mrg }
283 1.15 mrg }
284 1.15 mrg $1 ~ /^d....w/ \
285 1.27 lukem { print "\tRoot path directory " $10 " is group writeable." } \
286 1.15 mrg $1 ~ /^d.......w/ \
287 1.27 lukem { print "\tRoot path directory " $10 " is other writeable." }' \
288 1.15 mrg < $TMP1 >> $OUTPUT
289 1.9 cgd
290 1.15 mrg fi
291 1.15 mrg done
292 1.15 mrg if [ $umaskset = "no" -o -s $OUTPUT ] ; then
293 1.15 mrg printf "\nChecking root sh paths, umask values:\n$list\n"
294 1.15 mrg if [ -s $OUTPUT ]; then
295 1.15 mrg cat $OUTPUT
296 1.15 mrg fi
297 1.15 mrg if [ $umaskset = "no" ] ; then
298 1.27 lukem printf "\tRoot sh startup files do not set the umask.\n"
299 1.15 mrg fi
300 1.9 cgd fi
301 1.9 cgd fi
302 1.9 cgd
303 1.9 cgd # Root and uucp should both be in /etc/ftpusers.
304 1.32 lukem #
305 1.31 lukem if checkyesno check_ftpusers; then
306 1.28 lukem > $OUTPUT
307 1.28 lukem list="uucp "`awk '$2 == 0 { print $1 }' $MPBYUID`
308 1.27 lukem for i in $list; do
309 1.29 lukem if /usr/libexec/ftpd -C $i ; then
310 1.29 lukem printf "\t$i is not denied\n" >> $OUTPUT
311 1.27 lukem fi
312 1.27 lukem done
313 1.28 lukem if [ -s $OUTPUT ]; then
314 1.28 lukem printf "\nChecking the /etc/ftpusers configuration:\n"
315 1.28 lukem cat $OUTPUT
316 1.28 lukem fi
317 1.9 cgd fi
318 1.9 cgd
319 1.43 itojun # Uudecode should not be in the /etc/mail/aliases file.
320 1.32 lukem #
321 1.31 lukem if checkyesno check_aliases; then
322 1.43 itojun for f in /etc/mail/aliases /etc/aliases; do
323 1.43 itojun if [ -f $f ] && egrep '^[^#]*(uudecode|decode).*\|' $f; then
324 1.43 itojun printf "\nEntry for uudecode in $f file.\n"
325 1.43 itojun fi
326 1.43 itojun done
327 1.9 cgd fi
328 1.9 cgd
329 1.9 cgd # Files that should not have + signs.
330 1.32 lukem #
331 1.31 lukem if checkyesno check_rhosts; then
332 1.15 mrg list="/etc/hosts.equiv /etc/hosts.lpd"
333 1.15 mrg for f in $list ; do
334 1.15 mrg if [ -f $f ] && egrep '\+' $f > /dev/null ; then
335 1.15 mrg printf "\nPlus sign in $f file.\n"
336 1.15 mrg fi
337 1.15 mrg done
338 1.15 mrg
339 1.15 mrg # Check for special users with .rhosts files. Only root and toor should
340 1.16 mikel # have .rhosts files. Also, .rhosts files should not have plus signs.
341 1.15 mrg awk -F: '$1 != "root" && $1 != "toor" && \
342 1.15 mrg ($3 < 100 || $1 == "ftp" || $1 == "uucp") \
343 1.20 mycroft { print $1 " " $9 }' $MP |
344 1.19 mycroft sort -k2 |
345 1.15 mrg while read uid homedir; do
346 1.15 mrg if [ -f ${homedir}/.rhosts ] ; then
347 1.15 mrg rhost=`ls -ldgT ${homedir}/.rhosts`
348 1.46 christos printf -- "$uid: $rhost\n"
349 1.15 mrg fi
350 1.15 mrg done > $OUTPUT
351 1.15 mrg if [ -s $OUTPUT ] ; then
352 1.15 mrg printf "\nChecking for special users with .rhosts files.\n"
353 1.15 mrg cat $OUTPUT
354 1.15 mrg fi
355 1.15 mrg
356 1.15 mrg while read uid homedir; do
357 1.35 fair if [ -f ${homedir}/.rhosts -a -r ${homedir}/.rhosts ] && \
358 1.41 christos cat -f ${homedir}/.rhosts | egrep '\+' > /dev/null ; then
359 1.46 christos printf -- "$uid: + in .rhosts file.\n"
360 1.15 mrg fi
361 1.29 lukem done < $MPBYPATH > $OUTPUT
362 1.15 mrg if [ -s $OUTPUT ] ; then
363 1.15 mrg printf "\nChecking .rhosts files syntax.\n"
364 1.15 mrg cat $OUTPUT
365 1.15 mrg fi
366 1.9 cgd fi
367 1.9 cgd
368 1.9 cgd # Check home directories. Directories should not be owned by someone else
369 1.9 cgd # or writeable.
370 1.32 lukem #
371 1.31 lukem if checkyesno check_homes; then
372 1.15 mrg while read uid homedir; do
373 1.15 mrg if [ -d ${homedir}/ ] ; then
374 1.15 mrg file=`ls -ldgT ${homedir}`
375 1.46 christos printf -- "$uid $file\n"
376 1.9 cgd fi
377 1.29 lukem done < $MPBYPATH |
378 1.15 mrg awk '$1 != $4 && $4 != "root" \
379 1.15 mrg { print "user " $1 " home directory is owned by " $4 }
380 1.15 mrg $2 ~ /^-....w/ \
381 1.15 mrg { print "user " $1 " home directory is group writeable" }
382 1.15 mrg $2 ~ /^-.......w/ \
383 1.27 lukem { print "user " $1 " home directory is other writeable" }' \
384 1.27 lukem > $OUTPUT
385 1.15 mrg if [ -s $OUTPUT ] ; then
386 1.15 mrg printf "\nChecking home directories.\n"
387 1.15 mrg cat $OUTPUT
388 1.15 mrg fi
389 1.15 mrg
390 1.15 mrg # Files that should not be owned by someone else or readable.
391 1.27 lukem list=".Xauthority .netrc"
392 1.15 mrg while read uid homedir; do
393 1.15 mrg for f in $list ; do
394 1.15 mrg file=${homedir}/${f}
395 1.15 mrg if [ -f $file ] ; then
396 1.46 christos printf -- "$uid $f `ls -ldgT $file`\n"
397 1.15 mrg fi
398 1.15 mrg done
399 1.29 lukem done < $MPBYPATH |
400 1.15 mrg awk '$1 != $5 && $5 != "root" \
401 1.15 mrg { print "user " $1 " " $2 " file is owned by " $5 }
402 1.15 mrg $3 ~ /^-...r/ \
403 1.15 mrg { print "user " $1 " " $2 " file is group readable" }
404 1.15 mrg $3 ~ /^-......r/ \
405 1.15 mrg { print "user " $1 " " $2 " file is other readable" }
406 1.15 mrg $3 ~ /^-....w/ \
407 1.15 mrg { print "user " $1 " " $2 " file is group writeable" }
408 1.15 mrg $3 ~ /^-.......w/ \
409 1.27 lukem { print "user " $1 " " $2 " file is other writeable" }' \
410 1.27 lukem > $OUTPUT
411 1.15 mrg
412 1.15 mrg # Files that should not be owned by someone else or writeable.
413 1.19 mycroft list=".bash_history .bash_login .bash_logout .bash_profile .bashrc \
414 1.19 mycroft .cshrc .emacs .exrc .forward .history .klogin .login .logout \
415 1.27 lukem .profile .qmail .rc_history .rhosts .tcshrc .twmrc .xinitrc \
416 1.27 lukem .xsession"
417 1.15 mrg while read uid homedir; do
418 1.15 mrg for f in $list ; do
419 1.15 mrg file=${homedir}/${f}
420 1.15 mrg if [ -f $file ] ; then
421 1.46 christos printf -- "$uid $f `ls -ldgT $file`\n"
422 1.15 mrg fi
423 1.15 mrg done
424 1.29 lukem done < $MPBYPATH |
425 1.15 mrg awk '$1 != $5 && $5 != "root" \
426 1.15 mrg { print "user " $1 " " $2 " file is owned by " $5 }
427 1.15 mrg $3 ~ /^-....w/ \
428 1.15 mrg { print "user " $1 " " $2 " file is group writeable" }
429 1.15 mrg $3 ~ /^-.......w/ \
430 1.27 lukem { print "user " $1 " " $2 " file is other writeable" }' \
431 1.27 lukem >> $OUTPUT
432 1.15 mrg if [ -s $OUTPUT ] ; then
433 1.15 mrg printf "\nChecking dot files.\n"
434 1.15 mrg cat $OUTPUT
435 1.15 mrg fi
436 1.9 cgd fi
437 1.9 cgd
438 1.9 cgd # Mailboxes should be owned by user and unreadable.
439 1.32 lukem #
440 1.31 lukem if checkyesno check_varmail; then
441 1.63 lukem ls -l /var/mail | \
442 1.63 lukem awk ' NR == 1 { next; }
443 1.63 lukem $3 != $9 {
444 1.63 lukem print "user " $9 " mailbox is owned by " $3
445 1.63 lukem }
446 1.63 lukem $1 != "-rw-------" {
447 1.63 lukem print "user " $9 " mailbox is " $1 ", group " $4
448 1.63 lukem }' > $OUTPUT
449 1.15 mrg if [ -s $OUTPUT ] ; then
450 1.15 mrg printf "\nChecking mailbox ownership.\n"
451 1.15 mrg cat $OUTPUT
452 1.15 mrg fi
453 1.15 mrg fi
454 1.15 mrg
455 1.32 lukem # NFS exports shouldn't be globally exported
456 1.32 lukem #
457 1.32 lukem if checkyesno check_nfs && [ -f /etc/exports ]; then
458 1.32 lukem awk '{
459 1.22 lukem # ignore comments and blank lines
460 1.39 hubertf if ($0 ~ /^\#/ || $0 ~ /^$/ )
461 1.22 lukem next;
462 1.22 lukem
463 1.15 mrg readonly = 0;
464 1.15 mrg for (i = 2; i <= NF; ++i) {
465 1.15 mrg if ($i ~ /-ro/)
466 1.15 mrg readonly = 1;
467 1.15 mrg else if ($i !~ /^-/)
468 1.15 mrg next;
469 1.15 mrg }
470 1.15 mrg if (readonly)
471 1.15 mrg print "File system " $1 " globally exported, read-only."
472 1.15 mrg else
473 1.15 mrg print "File system " $1 " globally exported, read-write."
474 1.32 lukem }' < /etc/exports > $OUTPUT
475 1.32 lukem if [ -s $OUTPUT ] ; then
476 1.15 mrg printf "\nChecking for globally exported file systems.\n"
477 1.15 mrg cat $OUTPUT
478 1.15 mrg fi
479 1.9 cgd fi
480 1.9 cgd
481 1.9 cgd # Display any changes in setuid files and devices.
482 1.32 lukem #
483 1.31 lukem if checkyesno check_devices; then
484 1.28 lukem > $ERR
485 1.15 mrg (find / \( ! -fstype local -o -fstype fdesc -o -fstype kernfs \
486 1.15 mrg -o -fstype procfs \) -a -prune -o \
487 1.21 mycroft \( \( -perm -u+s -a ! -type d \) -o \
488 1.21 mycroft \( -perm -g+s -a ! -type d \) -o \
489 1.24 lukem -type b -o -type c \) -print0 | \
490 1.24 lukem xargs -0 ls -ldgTq | sort +9 > $LIST) 2> $OUTPUT
491 1.15 mrg
492 1.15 mrg # Display any errors that occurred during system file walk.
493 1.15 mrg if [ -s $OUTPUT ] ; then
494 1.28 lukem printf "Setuid/device find errors:\n" >> $ERR
495 1.28 lukem cat $OUTPUT >> $ERR
496 1.28 lukem printf "\n" >> $ERR
497 1.15 mrg fi
498 1.15 mrg
499 1.15 mrg # Display any changes in the setuid file list.
500 1.15 mrg egrep -v '^[bc]' $LIST > $TMP1
501 1.15 mrg if [ -s $TMP1 ] ; then
502 1.15 mrg # Check to make sure uudecode isn't setuid.
503 1.15 mrg if grep -w uudecode $TMP1 > /dev/null ; then
504 1.28 lukem printf "\nUudecode is setuid.\n" >> $ERR
505 1.15 mrg fi
506 1.15 mrg
507 1.48 abs CUR=$backup_dir/setuid.current
508 1.48 abs BACK=$backup_dir/setuid.backup
509 1.9 cgd
510 1.15 mrg if [ -s $CUR ] ; then
511 1.15 mrg if cmp -s $CUR $TMP1 ; then
512 1.15 mrg :
513 1.15 mrg else
514 1.15 mrg > $TMP2
515 1.15 mrg join -110 -210 -v2 $CUR $TMP1 > $OUTPUT
516 1.15 mrg if [ -s $OUTPUT ] ; then
517 1.28 lukem printf "Setuid additions:\n" >> $ERR
518 1.28 lukem tee -a $TMP2 < $OUTPUT >> $ERR
519 1.28 lukem printf "\n" >> $ERR
520 1.15 mrg fi
521 1.15 mrg
522 1.15 mrg join -110 -210 -v1 $CUR $TMP1 > $OUTPUT
523 1.15 mrg if [ -s $OUTPUT ] ; then
524 1.28 lukem printf "Setuid deletions:\n" >> $ERR
525 1.28 lukem tee -a $TMP2 < $OUTPUT >> $ERR
526 1.28 lukem printf "\n" >> $ERR
527 1.15 mrg fi
528 1.15 mrg
529 1.20 mycroft sort -k10 $TMP2 $CUR $TMP1 | \
530 1.27 lukem sed -e 's/[ ][ ]*/ /g' | \
531 1.27 lukem uniq -u > $OUTPUT
532 1.15 mrg if [ -s $OUTPUT ] ; then
533 1.28 lukem printf "Setuid changes:\n" >> $ERR
534 1.28 lukem column -t $OUTPUT >> $ERR
535 1.28 lukem printf "\n" >> $ERR
536 1.15 mrg fi
537 1.9 cgd
538 1.52 atatat backup_file update $TMP1 $CUR $BACK
539 1.9 cgd fi
540 1.15 mrg else
541 1.28 lukem printf "Setuid additions:\n" >> $ERR
542 1.28 lukem column -t $TMP1 >> $ERR
543 1.28 lukem printf "\n" >> $ERR
544 1.52 atatat backup_file add $TMP1 $CUR $BACK
545 1.9 cgd fi
546 1.15 mrg fi
547 1.15 mrg
548 1.27 lukem # Check for block and character disk devices that are readable or
549 1.27 lukem # writeable or not owned by root.operator.
550 1.15 mrg >$TMP1
551 1.61 lukem DISKLIST="ccd ch hk hp ld md ra raid rb rd rl rx \
552 1.57 simonb sd se ss uk up vnd wd xd xy"
553 1.27 lukem # DISKLIST="$DISKLIST ct mt st wt"
554 1.15 mrg for i in $DISKLIST; do
555 1.15 mrg egrep "^b.*/${i}[0-9][0-9]*[a-p]$" $LIST >> $TMP1
556 1.15 mrg egrep "^c.*/r${i}[0-9][0-9]*[a-p]$" $LIST >> $TMP1
557 1.15 mrg done
558 1.15 mrg
559 1.15 mrg awk '$3 != "root" || $4 != "operator" || $1 !~ /.rw-r-----/ \
560 1.25 lukem { printf "Disk %s is user %s, group %s, permissions %s.\n", \
561 1.25 lukem $11, $3, $4, $1; }' < $TMP1 > $OUTPUT
562 1.15 mrg if [ -s $OUTPUT ] ; then
563 1.28 lukem printf "\nChecking disk ownership and permissions.\n" >> $ERR
564 1.28 lukem cat $OUTPUT >> $ERR
565 1.28 lukem printf "\n" >> $ERR
566 1.9 cgd fi
567 1.9 cgd
568 1.15 mrg # Display any changes in the device file list.
569 1.20 mycroft egrep '^[bc]' $LIST | sort -k11 > $TMP1
570 1.15 mrg if [ -s $TMP1 ] ; then
571 1.48 abs CUR=$backup_dir/device.current
572 1.48 abs BACK=$backup_dir/device.backup
573 1.15 mrg
574 1.15 mrg if [ -s $CUR ] ; then
575 1.15 mrg if cmp -s $CUR $TMP1 ; then
576 1.15 mrg :
577 1.15 mrg else
578 1.15 mrg > $TMP2
579 1.15 mrg join -111 -211 -v2 $CUR $TMP1 > $OUTPUT
580 1.15 mrg if [ -s $OUTPUT ] ; then
581 1.28 lukem printf "Device additions:\n" >> $ERR
582 1.28 lukem tee -a $TMP2 < $OUTPUT >> $ERR
583 1.28 lukem printf "\n" >> $ERR
584 1.15 mrg fi
585 1.15 mrg
586 1.15 mrg join -111 -211 -v1 $CUR $TMP1 > $OUTPUT
587 1.15 mrg if [ -s $OUTPUT ] ; then
588 1.28 lukem printf "Device deletions:\n" >> $ERR
589 1.28 lukem tee -a $TMP2 < $OUTPUT >> $ERR
590 1.28 lukem printf "\n" >> $ERR
591 1.15 mrg fi
592 1.15 mrg
593 1.27 lukem # Report any block device change. Ignore
594 1.27 lukem # character devices, only the name is
595 1.27 lukem # significant.
596 1.15 mrg cat $TMP2 $CUR $TMP1 | \
597 1.27 lukem sed -e '/^c/d' | \
598 1.27 lukem sort -k11 | \
599 1.27 lukem sed -e 's/[ ][ ]*/ /g' | \
600 1.27 lukem uniq -u > $OUTPUT
601 1.15 mrg if [ -s $OUTPUT ] ; then
602 1.28 lukem printf "Block device changes:\n" >> $ERR
603 1.28 lukem column -t $OUTPUT >> $ERR
604 1.28 lukem printf "\n" >> $ERR
605 1.15 mrg fi
606 1.9 cgd
607 1.52 atatat backup_file update $TMP1 $CUR $BACK
608 1.9 cgd fi
609 1.15 mrg else
610 1.28 lukem printf "Device additions:\n" >> $ERR
611 1.28 lukem column -t $TMP1 >> $ERR
612 1.28 lukem printf "\n" >> $ERR
613 1.52 atatat backup_file add $TMP1 $CUR $BACK >> $ERR
614 1.9 cgd fi
615 1.28 lukem fi
616 1.28 lukem if [ -s $ERR ] ; then
617 1.28 lukem printf "\nChecking setuid files and devices:\n"
618 1.28 lukem cat $ERR
619 1.28 lukem printf "\n"
620 1.9 cgd fi
621 1.9 cgd fi
622 1.9 cgd
623 1.9 cgd # Check special files.
624 1.9 cgd # Check system binaries.
625 1.9 cgd #
626 1.9 cgd # Create the mtree tree specifications using:
627 1.9 cgd #
628 1.9 cgd # mtree -cx -pDIR -kcksum,gid,mode,nlink,size,link,time,uid > DIR.secure
629 1.38 kleink # chown root:wheel DIR.secure
630 1.16 mikel # chmod 600 DIR.secure
631 1.9 cgd #
632 1.9 cgd # Note, this is not complete protection against Trojan horsed binaries, as
633 1.9 cgd # the hacker can modify the tree specification to match the replaced binary.
634 1.9 cgd # For details on really protecting yourself against modified binaries, see
635 1.9 cgd # the mtree(8) manual page.
636 1.32 lukem #
637 1.31 lukem if checkyesno check_mtree; then
638 1.58 perry mtree -e -l -p / -f /etc/mtree/special > $OUTPUT
639 1.15 mrg if [ -s $OUTPUT ]; then
640 1.9 cgd printf "\nChecking special files and directories.\n"
641 1.9 cgd cat $OUTPUT
642 1.9 cgd fi
643 1.9 cgd
644 1.9 cgd > $OUTPUT
645 1.16 mikel for file in /etc/mtree/*.secure; do
646 1.16 mikel [ $file = '/etc/mtree/*.secure' ] && continue
647 1.9 cgd tree=`sed -n -e '3s/.* //p' -e 3q $file`
648 1.9 cgd mtree -f $file -p $tree > $TMP1
649 1.9 cgd if [ -s $TMP1 ]; then
650 1.9 cgd printf "\nChecking $tree:\n" >> $OUTPUT
651 1.9 cgd cat $TMP1 >> $OUTPUT
652 1.9 cgd fi
653 1.9 cgd done
654 1.15 mrg if [ -s $OUTPUT ]; then
655 1.9 cgd printf "\nChecking system binaries:\n"
656 1.9 cgd cat $OUTPUT
657 1.9 cgd fi
658 1.9 cgd fi
659 1.9 cgd
660 1.32 lukem # Backup disklabels of available disks
661 1.32 lukem #
662 1.32 lukem if checkyesno check_disklabels; then
663 1.32 lukem # generate list of old disklabels and remove them
664 1.48 abs ls -1d $backup_dir/disklabel.* 2>/dev/null |
665 1.52 atatat egrep -v '\.(backup|current)(,v)?$' > $LABELS
666 1.32 lukem xargs rm < $LABELS
667 1.32 lukem
668 1.63 lukem disks=`iostat -x | awk 'NR > 1 && $1 !~ /^[cfm]d/ { print $1; }'`
669 1.32 lukem for i in $disks; do
670 1.48 abs dlf="$backup_dir/disklabel.$i"
671 1.32 lukem disklabel $i > $dlf 2>/dev/null
672 1.32 lukem done
673 1.32 lukem
674 1.32 lukem # append list of new disklabels, sort list
675 1.48 abs ls -1d $backup_dir/disklabel.* 2>/dev/null |
676 1.52 atatat egrep -v '\.(backup|current)(,v)?$' >> $LABELS
677 1.32 lukem sort -u -o $LABELS $LABELS
678 1.62 atatat CHANGELIST="$LABELS $CHANGELIST"
679 1.62 atatat fi
680 1.62 atatat
681 1.62 atatat # Check for changes in the list of installed pkgs
682 1.62 atatat #
683 1.62 atatat if checkyesno check_pkgs && [ -d $pkg_dbdir ]; then
684 1.62 atatat pkgs=$backup_dir/pkgs
685 1.62 atatat ( cd $pkg_dbdir
686 1.62 atatat pkg_info | sort
687 1.62 atatat echo ""
688 1.62 atatat find . \( -name +REQUIRED_BY -o -name +CONTENTS \) -print0 |
689 1.62 atatat xargs -0 ls -l | sort -t. +1 | sed -e 's, \./, ,'
690 1.62 atatat ) > $pkgs
691 1.62 atatat echo $pkgs > $PKGS
692 1.62 atatat CHANGELIST="$PKGS $CHANGELIST"
693 1.32 lukem fi
694 1.32 lukem
695 1.9 cgd # List of files that get backed up and checked for any modifications. Each
696 1.48 abs # file is expected to have two backups, $backup_dir/file.{current,backup}.
697 1.9 cgd # Any changes cause the files to rotate.
698 1.32 lukem #
699 1.31 lukem if checkyesno check_changelist && [ -s /etc/changelist ] ; then
700 1.32 lukem CHANGELIST="/etc/changelist $CHANGELIST"
701 1.32 lukem fi
702 1.32 lukem
703 1.32 lukem if [ -n "$CHANGELIST" ]; then
704 1.32 lukem for file in `egrep -hv "^#|$MP" $CHANGELIST`; do
705 1.54 atatat # old changelist backup names
706 1.54 atatat OCUR=$backup_dir/${file##*/}.current
707 1.54 atatat OBACK=$backup_dir/${file##*/}.backup
708 1.54 atatat # new changelist backup names
709 1.54 atatat CUR=$backup_dir$file.current
710 1.54 atatat BACK=$backup_dir$file.backup
711 1.54 atatat # roll over old backups
712 1.54 atatat if [ ! -d ${CUR%/*} ]; then
713 1.54 atatat mkdir -p ${CUR%/*}
714 1.54 atatat fi
715 1.54 atatat if [ -f $OCUR -a ! -f $CUR ]; then
716 1.54 atatat mv $OCUR $CUR
717 1.54 atatat fi
718 1.54 atatat if [ -f $OCUR,v -a ! -f $CUR,v ]; then
719 1.54 atatat mv $OCUR,v $CUR,v
720 1.54 atatat fi
721 1.54 atatat if [ -f $OBACK -a ! -f $BACK ]; then
722 1.54 atatat mv $OBACK $BACK
723 1.54 atatat fi
724 1.54 atatat # and down to work
725 1.30 mycroft if [ -f $file ]; then
726 1.30 mycroft if [ -f $CUR ] ; then
727 1.9 cgd diff $CUR $file > $OUTPUT
728 1.9 cgd if [ -s $OUTPUT ] ; then
729 1.9 cgd printf "\n======\n%s diffs (OLD < > NEW)\n======\n" $file
730 1.9 cgd cat $OUTPUT
731 1.52 atatat backup_file update $file $CUR $BACK
732 1.9 cgd fi
733 1.9 cgd else
734 1.30 mycroft printf "\n======\n%s added\n======\n" $file
735 1.30 mycroft diff /dev/null $file
736 1.52 atatat backup_file add $file $CUR $BACK
737 1.30 mycroft fi
738 1.30 mycroft else
739 1.30 mycroft if [ -f $CUR ]; then
740 1.30 mycroft printf "\n======\n%s removed\n======\n" $file
741 1.30 mycroft diff $CUR /dev/null
742 1.52 atatat backup_file remove $file $CUR $BACK
743 1.9 cgd fi
744 1.9 cgd fi
745 1.9 cgd done
746 1.44 ad fi
747 1.44 ad
748 1.44 ad if [ -f /etc/security.local ]; then
749 1.44 ad echo ""
750 1.44 ad echo "Running /etc/security.local:"
751 1.44 ad . /etc/security.local
752 1.9 cgd fi
753