Up clam ex.sh

From Alpine Linux
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
#!/bin/sh

# update_clamd_extra_sigs.sh v0.2 by Dan Larsson <dl|at|tyfon|dot|net>
# ==============================================================================
# LICENSE
# ==============================================================================
# "THE BEER-WARE LICENSE" (Revision 42):
# <dl|at|tyfon|dot|net> wrote this file. As long as you retain this
# notice you can do whatever you want with this stuff. If we meet
# some day, and you think this stuff is worth it, you can buy me a
# beer in return. Dan Larsson
#
# ==============================================================================
# VERSION INFO
# ==============================================================================
# v0.2 - 2008-08-23
#   * Don't use non-word chars in function names
#   * Changed the SecuriteInfo signature source url
#     (Thank's to Bill Landry for pointing out the above two)
#   * Cleaned up and added comments
#   * Misc cosmetic changes
#
# v0.1 - 2008-08-22
#   * Initial release, branched from v1.4 of Bill Landry's
#     ss-msrbl.sh script
#
# ==============================================================================
# README
# ==============================================================================
# In order to run this script you need to have curl, rsync and clamd installed
# on your machine aswell as the basic set of unix-like tools (i.e. awk, sed,
# cat, cp, gunzip etc...).
#
# If this script fails to run on your system or you have made improvements that
# you wish to share, you're welcome to drop me a line.
#
# ==============================================================================
# USAGE
# ==============================================================================
# Using this script is easy, just configure the parameters, save the changes
# and execute from the prompt (or via cron). Should you want to add additional
# signature databases simply add their download urls to the appropriate
# section(s) here below and you're done! Naturally, it's just as easy to remove
# and edit :-) No script coding necessary!
#
# ==============================================================================
# SIGNATURE SOURCES
# ==============================================================================
# SaneSecurity (phish.ndb, scam.ndb)
# http://www.sanesecurity.com/clamav/usage.htm
#
# SecuriteInfo (vx.hdb)
# http://www.securiteinfo.com/services/clamav_unofficial_malwares_signatures.shtml
#
# MalwareBlockList (mbl.db)
# http://www.malware.com.br/clamav.txt
#
# MSRBL (MSRBL-Images.hdb, MSRBL-SPAM.ndb)
# http://www.msrbl.com/site/msrblimagesdownload
# http://www.msrbl.com/site/msrblspamdownload
#
# ==============================================================================
# SOURCE ARGUMENTS ( see below for more info in source arguments )
# ==============================================================================
# Name                Value        Comment
# ------------------- --------- ------------------------------------------------
# fetch_interval      integer   Forced delay in seconds between download
#                               attempts
# target_file         string    Use this name for the signature database
#                               (instead of extracting it from the source file)

################################################################################
#       SCRIPT USER EDIT SECTION - SET PROGRAM PATHS AND OTHER VARIABLES       #
################################################################################

# *** COMMENT OUT THE BELOW LINE WHEN YOU HAVE CONFIGURED THIS SCRIPT ***
#script_not_configured=1

# Set and export the command searchpaths
PATH=/root/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
export PATH

# Set path to ClamAV database dir location as well as
# the clamd user and group account
clamd_dbdir=/var/lib/clamav
clamd_user=clamav
clamd_group=clamav

# Set path to the clamd pidfile
# (comment out to disable forced database reload)
clamd_pidfile=/var/run/clamav/clamd.pid

# Set backup and temp working directory paths
# (edit to meet your own needs)
backup_dir=/var/backups/clamav
tmp_dir=/var/tmp/clamdb
rsync_dir=/var/tmp/rsync

# HTTP source urls - *MUST* be HTTP urls, one url per line
# (add/remove/modify urls as per preference and/or need,
# to disable, comment out the below six lines)
http_source_urls="
   http://www.sanesecurity.com/clamav/phishsigs/phish.ndb.gz
   http://www.sanesecurity.com/clamav/scamsigs/scam.ndb.gz
   http://clamav.securiteinfo.com/vx.hdb.gz
   http://www.malware.com.br/cgi/submit?action=list_clamav,fetch_interval=86400,target_file=mbl.db
