#!/bin/sh
#
# blacklight - file system attribute and checksum database. Unix/Linux.
#
# Checks for changes in file attributes, modification date, and checksum.
#  Written for Solaris 7, 8 & 9, works fine on Red Hat 7.1. Will work 
#  elsewhere with minor changes. Standard use would be to run with "-i" to
#  initialise the database, then periodically run without "-i" to check for
#  changed files.
#
# 23-Jun-2003	ver 1.30
#
#
# USAGE: blacklight [-ivh][-f database][-x exclude_file][files ...]
#
# eg, blacklight -i                # initialise checksum database
#     blacklight -i /etc /var      # init database from given dirs and files
#     blacklight                   # check database vs filesystem
#     blacklight -if /etc/my.db    # init using a different database filename
#     blacklight -ix ignore.txt    # init, exclude files & dirs in ignore.txt
#
#	-i	Initialise database. Use this first, then run without "-i".
#	-v	Verbose. More info. During checks, it will display changes.
#	-h	Usage help.
#	-f	Database file to use. Defaults to /etc/blacklight.db
#	-x	Exclude file. Contains files and dirs to ignore during init.
#		This is a text file containing full paths to files and dirs
#		for the files we expect to change, such as /etc/blacklight.db
#	files	This is a list of directories and files that should be 
#		recorded in the database. By default, some main OS dirs such
#		as "/etc /sbin" are set below in the "dirs" variable. Only
#		used during initialisation.
#
# COPYRIGHT: Copyright (c) 2003 Brendan Gregg.
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
#  (http://www.gnu.org/copyleft/gpl.html)
#
# 28-May-2003	Brendan Gregg	Created this.
# 23-Jun-2003	Brendan Gregg	Added command line features.


#
# --- Setup Vars and Subs ---
#
dirs="/etc /sbin /kernel /usr/bin /usr/sbin"	# dirs to check
database=/etc/blacklight.db			# database file
PATH=/usr/bin:/usr/sbin:$PATH
fields=`ls -ld $0 | wc -w`
xfile=""
verbose=0
initialise=0
if cksum $0 > /dev/null 2>&1; then
	checksum=cksum				# check cksum works,
else
	checksum=sum				# may use "md5"? ...
fi

# usage - print the usage message.
#
usage() {
	echo >&2 "USAGE: $0 [-ivh][-f database][-x exclude_file][files ...]
   eg, $0 -i               # initialise checksum database
       $0                  # check database vs filesystem
       $0 -if /etc/my.db   # init using a different database filename
       $0 -ix ignore.txt   # init, exclude files & dirs in ignore.txt"
}

# vecho - print message if $verbose if true.
#
vecho() {
	if [ $verbose -eq 1 ]; then echo $*; fi
}


#
# --- Parse Options ---
#
set -- `getopt vhif:x: $*`
if [ $? -ne 0 ]; then
	usage
	exit 1
fi

while [ $# -ne 0 ]
do
        case "$1" in
        -v)     verbose=1
                ;;
        -h)     usage
                exit 0
                ;;
        -f)     database=$2
		shift
                ;;
	-i)	initialise=1
		;;
	-x)	xfile=$2			# xfile is an exclude list
                if [ ! -r $xfile ]; then
                   echo >&2 "ERROR: $xfile, is not readable."
                   exit 2
                fi
		shift
		;;
        --)     shift
		break 
		;;
        esac
	shift
done
if [ "$1" != "" ]; then
	dirs=$*
fi


#
# --- Initialise database ---
#
if [ $initialise -eq 1 ]; then
	echo "Initialising Database..."
( 	for dir in $dirs; do
		if [ "$xfile" = "" ]; then
			find $dir | xargs ls -lLd
		else
			find $dir | xargs ls -lLd | fgrep -vf $xfile
		fi
		vecho "Inode data from: $dir" >&2
	done
	echo "------------"
	for dir in $dirs; do
                if [ "$xfile" = "" ]; then
			find $dir -type f | xargs $checksum
                else
			find $dir -type f | xargs $checksum | fgrep -vf $xfile
		fi
		vecho "Checksum data from: $dir" >&2
	done
)	> $database
	ls -l $database
	echo "Done."
	exit
fi

if [ ! -f "$database" ]; then
	echo >&2 "ERROR: Database $database not found.
       To initialise database use: $0 -i"
	exit 1
fi


#
# --- Run Checks ---
#
vecho "Filesystem Checks,"
cat $database | ( 
	vecho "Checking attributes..."
	while :; do
		read line
		if [ "$line" = ------------ ]; then break; fi
		set -- $line
		if [ "$fields" -eq 9 ]; then
			now=`ls -lLd $9`		# SVR4 ls
			file=$9
		else
			now=`ls -lLd $8`		# BSD ls
			file=$8
		fi
		if [ "$line" != "$now" ]; then
			if [ $verbose -eq 1 ]; then
				echo "File attribute change,"
				echo "now: $now"
				echo "old: $line"
				echo "--------"
			else
				echo "File attribute change: $file" 
			fi
		fi
	done
	vecho "Checking checksums..."
	while read line; do
		set -- $line
		now=`$checksum $3`
		file=$3
		if [ "$line" != "$now" ]; then
			if [ $verbose -eq 1 ]; then
				echo "Checksum change,"
				echo "now: $now"
				echo "old: $line"
				echo "--------"
			else
				echo "Checksum change: $file"
			fi
		fi
	done )
vecho "Done."

