Installing anomy email virus filter
and interfacing with f-prot or clamav antivirus scanner

Anomy works with procmail to scan incoming mail for viruses and harmful attachments. If you use sendmail, Anomy coexists well with SpamAssassin and doesn't require elaborate reconfiguration of your mail server. Some of the commercial virus scanners require you to move sendmail to a different port (instead of port 25), or to recompile Sendmail to use "milter" (a form of IPC). Using procmail is a much simpler solution.

name

Last updated July 9, 2007

Installing Anomy

  1. Obtain anomy sanitizer from http://mailtools.anomy.net
  2. Make sure procmail is working in your installation of sendmail (see linuxsetup50.html for details).
  3. Install Base64 and QuotedPrint perl modules if not already present (check by typing "locate Base64")
  4. Back up the old version. If the new version doesn't work for some reason, it is difficult to find out why.
  5. tar -xzvf anomy in /usr/local/bin
  6. Make sure sanitizer.pl is executable and owned by root
  7. Copy the Perl module files to the perl directory.
    mkdir /usr/lib/perl5/5.?.?/i586-linux*/Anomy/ 
                           (or wherever perl is located)        
    cd /usr/local/bin/anomy/bin/Anomy
    cp *.pm /usr/lib/perl5/5.?.?/i586-linux*/Anomy/
  8. Create /etc/procmailrc:
    VERBOSE=yes
    LOGFILE=/tmp/procmail-sanitizer.log    
    Anomy=/usr/local/bin/anomy/
    :0 fw
    |/usr/local/bin/anomy/bin/sanitizer.pl  /etc/sanitizer.cfg
    
    DROPPRIVS=yes
    :0 fw
    * < 256000
    | /usr/bin/spamc
  9. Create a configuration file in /etc/sanitizer.cfg according to the documentation in the sanitizer.html file supplied with anomy. In recent versions, the config file is necessary for anomy to run. Unfortunately, the syntax of this file is poorly documented. A minimal sanitizer.cfg file has just a single line:
    file_default_policy = defang 
  10. Create a quarantine directory if /etc/sanitizer.cfg requires it.
     mkdir /var/quarantine
     chown root.root /var/quarantine  
  11. Verify that anomy is installed correctly
     cd testcases
     mkdir myhost.ok
     cp tests.conf.SAMPLE tests.conf
     ./testall.sh
     ./testall.sh 
    It should say "ok" for each test the second time around. If not, it may work after you install f-prot. (Note: the command may fail if you run it as root.) Check the log files in the myhost.ok directory to find the problem.

    On one computer the testall script produced an error in sanitizer.defaults. This was fixed by editing /usr/lib/perl5/5.6.0/i586-linux/Anomy/Sanitizer.pm and commenting out line 1064 (binmode($fh)). (Use perldoc -f binmode to check whether binmode is even useful in your OS).

  12. Send a test email and check the mail headers for anomy X-Sanitizer tags.
     cat /var/spool/mail/tjnelson | grep [Aa]nomy | wc 

Interfacing Anomy with F-Prot

