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