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