"

# RSYNC source urls - *MUST* be RSYNC urls, one url per line
# (add/remove/modify urls as per preference and/or need,
# to disable, comment out the below four lines)
rsync_source_urls="
   rsync://rsync.mirror.msrbl.com/msrbl/MSRBL-Images.hdb
   rsync://rsync.mirror.msrbl.com/msrbl/MSRBL-SPAM.ndb
"

# Arguments can be appended to the source_url, if you do so
# seperate them from the source url and eachother with commas
# ( e.g. scheme://hostname/path,arg1=123,arg2=abc )
# Please note that it's very important you null their value when
# they've served their purpose, not doing so will lead to weird
# results

# Enable random sleeping before processing
# - recommeded when running via cron!
# (to disable this comment out the below line)
#sleep_enabled=1

# Show each slept second visually
# - disabled when running via cron.
# (to disable this comment out the below line)
sleep_visual=1

# Compress all downloaded *source files* with gzip
# (to disable this comment out the below line)
keep_sources_gzipped=1

################################################################################
# END OF SCRIPT USER EDIT SECTION - YOU SHOULD NOT NEED TO EDIT ANYTHING BELOW #
################################################################################

# Initializes the source arguments
sarg_init() {
   sarg_init_success=
   if [ -n "$source_args" ] ; then
      for arg in `echo $source_args | sed 's/,/ /g'` ; do
         eval $arg
         sarg_init_success=1
      done
      source_url=`echo $source_url | awk -F, '{print $1}'`
   fi
   source_args=
}

# Runs all source argument subroutines. If you add your own
# checks/processing add them to this function.
sarg_process() {
   # Check for fetch interval restriction
   if [ -n "$fetch_interval" ] && ! sarg_check_fetch_interval ; then
      echo
      echo Skipped due to interval restriction in effect
      continue
   fi
   # Insert your own argument processing here
}

# Handles processing of the "$fetch_interval" source argument
# Returns 0 when fetching is permitted ( i.e. elapsed seconds
# since last fetch is equal or greater than $fetch_interval )
# respectively returns 1 when fetching is not permitted.
sarg_check_fetch_interval() {
   local fetch_lastrun fetch_rundiff fetch_stampfile fetch_thisrun
   fetch_stampfile=$backup_dir/FETCHSTAMP.$source_file
   fetch_thisrun=`date +%s`

   fetch_stampfile_old=$backup_dir/LASTRUN.$source_file
   if [ -f $fetch_stampfile_old ] ; then
      mv $fetch_stampfile_old $fetch_stampfile
   fi

   if [ -f $fetch_stampfile ] ; then
      fetch_lastrun=`cat $fetch_stampfile`
      fetch_rundiff=$(($fetch_thisrun - $fetch_lastrun))
      if [ $fetch_rundiff -lt $fetch_interval ] ; then
         fetch_interval=
         return 1
      fi
   fi
   echo $fetch_thisrun > $fetch_stampfile
   fetch_interval=
   return 0
}

# Shows the source header
# (the below function also calls the source argument
# init and processing functions)
show_source_header() {
   sarg_init
   echo
   echo ====================================================
   echo Processing signature database: $target_file
   echo ====================================================
   # Process arguments if any are set for this source
   [ -n "$sarg_init_success" ] && sarg_process
}

#### actual script execution begins here ####
if [ -n "$script_not_configured" ] ; then
   echo '*** SCRIPT NOT CONFIGURED ***'
   echo Please take the time to configure this script before running it.
   echo When you have, comment out the \'script_not_configured=1\' line at
   echo the top in the user editables section and execute the script again
   exit 1
fi
echo "Script started: "`date`

# Check to see if the working directories exist.
# If not, create them. Otherwise, ignore and proceed with script
mkdir -p $tmp_dir $rsync_dir $backup_dir

# Change working directory to ClamAV database directory
cd $clamd_dbdir

