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