#!/bin/bash # # fetch-sanesecurity-sigs # by Malcolm Scott, Retrosnub Internet Services # # # $Revision: 352 $ # $Date: 2009-01-23 00:50:08 +0000 (Fri, 23 Jan 2009) $ # # ----------------------------------------------------------------------------- # Copyright (C) 2009 Malcolm Scott # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License version 2 as published by the # Free Software Foundation. # # 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 # ----------------------------------------------------------------------------- # # INSTALLATION AND USAGE: # # * Ensure that you have wget, gpg and rsync installed (in addition to a # standard set of UNIX tools). # * Configure this script by editing the configuration variables below. # * Set up cron to run this script periodically, at a randomly-selected time # (i.e. not just on the hour unless unavoidable), not more often than once # per hour. The script should be run either as root or as the user clamd # runs as. For example, add the following line to /etc/crontab or a file # in /etc/cron.d: # 42 * * * * root /path/to/fetch-sanesecurity-sigs >/dev/null # (Redirection of the output to /dev/null is recommended when running from # cron as the script is verbose in normal operation. This will not hide # errors, however.) # # Note that this script is tailored to the Sanesecurity setup (as of January # 2009). It should replace scripts using the pre-2009 setup (HTTP). It is # not intended to download non-Sanesecurity signatures; use another script # for that purpose. ### Configuration ### # ClamAV database location clamd_dbdir="/var/lib/clamav" # ClamAV daemon process ID file # (If this is commented out, the daemon will not be reloaded automatically) clamd_pidfile="/var/run/clamav/clamd.pid" # Directory in which this script will keep its persistent data data_dir="/var/lib/sanesecurity" # Directory in which this script will keep its cache # (This should not be the same as data_dir. Any unexpected files in this # directory will be deleted!) cache_dir="/var/cache/sanesecurity" # Mirror to use, in a form accepted by rsync # (Leave set to the round robin address unless you know what you are doing: # forcing the use of one particular mirror will cause excess load for that # mirror) mirror="rsync://rsync.sanesecurity.net/sanesecurity" # Extra options for rsync # (For example, if you have a slow link you may want to add -z here to # enable compression) rsync_extra_opts="" # Minimum interval between updates, in minutes # (Note that the download servers may be configured to drop connections made # at too great a rate) min_interval="30" # Randomly sleep before downloading if running noninteractively? # (Please leave this enabled, as it reduces peak load on the mirrors) random_sleep=1 # URL of the Sanesecurity GnuPG public key gpg_key_url="http://www.sanesecurity.net/publickey.gpg" # Exclude logical signatures (*.ldb)? # These are not supported by versions of ClamAV prior to 0.94. # If you use an old version of ClamAV, you should enable this option. #exclude_ldb=1 ### End of configuration ### umask 0022 # Check the configuration looks sane if [ ! -d "$clamd_dbdir" ] then echo "clamd_dbdir ($clamd_dbdir) does not exist; aborting" >&2 echo "(check your configuration)" >&2 exit 1 fi mkdir -p "$data_dir" "$cache_dir" # Set up GnuPG, if necessary if [ ! -d "$data_dir/gnupg" ] then echo "No GnuPG homedir found; initialising" >&2 echo "(This should only occur once)" >&2 mkdir "$data_dir/gnupg" chmod 0700 "$data_dir/gnupg" if ! wget -O- "$gpg_key_url" | gpg --no-options --homedir "$data_dir/gnupg" --import - then echo "ERROR: could not import GnuPG public key; aborting" >&2 rm -r "$data_dir/gnupg" exit 4 fi fi # This appears to be the most portable way to find the current timestamp # (suggestions on how to avoid calling perl are very welcome) time_now="$(perl -le print+time)" if [ ! "$time_now" -gt 1 ] then echo "Could not find current timestamp -- is perl installed?" >&2 exit 5 fi # Check that min_interval seconds have elapsed since last run if [ -s "$data_dir/update-stamp" ] then time_then="$(<"$data_dir/update-stamp")" minutes_elapsed=$(( (time_now - time_then) / 60 )) if [ "$minutes_elapsed" -lt "$min_interval" ] then echo "Must wait at least $min_interval between updates; aborting" >&2 exit 2 fi fi # Random sleep (see comment in configuration section) if [ "$random_sleep" = "1" ] then # Are we running noninteractively, i.e. without a tty on stdin? if ! tty -s then # $RANDOM is between 0 and 32767. # Use this to generate a time between 30 and 32767/200+30 = 193 seconds. sleep_time=$((RANDOM/200+30)) echo "Sleeping for $sleep_time seconds." sleep $sleep_time fi fi # Update the cache if [ "$exclude_ldb" = "1" ] then rsync_extra_opts="$rsync_extra_opts --exclude=*.ldb" rm -f "$cache_dir"/*.ldb fi if ! rsync --progress --delete -rt $rsync_extra_opts "$mirror/." "$cache_dir/" then echo "rsync failed; aborting." >&2 exit 3 fi echo "$time_now" > "$data_dir/update-stamp" chmod 0644 "$cache_dir"/*.?db echo # Iterate through the databases in the cache installed=0 for db in "$cache_dir"/*.?db do db_name=$(basename "$db") # Only pay any attention to this database if it's newer than the installed version if [ -e "$clamd_dbdir/sanesecurity-$db_name" -a ! "$db" -nt "$clamd_dbdir/sanesecurity-$db_name" ] then echo "$db_name is already up-to-date; skipping" continue fi # Check that there actually is a GnuPG signature # (there should be, and its absence could be due to tampering) if [ ! -e "$db.sig" ] then echo "SECURITY ERROR: $db_name is missing a GnuPG signature; discarding" >&2 continue fi # Check that the GnuPG signature is correct if ! gpg_out=$(gpg --no-options --homedir "$data_dir/gnupg" --verify "$db.sig" "$db" 2>&1) then echo "SECURITY ERROR: $db_name has a bad GnuPG signature; discarding:" >&2 echo "$gpg_out" >&2 continue fi # Zero-length databases have no value and confuse the test below if [ ! -s "$db" ] then echo "$db_name is zero-length; discarding" continue fi # Test the database by asking ClamAV to check something with it if ! clamscan --quiet --tempdir="${TMPDIR:-/tmp}" --database="$db" - < /dev/null then echo "ERROR: $db_name fails a simple test; discarding" >&2 continue fi # Now we can actually install this database echo "Installing $db_name into $clamd_dbdir/sanesecurity-$db_name" if cp -p "$db" "$clamd_dbdir/sanesecurity-$db_name" then installed=$((installed+1)) # Clean up stuff left behind by old scripts rm -f "$clamd_dbdir/$db_name"* fi done # Finished; display summary and perhaps reload clamd echo if [ "$installed" -gt 0 ] then if [ "$installed" -eq 1 ] then s="" else s="s" fi echo "Installed $installed database$s" # Is clamd running? if [ "$clamd_pidfile" -a -f "$clamd_pidfile" ] then echo "Reloading ClamAV daemon" kill -USR2 $(cat "$clamd_pidfile") fi else echo "No databases installed." fi exit 0