# Get the timestamp from the previous run if it exists and
# update it.
stamp_lastrun=0
stamp_thisrun=`date +%s`
if [ -f $backup_dir/LASTRUN ] ; then
   stamp_lastrun=`cat $backup_dir/LASTRUN`
fi
echo $stamp_thisrun > $backup_dir/LASTRUN

# To "play nice" with the source servers don't run more frequently
# than once every hour. Also, attempt to keep off any peak crontimes
# by adding a randomized (between 30 seconds and 10 minutes) sleep period.
#  --- Idea inspired by Rick Cooper's "UpdateSaneSecurity" script.
# ( You can ofcourse disable the sleep-feature by commenting out the
# 'sleep_enabled=1' line in the user editables section here above )
if [ -n "$sleep_enabled" ] ; then
   # Calculate if we have run in the last hour. If we have add the
   # remainder to the sleep time
   sleep_forced=0
   if [ $stamp_lastrun -gt 0 ] ; then
      stamp_rundiff=$(($stamp_thisrun - $stamp_lastrun))
      if [ $stamp_rundiff -lt 3600 ] ; then
         sleep_forced=$((3600 - $stamp_rundiff))
      fi
   fi

   # NOTE:
   # Please note that I'm very well aware of the $RANDOM variable, however
   # since it is not a FreeBSD sh(1) native variable (which is the O/S and
   # shell I'm running this script under) I'm staying off that path. Feel
   # free to implement and use the $RANDOM method, if you want to :-)

   # Get a random number between 30 and 600. First attempt this by using
   # the jot(1) utility (installed by default on *BSD systems)...
   sleep_random=`jot -r 1 30 600 2>/dev/null`

   # ...if jot(1) failed attempt another (more portable?) method
   if [ -z "$sleep_random" ] ; then
      sleep_random=0
      while [ $sleep_random -lt 30 ] || [ $sleep_random -gt 600 ] ; do
         sleep_random=`head -1 /dev/urandom | od -N 1 | awk '$2~/^0/{ print $2 / 1 }'`
      done
   fi

   # Add the two values together and sleep for that amount of seconds.
   # If the $TERM variable isn't set we're probably running from cron so
   # disable visual sleeping in that case
   sleep_forced=$(($sleep_forced + $sleep_random))
   echo ====================================================
   echo Sleeping $sleep_forced seconds before proceeding...
   echo ====================================================
   if [ -n "$TERM" -a -n "$sleep_visual" ] ; then
      while [ $sleep_forced -gt 0 ] ; do
         sleep_forced=$(($sleep_forced - 1))
         echo -n .
         sleep 1
      done
      echo
   else
      sleep $sleep_forced
   fi
fi

