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