
The exiscan scanner patch for exim 4 
------------------------------------------------------------------------------
by Tom Kistner <tom@duncanthrax.net>
http://duncanthrax.net/exiscan/



INTRODUCTION & OVERVIEW
------------------------------------------------------------------------------

exiscan is a patch against exim version 4, providing support for content
scanning in email messages received by exim. It works after the sending
client has completed the SMTP data phase and waits for an answer from the
server. Messages containing unwanted content can be rejected at that stage,
so the job of generating a bounce message is the job of the sending host.

exiscan supports 4 different 'scanning' facilities:

  - virus scanning, using an external scanner. Generic support for all
    command line scanners is available. The 'sophie' and 'kavdaemon'
    (v3 or v4) scanner daemons are supported too.
  - spam scoring with Spamassassin.
  - regular expression scanning.
  - file extension scanning (block vbs/pif/bat/scr/exe/com).

Each of the facilities can be used conditionally per-message. Of course,
each facility can be switched off completely if you do not need it.

For each of the facilities, you can set an "action" that will be taken
when a message is intercepted:

  - reject (the message is rejected, stating a cause)
  - freeze (the message is accepted but frozen)
  - blackhole (the message is accepted and destroyed)
  - redirect (the message is accepted, but the envelope recipient(s)
              will be replaced with a configurable address)
  - pass (the message is accepted, but carries an "X-" header with
          a proper warning)
         
Every facility puts headers with information into the message. End users
can use this information in their MUAs to automatically sort or "treat"
messages accordingly.



INSTALLATION
------------------------------------------------------------------------------

exiscan is distributed as a patch file, to be applied to the exim source
tree with the 'patch' program:

	[tom@foobar exim-4.01]$ patch -p1 < exiscan-4.01-1.patch

This will install all required files inside the source tree.

exiscans version numbers are the same as the corresponding exim version it
must be applied against, plus a postfix with a release number.

It is no problem to apply the patch to an already configured source tree.
In that case, you MUST delete the build directory and run the command

	[tom@foobar exim-4.01]$ make makefile

on the source tree to re-create the exim makefile.

You can then proceed to compile exim as described in its installation
manual.



CONFIGURATION OVERVIEW
------------------------------------------------------------------------------

exiscan uses the main exim config file. All exiscan entries go into
Section 1 of that file. All of the exiscan options start with "exiscan_".

Here is an "overview" list of all available options:

Global options: 

                exiscan_condition
                exiscan_crypt_salt
                exiscan_timeout
                exiscan_unpack_mime

Antivirus facility (AV) options: 

                exiscan_av_condition
                exiscan_av_action
                exiscan_av_scanner
                exiscan_av_scanner_path
                exiscan_av_scanner_options
                exiscan_av_scanner_regexp_description
                exiscan_av_scanner_regexp_trigger                 
                exiscan_av_sophie_socket
                exiscan_av_kavdaemon_socket
                        
Spamassassin facility (spamd) options: 

                exiscan_spamd_condition
                exiscan_spamd_action
                exiscan_spamd_address
                exiscan_spamd_treshold
                              
Regular expression facility (regex) options:

                exiscan_regex_condition
                exiscan_regex_action
                exiscan_regex_data
                         
File extension facility (extension) options:

                exiscan_extension_action
                exiscan_extension_data
                exiscan_extension_condition              



