#!/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