security revision 1.73 1 1.1 cgd #!/bin/sh -
2 1.1 cgd #
3 1.73 lukem # $NetBSD: security,v 1.73 2001/11/09 09:01:20 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.15 mrg -o -fstype procfs \) -a -prune -o \
572 1.21 mycroft \( \( -perm -u+s -a ! -type d \) -o \
573 1.21 mycroft \( -perm -g+s -a ! -type d \) -o \
574 1.24 lukem -type b -o -type c \) -print0 | \
575 1.24 lukem xargs -0 ls -ldgTq | sort +9 > $LIST) 2> $OUTPUT
576 1.15 mrg
577 1.15 mrg # Display any errors that occurred during system file walk.
578 1.15 mrg if [ -s $OUTPUT ] ; then
579 1.28 lukem printf "Setuid/device find errors:\n" >> $ERR
580 1.28 lukem cat $OUTPUT >> $ERR
581 1.28 lukem printf "\n" >> $ERR
582 1.15 mrg fi
583 1.15 mrg
584 1.15 mrg # Display any changes in the setuid file list.
585 1.15 mrg egrep -v '^[bc]' $LIST > $TMP1
586 1.15 mrg if [ -s $TMP1 ] ; then
587 1.15 mrg # Check to make sure uudecode isn't setuid.
588 1.15 mrg if grep -w uudecode $TMP1 > /dev/null ; then
589 1.28 lukem printf "\nUudecode is setuid.\n" >> $ERR
590 1.15 mrg fi
591 1.15 mrg
592 1.67 lukem file=$work_dir/setuid
593 1.67 lukem migrate_file "$backup_dir/setuid" "$file"
594 1.67 lukem CUR=${file}.current
595 1.67 lukem BACK=${file}.backup
596 1.15 mrg if [ -s $CUR ] ; then
597 1.15 mrg if cmp -s $CUR $TMP1 ; then
598 1.15 mrg :
599 1.15 mrg else
600 1.15 mrg > $TMP2
601 1.15 mrg join -110 -210 -v2 $CUR $TMP1 > $OUTPUT
602 1.15 mrg if [ -s $OUTPUT ] ; then
603 1.28 lukem printf "Setuid additions:\n" >> $ERR
604 1.28 lukem tee -a $TMP2 < $OUTPUT >> $ERR
605 1.28 lukem printf "\n" >> $ERR
606 1.15 mrg fi
607 1.15 mrg
608 1.15 mrg join -110 -210 -v1 $CUR $TMP1 > $OUTPUT
609 1.15 mrg if [ -s $OUTPUT ] ; then
610 1.28 lukem printf "Setuid deletions:\n" >> $ERR
611 1.28 lukem tee -a $TMP2 < $OUTPUT >> $ERR
612 1.28 lukem printf "\n" >> $ERR
613 1.15 mrg fi
614 1.15 mrg
615 1.20 mycroft sort -k10 $TMP2 $CUR $TMP1 | \
616 1.27 lukem sed -e 's/[ ][ ]*/ /g' | \
617 1.27 lukem uniq -u > $OUTPUT
618 1.15 mrg if [ -s $OUTPUT ] ; then
619 1.28 lukem printf "Setuid changes:\n" >> $ERR
620 1.28 lukem column -t $OUTPUT >> $ERR
621 1.28 lukem printf "\n" >> $ERR
622 1.15 mrg fi
623 1.9 cgd
624 1.52 atatat backup_file update $TMP1 $CUR $BACK
625 1.9 cgd fi
626 1.15 mrg else
627 1.28 lukem printf "Setuid additions:\n" >> $ERR
628 1.28 lukem column -t $TMP1 >> $ERR
629 1.28 lukem printf "\n" >> $ERR
630 1.52 atatat backup_file add $TMP1 $CUR $BACK
631 1.9 cgd fi
632 1.15 mrg fi
633 1.15 mrg
634 1.27 lukem # Check for block and character disk devices that are readable or
635 1.27 lukem # writeable or not owned by root.operator.
636 1.15 mrg >$TMP1
637 1.61 lukem DISKLIST="ccd ch hk hp ld md ra raid rb rd rl rx \
638 1.57 simonb sd se ss uk up vnd wd xd xy"
639 1.27 lukem # DISKLIST="$DISKLIST ct mt st wt"
640 1.15 mrg for i in $DISKLIST; do
641 1.15 mrg egrep "^b.*/${i}[0-9][0-9]*[a-p]$" $LIST >> $TMP1
642 1.15 mrg egrep "^c.*/r${i}[0-9][0-9]*[a-p]$" $LIST >> $TMP1
643 1.15 mrg done
644 1.15 mrg
645 1.15 mrg awk '$3 != "root" || $4 != "operator" || $1 !~ /.rw-r-----/ \
646 1.25 lukem { printf "Disk %s is user %s, group %s, permissions %s.\n", \
647 1.25 lukem $11, $3, $4, $1; }' < $TMP1 > $OUTPUT
648 1.15 mrg if [ -s $OUTPUT ] ; then
649 1.28 lukem printf "\nChecking disk ownership and permissions.\n" >> $ERR
650 1.28 lukem cat $OUTPUT >> $ERR
651 1.28 lukem printf "\n" >> $ERR
652 1.9 cgd fi
653 1.9 cgd
654 1.15 mrg # Display any changes in the device file list.
655 1.20 mycroft egrep '^[bc]' $LIST | sort -k11 > $TMP1
656 1.15 mrg if [ -s $TMP1 ] ; then
657 1.67 lukem file=$work_dir/device
658 1.67 lukem migrate_file "$backup_dir/device" "$file"
659 1.67 lukem CUR=${file}.current
660 1.67 lukem BACK=${file}.backup
661 1.15 mrg
662 1.15 mrg if [ -s $CUR ] ; then
663 1.15 mrg if cmp -s $CUR $TMP1 ; then
664 1.15 mrg :
665 1.15 mrg else
666 1.15 mrg > $TMP2
667 1.15 mrg join -111 -211 -v2 $CUR $TMP1 > $OUTPUT
668 1.15 mrg if [ -s $OUTPUT ] ; then
669 1.28 lukem printf "Device additions:\n" >> $ERR
670 1.28 lukem tee -a $TMP2 < $OUTPUT >> $ERR
671 1.28 lukem printf "\n" >> $ERR
672 1.15 mrg fi
673 1.15 mrg
674 1.15 mrg join -111 -211 -v1 $CUR $TMP1 > $OUTPUT
675 1.15 mrg if [ -s $OUTPUT ] ; then
676 1.28 lukem printf "Device deletions:\n" >> $ERR
677 1.28 lukem tee -a $TMP2 < $OUTPUT >> $ERR
678 1.28 lukem printf "\n" >> $ERR
679 1.15 mrg fi
680 1.15 mrg
681 1.27 lukem # Report any block device change. Ignore
682 1.27 lukem # character devices, only the name is
683 1.27 lukem # significant.
684 1.15 mrg cat $TMP2 $CUR $TMP1 | \
685 1.27 lukem sed -e '/^c/d' | \
686 1.27 lukem sort -k11 | \
687 1.27 lukem sed -e 's/[ ][ ]*/ /g' | \
688 1.27 lukem uniq -u > $OUTPUT
689 1.15 mrg if [ -s $OUTPUT ] ; then
690 1.28 lukem printf "Block device changes:\n" >> $ERR
691 1.28 lukem column -t $OUTPUT >> $ERR
692 1.28 lukem printf "\n" >> $ERR
693 1.15 mrg fi
694 1.9 cgd
695 1.52 atatat backup_file update $TMP1 $CUR $BACK
696 1.9 cgd fi
697 1.15 mrg else
698 1.28 lukem printf "Device additions:\n" >> $ERR
699 1.28 lukem column -t $TMP1 >> $ERR
700 1.28 lukem printf "\n" >> $ERR
701 1.52 atatat backup_file add $TMP1 $CUR $BACK >> $ERR
702 1.9 cgd fi
703 1.28 lukem fi
704 1.28 lukem if [ -s $ERR ] ; then
705 1.28 lukem printf "\nChecking setuid files and devices:\n"
706 1.28 lukem cat $ERR
707 1.28 lukem printf "\n"
708 1.9 cgd fi
709 1.9 cgd fi
710 1.9 cgd
711 1.9 cgd # Check special files.
712 1.9 cgd # Check system binaries.
713 1.9 cgd #
714 1.9 cgd # Create the mtree tree specifications using:
715 1.67 lukem # mtree -cx -pDIR -kmd5,uid,gid,mode,nlink,size,link,time > DIR.secure
716 1.38 kleink # chown root:wheel DIR.secure
717 1.67 lukem # chmod u+r,go= DIR.secure
718 1.9 cgd #
719 1.9 cgd # Note, this is not complete protection against Trojan horsed binaries, as
720 1.9 cgd # the hacker can modify the tree specification to match the replaced binary.
721 1.9 cgd # For details on really protecting yourself against modified binaries, see
722 1.9 cgd # the mtree(8) manual page.
723 1.32 lukem #
724 1.31 lukem if checkyesno check_mtree; then
725 1.67 lukem for file in $special_files; do
726 1.67 lukem [ ! -s $file ] && continue
727 1.67 lukem mtree -e -l -p / -f $file
728 1.67 lukem done > $OUTPUT
729 1.15 mrg if [ -s $OUTPUT ]; then
730 1.9 cgd printf "\nChecking special files and directories.\n"
731 1.9 cgd cat $OUTPUT
732 1.9 cgd fi
733 1.9 cgd
734 1.16 mikel for file in /etc/mtree/*.secure; do
735 1.16 mikel [ $file = '/etc/mtree/*.secure' ] && continue
736 1.9 cgd tree=`sed -n -e '3s/.* //p' -e 3q $file`
737 1.9 cgd mtree -f $file -p $tree > $TMP1
738 1.9 cgd if [ -s $TMP1 ]; then
739 1.67 lukem printf "\nChecking $tree:\n"
740 1.67 lukem cat $TMP1
741 1.9 cgd fi
742 1.67 lukem done > $OUTPUT
743 1.15 mrg if [ -s $OUTPUT ]; then
744 1.9 cgd printf "\nChecking system binaries:\n"
745 1.9 cgd cat $OUTPUT
746 1.9 cgd fi
747 1.9 cgd fi
748 1.9 cgd
749 1.32 lukem # Backup disklabels of available disks
750 1.32 lukem #
751 1.32 lukem if checkyesno check_disklabels; then
752 1.67 lukem # migrate old disklabels
753 1.67 lukem for file in `ls -1d $backup_dir/$backup_dir/disklabel.* \
754 1.67 lukem $backup_dir/disklabel.* 2>/dev/null`; do
755 1.67 lukem migrate_file "$file" "$work_dir/${file##*/}"
756 1.67 lukem done
757 1.67 lukem
758 1.67 lukem # generate list of old disklabels & fdisks and remove them
759 1.67 lukem ls -1d $work_dir/disklabel.* $work_dir/fdisk.* 2>/dev/null |
760 1.52 atatat egrep -v '\.(backup|current)(,v)?$' > $LABELS
761 1.32 lukem xargs rm < $LABELS
762 1.32 lukem
763 1.67 lukem # generate disklabels of all disks excluding: cd fd md
764 1.63 lukem disks=`iostat -x | awk 'NR > 1 && $1 !~ /^[cfm]d/ { print $1; }'`
765 1.32 lukem for i in $disks; do
766 1.67 lukem disklabel $i > "$work_dir/disklabel.$i" 2>/dev/null
767 1.32 lukem done
768 1.32 lukem
769 1.67 lukem # if fdisk is available, generate fdisks for: ed ld sd wd
770 1.67 lukem if [ -x /sbin/fdisk ]; then
771 1.67 lukem disks=`iostat -x| awk 'NR > 1 && $1 ~ /^[elsw]d/ { print $1; }'`
772 1.67 lukem for i in $disks; do
773 1.67 lukem /sbin/fdisk $i > "$work_dir/fdisk.$i" 2>/dev/null
774 1.67 lukem done
775 1.67 lukem fi
776 1.67 lukem
777 1.67 lukem # append list of new disklabels and fdisks
778 1.67 lukem ls -1d $work_dir/disklabel.* $work_dir/fdisk.* 2>/dev/null |
779 1.52 atatat egrep -v '\.(backup|current)(,v)?$' >> $LABELS
780 1.62 atatat CHANGELIST="$LABELS $CHANGELIST"
781 1.62 atatat fi
782 1.62 atatat
783 1.62 atatat # Check for changes in the list of installed pkgs
784 1.62 atatat #
785 1.65 lukem if checkyesno check_pkgs && [ -d $pkgdb_dir ]; then
786 1.67 lukem pkgs=$work_dir/pkgs
787 1.67 lukem migrate_file "$backup_dir/pkgs" "$pkgs"
788 1.65 lukem ( cd $pkgdb_dir
789 1.62 atatat pkg_info | sort
790 1.62 atatat echo ""
791 1.62 atatat find . \( -name +REQUIRED_BY -o -name +CONTENTS \) -print0 |
792 1.72 lukem xargs -0 ls -ldgTq | sort -t. +1 | sed -e 's, \./, ,'
793 1.62 atatat ) > $pkgs
794 1.67 lukem echo "$pkgs" > $PKGS
795 1.62 atatat CHANGELIST="$PKGS $CHANGELIST"
796 1.32 lukem fi
797 1.32 lukem
798 1.67 lukem # List of files that get backed up and checked for any modifications.
799 1.9 cgd # Any changes cause the files to rotate.
800 1.32 lukem #
801 1.67 lukem if checkyesno check_changelist ; then
802 1.67 lukem for file in $special_files; do
803 1.67 lukem [ ! -s $file ] && continue
804 1.67 lukem mtree -D -k type -f $file -E exclude |
805 1.67 lukem sed '/^type=file/!d ; s/type=file \.//'
806 1.67 lukem done > $CHANGEFILES
807 1.67 lukem
808 1.68 lukem # Add other files which might dynamically exist:
809 1.67 lukem # /etc/ifconfig.*
810 1.67 lukem # /etc/raid*.conf
811 1.68 lukem # /etc/rc.d/*
812 1.67 lukem # /etc/rc.conf.d/*
813 1.68 lukem #
814 1.68 lukem ls -1d $backup_dir/etc/ifconfig.*.current \
815 1.68 lukem $backup_dir/etc/raid*.conf.current \
816 1.68 lukem $backup_dir/etc/rc.d/*.current \
817 1.68 lukem $backup_dir/etc/rc.conf.d/*.current \
818 1.68 lukem 2>/dev/null |
819 1.67 lukem sed "s,^$backup_dir/,/, ; s,\.current$,," >> $CHANGEFILES
820 1.68 lukem ls -1d /etc/ifconfig.* \
821 1.68 lukem /etc/raid*.conf \
822 1.68 lukem /etc/rc.d/* \
823 1.68 lukem /etc/rc.conf.d/* \
824 1.67 lukem 2>/dev/null >> $CHANGEFILES
825 1.67 lukem
826 1.68 lukem # Add /etc/changelist
827 1.68 lukem #
828 1.68 lukem if [ -s /etc/changelist ]; then
829 1.68 lukem grep -v '^#' /etc/changelist >> $CHANGEFILES
830 1.68 lukem fi
831 1.68 lukem
832 1.67 lukem CHANGELIST="$CHANGEFILES $CHANGELIST"
833 1.67 lukem fi
834 1.67 lukem
835 1.67 lukem # Special case backups, including the master password file and
836 1.67 lukem # ssh private host keys. The normal backup mechanisms for
837 1.67 lukem # $check_changelist (see below) also print out the actual file
838 1.67 lukem # differences and we don't want to do that for these files
839 1.67 lukem #
840 1.67 lukem echo $MP > $TMP1 # always add /etc/master.passwd
841 1.67 lukem for file in $special_files; do
842 1.67 lukem [ ! -s $file ] && continue
843 1.70 lukem mtree -D -k type -f $file -I nodiff |
844 1.67 lukem sed '/^type=file/!d ; s/type=file \.//'
845 1.67 lukem done >> $TMP1
846 1.73 lukem grep -v '^$' $TMP1 | sort -u > $TMP2
847 1.68 lukem
848 1.69 lukem while read file; do
849 1.67 lukem backup_and_diff "$file" no
850 1.69 lukem done < $TMP2
851 1.67 lukem
852 1.32 lukem
853 1.32 lukem if [ -n "$CHANGELIST" ]; then
854 1.73 lukem grep -h -v '^$' $CHANGELIST | sort -u > $TMP1
855 1.68 lukem comm -23 $TMP1 $TMP2 | while read file; do
856 1.67 lukem backup_and_diff "$file" yes
857 1.9 cgd done
858 1.44 ad fi
859 1.44 ad
860 1.44 ad if [ -f /etc/security.local ]; then
861 1.44 ad echo ""
862 1.44 ad echo "Running /etc/security.local:"
863 1.44 ad . /etc/security.local
864 1.9 cgd fi
865