#!/usr/pkg/bin/bash
#
#   logrider.sh: Log file checker
#
#   Based on the logcheck by Craig Rowland <crowland@psionic.com>,
#   but rewritten from scratch with lot of important improvements:
#
#   1) strings matched any filter are excluded from processing by next filters
#   2) filters may be dynamically composed from directory with small sub-filters
#   3) configuration separated from program to standalone file, i.e., LogRider
#      may be easily adopted to new platform without rewriting program body
#   4) no more logtail binary that must be compiled on any target platform
#
#   Written by Ilya Evseev <evseev@ucvt.ru> at Jan 2002.
#   Distributed under terms of GNU GPL.
#

doit=
if [ "$1" = "-d" ]; then
	shift
	doit=echo
	# set -x
fi

if [ "$1" = "-V" -o "$1" = "--version" ]; then
	echo "0.2"
	exit 0
fi

#=======================================================================
##
###	Configure options
##
#=======================================================================

PKGNAME=logrider

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#   Assign defaults
#

: ${CONF_DIR:=/usr/pkg/etc/${PKGNAME}}
: ${CONF_FILE:=${CONF_DIR}/${PKGNAME}.conf}
: ${SYSADMIN:=root}
: ${LOGTAIL:=/usr/pkg/bin/logtail}
: ${LOGTEMP:=/var/lib/${PKGNAME}}
: ${GREP:=egrep}
: ${MAIL:=mail}
: ${LOGDIR:=/var/log}

: ${HACKING_FILE:=$CONF_DIR/hacking}
: ${VIOLATIONS_FILE:=$CONF_DIR/violations}
: ${VIOLATIONS_IGNORE_FILE:=$CONF_DIR/violations.ignore}
: ${IGNORE_FILE:=$CONF_DIR/ignore}

: ${LOG_SOURCES:="$LOGDIR/messages $LOGDIR/secure $LOGDIR/mail/info $LOGDIR/mail/warnings"}

HOSTNAME=`hostname`
DATE=`date +%m/%d/%y:%H.%M`

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#   Reading configuration from file
#

if [ -n "$1" ]; then
	CONF_FILE=$1
	shift
fi

if [ -r $CONF_FILE ]; then
	. $CONF_FILE || exit 1
else
	echo "Error: cannot read configuration from $CONF_FILE, exit."
	exit 1
fi

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#   Assign filenames for temporary data
#

[ -n "$1" ] && SUFFIX=$1 || SUFFIX=$$
CHECKLIST=$LOGTEMP/check.$SUFFIX
OUTPUT=$LOGTEMP/checkoutput.$SUFFIX
REPORT=$LOGTEMP/checkreport.$SUFFIX
FILTER=$LOGTEMP/checkfilter.$SUFFIX

umask 077

#=======================================================================
##
###	Subroutines
##
#=======================================================================

function debug_echo()
{
	$doit : $*
}

function clean_temp_files()
{
	for fname in $CHECKLIST $OUTPUT $REPORT $FILTER; do
		rm -f $fname
		if [ -e $fname ]; then
			echo "
Log file $fname exist that cannot be removed.
This may be an attempt to spoof the log checker.
			" | $MAIL -s "$HOSTNAME $DATE ACTIVE SYSTEM ATTACK!" $SYSADMIN
			return 1
		fi
	done
	return 0
}

function make_single_filter()	#  $1 = srcpath  -->  $SINGLE_FILTER = destpath
{
	if [ -f "$1" ]; then
		SINGLE_FILTER=$1
	elif [ -d "$1" ]; then
		rm -f $FILTER
		cat $1/* >> $FILTER
		SINGLE_FILTER=$FILTER
	else
		echo $1 not found...
		exit 1
	fi
	return 0
}

function exclude_strings_basic()
	#  $1 = exclude filter, $2* = additional grep options
{
	$GREP -v -f $* $CHECKLIST > $OUTPUT
	mv -f $OUTPUT $CHECKLIST
}

function exclude_strings()		#  $1 = filter path
{
	make_single_filter $1 || return 1
	exclude_strings_basic $SINGLE_FILTER
}

function out2report()			#  $* = hint lines
{
	echo "" >> $REPORT
	for line in "$@"; do echo $line >> $REPORT; done
	if [ -r $OUTPUT ]
		then cat $OUTPUT    >> $REPORT
		else cat $CHECKLIST >> $REPORT
	fi
}

function checklist_have_strings()	#  $1 = filters list, $2* = hint lines
{
	result=1    # assume "false"
	debug_echo $2 "..."
	make_single_filter $1 || return 1
	if $GREP -i -f $SINGLE_FILTER $CHECKLIST > $OUTPUT; then
		result=0    # assume "true"
		shift
		out2report "$@"
	fi
	exclude_strings_basic $SINGLE_FILTER -i
	return $result
}

#=======================================================================
##
###	Prepare environment
##
#=======================================================================

clean_temp_files || return 1

for f in $LOG_SOURCES; do
	$LOGTAIL $f >> $CHECKLIST
done

FOUND=0
ATTACK=0

if [ ! -s $CHECKLIST ]; then
	debug_echo "Nothing to check, exit."
	rm -f $CHECKLIST	
	exit 0
fi

#=======================================================================
##
###	Do filtering
##
#=======================================================================

if checklist_have_strings "$HACKING_FILE" \
	"Active System Attack Alerts" \
	"=-=-=-=-=-=-=-=-=-=-=-=-=-="
then
	FOUND=1
	ATTACK=1
fi

exclude_strings $VIOLATIONS_IGNORE_FILE

if checklist_have_strings $VIOLATIONS_FILE \
	"Security Violations" \
	"=-=-=-=-=-=-=-=-=-="
then
	FOUND=1
fi

exclude_strings "$IGNORE_FILE"

if [ -s "$CHECKLIST" ]; then
	out2report "Unusual System Events" \
	           "=-=-=-=-=-=-=-=-=-=-="
	FOUND=1
fi

if [ "$ATTACK" -eq 1 ]; then
	cat $REPORT | $MAIL -s "$HOSTNAME $DATE ACTIVE SYSTEM ATTACK!" $SYSADMIN
elif [ "$FOUND" -eq 1 ]; then
	cat $REPORT | $MAIL -s "$HOSTNAME $DATE system check" $SYSADMIN 
fi

test -n "$KEEP_TEMP_FILES" || clean_temp_files

## EOF ##
