#!/bin/sh
#
# $Id$
#
# The author disclaims all copyrights and releases this script into the
# public domain.
#
# Virus definitions updating utility. Intended to be a generic means of
# updating definitions for any product, but currently only supports Clam
# AntiVirus.
#
# Usage: run from cron, or from the command line with -f option to skip
# the default random delay.
# where to find freshclam command
FRESHCLAM=/usr/bin/freshclam
# where to find clamav configuration
CLAMD_CONF=/etc/clamd.conf
# timestamp file to prevent DoS due to too frequent updates
# see code below for customizing to your site
TIMESTAMP_FILE=/var/run/up-avdefs.lastupdate
# timestamp file must be new, or at least this old (mtime in minutes)
# for update to work
TIMESTAMP_AGE=5
# whether to delay for random period of time before updating
# set to "no" or use -f command line argument to disable
SLEEP=yes
# allow above to be set in preferences file
[ -f /etc/sysconfig/up-avdefs ] && . /etc/sysconfig/up-avdefs
BASENAME=`basename $0`
# script's exit code; propogate errors from apps we call
STATUS=0
# error logging routine ($1 message, $2 facility/priority)
remark () {
MESSAGE=$1
TAG=$2
if test "a$TAG" = "a" ; then
TAG="daemon.info"
fi
logger -i -t $BASENAME -p "$TAG" -- "$MESSAGE"
}
# update routines
update_clamav () {
if ! test -x $FRESHCLAM ; then
remark "freshclam not executable: file=$FRESHCLAM" "daemon.warning"
STATUS=1
return
fi
# logging done via syslog, and are checking the exit codes...
$FRESHCLAM >/dev/null 2>&1
RESULT=$?
# see freshclam manual on "RETURN CODES"
if test $RESULT = 0 ; then
remark "freshclam ok: definitions updated"
elif test $RESULT = 1 ; then
remark "freshclam ok: definitions up-to-date"
else
remark "unknown freshclam exit: status=$RESULT" "daemon.warning"
STATUS=$RESULT
fi
# poke at clamd socket, check result (way to do this without perl?)
CLAMD_SOCKET=`awk '/^LocalSocket /{print $2}' < $CLAMD_CONF`
# TODO warn if no socket to poke at?
if [ -f $CLAMD_SOCKET ]; then
RESPONSE=`perl -MIO::Socket::UNIX -le '$s = IO::Socket::UNIX->new(shift);' \
-e 'exit 1 unless $s; $s->print("RELOAD");' \
-e 'print $s->getline; $s->close' $CLAMD_SOCKET`
if [ "$RESPONSE" != "RELOADING" ]; then
remark "problem notifying clamd: response=$RESPONSE" "daemon.warning"
fi
fi
}
# process arguments
OPT=
while getopts f OPT; do
case $OPT in
f)
SLEEP=no
;;
esac
done
shift $(($OPTIND - 1))
TIMESTAMP_FILENAME=`basename $TIMESTAMP_FILE`
TIMESTAMP_DIR=`dirname $TIMESTAMP_FILE`
# check for recent update file: prevent DoS by too frequent updates
if [ -e $TIMESTAMP_FILE ]; then
if find $TIMESTAMP_DIR -name $TIMESTAMP_FILENAME -maxdepth 1 -mmin +$TIMESTAMP_AGE | \
fgrep -- $TIMESTAMP_FILENAME >/dev/null 2>&1; then
:
else
remark "timestamp too recent for update"
exit 1
fi
fi
# Sleep for random time period by default. This limits simultaneous runs
# of this script (on different hosts) from hitting the update server at
# the same time. With the freshclam proxy option, delayed runs should
# get proxy cache hits.
if ! test $SLEEP = "no" ; then
# KLUGE limit sleep to 0 - 99 seconds, either from shell RANDOM
# variable if available, or script's process ID
MYRAND=$RANDOM
MYRAND=${MYRAND:=$$}
if test $MYRAND -gt 99 ; then
sleep `echo $MYRAND | sed 's/.*\(..\)$/\1/' | sed 's/^0//'`
elif test $MYRAND -gt 0 ; then
sleep $MYRAND
fi
fi
# call various update functions (multiple updates will complicate STATUS
# handling if only some updates fail)
update_clamav
if [ $STATUS -eq 0 ]; then
touch $TIMESTAMP_FILE
fi
exit $STATUS