# Process http://urls
for source_url in $http_source_urls ; do
   source_file=`basename $source_url | awk -F, '{print $1}'`
   source_args=`basename $source_url | sed "s/^\$source_file//;s/^,//"`
   target_file=`echo $source_file | sed 's/\.gz$//'`

   # If the source and target filenames are equal the source is not gzipped
   # (this will have to be expanded upon if/when additional forms of source
   # compression are to be supported).
   source_not_gzipped=
   if [ $source_file = $target_file ] ; then
      source_not_gzipped=1
   fi

   # Remove any non-word characters from the source filename.
   # We need this since it's used in various file operations
   source_file=`echo $source_file | sed 's/[^[:alnum:]\.-]/_/g'`

   # Produce the source header
   show_source_header

   # Check for an existing database file. If it exists then run an
   # update check. Otherwise, just download and extract the database file.
   if [ ! -s $target_file ] ; then
      # Redirect stderr to stdout while downloading the file.
      ( curl -L -R -o $tmp_dir/$source_file $source_url 2>&1 )

      # If the source isn't gzipped, compress it if $keep_sources_gzipped
      # is non-empty
      if [ -n "$keep_sources_gzipped" -a -n "$source_not_gzipped" ] ; then
         test -s $tmp_dir/$source_file && \
            gzip -9f $tmp_dir/$source_file && \
            source_file=${source_file}.gz
      fi

      # Validate the source file through a series of tests.
      # If all tests succeed install the source and database files
      # in the ClamAV database directory ($clamd_dbdir).
      test -s $tmp_dir/$source_file && \
         gunzip -cdf $tmp_dir/$source_file > $tmp_dir/$target_file && \
         clamscan --quiet -d $tmp_dir/$target_file - < /dev/null && \
         mv -f $tmp_dir/$target_file $tmp_dir/$source_file . && \
         do_clamd_reload=$(($do_clamd_reload + 1))
   else
      # Select which file to use as a timestamp reference.
      source_timeref=$source_file
      if [ -n "$keep_sources_gzipped" -a -f ${source_file}.gz ] || \
         [ ! -f $source_file -a -f ${source_file}.gz ] ; then
         source_timeref=${source_file}.gz
      fi

      # Redirect stderr to stdout while downloading the source file, tell curl
      # to use $source_timeref as a timestamp reference
      ( curl -L -R -z $source_timeref -o $tmp_dir/$source_file $source_url 2>&1 )

      # If the source isn't gzipped...
      if [ -n "$keep_sources_gzipped" -a -n "$source_not_gzipped" ] ; then
         test -s $tmp_dir/$source_file && \
            gzip -9f $tmp_dir/$source_file && \
            source_file=${source_file}.gz
      fi

      # Validate the source file...
      test -s $tmp_dir/$source_file && \
         gunzip -cdf $tmp_dir/$source_file > $tmp_dir/$target_file && \
         clamscan --quiet -d $tmp_dir/$target_file - < /dev/null && \
         cp -f -p $target_file $backup_dir && \
         mv -f $tmp_dir/$target_file $tmp_dir/$source_file . && \
         do_clamd_reload=$(($do_clamd_reload + 1))
   fi
done

# Process rsync://urls
for source_url in $rsync_source_urls ; do
   source_file=`basename $source_url | awk -F, '{print $1}'`
   source_args=`basename $source_url | sed "s/^\$source_file//;s/^,//"`
   target_file=$source_file

   # Produce the source header
   show_source_header

   # Check for an existing database file. If it exists then run an
   # update check. Otherwise, just download and extract the database file.
   if [ ! -s $target_file ] ; then
      # Redirect stderr to stdout while downloading the file.
      ( rsync -t --stats $source_url $rsync_dir/$target_file 2>&1 )

      # Validate the source file through a series of tests.
      # If all tests succeed install the source and database files
      # in the ClamAV database directory ($clamd_dbdir).
      cp -p $rsync_dir/$target_file $tmp_dir && \
      test -s $tmp_dir/$target_file && \
         clamscan --quiet -d $tmp_dir/$target_file - < /dev/null && \
         mv -f $tmp_dir/$target_file . && \
         do_clamd_reload=$(($do_clamd_reload + 1))
   else
      # Download the source file...
      ( rsync -tu --stats $source_url $rsync_dir/$target_file 2>&1 )

      # Validate the source file...
      test $rsync_dir/$target_file -nt $target_file && \
         cp -p $rsync_dir/$target_file $tmp_dir && \
         test -s $tmp_dir/$target_file && \
            clamscan --quiet -d $tmp_dir/$target_file - < /dev/null && \
            cp -f -p $target_file $backup_dir && \
            mv -f $tmp_dir/$target_file . && \
            do_clamd_reload=$(($do_clamd_reload + 1))
   fi
done

# Set appropriate file access permissions
chown -R $clamd_user:$clamd_group $clamd_dbdir

# Remove any leftover files in the $tmp_dir working directory
# (should only happen when a corrupted database is detected)
rm -f $tmp_dir/*

# Reload the clamd database if $clamd_pidfile and $do_clamd_reload
# are both non-empty
if [ -n "$clamd_pidfile" -a -n "$do_clamd_reload" ] ; then
   echo
   echo ====================================================
   echo Reloading the ClamAV databases \($do_clamd_reload updated\)
   echo ====================================================
   kill -USR2 `cat $clamd_pidfile`
fi

echo
echo "Script ended: "`date`

exit $?