[alt.sources] Check system files for changes

djl@dplace.UUCP (Dave Lampe) (03/28/89)

This is the first distribution of two shell scripts that increase my peace
of mind in the face of virus scares.
#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#	Run the following text with /bin/sh to create:
#	  README
#	  buildlist
#	  checksys
#
echo "x - extracting README (Text)"
sed 's/^X//' << 'SHAR_EOF' > README &&
XThese are two shells I wrote in attempt to detect changes in system files,
Xeither due to a virus infecting the system or due to dumb mistakes.
XI know they run on System V, they should run on BSD 4.X, but I can't
Xcheck.
XI check the obvious things like /unix, /bin/*, /usr/bin/*. I also check
X/usr/lib, /usr/include, /usr/lib/uucp and a few other local directories.
XI run checksys from the crontab once a week and mail the results to me.
XThe entry is:
X15 1 * * 1 /u/djl/security/checksys | mail djl
X
XOne thing to remember is that the checkfile built by buildlist will
Xneed editing by hand. For example /tmp should not have the files checked,
Xthe status files in uucp cannot be checksumed or sized.
X
XThere is of course one major security hole. Since the checklist is kept
Xon the system, anyone who has gained root access can change the list
Xto hide his misdeeds. You may want to change the name of the list to make it
Xa little less obvious.
X
XIf anyone has any suggestions, feel free to send me updates.
X
XThis is not copywrited, if you can make any money from this, more power
Xto you.
X
X
X
XDave Lampe
X{ames | lll-tis | sun | pyramid}!pacbell!dplace!djl
X(415) 455-1571
SHAR_EOF
chmod 0644 README || echo "restore of README fails"
set `wc -c README`;Sum=$1
if test "$Sum" != "1162"
then echo original size 1162, current size $Sum;fi
echo "x - extracting buildlist (Text)"
sed 's/^X//' << 'SHAR_EOF' > buildlist &&
X# @(#)buildlist.sh	1.1  DeltaDate 3/27/89   ExtrDate 3/27/89
X
X# This shell will build the checklist command file
X#Usage is: buildlist [filename]
X
Xmydir=`pwd`
Xcd /
X
X# Check if output file specified
X#
Xif [ $# -eq 1 ]
Xthen
X    ofile="$1"
Xelse
X    ofile="checklist"	# Use default
Xfi
Xif
X    expr "$ofile" : '^/' >/dev/null
Xthen
X    :
Xelse
X    ofile=$mydir/$ofile		# Make output path absolute
Xfi
X
X>$ofile
Xtrap "rm -f /tmp/t$$ ; exit" 1 2 3 15
X#
X# Loop reading files/directories to check
X#
Xwhile 
X    echo "File/Directory to check: \c"
X    read fname
Xdo
X    if [ -z "$fname" ]		# Terminate on null input
X    then
X	break
X    fi
X
X    #make absolute pathname if not given
X    #
X    if
X	expr "$fname" : '^/' >/dev/null
X    then
X	:
X    else
X	fname=$mydir/$fname
X    fi
X
X    if [ ! -r "$fname" ]
X    then
X	echo $fname is not readable
X	continue
X    fi
X    if [ -d "$fname" ]
X    then
X	echo "$fname\t" >/tmp/t
X	#
X	# Get information about the directory
X	#
X	ls -ld $fname |
X	sed  -e 's;\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\(.*\) \(.*\);,\1, \3, \4,;' >>/tmp/t
X	#
X	# Get names of the files in the directory
X	#
X	ls -a $fname  | sed -e '/^\.$/d' -e '/^\.\.$/d' >>/tmp/t
X	ed - /tmp/t <<\EOF >/dev/null
X	    1,$s/^/		/
X	    1,2j
X	    1s/		//g
X	    w
X	    1,$-s/$/, \\/
X	    w
X	    q
XEOF
X	cat /tmp/t$$ >>$ofile
X	rm /tmp/t$$
X	#
X	echo "    Should files be checked? (y/n) \c"
X	read ans
X	if [ "$ans" != "y" ]
X	then
X	    continue
X	fi
X	#
X	# Get information about each file
X	#
X	ls -a -l $fname  | sed -e '/ \.$/d' -e '/ \.\.$/d' | \
X	sed -n -e '2,$s;\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\(.*\) \(.*\);\7   csum \1 \3 \4 \5;p' | \
X	while
X	    read name csum mode owner group size
X	do
X	    if [ -d $fname/$name ]
X	    then
X		continue;
X	    fi
X	    csum=`sum $fname/$name | sed 's/ .*//'`
X	    echo "$fname/$name\t$csum, $mode, $owner, $group, $size"
X	done >>$ofile
X
X    else	# plain file
X
X	# Get information about the file
X	#
X	ls -l $fname | \
X	sed -e 's;\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\(.*\) \(.*\);\7   csum \1 \3 \4 \5;' | \
X	while
X	    read name csum mode owner group size
X	do
X	    csum=`sum $name | sed 's/ .*//'`
X	    echo "$name\t$csum, $mode, $owner, $group, $size"
X	done >>$ofile
X    fi
X
Xdone
SHAR_EOF
chmod 0755 buildlist || echo "restore of buildlist fails"
set `wc -c buildlist`;Sum=$1
if test "$Sum" != "2231"
then echo original size 2231, current size $Sum;fi
echo "x - extracting checksys (Text)"
sed 's/^X//' << 'SHAR_EOF' > checksys &&
X# @(#)checksys.sh	1.1  DeltaDate 3/27/89   ExtrDate 3/27/89
X
X#!/bin/sh
X#This shell will check for changed files in system places.
X#The list of places to check is in a "/etc/checklist"
X#Each line in the file contains a file name or a directory name.
X#They must be absolute pathnames.
X#Lines begining with a # are comments.
X#
X#If the line contains a file name, it is followed by comma separated fields.
X#     Field	Type
X#	1	Checksum (computed by /bin/sum)
X#	2	Mode
X#	3	Owner
X#	4	Group
X#	5	Size
X#If a field is null, it will not be checked
X#
X#If the line is a directory name, following the size field may be a list
X#of 0 or more comma separated file names.  Exactly those files must appear
X#in the directory. Note that this does not check the contents of the file.
X#To do that there must be a file line also.  The line may be continued
X#with a '\' if necessary.  If the contents of the directory is not to be
X#checked, e.g. /tmp, the field must be missing -- omit the comma.
X#
X# #nothing is said about the contents of /tmp
X# /tmp		,drwxrwxrwx,root,root
X# #/lost+found must be empty
X# /lost+found	,drwxrwxrwx,root,root,,
X
X
XPATH="/usr/bin:/bin" ; export PATH
XIFS="`echo \" \t\n\c\"`" ; export IFS
XVERBOSE=
XCHECKFILE="/etc/checklist"
Xtrap "rm -f /tmp/cfiles$$ /tmp/files$$ /tmp/diff$$ ; exit" 1 2 3 15
X
X#
X#Process command options
X#
Xset -- `getopt "vf:" $*`
Xfor i in $*
Xdo
X    case $i in
X    -v) VERBOSE=1; shift;;
X    -f) CHECKFILE=$2; shift 2;;
X    --) shift; break;;
X    *) echo "usage: checksys [-v] [-f checkfile]"; exit;;
X    esac
Xdone
Xif [ -n "$1" ]
Xthen
X    CHECKFILE=$1
X    shift
Xfi
X
X#
X#Setup to read checkfile
X#
Xexec <$CHECKFILE
Xcd /
X
X#
X#Process each line
X#
Xwhile
X    read file options
Xdo
X    #check for a comment
X    if
X	expr "$file" : '^#' >/dev/null
X    then
X	continue
X    fi
X
X    if [ ! \( -f "$file" -o -d "$file" -o -c "$file" -o -b "$file" -o -p "$file" \) ]
X    then
X	echo "$file: Missing"
X	continue
X    fi
X
X    #Get each argument
X    sum=`expr "$options" : '\([^,]*\)'`
X    mode=`expr "$options" : '[^,]*,[ 	]*\([^,]*\)'`
X    owner=`expr "$options" : '[^,]*,[ 	]*[^,]*,[ 	]*\([^,]*\)'`
X    group=`expr "$options" : '[^,]*,[ 	]*[^,]*,[ 	]*[^,]*,[ 	]*\([^,]*\)'`
X    size=`expr "$options" : '[^,]*,[ 	]*[^,]*,[ 	]*[^,]*,[ 	]*[^,]*,[ 	]*\([^,]*\)'`
X
X    set -- `ls -ld $file`
X    cmode="$1"
X    clinks="$2"
X    cowner="$3"
X    cgroup="$4"
X    csize="$5"
X
X    #save field separators
X    OIFS="$IFS"
X    #set separators to comma, blank, or tab
X    IFS=', 	'
X    #
X    # Break apart the option string
X    set -- $options
X    #
X    #reset separator characters
X    IFS="$OIFS"
X
X    if [ -n "$sum" ]
X    then
X	shift
X	csum=`sum $file | sed 's/ .*//'`
X	if [ $csum -ne $sum ]
X	then
X	    echo "$file: checksum error"
X	else
X	    if [ $VERBOSE ]
X	    then
X		echo "$file: checksum OK"
X	    fi
X	fi
X    fi
X
X    if [ -n "$mode" ]
X    then
X	shift
X	if [ "$cmode" != "$mode" ]
X	then
X	    echo "$file: mode error, should be $mode, is $cmode"
X	else
X	    if [ $VERBOSE ]
X	    then
X		echo "$file: mode OK"
X	    fi
X	fi
X    fi
X
X    if [ -n "$owner" ]
X    then
X	shift
X	if [ $cowner != $owner ]
X	then
X	    echo "$file: owner error, should be $owner, is $cowner"
X	else
X	    if [ $VERBOSE ]
X	    then
X		echo "$file: owner OK"
X	    fi
X	fi
X    fi
X
X    if [ -n "$group" ]
X    then
X	shift
X	if [ $cgroup != $group ]
X	then
X	    echo "$file: group error, should be $group, is $cgroup"
X	else
X	    if [ $VERBOSE ]
X	    then
X		echo "$file: group OK"
X	    fi
X	fi
X    fi
X
X    if [ -n "$size" ]
X    then
X	shift
X	if [ $csize -ne $size ]
X	then
X	    echo "$file: size error, should be $size, is $csize"
X	else
X	    if [ $VERBOSE ]
X	    then
X		echo "$file: size OK"
X	    fi
X	fi
X    fi
X
X    # if it is a directory
X    if [ -d $file ]
X    then 
X	# and the contents are to be checked
X	if
X	    expr "$options" : '.*,.*,.*,.*,.*,' >/dev/null
X	then
X	    :
X	else
X	    continue
X	fi
X	# get list of files in directory
X	ls -a $file | sed -e '/^\.$/d' -e '/^\.\.$/d' >/tmp/files$$
X	#get list of files to check
X	>/tmp/cfiles$$
X	while [ -n "$1" ]
X	do
X	    echo "$1" >>/tmp/cfiles$$
X	    shift
X	done
X	sort -o /tmp/cfiles$$ /tmp/cfiles$$
X	#check for differences
X	if
X	    cmp /tmp/cfiles$$ /tmp/files$$ >/dev/null 2>/dev/null
X	then
X	    if [ $VERBOSE ]
X	    then
X		echo "Directory $file is OK."
X	    fi
X	else
X	    echo "In directory $file"
X	    comm -23 /tmp/cfiles$$ /tmp/files$$ >/tmp/diff$$
X	    if [ -s /tmp/diff$$ ]
X	    then
X		echo "The following files were missing:"
X		sed 's/^/    /' </tmp/diff$$
X	    fi
X	    comm -13 /tmp/cfiles$$ /tmp/files$$ >/tmp/diff$$
X	    if [ -s /tmp/diff$$ ]
X	    then
X		echo "The following files were added:"
X		sed 's/^/    /' </tmp/diff$$
X	    fi
X	fi
X	echo ""
X	rm -f /tmp/files$$ /tmp/cfiles$$ /tmp/diff$$
X
X    fi
Xdone
X
SHAR_EOF
chmod 0755 checksys || echo "restore of checksys fails"
set `wc -c checksys`;Sum=$1
if test "$Sum" != "4701"
then echo original size 4701, current size $Sum;fi
exit 0