diff -uN disspam/configuration.txt disspam-dsd/configuration.txt --- disspam/configuration.txt 2003-05-06 23:36:46.000000000 +0100 +++ disspam-dsd/configuration.txt 2003-11-17 20:02:26.218315872 +0000 @@ -14,6 +14,9 @@ settings (think apache configs and virtualhosts). See the SAMPLE.CONF file for a skeleton example of a configuration file. +DisSpam is also capable of using the ClamAV open-source virus scanner +to detect and delete virus infected email. + The configuration file is divided into several sections. Each section is denoted by a unique name and is started by enclosing that name in square brackets. @@ -82,9 +85,18 @@ The following keys are optional and may be specified in the [GLOBAL] section. + + AVTEMPORARY * + + CLAMAV + + MIMESTORE * SPAMASSASSIN +Keys marked with a * above (avtemporary/mimestore) MUST be set if the +ClamAV virus detection key (clamav) is 'yes'. + The following keys are optional and may be specified in the [GLOBAL] section for a global setting or inside a mailbox section for a local setting specific only to that mailbox. @@ -130,6 +142,12 @@ The following is a description of what each of the keys mentioned above does and what it could be set to: + AVTEMPORARY + This key MUST be set to a filename if CLAMAV virus + detection is enabled. This temporary file is only used + internally and will be removed once DisSpam has + completed. A value such as "/tmp/clamav.tmp" is + recommended. BACKUPFILE Set this to a filename to have all the emails detected as spam saved into this file first before they're @@ -164,6 +182,12 @@ BAN_TO_FILE Just like BAN_FROM_FILE, except it matches the To: header instead of the From: header. + CLAMAV + This directive instructs DisSpam to use ClamAV for + virus detection. Virus detection works *alongside* the + spamassassin/RBL spam detection (i.e. DisSpam can check + your mails for both spam and viruses). Set to "yes" to + enable, "no" to disable. CHECKONLYONCE Set this to "yes" to have DisSpam check each message for spam only once and never again. The default is "no" @@ -211,6 +235,15 @@ email address. This is similar to what the program FETCHMAIL does, except it won't fetch spam ! Leave empty to disable this feature. + MIMESTORE + This key MUST be set to a directory path if CLAMAV virus + detection is enabled. This temporary directory is only + used internally and will be cleared and removed once + DisSpam has completed. A value such as "/tmp/mimestore" + is recommended. DisSpam will attempt to create this + directory if it does not exist. + This is a "generic" option because future additions to + DisSpam may benefit from having the MIME parts decoded. PIDFILE Set this to the full path of a filename that DisSpam can use to store it's own Process ID and uses as a lock diff -uN disspam/disspam.pl disspam-dsd/disspam.pl --- disspam/disspam.pl 2003-05-06 23:46:14.000000000 +0100 +++ disspam-dsd/disspam.pl 2003-11-17 21:04:32.154887416 +0000 @@ -1,12 +1,13 @@ -#!/usr/local/bin/perl +#!/usr/bin/perl #################################################### # # $Header: /cvsroot/disspam/disspam.pl,v 1.71 2003/05/06 22:46:14 mina Exp $ # -# DisSpam version 0.12 +# DisSpam version 0.12-dsd # # Just one more script that tries to combat spam +# (and viruses!) # # Written by Mina Naguib, http://www.topfx.com, webmaster@topfx.com # @@ -14,9 +15,9 @@ use strict; use Net::POP3; -use vars qw($VERSION $CONFFILENAME %RBL %MAILBOX $SENDMAIL $SMARTRELAY $DATAFILE $PIDFILE %HEADERHASHES $SPAMASSASSIN $SAOBJECT); +use vars qw($VERSION $CONFFILENAME %RBL %MAILBOX $SENDMAIL $SMARTRELAY $DATAFILE $PIDFILE $AVTEMPORARY $MIMESTORE %HEADERHASHES $SPAMASSASSIN $CLAMAV $SAOBJECT $CAVOBJECT $_VIRUSFOUND); -$VERSION = '0.12'; +$VERSION = '0.12-dsd'; print "\nThis is DisSpam version $VERSION. The time is now ", scalar localtime(time), "\n\n"; @@ -25,6 +26,10 @@ parseconffile(); +if ($CLAMAV) { + createmimestore(); +} + loadheaderhashes(); checkemail(); @@ -33,6 +38,10 @@ deletepidfile(); +if ($CLAMAV) { + deletemimestore(); +} + # # This sub is the main loop. It loops through all the mailboxes defined in hash %MAILBOX # , checks them for spam, and does whatever's appropriate if spam's found (backup to @@ -102,10 +111,10 @@ foreach $message_number (keys %{$messages}) { undef $headers; undef $message; - if ($SPAMASSASSIN) { + if ($SPAMASSASSIN || $CLAMAV) { # - # We need the entire message for spamassassin + # We need the entire message for spamassassin or clamav # print "\tRETRIEVING ENTIRE MESSAGE\n"; $message = $pop->get($message_number); @@ -267,7 +276,7 @@ } # -# This sub parses the config file, populating %RBL, %MAILBOX, $SENDMAIL, $SMARTRELAY, $DATAFILE, $PIDFILE +# This sub parses the config file, populating %RBL, %MAILBOX, $SENDMAIL, $SMARTRELAY, $DATAFILE, $PIDFILE, $AVTEMPORARY, $MIMESTORE # Also does sanity checking and dies if it sees errors. # sub parseconffile { @@ -343,7 +352,15 @@ } # + # We check that they've defined a mimestore and avtemporary if they want virus detection + # + if ($MAILBOX{global}{clamav} =~ /y|1/i && ($MAILBOX{global}{avtemporary} eq '' || $MAILBOX{global}{mimestore} eq '')) { + die "Error: You must define the MIMESTORE and AVTEMPORARY variables if you wish to use ClamAV virus detection.\n"; + } + + # # We remove keys from %MAILBOX that are internal and not real mailbox definitions + # if (ref($MAILBOX{rbl}) eq "HASH") { %RBL = %{ $MAILBOX{rbl} }; } @@ -364,8 +381,14 @@ delete $global{datafile}; $PIDFILE = $global{pidfile}; delete $global{pidfile}; + $MIMESTORE = $global{mimestore}; + delete $global{mimestore}; + $AVTEMPORARY = $global{avtemporary}; + delete $global{avtemporary}; $SPAMASSASSIN = ($global{spamassassin} =~ /y|1/i) ? 1 : 0; delete $global{spamassassin}; + $CLAMAV = ($global{clamav} =~ /y|1/i) ? 1 : 0; + delete $global{clamav}; # # Now we inherit the settings from %global if they're not defined per mailbox @@ -420,6 +443,12 @@ if ($SMARTRELAY) { require Net::SMTP; } + if ($CLAMAV) { + require Mail::ClamAV; + require MIME::Parser; + $CAVOBJECT = Mail::ClamAV->new(Mail::ClamAV::retdbdir()); + $CAVOBJECT->buildtrie(); + } if ($SPAMASSASSIN) { require Mail::SpamAssassin; } @@ -502,8 +531,14 @@ following: * Study the reason mentioned above. Sometimes - it's self explanatory (you're banned, subject - of your message is banned etc...) + it's self explanatory (virus detected, you're + banned, subject of your message is banned, + etc...) + * If a virus was detected, there is a chance + that it did not originate from your machine, + as many email viruses forge their FROM + address. You should look up the virus to + confirm its behavior in this situation. * Re-send your message through another account that does not use the above blacklisted mailserver, sender name, subject... @@ -594,6 +629,22 @@ } # +# This sub creates the mime store for temporary usage by the anti-virus mechanism +# +sub createmimestore { + if (!-d $MIMESTORE && !mkdir($MIMESTORE)) { + die "Error: Could not create MIMESTORE directory [$MIMESTORE]: $!\n"; + } +} + +# +# This sub deletes the temporary mime store +# +sub deletemimestore { + system("rm -rf $MIMESTORE"); +} + +# # This sub takes an email address and returns if it's valid or not # sub validemail { @@ -683,14 +734,17 @@ my ($from, $subject, $to); my %ip; my $temp; - my ($status, $score); - + my $temp2; + my $entity; + my ($status, $avstatus, $score, $mimeparser); + # # Sanity: # if ($messageref && ref($messageref) ne "SCALAR") { die "Error: Supplied messageref to isaspam is not a reference to a scalar: $messageref\n"; } + $temp2 = $messageref; # # First, let's split the headers into an array @@ -780,9 +834,41 @@ } } } + + # OK, the message is not spam, should it be checked for viruses? + if ($CLAMAV) { + # Virus detection with ClamAV + # contributed by Daniel Drake (dsd) + + $mimeparser = new MIME::Parser; + $mimeparser->output_under($MIMESTORE); + + # Nasty hack. Tried getting ClamAV to work with variables holding the mail, and failed. + # This approach writes the mail to a temporary file, then scans the file. Temporary file is then deleted. + open(FILEHANDLE, "> $AVTEMPORARY") or die "Error: Could not create AVTEMPORARY [$AVTEMPORARY].\n"; + print(FILEHANDLE $$messageref); + close(FILEHANDLE); + + open(FILEHANDLE, "$AVTEMPORARY"); + $entity = $mimeparser->read(\*FILEHANDLE); + close(FILEHANDLE); + unlink($AVTEMPORARY); + + $_VIRUSFOUND = ''; + + # Recursively save all of the mail parts + virus scan them. + dump_entity($entity); + + if($_VIRUSFOUND ne '') { + chop($_VIRUSFOUND); + return "Virus(es) detected by ClamAV: $_VIRUSFOUND"; + } + + } + # - # Message is not spam if it reached here + # Message is not spam (or virus) if it reached here # return undef; @@ -805,3 +891,38 @@ close(FH); return wantarray ? @data : \@data; } + + +# This sub recurses through all MIME parts of a file +# and scans them for viruses. +# Based on sub from example file in MIME::Tools +sub dump_entity { + my ($entity, $name) = @_; + defined($name) or $name = "'anonymous'"; + my $virusstatus; + my @temppath; + + # Output the body: + my @parts = $entity->parts; + if (@parts) { # multipart... + my $i; + foreach $i (0 .. $#parts) { # dump each part... + dump_entity($parts[$i], ("$name, part ".(1+$i))); + } + } else { # single part... + # Save and scan the part + my $body = $entity->bodyhandle; + my ($type, $subtype) = split('/', $entity->head->mime_type); + my $path = $body->path; + + @temppath = reverse(split(/\//, $path)); + $virusstatus = $CAVOBJECT->scan($path, Mail::ClamAV->CL_RAW); + + if ($virusstatus->virus) { + print "\tFILE \"".$temppath[0]."\" IS A VIRUS: $virusstatus\n"; + $_VIRUSFOUND .= $virusstatus . " "; + } + } + 1; +} + diff -uN disspam/readme.txt disspam-dsd/readme.txt --- disspam/readme.txt 2003-05-06 23:36:46.000000000 +0100 +++ disspam-dsd/readme.txt 2003-11-17 20:12:05.380269872 +0000 @@ -11,6 +11,9 @@ DisSpam may also be configured to do fetchmail's job and download and re-send clean (non-spam) emails to an arbitary mailbox. +DisSpam may also be configured to check incoming mails for viruses, +using ClamAV. + DisSpam should be run periodically, possibly from a cron job. It works best if the frequency it runs as is shorter than the frequency which you pop the mailboxes with your email client. This prevents spam from @@ -28,7 +31,7 @@ Much of the SpamAssassin and SmartRelay is by Craig Macdonald ban_to suggested by Daniel Drake - +Virus detection written by Daniel Drake OBTAINING DISSPAM @@ -64,19 +67,28 @@ * There's no need for an [RBL] section. You may wish to delete it from your config file for simplicity. -4. Load up the new SAMPLE.CONF file and look over the [GLOBAL] +4. If you wish to use DisSpam to filter your mailbox for viruses as + well as spam, then you will need to install the following packages: + * The core ClamAV software. + http://clamav.elektrapro.com/ + * The Mail::ClamAV perl interface to ClamAV + (available through CPAN) + * The MIME::Parser family of perl modules + (available through CPAN) + +5. Load up the new SAMPLE.CONF file and look over the [GLOBAL] section. If you see any keys that do not exist in your existing - conf file, copy them there and customize their values if + conf file, copy them there and customize their values if necessary. -5. Skim over the CONFIGURATION.TXT file. Between different releases +6. Skim over the CONFIGURATION.TXT file. Between different releases of DisSpam more configuration directives are implemented and they will not appear in the SAMPLE.CONF file, so the only way to find out about them or about general changes to the configuration syntax is by going over CONFIGURATION.TXT. If necessary, adjust your conf file as per the instructions in CONFIGURATION.TXT -6. Manually (not through a cron job) run disspam.pl on your conf file +7. Manually (not through a cron job) run disspam.pl on your conf file and verify that everything's working and there are no errors. Between different releases of DisSpam the requirements for the conf @@ -114,6 +126,8 @@ Net::DNS Net::SMTP Mail::SpamAssassin + Mail::ClamAV + MIME::Tools If perl complains about any of them not found, you can easily install them like so: diff -uN disspam/sample.conf disspam-dsd/sample.conf --- disspam/sample.conf 2002-12-29 07:33:44.000000000 +0000 +++ disspam-dsd/sample.conf 2003-11-17 19:49:22.337483872 +0000 @@ -9,6 +9,9 @@ # smartrelay=smtp.yourisp.com deletespam=yes # spamassassin=yes +# clamav=yes +# avtemporary=/tmp/clamav.temp +# mimestore=/tmp/mimestore [RBL] bl.spamcop.net=127\.0\.0\.2