Anomy executes the command-line version of a virus scanner such as F-prot (from http://www.f-prot.is) and uses the return code to determine whether a virus is present. Unfortunately, F-prot is expensive ($290 per year for a mail server). For our site, this comes to about $72.50 per email message, unless you count the spam that we receive, in which case the price drops to $0.007 per message. Because of this, we switched to ClamAV (see below).

  1. Install f-prot
     cd /usr/local
     tar -xzvf /home/tjnelson/anomy/fprot-linux-ms.trial.tar.gz
     cd f-prot
     ./install-f-prot.pl
    Do not allow the installation script to start any daemons. This will run the SuSE configuration scripts which may trash your sendmail configuration. Reset the permissions and ownership of /var/spool/clientmqueue to smmsp.smmsp if necessary.
    The virus scanner is installed in /usr/local/f-prot/f-prot.
  2. Edit /etc/sanitizer.cfg using the "real-world configuration" described in the sanitizer.html file as a starting point. Set the following:
    file_list_4_scanner = 0:5:3,4:/usr/local/f-prot/f-prot %FILENAME
    file_list_4_policy  = accept:accept:save:save
    The numbers correspond to exit codes of the f-prot virus scanner.
     0=Clean files - no infections found.
     ?=Cleaned files - infections found but were successfully disinfected.
     3=Infected files - unremovable infections were found.
     ?=Errors.
    The default is to mangle the filenames of infected attachments, but still deliver them.
  3. Run f-prot against a sample virus (easily obtained from any Windows user) and test the return code to see whether f-prot really finds viruses:
    f-prot -verno
    f-prot /etc/passwd > /dev/null; echo $?
    0
    f-prot S3MSONG.DOC.scr > /dev/null; echo $?
    3
    f-prot var/spool/mail/clickhappyuser > /dev/null; echo $?
    3
  4. Add a cron job for root to automatically get virus signature files:
    27 4,16 * * * /usr/local/f-prot/tools/check-updates.pl -cron
    This example will check the server every day at 04:27 and 16:27.
  5. Send a test message and make sure f-prot adds the following tag to the headers (in addition to the anomy X-Sanitizer tags):
    X-Antivirus: Scanned by F-Prot Antivirus (http://www.f-prot.com/)
  6. Finally, send a message containing a virus and make sure f-prot informs the end user that a virus is present (note: so far, we have not been able to get this step to work).

Interfacing Anomy with ClamAV

Anomy can also interface with the free Linux antivirus package ClamAV. The easiest way to scan for incoming viruses with ClamAV is to have anomy run the command-line version of ClamAV, known as clamscan, in procmail. See linuxsetup56.html for an alternative way of running ClamAV using sendmail's milter.

Installing ClamAV

Note: this procedure has changed from previous versions. We have had problems with later versions of clamscan hanging.

  1. Install clamav
    su
    useradd clamav
    groupadd clamav
    exit
    tar -xzvf clamav-0.60.tar.gz
    cd clam*
    configure
    make
    su
    make install
    ldconfig
  2. Configure Clamav by editing /usr/local/etc/clamd.conf
  3. Edit /usr/local/etc/freshclam.conf
  4. Run /usr/local/bin/freshclam as root with no options to create database. This will download a new database from the clam AV homepage. Port 80 must be open on your firewall. freshclam should connect to port 80 at vhost.sourceforge.net and say:
    Checking for a new database - started at Tue Nov 11 12:04:10 2003
    Connected to clamav.elektrapro.com.
    Reading md5 sum (viruses.md5): OK
    Reading md5 sum (viruses2.md5): OK
    Downloading viruses.db ...... done
    Downloading viruses.db2 ...... done
    Database updated (containing in total 10131 signatures).
    Database updated from clamav.elektrapro.com.  
  5. Test clamscan to determine whether it can find viruses and produce a nonzero return code. Note that unlike f-prot, clamav sends all its output to stderr.
    /usr/local/bin/clamscan S3MSONG.DOC.scr 2> /dev/null; echo $? 
        1
  6. To completely scan mail files, clamscan must be run twice: with and without the '--mbox' option.
    cd /var/spool/
    /usr/local/bin/clamscan --mbox mail
    /usr/local/bin/clamscan mail
    If your site is anything like ours, this will produce a list of every virus, worm, and email exploit known to man.
  7. Next, run the following commands:
    touch /var/log/clam-update.log
    chmod 600 /var/log/clam-update.log
    chown clamav /var/log/clam-update.log
  8. Add a line to root's or clamav's crontab such as:
    45 01 * * *   /usr/local/bin/freshclam --quiet -l /var/log/clam-update.log
  9. Anomy Sanitizer is hard-coded to use f-prot regardless of any options in its .cfg file. This means it won't use clamav even if you specify it. To fix this, edit /usr/local/bin/anomy/bin/sanitizer.pl, replace all occurrences of "f-prot" with "clamscan", and replace the "-ai -archive -dumb" options with "--mbox". The modified section should look like this:
    elsif ((!$no_fprotc) && (-e "/usr/local/bin/clamscan"))
    {
        # clamscan daemon default configuration:
        #  - Scan everything with clamscan.
        #  - Mangle infected attachments (they are still delivered).
        print STDERR "Configuring clamscan command line scanner.\n" 
        if ($ENV{SANITIZER_DEBUG});
        push @SCANNER_CONF,
    	 ('file_list_2_scanner = 0:6:3,8:/usr/local/bin/clamscan --mbox %FILENAME',
              'file_list_2_policy  = unknown:unknown:mangle:defang',
              'file_list_2 = .*',
    	  'header_rev += \nX-Antivirus: Scanned by clamscan 
              Antivirus (http://www.clamscan.com/)');
    } 
  10. Edit /etc/sanitizer.cfg using the "real-world configuration" described in the sanitizer.html file as a starting point. Set the following:
    file_list_4_scanner = 0:1:1,4:/usr/local/bin/clamscan %FILENAME
    file_list_4_policy  = accept:save:save:save
    file_list_4         = (?i)\.(xls|d(at|oc)|p(pt|l)|rtf|[sp]?html?
    file_list_4        += |class|upd|wp\d?|m?db
    file_list_4        += |z(ip|oo)|ar[cj]|lha|[tr]ar|rpm|deb|slp|tgz
    file_list_4        += )(\.g?z|\.bz\d?)*$
    The numbers correspond to exit codes of the clamav virus scanner. Note that clamscan's exit codes are different from f-prot's.
     0 = Clean files - no infections found.
     ? = Cleaned files - infections found but were successfully disinfected.
     1 = Infected files - unremovable infections were found.
     256 or -1 = Errors.
    The options are: The default is to mangle the filenames of infected attachments, but still deliver them.
  11. Email a sample virus to yourself to make sure it's being identified. (It may be necessary to add an .html extension to the virus to prevent Anomy from defanging it first). There should be a message in the main body of the email that says:
    ****
    NOTE:  An attachment was deleted from this part of the message,
    because it failed one or more checks by the virus scanning system.
    The file has been quarantined on the mail server, with the following
    file name:
    
            att-S3MSONG.DOC.scr.html-3fe8a70d.96
    
    The removed attachment's original name was:
    
            S3MSONG.DOC.scr.html
    
    It is recommended that you contact your system administrator if you
    need access to the file.  It might also be a good idea to contact the
    sender, and warn them that their system may be infected.
    ****
    Make sure the file is really being quarantined. If the permissions in /var/quarantine are incorrect, the attachment could be lost.
  12. If a problem occurs, check the log file indicated in /etc/procmailrc (in this case, /tmp/procmail-sanitizer.log).
Note that clamscan frequently misidentifies the virus, or gives it a generic name.

Finding the virus in a mail file

Clamscan doesn't give enough information for users to know which message in a mail file contains a virus. To fix this, we edited the file libclamav/matcher.c to print (in a crude way) the text surrounding the bad email message. The text is put into the file "clamscan.results". Users can run clamscan against their inbox and check this file to determine which of their messages contains a virus. Here is a diff file:

diff -c3 matcher.c.bak matcher.c


*** matcher.c.bak       2004-01-05 16:26:24.000000000 -0500
--- matcher.c   2004-01-05 15:56:29.000000000 -0500
***************
*** 180,185 ****
--- 180,188 ----
        int i, position, *partcnt;
  
      current = (struct cl_node *) root;
+ char tempstring[1000];
+ int start=0;
+ FILE *fp;
      partcnt = (int *) cli_calloc(root->partsigs + 1, sizeof(int));
  
      for(i = 0; i < length; i++)  {
***************
*** 197,202 ****
--- 200,223 ----
                                if(virname)
                                    *virname = pt->virname;
                                free(partcnt);
+ 
+ start = position - 1000;
+ fp = fopen("clamscan.results", "wt");
+ if(start > 0)
+ {
+ strncpy(tempstring, buffer+start, 999);
+ tempstring[999]=0;
+ fprintf(fp,"\nA %d\n**************************************************\n\
+ First 1000 bytes preceding the infected part of the file are:\n\
+ **************************************************\n\n%s\n", position, tempstring);
+ }
+ 
+ strncpy(tempstring, buffer+position, 999);
+ tempstring[999]=0;
+ fprintf(fp,"\nA %d\n**************************************************\n\
+ First 1000 bytes of infected part of file are:\n\
+ **************************************************\n\n%s\n", position, tempstring);
+ fclose(fp);
                                return CL_VIRUS;
                            }
                        }
***************
*** 204,209 ****
--- 225,247 ----
                        if(virname)
                            *virname = pt->virname;
                        free(partcnt);
+ 
+ start = position - 1000;
+ fp = fopen("clamscan.results", "wt");
+ if(start > 0)
+ {
+ strncpy(tempstring, buffer+start, 999);
+ tempstring[999]=0;
+ fprintf(fp,"\nB %d\n**************************************************\n\
+ First 1000 bytes preceding the infected part of the file are:\n\
+ **************************************************\n\n%s\n", position, tempstring);
+ }
+ strncpy(tempstring, buffer+position, 999);
+ tempstring[999]=0;
+ fprintf(fp,"\nB %d\n**************************************************\n\
+ First 1000 bytes of infected part of file are:\n\
+ **************************************************\n\n%s\n", position, tempstring);
+ fclose(fp);
                        return CL_VIRUS;
                    }
                }

Back