CONFIGURATION OPTIONS EXPLAINED
------------------------------------------------------------------------------

  Global options
  -------------------------------------------------------------------------
  These options apply to all facilities.
  
    exiscan_condition   (string, mantadory, default unset)
    ------------------------------------------------------
    This option is the "master condition" that is evaluated to see if 
    ANY exiscan facility should be used to scan the current message. If
    the condition does not apply, exiscan just skips over the message (no
    facilities are used). When this options is not set, exiscan will
    be disabled. Note: facilities have individual conditions as well.
    
    Example: to make exiscan only work on messages coming in with SMTP or
             ESMTP, use
             
             exiscan_condition = \ 
                ${if or {{eq{$received_protocol}{esmtp}} \
                         {eq{$received_protocol}{smtp}}} \
                            {1}{0} }

    Please read the "Setting Conditions" section below for more information
    on setting conditions.
    
  

    exiscan_crypt_salt   (string, mantadory, default unset)
    -------------------------------------------------------
    exiscan inserts a crypt()ed version of the message ID into the header
    when it has successfully scanned a message. This 'tag' is used to
    determine if the message is 'clean' if it should be re-sent or delayed.
    The exiscan_crypt_salt setting defines a 2-character string to be used
    as a "seed" for the crypt process. You MUST set this option to a
    2-character string, otherwise exiscan will be disabled.

    Example: 
    
             exiscan_crypt_salt = fo


    
    exiscan_unpack_mime   (bool, optional, default "true")
    ------------------------------------------------------
    Normally, exiscan unpacks MIME and TNEF containers (Thanks to
    Paul L. Daniels ripMIME library).
    If your scanner is able to scan on mailpacks (MBOX style files)
    directly, we do not need to unpack the mails. ONLY disable this
    option if this works with your scanner ! The default is "true",
    so you do not need to explicitly set this option.
    
    Example:
    
             exiscan_unpack_mime = true
             
             
    
    exiscan_timeout   (time,optional, default "15m")
    ------------------------------------------------
    To cope with mishaps in the scanner process, exim uses a timeout on
    the exiscan function call. If exiscan does not return in the given
    timeframe, exim will assume a local problem and temporarily reject
    the message. This timeout tells exim how long it will wait for
    exiscan to return. The default is 900 seconds (15 minutes).
    
    Example: This will set a timeout of 5 minutes
    
             exiscan_timeout = 5m



  Antivirus facility (av) options
  ---------------------------------------------------------------------
  These options are used by the antivirus facility. You need an
  external virus scanner on your system.
  

    exiscan_av_condition   (string, default unset)
    ----------------------------------------------
    If this condition evaluates to "true", exiscan will call the virus
    scanner facility on that message.
    Please read the "Setting Conditions" section below for more
    information on setting conditions.

    Example: To scan ALL messages, just set this variable to "1"
    
             exiscan_av_condition = 1


    exiscan_av_action   (string, default 'reject')
    ----------------------------------------------
    This defines the action exiscan should take when it finds a virus
    in the message.
    Possible values are 'pass','reject','blackhole','freeze' or
    'redirect <address>'. When this option is unset, it defaults to
    'reject'.
    Important: Please read the "Setting Actions" section below for more
    information on actions. 
    
    Example: redirect messages with viruses to postmaster
    
             exiscan_av_action = redirect postmaster@mydomain.com
        

    exiscan_av_scanner   (string, default unset)
    --------------------------------------------
    This option tells exiscan what type of virus scanner to use. It
    can be one of
    
      keyword   | scanner
      -------------------------------------------------------------
      cmdline   | generic command line scanner
      sophie    | sophie AV daemon (http://www.vanja.com/tools/sophie/)
      kavdaemon | Kapersky AVP Daemon 3.x (http://www.kapersky.com)
      
    Depending on the scanner type you choose with this option, you
    need to declare one or more further options below.
    
    Example: To use the (generic) cmdline scanner type, use
    
             exiscan_av_scanner = cmdline
    
        
    exiscan_av_scanner_path   (string, default unset)
    -------------------------------------------------
    This option is needed ONLY for the cmdline av scanner type.
    It contains the path to the virus scanner executable
    That means FULL ABSOLUTE PATH AND EXECUTABLE !
    Sorry for the caps but people keep messing this up.
    
    Example: Sophos Sweep in /usr/local/bin
    
             exiscan_av_scanner_path = /usr/local/bin/sweep


    exiscan_av_scanner_options   (string, default unset)
    ----------------------------------------------------
    This option is needed ONLY for the cmdline av scanner type.
    It containts the options to be passed to the scanner on the command
    line.
    ATTENTION: the given string MUST containe ONE pipe ('|') symbol,
    which will be replaced by exiscan with the path to be scanned.
    Normally, the pipe will be at the end of the string, but some
    scanners may also expect is somewhere else.

    Example: this works for Sophos Sweep
    
              exiscan_av_scanner_options = -all -archive -ss |


    exiscan_av_scanner_regexp_trigger   (string, default unset)
    -----------------------------------------------------------
    This option is needed ONLY for the cmdline av scanner type.
    exiscan parses both STDOUT and STDERR output of the scanner, line
    by line. To determine if a virus was found, we use a perl-compatible
    regular expression. In the simplest case, this will simply be a
    string just like the example below which will work with Sophos Sweep.

    Example: this works for Sophos Sweep
    
             exiscan_scanner_regexp_trigger = found in
    

    exiscan_av_scanner_regexp_description   (string, default unset)
    ---------------------------------------------------------------
    This option is needed ONLY for the cmdline av scanner type.
    It contains a regular expression to fish the viruses' name out
    of the scanner output.
    IMPORTANT: this expression MUST contain exactly ONE pair of braces,
    matching the substring with the virus info.
    Typically, the braces will contain '.*', to match any number
    of any character inside. To the left and right of the braces, you
    should place other matching criteria, of course !
    
    Example: Sophos Sweep reports a virus on a line like this:

              >>> Virus 'W32/Magistr-B' found in file ./those.bat

             We want to get the W32/Magistr-B string, so we can match
             for the single quotes left and right of it, resulting in
             the regex '(.*)' (WITH the quotes!)

             exiscan_av_scanner_regexp_description = '(.*)'
              
              
    exiscan_av_sophie_socket  (string, default unset)
    -------------------------------------------------
    This option is needed ONLY for the sophie av scanner type.
    Sophie opens a unix socket in your file system. The default is
    /var/run/sophie.
    Please make sure that exim can access that socket (permissions!).
    Also make sure that the user that Sophie runs with (./configure
    option !!) is allowed to read the exim queue directory.
    Sophie drops privileges, so while it may show up as running as root
    in 'ps', it may have set its effective UID to another user !
    Ideally, exims and sophies effective user settings should be the
    same.
                   

    exiscan_av_kavdaemon_socket   (string, default unset)
    -----------------------------------------------------
    This option is needed ONLY for the kavdaemon av scanner type.
    kavdaemon opens a unix socket in your file system. The default
    is /opt/AVP/AvpCtl.
    Please make sure that exim can access that socket (permissions!).
    Also make sure that the user that kavdaemon runs with is allowed
    to read the exim queue directory.
    
    Attention: you need to run kavdaemon with the disinfection option
    disabled, and with proper path settings, like this:
     
      ./kavdaemon -E -f=/opt/AVP /

    Note the slash at the end, it is important. /opt/AVP is the
    default AVP base directory.

    Example:
     
             exiscan_kavdaemon_socket = /opt/AVP/AvpCtl
      
      
      
  Antispam facility (spamd) options
  ---------------------------------------------------------------------
  These options are used by the antispam facility. You need to install
  SpamAssassin on your system. You can get it at
    
    http://www.spamassassin.org
    
  exiscan uses the 'spamd' daemon directly, it needs to run in order for
  this facility to work.
  
  Please read the section on header lines and actions further below to
  learn what you can do with this facility.
  
  
    exiscan_spamd_condition   (string, default unset)
    -------------------------------------------------
    If this condition evaluates to "true", exiscan will call the
    antispam facility on that message.
    Please read the "Setting Conditions" section below for more
    information on setting conditions.

    Example: To scan ALL messages, just set this variable to "1"
    
             exiscan_spamd_condition = 1
  
  
    exiscan_spamd_action   (string, default unset)
    ----------------------------------------------
    This defines the action exiscan should take when a message
    exceeds the defined spam score treshold (see below).
    Possible values are 'pass','reject','blackhole','freeze' or
    'redirect <address>'. When this option is unset, it defaults to
    'pass' (meaning that only a header with spam info is added to
    the message - see section "Header Lines" below).
    Important: Please read the "Setting Actions" section below for more
    information on actions. 
    
    Example: reject messages exceeding the spam score treshold
    
             exiscan_spamd_action = reject
    
    
    exiscan_spamd_treshold   (integer, default 999)
    ----------------------------------------------
    This defines the number of "spam score" points a message must
    exceed to be classified as "spam" by exiscan. The default value
    is very high, so if you only want to add headers to messages,
    you do not need to set this option. Sensible value ranges
    are 4-20. The lower you set this value, the more spam you may
    catch, however the possibility of false positives is also higher.
    
    Example: set spam score treshold to 6 points
    
             exiscan_spamd_treshold = 6
    
    
    exiscan_spamd_address   (string, default unset)
    -----------------------------------------------
    This contains the IP address and port where the spamd is listening,
    separated by a whitespace. By default, it resides on localhost port
    783. You can also run it on another machine to decrease the load on
    the mail server. Uncommenting this option turns off the antispam
    facility.
    
    Example: spamd running on localhost with default port
    
             exiscan_spamd_address = 127.0.0.1 783
    
    
    
  Regular expression scanning facility (regex) options
  ---------------------------------------------------------------------
  This facility can be used to scan a message for a set of regular
  expressions. The scanning will be done line-by-line on the complete
  message, including all headers, except for exiscan's own X- header.
  
  This facility is handy for blocking content that cannot yet be caught
  by your AV scanner, or to crack down on spam (try 'mortgage' :).
  
  To prevent double bounces, this facility will not scan bounce messages
  (messages with an empty envelope sender)
  
    exiscan_regex_condition   (string, default unset)
    -------------------------------------------------
    If this condition evaluates to "true", exiscan will call the
    regex facility on that message.
    Please read the "Setting Conditions" section below for more
    information on setting conditions.

    Example: To regex scan ALL messages, just set this variable to "1"
    
             exiscan_regex_condition = 1
  
  
    exiscan_regex_action   (string, default 'reject')
    -------------------------------------------------
    This defines the action exiscan should take when a message
    matches a defined regular expression.
    Possible values are 'pass','reject','blackhole','freeze' or
    'redirect <address>'. When this option is unset, it defaults to
    'reject'.
    Important: Please read the "Setting Actions" section below for more
    information on actions. 
    
    Example: blackhole messages matching a regular expression
    
             exiscan_regex_action = blackhole
    
    
    exiscan_regex_data   (string, default unset)
    --------------------------------------------
    This option contains the regular expressions you wish to match
    against messages, as a colon-separated list.
    To put a colon inside a regular expression, you need to double
    it (::).
    
    Example: Match 'mortgate' with case-insensitive 'm' and
             'make money'
    
             exiscan_regex_data = [Mm]ortage : make money
             
    
    
  File extension scanning facility (extension) options
  --------------------------------------------------------------------
  This facility can be used to block mails containing files with
  specific extensions, mostly those that may cause harm on the Windows
  platform (vbs,pif,bat,exe,com etc.).
  
  To prevent double bounces, this facility will not scan bounce messages
  (messages with an empty envelope sender)
  
    exiscan_extension_condition   (string, default unset)
    -----------------------------------------------------
    If this condition evaluates to "true", exiscan will call the
    extension facility on that message.
    Please read the "Setting Conditions" section below for more
    information on setting conditions.

    Example: To regex scan ALL messages, just set this variable to "1"
    
             exiscan_extension_condition = 1
  
  
    exiscan_extension_action   (string, default 'reject')
    -----------------------------------------------------
    This defines the action exiscan should take when a message
    contains one of the defined file types.
    Possible values are 'pass','reject','blackhole','freeze' or
    'redirect <address>'. When this option is unset, it defaults to
    'reject'.
    Important: Please read the "Setting Actions" section below for more
    information on actions. 
    
    Example: freeze messages containing an unwanted file type
    
             exiscan_extension_action = freeze
    
    
    exiscan_extension_data   (string, default unset)
    ------------------------------------------------
    This option contains the file extension for which you would like
    to scan messages, as a colon-separated list.
    
    Example: Match 'exe', 'com', and 'vbs'
    
             exiscan_extension_data = exe:com:vbs
    


SETTING CONDITIONS
------------------------------------------------------------------------------

exiscan has five 'condition' options (see above): one 'master' condition and
one per facility. Each of these conditions is a string that may contain
'expandable' components. Read chapter 11 of the exim 4 spec to learn more
about string expansion in exim.

A condition is 'false' when it

  - is unset
  - expands to 0 (string or number)
  
All other values result in a 'true' condition.

The master condition (option exiscan_condition) decides if exiscan is run
on a message. You should use it to skip messages that do not need to be
scanned. Typically, you will only want to scan messages that come in via
smtp or esmtp:

  exiscan_condition = \ 
                ${if or {{eq{$received_protocol}{esmtp}} \
                         {eq{$received_protocol}{smtp}}} \
                            {1}{0} }
                            
This will skip scanning messages coming from local sources or from authen-
ticated senders (asmtp).

Each facility has its own condition to decide if it should be applied to
a message (exiscan-<facility>-condition). For example, you can use those
with file lookups to use a facility only on specific sender or recipient
domains. The excercise is left up to the reader :)

To make a condition always true, just set it to '1'.



SETTING ACTIONS
------------------------------------------------------------------------------

Every facility in exiscan that 'matches' a message (found a virus, spam over
treshold, found regex/extension) can trigger a configurable action. Each
facility has an "action" option (exiscan_<facility>_action) where you can set
the action identifier for that facility.

The following actions are available:

  - reject    The message is rejected with a permanent error (5xx), stating
              the cause including information for the sender of the message.
  
  - freeze    The message is accepted and immediately frozen, with the cause
              saved in the header file. The postmaster can then review the
              frozen messages and eventually thaw or delete them.
              (NB: does someone want to write a web frontend for that task ?
              Submissions welcome ;)
              IMPORTANT: If you use an automatic unfreeze timer in your exim
              config, exim will automatically thaw these messages after the
              specified time, resulting in delivery !
              It might also be a good idea to use exim's 'move_frozen_messages'
              option in conjunction with this action.
              
  - blackhole The message is accepted and then destroyed by removing all reci-
              pients. I do not recommended to use this action unless you have
              a good cause to do so.
              
  - redirect <newaddress>  The messages' envelope recipients are replaced by
                           an address stated behind the 'redirect' parameter.
                           Example:
                           
                             exiscan_spamd_action = redirect the@new.address
                          
                           Since the original envelope addresses are destroyed
                           by that action, you must rely on the headers to
                           figure out the intended original recipients.
                           
  - pass      No action is taken on the message, except that the facility
              will add it's X- header line to the message. This is especially
              useful for the spamd facility, if you only want to "mark" spam.
              See the "added headers" section below to learn what headers
              exiscan adds to messages.
              


ADDED HEADERS
------------------------------------------------------------------------------

exiscan can add five different headers to a message when it is processed:

 - X-Scanner       This header is always added when exiscan_condition was
                   true, no matter if any facilities were run. It contains
                   an "ad" banner and a tag that exiscan can use to determine
                   if it has already scanned a message.


 - X-Infected      This header is added by the antivirus facility. It states
                   the name of the virus found.

               
 - X-Spam-Score    This header is added by the antispam facility and looks
                   like this:

                   X-Spam-Score: <num> (<bar>)

                   Where <num> is a floating point number which may be null,
                   positive or negative. The higher this number, the higher
                   is the possibility of that message being spam. The <bar>
                   is a textual representation of the number, consisting of
                   a number of '+' signs for a positive score, and '-' signs
                   for negative scores. 
                   For example, a message with a score of 6.5 will have a
                   header like this:
                   
                   X-Spam-Score: 6.5 (++++++)

                   The <bar> makes it easier to have filters in MUAs and
                   processors like procmail, since you can just say "anything
                   with six plus signs goes to the Trash folder". Such a
                   filter will then match on six OR MORE "spam points".


 - X-Contains-File This header is added by the file extension scanning faci-
                   lity. It contains the extension of the file included in
                   the message. 


 - X-Regex-Match   This header is added by the regular expression matching
                   facility. It contains the regular expression that a line
                   of the email has matched.
                   
                   
When a header is added to a message, exiscan will remove already existing
headers of the same type.




CREDITS
------------------------------------------------------------------------------

Philip Hazel for exim
Paul L. Daniels for ripMIME

Thanks a lot !



CONTACT
------------------------------------------------------------------------------

Tom Kistner
<tom@duncanthrax.net>
ICQ 1501527
dcanthrax@efnet
