Provided by: mimedefang_2.53-1_i386 bug

NAME

       mimedefang-filter - Configuration file for MIMEDefang mail filter.

DESCRIPTION

       mimedefang-filter  is  a Perl fragment which controls how mimedefang.pl
       disposes of various parts of a MIME message.  In addition, it  contains
       some   global   variable   settings   which  affect  the  operation  of
       mimedefang.pl.

CALLING SEQUENCE

       Incoming e-mail is handled as follows:

       1) A temporary working directory is created.  It is  made  the  current
       working  directory  and  the e-mail message is split into parts in this
       directory.

       2) If the file /etc/mail/mimedefang-filter.pl defines a  Perl  function
       called  filter_begin, it is called with no arguments.  Any return value
       is ignored.

       3) For each leaf part of the mail message, filter is called  with  four
       arguments: entity, a MIME::Entity object; fname, the suggested filename
       taken  from  the  MIME  Content-Disposition  header;  ext,   the   file
       extension,  and  type,  the MIME Content-Type value.  For each non-leaf
       part of the mail message, filter_multipart is called with the same four
       arguments  as  filter.   A  non-leaf  part of a message is a part which
       contains nested parts.  Such a part has no useful body, but you  should
       still  perform filename checks to check for viruses which use malformed
       MIME  to  masquerade  as  non-leaf  parts  (like  message/rfc822).   In
       general, any action you perform in filter_multipart applies to the part
       itself and any contained parts.

       Note that both filter and filter_multipart are optional.  If you do not
       define  them, a default function that simply accepts each part is used.

       4) After all parts have been  processed,  the  function  filter_end  is
       called  if  it  has  been  defined.   It  is  passed  a single argument
       consisting of the (possibly modified) MIME::Entity object  representing
       the message about to be delivered.

DISPOSITION

       mimedefang.pl  examines  each  part of the MIME message is examined and
       chooses a disposition.  Unless otherwise  indicated,  the  dispositions
       should be called only from filter and not filter_begin or filter_end.

       The available dispositions are:

       accept The part is passed through unchanged.

       accept_with_warning
              The  part is passed through unchanged, but a warning is added to
              the mail message.

       drop   The part is deleted without any notification to the  recipients.

       drop_with_warning
              The  part is deleted and a warning is added to the mail message.

       replace_with_warning
              The part is deleted and instead replaced with a text message.

       defang The part is passed through unchanged,  but  its  MIME  type  and
              filename  are  changed  to  values which make social engineering
              attacks harder.

       quarantine
              The part is deleted and a warning is added to the mail  message.
              In  addition,  a copy of the part is saved on the mail server in
              the directory /var/spool/MIMEDefang and a notification  is  sent
              to the MIMEDefang administrator.

       bounce The  entire  e-mail message is rejected and an error returned to
              the sender.  The intended recipients are not notified.

       discard
              The entire e-mail message is discarded  silently.   Neither  the
              sender nor the intended recipients are notified.

CONTROLLING RELAYING

       You  can  define  a  function called filter_relay in your filter.  This
       lets you reject SMTP connection attempts early on in the  SMTP  dialog,
       rather  than  waiting until the whole message has been sent.  Note that
       for this check to take place, you must use the -r flag with mimedefang.

       filter_relay  is passed two arguments: $hostip is the IP address of the
       relay host (for example, "127.0.0.1"), and $hostname is the  host  name
       if  known (for example, "localhost.localdomain") If the host name could
       not be determined, $hostname is $hostip enclosed  in  square  brackets.
       (That is, ("$hostname" eq "[$hostip]") will be true.)

       filter_relay  must  return  a  two-element  list:  ($code, $msg).  $msg
       specifies the text message to use for the SMTP reply,  but  because  of
       limitations  in  the  Milter  API,  this  message  is for documentation
       purposes only---you cannot set the text of the SMTP message returned to
       the SMTP client from filter_relay.

       $code is a literal string, and can have one of the following values:

       â€â€™REJECTâ€â€™
              if the connection should be rejected.

       â€â€™CONTINUEâ€â€™
              if the connection should be accepted.

       â€â€™TEMPFAILâ€â€™
              if a temporary failure code should be returned.

       â€â€™DISCARDâ€â€™
              if the message should be accepted and silently discarded.

       â€â€™ACCEPT_AND_NO_MORE_FILTERINGâ€â€™
              if  the  connection  should be accepted and no further filtering
              done.

       Earlier versions of MIMEDefang used -1 for TEMPFAIL, 0 for REJECT and 1
       for CONTINUE.  These values still work, but are deprecated.

       In  the case of REJECT or TEMPFAIL, $msg specifies the text part of the
       SMTP reply.  $msg must not contain newlines.

       For example, if you wish to reject connection attempts from any machine
       in the spammer.com domain, you could use this function:

       sub filter_relay {
            my ($ip, $name) = @_;
            if ($name =~ /spammer\.com$/) {
                 return (’REJECT’, "Sorry; spammer.com is blacklisted");
            }
            return (’CONTINUE’, "ok");
       }

FILTERING BY SENDER

       You  can  define  a function called filter_sender in your filter.  This
       lets you reject messages from  certain  senders,  rather  than  waiting
       until  the  whole  message  has been sent.  Note that for this check to
       take place, you must use the -s flag with mimedefang.

       filter_sender is passed four arguments:  $sender is the envelope e-mail
       address  of  the sender (for example, "<dfs@roaringpenguin.com>").  The
       address may or may not be surrounded by angle brackets.  $ip and  $name
       are  the IP address and host name of the SMTP relay.  Finally, $helo is
       the argument to the SMTP "HELO" command.

       Inside filter_sender, you can  access  any  ESMTP  arguments  (such  as
       "SIZE=12345")  in  the  array @ESMTPArgs.  Each ESMTP argument occupies
       one array element.

       filter_sender must return a two-to-five  element  list:  ($code,  $msg,
       $smtp_code, $smtp_dsn, $delay).  $msg specifies the text message to use
       for the SMTP reply.  If $smtp_code and  $smtp_dsn  are  supplied,  they
       become  the  SMTP numerical reply code and the enhanced status delivery
       code (DSN code).  If they are not supplied, sensible defaults are used.
       $delay  specifies  a delay in seconds; the C milter code will sleep for
       $delay seconds before returning the reply to Sendmail.  $delay defaults
       to zero.

       (Note  that  the  delay  is  implemented  in  the Milter C code; if you
       specify a delay of 30 seconds, that doesn’t mean a Perl slave  is  tied
       up  for  the  duration  of  the delay.  The delay only costs one Milter
       thread.)

       For example, if you wish to reject  messages  from  spammer@badguy.com,
       you could use this function:

       sub filter_sender {
            my ($sender, $ip, $hostname, $helo) = @_;
            if ($sender =~ /^<?spammer\@badguy\.com>?$/i) {
                 return (’REJECT’, ’Sorry; spammer@badguy.com is blacklisted.’);
            }
            return (’CONTINUE’, "ok");
       }

       As  another  example,  some spammers identify their own machine as your
       machine in the SMTP "HELO" command.  This function  rejects  a  machine
       claiming to be in the "roaringpenguin.com" domain unless it really is a
       Roaring Penguin machine:

       sub filter_sender {
         my($sender, $ip, $hostname, $helo) = @_;
         if ($helo =~ /roaringpenguin.com/i) {
           if ($ip ne "127.0.0.1" and
               $ip ne "216.191.236.23" and
               $ip ne "216.191.236.30") {
                 return(’REJECT’, "Go away... $ip is not in roaringpenguin.com");
           }
         }
         return (’CONTINUE’, "ok");
       }

       As a third example, you may wish to prevent spoofs  by  requiring  SMTP
       authentication  when  email  is  sent  from  some email addresses. This
       function rejects mail from "king@example.com",  unless  the  connecting
       user properly authenticated as "elvisp". Note that this needs access to
       the %SendmailMacros global, which is  not  available  in  filter_sender
       until after a call to read_commands_file.

       sub filter_sender {
               my($sender, $ip, $hostname, $helo) = @_;
               read_commands_file();
               ### notice: This assumes The King uses authentication without realm!
               if ($sender =~ /^<?king\@example\.com>?$/i and
                   $SendmailMacros{auth_authen} ne "elvisp") {
                       return(’REJECT’, "Faking mail from the king is not allowed.");
               }
               return (’CONTINUE’, "ok");
       }

FILTERING BY RECIPIENT

       You can define a function called filter_recipient in your filter.  This
       lets you reject messages to certain  recipients,  rather  than  waiting
       until  the  whole  message  has been sent.  Note that for this check to
       take place, you must use the -t flag with mimedefang.

       filter_recipient is passed nine arguments:  $recipient is the  envelope
       address  of the recipient and $sender is the envelope e-mail address of
       the sender (for example,  "<dfs@roaringpenguin.com>").   The  addresses
       may  or may not be surrounded by angle brackets.  $ip and $name are the
       IP address and host name of the SMTP relay.   $first  is  the  envelope
       address  of  the  first  recipient  for  this message, and $helo is the
       argument to  the  SMTP  "HELO"  command.   The  last  three  arguments,
       $rcpt_mailer,  $rcpt_host  and $rcpt_addr are the Sendmail mailer, host
       and address triple for the recipient address.  For example,  for  local
       recipients,  $rcpt_mailer  is  likely  to  be "local", while for remote
       recipients, it is likely to be "esmtp".

       Inside filter_recipient, you can access any ESMTP  arguments  (such  as
       "NOTIFY=never")  in the array @ESMTPArgs.  Each ESMTP argument occupies
       one array element.

       filter_recipient  must  return  a  two-to-five   element   list   whose
       interpretation  is  the same as for filter_sender.  Note, however, that
       if filter_recipient returns ’DISCARD’, then the entire message for  all
       recipients is discarded.  (It doesn’t really make sense, but that’s how
       Milter works.)

       For example, if you wish to reject  messages  from  spammer@badguy.com,
       unless   they  are  to  postmaster@mydomain.com,  you  could  use  this
       function:

       sub filter_recipient {
            my ($recipient, $sender, $ip, $hostname, $first, $helo,
                   $rcpt_mailer, $rcpt_host, $rcpt_addr) = @_;
            if ($sender =~ /^<?spammer\@badguy\.com>?$/i) {
                 if ($recipient =~ /^<?postmaster\@mydomain\.com>?$/i) {
                      return (’CONTINUE’, "ok");
                 }
                 return (’REJECT’, ’Sorry; spammer@badguy.com is blacklisted.’);
            }
            return (’CONTINUE’, "ok");
       }

INITIALIZATION AND CLEANUP

       Just before a slave begins processing messages, mimedefang.pl calls the
       functions  filter_initialize  (if it is defined) with no arguments.  By
       the time filter_initialize is  called,  all  the  other  initialization
       (such as setting up syslog facility and priority) has been done.

       If  you  are not using an embedded Perl interpreter, then performing an
       action inside filter_initialize is practically the same  as  performing
       it  directly  in  the  filter  file,  outside  any function definition.
       However, if you are using an embedded Perl interpreter,  then  anything
       you  call  directly from outside a function definition is executed once
       only in the parent process.  Anything in filter_initialize is  executed
       once  per  slave.   If  you  use  any code that opens a descriptor (for
       example, a connection to a database server), you  must  run  that  code
       inside  filter_initialize and not directly from the filter, because the
       multiplexor closes all open descriptors when it activates a new  slave.

       When  a  slave  is  about  to  exit,  mimedefang.pl  calls the function
       filter_cleanup (if it is defined) with no arguments.  This function can
       do  whatever  cleanup  you  like,  such as closing file descriptors and
       cleaning  up  long-lived  slave  resources.   The  return  value   from
       filter_cleanup becomes the slave’s exit status.

       If  filter_cleanup  takes  longer  than 10 seconds to run, the slave is
       sent a SIGTERM  signal.   If  that  doesn’t  kill  it  (because  you’re
       catching  signals, perhaps), then a further 10 seconds later, the slave
       is sent a SIGKILL signal.

CONTROLLING PARSING

       If  you  define  a  function  called  filter_create_parser  taking   no
       arguments,  then  mimedefang.pl  will  call it to create a MIME::Parser
       object for parsing mail messages.

       Filter_create_parser is expected to return a MIME::Parser object (or an
       instance of a class derived from MIME::Parser).

       You  can  use  filter_create_parser  to  change  the  behavior  of  the
       MIME::Parser used by mimedefang.pl.

       If you do not define a filter_create_parser function, then  a  built-in
       version equivalent to this is used:

            sub filter_create_parser () {
                 my $parser = MIME::Parser->new();
                 $parser->extract_nested_messages(1);
                 $parser->extract_uuencode(1);
                 $parser->output_to_core(0);
                 $parser->tmp_to_core(0);
                 return $parser;
            }

EXTENDING MIMEDEFANG

       The  man page for mimedefang-protocol(7) lists commands that are passed
       to slaves in server mode (see "SERVER COMMANDS".)   You  can  define  a
       function  called  filter_unknown_cmd to extend the set of commands your
       filter can handle.

       If you define filter_unknown_cmd, it is passed the unknown command as a
       single  argument.   It  should return a list of values as follows:  The
       first element of the list must be either "ok"  or  "error:"  (with  the
       colon.)    The   remaining  arguments  are  percent-encoded.   All  the
       resulting pieces are joined together with a single space between  them,
       and the resulting string passed back as the reply to the multiplexor.

       For  example,  the  following function will make your filter reply to a
       "PING" command with "PONG":

       sub filter_unknown_cmd ($) {
           my($cmd) = @_;
           if ($cmd eq "PING") {
               return("ok", "PONG");
           }
           return("error:", "Unknown command");
       }

       You can test this filter by typing the following as root:

       md-mx-ctrl PING

       The response should be:

       ok PONG

       If you extend the set of commands using filter_unknown_cmd, you  should
       make all your commands start with an upper-case letter to avoid clashes
       with future built-in commands.

REJECTING UNKNOWN USERS EARLY

       A very common mail setup is to have a MIMEDefang machine act as an SMTP
       proxy,  accepting  and  scanning  mail and then relaying it to the real
       mail server.  Unfortunately, this means  that  the  MIMEDefang  machine
       cannot  know  if  a local address is valid or not, and will forward all
       mail for the appropriate domains.  If a mail comes in  for  an  unknown
       user,  the  MIMEDefang  machine  will  be  forced  to generate a bounce
       message when it tries to relay the mail.

       It’s often desirable to have the MIMEDefang host  reply  with  a  "User
       unknown" SMTP response directly.  While this can be done by copying the
       list of local users to the MIMEDefang machine, MIMEDefang has a  built-
       in  function  called  md_check_against_smtp_server for querying another
       relay host:

       md_check_against_smtp_server($sender, $recip,  $helo,  $server,  $port)
       This
              function connects to the SMTP server  $server  and  pretends  to
              send  mail from $sender to $recip.  The return value is always a
              two-element array.  If the RCPT TO: command succeeds, the return
              value is ("CONTINUE", "OK").  If the RCPT fails with a permanent
              failure, the return value is ("REJECT", $msg), where $msg is the
              message   from   the   SMTP  server.   Any  temporary  failures,
              connection errors, etc. result in a return value of ("TEMPFAIL",
              $msg).

              The  optional  argument  $port specifies the TCP port to connect
              to.  If it is not supplied, then the default SMTP port of 25  is
              used.

       Suppose  the  machine  filter.domain.tld is filtering mail destined for
       the   real   mail   server   mail.domain.tld.    You   could   have   a
       filter_recipient function like this:

       sub filter_recipient
       {
           my($recip, $sender, $ip, $host, $first, $helo,
              $rcpt_mailer, $rcpt_host, $rcpt_addr) = @_;
           return md_check_against_smtp_server($sender, $recip,
                                "filter.domain.tld",
                                "mail.domain.tld");
       }

       For  each  RCPT  TO:  command,  MIMEDefang  opens an SMTP connection to
       mail.domain.tld and checks if the command would succeed.

       Please note that you should only  use  md_check_against_smtp_server  if
       your  mail server responds with a failure code for nonexistent users at
       the RCPT TO: level.  Also, this function may impose too  much  overhead
       if  you  receive  a lot of e-mail, and it will generate lots of useless
       log entries on the real mail  server  (because  of  all  the  RCPT  TO:
       probes.)   It may also significantly increase the load on the real mail
       server.

GLOBAL VARIABLES YOU CAN SET

       The following Perl global variables should be set in mimedefang-filter:

       $AdminAddress
              The e-mail address of the MIMEDefang administrator.

       $DaemonAddress
              The    e-mail    address    from   which   MIMEDefang-originated
              notifications come.

       $AddWarningsInline
              If this variable is set to 0, then all MIMEDefang warnings (such
              as created by action_quarantine or action_drop_with_warning) are
              collected together and added in  a  separate  MIME  part  called
              WARNING.TXT.  If the variable is set to 1, then the warnings are
              added directly in the first text/plain and  text/html  parts  of
              the  message.  If the message does not contain any text/plain or
              text/html parts, then  a  WARNING.TXT  MIME  part  is  added  as
              before.

       $MaxMIMEParts
              A  message  containing  many MIME parts can cause MIME::Tools to
              consume large amounts of memory and bring  your  system  to  its
              knees.  If you set $MaxMIMEParts to a positive number, then MIME
              parsing is terminated for messages  with  more  than  that  many
              parts,  and  the message is bounced.  In this case, none of your
              filter functions is called.

              By default, $MaxMIMEParts is set to  -1,  meaning  there  is  no
              limit  on  the number of parts in a message.  Note that in order
              to use this variable,  you  must  install  the  Roaring  Penguin
              patched  version of MIME::Tools, version 5.411a-RP-Patched-02 or
              newer.

       $Stupidity{"NoMultipleInlines"}
              Set this to 1 if your e-mail is too stupid to  display  multiple
              MIME parts in-line.  In this case, a nasty hack causes the first
              part of the original message  to  appear  as  an  attachment  if
              warning  are issued.  Mail clients which are not this stupid are
              Netscape Communicator and Pine.  On the  other  hand,  Microsoft
              Exchange  and Microsoft Outlook are indeed this stupid.  Perhaps
              users of those clients should switch.

              The following global variables may optionally be set.   If  they
              are not set, sensible defaults are used:

       $AddApparentlyToForSpamAssassin
              By default, MIMEDefang tries to pass SpamAssassin a message that
              looks exactly like one it  would  receive  via  procmail.   This
              means  adding  a Received: header, adding a Message-ID header if
              necessary,  and  adding  a  Return-Path:  header.   If  you  set
              $AddApparentlyToForSpamAssassin  to 1, then MIMEDefang also adds
              an Apparently-To: header with all the envelope recipients before
              passing  the  message  to  SpamAssassin.  This lets SpamAssassin
              detect possibly whitelisted recipient addresses.

              The default value for $AddApparentlyToForSpamAssassin is 0.

       $SyslogFacility
              This specifies the logging facility used by  mimedefang.pl.   By
              default,  it  is  set  to  "mail",  but  you can set it to other
              possibilites.  See the openlog(3) man  page  for  details.   You
              should  name  facilities  as  all-lowercase  without the leading
              "LOG_".  That is, use "local3", not "LOG_LOCAL3".

       $WarningLocation (default 0)
              If set to 0 (the default), non-inline warnings are placed first.
              If  you  want  the  warning  at  the  end  of  the  e-mail,  set
              $WarningLocation to -1.

       $DaemonName (default "MIMEDefang")
              The full name used when MIMEDefang sends out notifications.

       $AdminName (default "MIMEDefang Administrator")
              The full name of the MIMEDefang administrator.

       $SALocalTestsOnly (default 1)
              If set to 1, SpamAssassin calls will use only local tests.  This
              is the default and recommended setting.  This disables Received,
              RBL and Razor tests in an all or nothing fashion.  To use  Razor
              this  MUST be set to 0.  You can add ’skip_rbl_checks 1’ to your
              SpamAssassin config file if you need to.

       $NotifySenderSubject (default "MIMEDefang Notification")
              The   subject   used   when    e-mail    is    sent    out    by
              action_notify_sender().  If you set this, you should set it each
              time you call action_notify_sender() to ensure consistency.

       $NotifyAdministratorSubject (default "MIMEDefang Notification")
              The   subject   used   when    e-mail    is    sent    out    by
              action_notify_administrator().   If you set this, you should set
              it each time you call  action_notify_administrator()  to  ensure
              consistency.

       $QuarantineSubject (default "MIMEDefang Quarantine Report")
              The  subject  used  when  a  quarantine  notice  is  sent to the
              administrator.  If you set this, you should set it each time you
              call  action_quarantine() or action_quarantine_entire_message().

       $NotifyNoPreamble (default 0)
              Normally, notifications sent by  action_notify_sender()  have  a
              preamble  warning  about  message  modifications.  If you do not
              want this, set $NotifyNoPreamble to 1.

       $OpenAVHost (default 127.0.0.1:8127)
              Host     used     for     OpenAV     daemon     calls     within
              message_contains_virus_openantivirus                         and
              entity_contains_virus_openantivirus unless a host is provided by
              the calling routine.

       $CSSHost (default 127.0.0.1:7777:local)
              Host and port for the Symantec CarrierScan Server virus scanner.
              This takes the form ip_addr:port:local_or_nonlocal.  The ip_addr
              and  port  are  the host and port on which CarrierScan Server is
              listening.  If you want to scan local files,  append  :local  to
              force  the  use  of the AVSCANLOCAL command.  If the CarrierScan
              Server is on another host, append :nonlocal to  force  the  file
              contents to be sent to the scanner over the socket.

       $SophieSock (default /var/spool/MIMEDefang/sophie)
              Socket     used     for     Sophie     daemon    calls    within
              message_contains_virus_sophie  and  entity_contains_virus_sophie
              unless a socket is provided by the calling routine.

       $ClamdSock (default /var/spool/MIMEDefang/clamd.sock)
              Socket     used     for     clamd     daemon     calls    within
              message_contains_virus_clamd   and   entity_contains_virus_clamd
              unless a socket is provided by the calling routine.

       $TrophieSock (default /var/spool/MIMEDefang/trophie)
              Socket     used     for     Trophie    daemon    calls    within
              message_contains_virus_trophie and entity_contains_virus_trophie
              unless a socket is provided by the calling routine.

FILTER

       The  heart  of  mimedefang-filter  is  the  filter  procedure.  See the
       examples which came with MIMEDefang to learn to write  a  filter.   The
       filter is called with the following arguments:

       $entity
              The  MIME::Entity  object.   (See  the  MIME::tools  Perl module
              documentation.)

       $fname The suggested attachment filename, or "" if none was supplied.

       $ext   The file extension (all characters from the rightmost period  to
              the end of the filename.)

       $type  The MIME type (for example, "text/plain".)

       The filename is derived as follows:

       o      First, if the Content-Disposition header has a "filename" field,
              it is used.

       o      Otherwise, if the Content-Type header has a "name" field, it  is
              used.

       o      Otherwise, the Content-Description header value is used.

       Note  that  the truly paranoid will check all three fields for matches.
       The functions re_match  and  re_match_ext  perform  regular  expression
       matches  on  all  three  of the fields named above, and return 1 if any
       field matches.  See  the  sample  filters  for  details.   The  calling
       sequence is:

            re_match($entity, "regexp")
            re_match_ext($entity, "regexp")

       re_match  returns  true if any of the fields matches the regexp without
       regard to case.  re_match_ext returns true  if  the  extension  in  any
       field  matches.   An extension is defined as the last dot in a name and
       all remaining characters.

       A third function called re_match_in_zip_directory will look inside  zip
       files  and  return true if any of the file names inside the zip archive
       match the regular expression.  Call it like this:

            my $bh = $entity->bodyhandle();
            my $path = (defined($bh)) ? $bh->path() : undef;
            if (defined($path) and re_match_in_zip_directory($path, "regexp")) {
                # Take action...
            }

       You should not call re_match_in_zip_directory unless you know that  the
       entity is a zip file attachment.

GLOBAL VARIABLES SET BY MIMEDEFANG.PL

       The  following  global  variables  are  set  by  mimedefang.pl  and are
       available for use in your filter.  All of these  variables  are  always
       available to filter_begin, filter, filter_multipart and filter_end.  In
       addition, some of them are available in filter_relay, filter_sender  or
       filter_recipient.  If this is the case, it will be noted below.

       %Features
              This  hash  lets  you  determine  at  run-time  whether  certain
              functionality is available.  This hash is available at all times
              assuming  the  detect_and_load_perl_modules()  function has been
              called.  The defined features are:

              $Features{"SpamAssassin"} is 1 if SpamAssassin 1.6 or better  is
              installed; 0 otherwise.

              $Features{"HTMLCleaner"}   is   1   if   Anomy::HTMLCleaner   is
              installed; 0 otherwise.

              $Features{"File::Scan"} is  1  if  File::Scan  is  installed;  0
              otherwise.

              $Features{"HTML::Parser"}  is  1 if HTML::Parser is installed; 0
              otherwise.

              $Features{"Virus:FileScan"}       is       a       copy       of
              $Features{"File::Scan"}.

              $Features{"Virus:OpenAV"}  is  provided  for completeness and is
              currently always 0.  Set it to 1 in your filter file if you have
              OpenAntiVirus.

              $Features{"Virus:FPROTD"} is currently always 0.  Set it to 1 in
              your filter file if you have F-Risk’s FPROTD scanner.

              $Features{"Virus:SymantecCSS"} is currently always 0.  Set it to
              1  in  your  filter  file  if  you have the Symantec CarrierScan
              Server virus scanner.

              $Features{"Virus:NAI"} is the full path to NAI uvscan if  it  is
              installed; 0 if it is not.

              $Features{"Virus:BDC"} is the full path to Bitdefender bdc if it
              is installed; 0 if it is not.

              $Features{"Virus:NVCC"} is the full path to Norman Virus Control
              nvcc if it is installed; 0 if it is not.

              $Features{"Virus:HBEDV"}  is  the full path to H+BEDV AntiVir if
              it is installed; 0 if it is not.

              $Features{"Virus:VEXIRA"} is the full path  to  Central  Command
              Vexira if it is installed; 0 if it is not.

              $Features{"Virus:SOPHOS"} is the full path to Sophos sweep if it
              is installed; 0 if it is not.

              $Features{"Virus:CLAMAV"} is the full path to Clam  AV  clamscan
              if it is installed; 0 if it is not.

              $Features{"Virus:AVP"} is the full path to AVP AvpLinux if it is
              installed; 0 if it is not.

              $Features{"Virus:AVP5"}  is   the   full   path   to   Kaspersky
              "aveclient" if it is installed; 0 if it is not.

              $Features{"Virus:CSAV"}  is  the full path to Command csav if it
              is installed; 0 if it is not.

              $Features{"Virus:FSAV"} is the full path to F-Secure fsav if  it
              is installed; 0 if it is not.

              $Features{"Virus:FPROT"} is the full path to F-Risk f-prot if it
              is installed; 0 if it is not.

              $Features{"Virus:SOPHIE"} is the full path to Sophie  if  it  is
              installed; 0 if it is not.

              $Features{"Virus:CLAMD"}  is  the  full  path  to clamd if it is
              installed; 0 if it is not.

              $Features{"Virus:TROPHIE"} is the full path to Trophie if it  is
              installed; 0 if it is not.

              NOTE:  Perl-module based features (SpamAssassin, HTMLCleaner and
              Virus:FileScan) are determined at  runtime  and  may  change  as
              these   are   added   and  removed.   Most  Virus  features  are
              predetermined at the time of configuration and do not  adapt  to
              runtime availability unless changed by the filter rules.

       $CWD   This  variable  holds  the  working  directory  for  the current
              message.  During filter processing, mimedefang.pl  chdir’s  into
              this  directory  before  calling  any  of the filter_ functions.
              Note that this variable is set correctly  in  filter_sender  and
              filter_recipient, but not in filter_relay.

       $SuspiciousCharsInHeaders
              If  this  variable  is  true,  then  mimedefang  has  discovered
              suspicious characters in message  headers.   This  might  be  an
              exploit  for bugs in MIME-parsing routines in some badly-written
              mail user agents (e.g. Microsoft Outlook.)   You  should  always
              drop such messages.

       $SuspiciousCharsInBody
              If  this  variable  is  true,  then  mimedefang  has  discovered
              suspicious characters in the message body.   This  might  be  an
              exploit  for bugs in MIME-parsing routines in some badly-written
              mail user agents (e.g. Microsoft Outlook.)   You  should  always
              drop such messages.

       $RelayHostname
              The  host name of the relay.  This is the name of the host which
              is attempting to send e-mail to your host.  May  be  "undef"  if
              the  host  name  could  not  be  determined.   This  variable is
              available in filter_relay, filter_sender and filter_recipient.

       $RelayAddr
              The IP address of the sending relay (as a string  consisting  of
              four  dot-separated  decimal  numbers.)   One  potential  use of
              $RelayAddr is to limit mailing to certain lists to people within
              your  organization.  This variable is available in filter_relay,
              filter_sender and filter_recipient.

       $Helo  The argument given to the SMTP "HELO" command.  This variable is
              available  in  filter_sender  and  filter_recipient,  but not in
              filter_relay.

       $Subject
              The contents of the "Subject:" header.

       $Sender
              The sender of the e-mail.  This variable is set in filter_sender
              and filter_recipient.

       @Recipients
              A list of the recipients.  In filter_recipient, it is set to the
              single  recipient  currently  under  consideration.  Or,   after
              calling  read_commands_file within filter_recipient, the current
              recipient under consideration is in the final  position  of  the
              array,  at  $Recipients[-1],  while  any previous (and accepted)
              recipients are at the  beginning  of  the  array,  that  is,  in
              @Recipients[0 .. $#Recipients-1].

       $MessageID
              The  contents  of  the  "Message-ID:"  header if one is present.
              Otherwise, contains the string "NOQUEUE".

       $QueueID
              The  Sendmail  queue  identifier  if  it  could  be  determined.
              Otherwise,  contains  the string "NOQUEUE". This variable is set
              correctly in filter_sender and filter_recipient, but it  is  not
              available in filter_relay.

       $MsgID Set  to $QueueID if the queue ID could be determined; otherwise,
              set to $MessageID.  This identifier should be used  in  logging,
              because  it  matches  the  identifier  used  by  Sendmail to log
              messages.   Note  that  this  variable  is  set   correctly   in
              filter_sender  and  filter_recipient, but it is not available in
              filter_relay.

       $VirusScannerMessages
              Each time a virus-scanning function is called, messages (if any)
              from  the  virus  scanner are accumulated in this variable.  You
              can use it in filter_end to formulate  a  notification  (if  you
              wish.)

       $VirusName
              If  a  virus-scanning function found a virus, this variable will
              hold the virus name (if it could be determined.)

       $SASpamTester
              If defined, this is  the  configured  Mail::SpamAssassin  object
              used  for  mail  tests.   It  may  be initialized with a call to
              spam_assassin_init which also returns it.

       %SendmailMacros
              This hash contains the values of some Sendmail macros.  The hash
              elements  exist  only  for  macros defined by Sendmail.  See the
              Sendmail documentation for the meanings of the macros.

              By default,  mimedefang  passes  the  values  of  the  following
              macros:  ${daemon_name},  ${if_name},  ${if_addr},  $j,  $_, $i,
              ${tls_version},  ${cipher},   ${cipher_bits},   ${cert_subject},
              ${cert_issuer},   ${auth_type},   ${auth_authen},   ${auth_ssf},
              ${auth_author}, ${mail_mailer}, ${mail_host} and ${mail_addr}.

              If any macro is not set or not passed  to  milter,  it  will  be
              unavailable.  To access the value of a macro, use:

                   $SendmailMacros{"macro_name"}

              Do  not  place  curly  brackets  around  the  macro  name.  This
              variable is  available  in  filter_sender  and  filter_recipient
              after a call to read_commands_file.

       @SenderESMTPArgs
              This array contains all the ESMTP arguments supplied in the MAIL
              FROM: command.  For example:

              sub print_sender_esmtp_args {
                  foreach (@SenderESMTPArgs) {
                      print STDERR "Sender ESMTP arg: $_0;
                  }
              }

       %RecipientESMTPArgs
              This hash contains all the ESMTP arguments supplied in each RCPT
              TO: command.  For example:

              sub print_recip_esmtp_args {
                  foreach my $recip (@Recipients) {
                      foreach(@{$RecipientESMTPArgs{$recip}}) {
                          print STDERR "Recip ESMTP arg for $recip: $_0;
                      }
                  }
              }

       %RecipientMailers
              This hash contains the Sendmail "mailer-host-address" triple for
              each recipient.  Here’s an example of how to use it:

              sub print_mailer_info {
                  my($recip, $mailer, $host, $addr);
                  foreach $recip (@Recipients) {
                      $mailer = ${RecipientMailers{$recip}}[0];
                      $host = ${RecipientMailers{$recip}}[1];
                      $addr =  ${RecipientMailers{$recip}}[2];
                      print STDERR "$recip: mailer=$mailer, host=$host, addr=$addr\n";
                  }
              }

              In filter_recipient, this  variable  by  default  only  contains
              information  on  the  recipient  currently  under investigation.
              Information  on  all  recipients  is  available  after   calling
              read_commands_file.

ACTIONS

       When  the  filter procedure decides how to dispose of a part, it should
       call one or more action_ subroutines.  The action subroutines are:

       action_accept()
              Accept the part.

       action_rebuild()
              Rebuild the mail body, even if mimedefang thinks no changes were
              made.   Normally,  mimedefang  does  not  alter  a message if no
              changes were made.  action_rebuild  may  be  used  if  you  make
              changes  to  entities  directly (by manipulating the MIME::Head,
              for example.)  Unless you call action_rebuild,  mimedefang  will
              be unaware of the changes.  Note that all the built-in action...
              routines which change a message implicitly call  action_rebuild.

       action_add_header($hdr, $val)
              Add a header from the message.  This can be used in filter_begin
              or filter_end.  The $hdr component is the  header  name  without
              the  colon,  and  the $val is the header value.  For example, to
              add the header:

                   X-MyHeader: A nice piece of text

              use:

                   action_add_header("X-MyHeader", "A nice piece of text");

       action_change_header($hdr, $val, $index)
              Changes an existing header in the message. This can be  used  in
              filter_begin  or  filter_end.   The $hdr parameter is the header
              name without the colon, and $val is the header  value.   If  the
              header  does  not  exist,  then a header with the given name and
              value is added.

              The $index parameter is optional; it  defaults  to  1.   If  you
              supply  it,  then  the  $index’th  occurrence  of  the header is
              changed, if there is more than one header with  the  same  name.
              (This is common with the Received: header, for example.)

       action_delete_header($hdr, $index)
              Deletes  an  existing header in the message. This can be used in
              filter_begin or filter_end.  The $hdr parameter  is  the  header
              name without the colon.

              The  $index  parameter  is  optional;  it defaults to 1.  If you
              supply it, then  the  $index’th  occurrence  of  the  header  is
              deleted, if there is more than one header with the same name.

       action_delete_all_headers($hdr)
              Deletes  all  headers with the specified name.  This can be used
              in filter_begin or filter_end.  The $hdr parameter is the header
              name without the colon.

       action_drop()
              Drop  the  part.   If  called  from  filter_multipart, drops all
              contained parts also.

       action_drop_with_warning($msg)
              Drop the part, but add the warning $msg to the  e-mail  message.
              If called from filter_multipart, drops all contained parts also.

       action_accept_with_warning($msg)
              Accept the part, but add the warning $msg to the e-mail message.

       action_replace_with_warning($msg)
              Drop  the  part and replace it with a text part $msg.  If called
              from filter_multipart, drops all contained parts also.

       action_replace_with_url($entity, $doc_root, $base_url, $msg, [$cd_data,
       $salt])
              Drop the part, but save it in a unique location under $doc_root.
              The  part  is  replaced  with the text message $msg.  The string
              "_URL_" in $msg is replaced with $base_url/something, which  can
              be used to retrieve the message.

              You should not use this function in filter_multipart.

              This  action  is  intended  for stripping large parts out of the
              message and replacing them to a link on a  Web  server.   Here’s
              how you would use it in filter():

              $size = (stat($entity->bodyhandle->path))[7];
              if ($size > 1000000) {
                   return action_replace_with_url($entity,
                        "/home/httpd/html/mail_parts",
                        "http://mailserver.company.com/mail_parts",
                        "The attachment was larger than 1,000,000 bytes.\n" .
                        "It was removed, but may be accessed at this URL:\n\n" .
                        "\t_URL_\n");
              }

              This example moves attachments greater than 1,000,000 bytes into
              /home/httpd/html/mail_parts and replaces them with a link.   The
              directory   should   be   accessible   via   a   Web  server  at
              http://mailserver.company.com/mail_parts.

              The generated name is created by performing a SHA1 hash  of  the
              part and adding the extension to the ASCII-HEX representation of
              the hash.  If many different  e-mails  are  sent  containing  an
              identical  large  part,  only  one  copy  of the part is stored,
              regardless of the number of senders or recipients.

              For privacy reasons, you must turn off Web  server  indexing  in
              the  directory  in which you place mail parts, or anyone will be
              able to read them.  If indexing is disabled, an  attacker  would
              have to guess the SHA1 hash of a part in order to read it.

              Optionally,  a fifth argument can supply data to be saved into a
              hidden dot filename based on the generated name.  This data  can
              then  be  read  in on the fly by a CGI script or mod_perl module
              before serving the file  to  a  web  client,  and  used  to  add
              information to the response, such as Content-Disposition data.

              A  sixth optional argument, $salt, is mixed in to the SHA1 hash.
              This salt can be any string and  should  be  kept  confidential.
              The  salt is designed to prevent people from guessing whether or
              not a particular attachment has been received on your server  by
              altering the SHA1 hash calculation.

       action_defang($entity, $name, $fname, $type)
              Accept  the  part,  but  change its name to $name, its suggested
              filename to $fname and its MIME type  to  $type.   If  $name  or
              $fname  are  "", then mimedefang.pl generates generic names.  Do
              not use this action in filter_multipart.

              If you use action_defang, you must define  a  subroutine  called
              defang_warning   in   your   filter.   This  routine  takes  two
              arguments: $oldfname (the original name of  an  attachment)  and
              $fname  (the  defanged  version.)   It  should  return a message
              telling the user what happened.  For example:

              sub defang_warning {
                  my($oldfname, $fname) = @_;
                  return "The attachment ’$oldfname’ was renamed to ’$fname’\n";
              }

       action_external_filter($entity, $cmd)
              Run an external UNIX command $cmd.  This command must  read  the
              part  from  the  file  ./FILTERINPUT  and  leave  the  result in
              ./FILTEROUTPUT.  If the command executes  successfully,  returns
              1,  otherwise 0.  You can test the return value and call another
              action_ if the  filter  failed.   Do  not  use  this  action  in
              filter_multipart.

       action_quarantine($entity, $msg)
              Drop and quarantine the part, but add the warning $msg to the e-
              mail message.

       action_quarantine_entire_message($msg)
              Quarantines the entire message in a quarantine directory on  the
              mail  server,  but  does not otherwise affect disposition of the
              message.   If  "$msg"  is  non-empty,  it  is  included  in  any
              administrator notification.

       action_sm_quarantine($reason)
              Quarantines  a  message in the Sendmail mail queue using the new
              QUARANTINE facility of  Sendmail  8.13.   Consult  the  Sendmail
              documentation  for  details  about  this  facility.   If you use
              action_sm_quarantine with a version of Sendmail that  lacks  the
              QUARANTINE  facility,  mimedefang  will log an error message and
              not quarantine the message.

       action_bounce($reply, $code, $dsn)
              Reject the entire e-mail message with an SMTP failure code,  and
              the  one-line  error  message $reply.  If the optional $code and
              $dsn arguments are supplied, they  specify  the  numerical  SMTP
              reply  code  and  the  extended  status code (DSN code).  If the
              codes you supply do not  make  sense  for  a  bounce,  they  are
              replaced with "554" and "5.7.1" respectively.

              action_bounce  merely  makes  a  note  that the message is to be
              bounced; remaining parts are still processed.  If  action_bounce
              is  called  for more than one part, the mail is bounced with the
              message in the final call to action_bounce.  You can  profitably
              call  action_quarantine followed by action_bounce if you want to
              keep a copy of the offending part.  Note that the message is not
              bounced  immediately;  rather, remaining parts are processed and
              the message is bounced after all parts have been processed.

              Note that despite its name, action_bounce does  not  generate  a
              "bounce  message".   It  merely rejects the message with an SMTP
              failure code.

              WARNING: action_bounce() may cause the sending relay to generate
              spurious  bounce  messages if the sender address is faked.  This
              is a particular problem with viruses.  However, we believe  that
              on  balance,  it’s  better  to  bounce  a virus than to silently
              discard it.  It’s almost never a good idea to hide a problem.

       action_tempfail($msg, $code, $dsn)
              Cause an SMTP "temporary failure" code to be  returned,  so  the
              sending  mail  relay requeues the message and tries again later.
              The message $msg is included with the  temporary  failure  code.
              If  the  optional  $code  and  $dsn arguments are supplied, they
              specify the numerical SMTP reply code and  the  extended  status
              code  (DSN code).  If the codes you supply do not make sense for
              a temporary failure, they are replaced with  "450"  and  "4.7.1"
              respectively.

       action_discard()
              Silently   discard  the  message,  notifying  nobody.   You  can
              profitably call action_quarantine followed by action_discard  if
              you  want  to  keep a copy of the offending part.  Note that the
              message is not discarded immediately;  rather,  remaining  parts
              are  processed and the message is discarded after all parts have
              been processed.

       action_notify_sender($message)
              This action sends an e-mail back to the original sender with the
              indicated  message.  You may call another action after this one.
              If action_notify_sender is called more than once,  the  messages
              are  accumulated  into  a  single  e-mail message -- at most one
              notification message is sent per incoming message.  The  message
              should be terminated with a newline.

              The notification is delivered in deferred mode; you should run a
              client-queue runner if you are using Sendmail 8.12.

              NOTE: Viruses often fake the sender address.  For  that  reason,
              if a virus-scanner has detected a virus, action_notify_sender is
              disabled and will simply log an error message if you try to  use
              it.

       action_notify_administrator($message)
              This  action  e-mails  the MIMEDefang administrator the supplied
              message.   You  may  call  another  action   after   this   one;
              action_notify_administrator does not affect mail processing.  If
              action_notify_administrator  is  called  more  than  once,   the
              messages are accumulated into a single e-mail message -- at most
              one notification message is  sent  per  incoming  message.   The
              message should be terminated with a newline.

              The notification is delivered in deferred mode; you should run a
              client-queue runner if you are using Sendmail 8.12.

       anomy_clean_html($entity, {"name" => val , ...})
              If    you    have    the    Anomy    mail     cleaning     tools
              (http://mailtools.anomy.net)   and   have  installed  the  Anomy
              modules in a standard Perl include directory, this function uses
              an  Anomy::HTMLCleaner  object  to  sanitize  the  HTML  code in
              $entity,  which  assumed  to  be   of   type   text/html.    The
              configuration   arguments  are  optional;  possible  values  are
              documented in comments in the Anomy/HTMLCleaner.pm Perl  module.

       append_text_boilerplate($entity, $boilerplate, $all)
              This  action  should only be called from filter_end.  It appends
              the text "\n$boilerplate\n" to the  first  text/plain  part  (if
              $all is 0) or to all text/plain parts (if $all is 1).

       append_html_boilerplate($entity, $boilerplate, $all)
              This  action should only be called from filter_end.  It adds the
              text "\n$boilerplate\n" to the first text/html part (if $all  is
              0)  or  to  all  text/html  parts (if $all is 1).  This function
              tries to be smart  about  inserting  the  boilerplate;  it  uses
              HTML::Parser  to detect closing tags and inserts the boilerplate
              before the </body> tag if there is one, or  before  the  </html>
              tag  if  there is no </body>.  If there is no </body> or </html>
              tag, it appends the boilerplate to the end of the part.

              Do not use append_html_boilerplate unless you have installed the
              HTML::Parser Perl module.

              Here  is  an  example  illustrating  how  to use the boilerplate
              functions:

                   sub filter_end {
                        my($entity) = @_;
                        append_text_boilerplate($entity,
                             "Lame text disclaimer", 0);
                        append_html_boilerplate($entity,
                             "<em>Lame</em> HTML disclaimer", 0);
                   }

       action_add_part($entity, $type, $encoding, $data, $fname,  $disposition
       [, $offset])
              This action should only be called from the  filter_end  routine.
              It  adds  a  new  part  to  the message, converting the original
              message to mutipart if necessary.  The function returns the part
              so  that additional mime attributes may be set on it.  Here’s an
              example:

                   sub filter_end {
                        my($entity) = @_;

                        action_add_part($entity, "text/plain", "-suggest",
                                  "This e-mail does not represent" .
                                  "the official policy of FuBar, Inc.\n",
                                  "disclaimer.txt", "inline");
                      }

              The  $entity  parameter  must  be  the  argument  passed  in  to
              filter_end.   The  $offset parameter is optional; if omitted, it
              defaults to -1, which adds the new part at  the  end.   See  the
              MIME::Entity  man  page and the add_part member function for the
              meaning of $offset.

              Note that action_add_part tries  to  be  more  intelligent  than
              simply  calling  $entity->add_part.   The decision process is as
              follows:

       o      If the top-level entity is multipart/mixed,  then  the  part  is
              simply added.

       o      Otherwise,   a   new   top-level  multipart/mixed  container  is
              generated, and the original top-level entity is made  the  first
              part  of  the  multipart/mixed  container.  The new part is then
              added to the multipart/mixed container.

USEFUL ROUTINES

       mimedefang.pl includes some useful functions you  can  call  from  your
       filter:

       detect_and_load_perl_modules()
              Unless  you really know what you’re doing, this function must be
              called first thing in your filter file.  It causes mimedefang.pl
              to  detect  and  load  Perl  modules such as Mail::SpamAssassin,
              Net::DNS, etc., and to populate the %Features hash.

       send_quarantine_notifications()
              This function should be called from filter_end.   If  any  parts
              were  quarantined,  a  quarantine  notification  is  sent to the
              MIMEDefang administrator.  Please note that if you do  not  call
              send_quarantine_notifications,  then no quarantine notifications
              are sent.

       get_quarantine_dir()
              This function returns the  full  path  name  of  the  quarantine
              directory.   If  you  have  not yet quarantined any parts of the
              message, a quarantine directory  is  created  and  its  pathname
              returned.

       add_recipient($recip)
              This function adds $recip to the list of envelope recipients.  A
              copy of the message (after any modifications by MIMEDefang) will
              be  sent to $recip in addition to the original recipients.  Note
              that add_recipient does not modify  the  @Recipients  array;  it
              just makes a note to Sendmail to add the recipient.

       delete_recipient($recip)
              This  function deletes $recip from the list of recipients.  That
              person will not receive a  copy  of  the  mail.   $recip  should
              exactly   match   an   entry   in   the  @Recipients  array  for
              delete_recipient() to work.  Note that delete_recipient does not
              modify  the  @Recipients array; it just makes a note to Sendmail
              to delete the recipient.

       resend_message($recip1, $recip2, ...)
              or

       resend_message(@recips)
              This function immediately resends the original, unmodified  mail
              message  to  each of the named recipients.  The sender’s address
              is preserved.  Be very careful when using this function, because
              it  resends  the  original  message, which may contain undesired
              attachments.  Also, you  should  not  call  this  function  from
              filter(), because it resends the message each time it is called.
              This may result in multiple copies being sent  if  you  are  not
              careful.  Call from filter_begin() or filter_end() to be safe.

              The function returns true on success, or false if it fails.

              Note  that  the  resend_message  function  delivers  the mail in
              deferred mode (using Sendmail’s "-odd" flag.)  You  must  run  a
              client-submission  queue processor if you use Sendmail 8.12.  We
              recommend executing this command as part of the Sendmail startup
              sequence:

                   sendmail -Ac -q5m

       remove_redundant_html_parts($entity)
              This function should only be called from filter_end.  It removes
              redundant HTML parts from the message.  It works by deleting any
              part  of type text/html from the message if (1) it is a sub-part
              of a multipart/alternative part, and (2) there is  another  part
              of type text/plain under the multipart/alternative part.

       replace_entire_message($entity)
              This  function  can only be called from filter_end.  It replaces
              the entire message with $entity, a MIME::Entity object that  you
              have  constructed.  You can use any of the MIME::Tools functions
              to construct the entity.

       read_commands_file()
              This function should  only  be  called  from  filter_sender  and
              filter_recipient. This will read the COMMANDS file (as described
              in  mimedefang-protocol(7)),  and  will  fill  or   update   the
              following     global     variables:     $Sender,    @Recipients,
              %RecipientMailers, $RelayAddr,  $RealRelayAddr,  $RelayHostname,
              $RealRelayHostname, $QueueID, $Helo, %SendmailMacros.

              If you do not call read_commands_file, then the only information
              available in filter_sender and filter_recipient is that which is
              passed as an argument to the function.

       stream_by_domain()
              Do  not  use  this  function  unless  you have Sendmail 8.12 and
              locally- submitted e-mail is submitted using SMTP.

              This function should only be called at  the  very  beginning  of
              filter_begin(), like this:

                   sub filter_begin {
                        if (stream_by_domain()) {
                             return;
                        }
                        # Rest of filter_begin
                   }

              stream_by_domain()  looks  at all the recipients of the message,
              and if they belong to the  same  domain  (e.g.,  joe@domain.com,
              jane@domain.com  and  sue@domain.com), it returns 0 and sets the
              global variable  $Domain  to  the  domain  (domain.com  in  this
              example.)

              If  users  are  in different domains, stream_by_domain() resends
              the message (once to each domain) and returns 1 For example,  if
              the   original  recipients  are  joe@abc.net,  jane@xyz.net  and
              sue@abc.net, the original message is resent twice: One  copy  to
              joe@abc.net  and  sue@abc.net, and another copy to jane@xyz.net.
              Also,  any  subsequent  scanning  is  canceled   (filter()   and
              filter_end()  will  not  be called for the original message) and
              the message is silently discarded.

              If you have Sendmail 8.12, then locally-submitted  messages  are
              sent  via  SMTP,  and  MIMEDefang will be called for each resent
              message.  It is possible to set up  Sendmail  8.12  so  locally-
              submitted   messages  are  delivered  directly;  in  this  case,
              stream_by_domain will not work.

              Using stream_by_domain allows you to customize your filter rules
              for  each  domain.   If you use the function as described above,
              you can do this in your filter routine:

                   sub filter {
                        my($entity, $fname, $ext, $type) = @_;
                        if ($Domain eq "abc.com") {
                             # Filter actions for abc.com
                        } elsif ($Domain eq "xyz.com") {
                             # Filter actions for xyz.com
                        } else {
                             # Default filter actions
                        }
                   }

              You cannot rely on $Domain being  set  unless  you  have  called
              stream_by_domain().

       stream_by_recipient()
              Do  not  use  this  function  unless  you have Sendmail 8.12 and
              locally- submitted e-mail is submitted using SMTP.

              This function should only be called at  the  very  beginning  of
              filter_begin(), like this:

                   sub filter_begin {
                        if (stream_by_recipient()) {
                             return;
                        }
                        # Rest of filter_begin
                   }

              If  there  is  more  than  one  recipient, stream_by_recipient()
              resends the message once to each recipient.  That way,  you  can
              customize  your filter rules on a per-recipient basis.  This may
              increase the load on your mail server considerably.

              Also, a "recipient" is determined before  alias  expansion.   So
              "all@mydomain.com"  is  considered  a  single recipient, even if
              Sendmail delivers to a list.

              If you have Sendmail 8.12, then locally-submitted  messages  are
              sent  via  SMTP,  and  MIMEDefang will be called for each resent
              message.  It is possible to set up  Sendmail  8.12  so  locally-
              submitted   messages  are  delivered  directly;  in  this  case,
              stream_by_recipient() will not work.

              stream_by_recipient() allows you to customize your filter  rules
              for each recipient in a manner similar to stream_by_domain().

LOGGING

       md_graphdefang_log_enable($facility, $enum_recips)
              Enables  the  md_graphdefang_log function (described next).  The
              function logs to syslog using the specified  facility.   If  you
              omit  $facility,  it  defaults  to  ’mail’.   If you do not call
              md_graphdefang_log_enable in your  filter,  then  any  calls  to
              md_graphdefang_log simply do nothing.

              If  you  supply  $enum_recips  as  1,  then a line of logging is
              output for each recipient of a mail message.   If  it  is  zero,
              then only a single line is output for each message.  If you omit
              $enum_recips, it defaults to 1.

       md_graphdefang_log($event, $v1, $v2)
              Logs an event with up to  two  optional  additional  parameters.
              The log message has a specific format useful for graphing tools;
              the message looks like this:

                   MDLOG,msgid,event,v1,v2,sender,recipient,subj

              "MDLOG"  is  literal  text.   "msgid"  is  the  Sendmail   queue
              identifier.   "event"  is  the event name, and "v1" and "v2" are
              the additional parameters.   "sender"  is  the  sender’s  e-mail
              address.  "recipient"  is  the  recipient’s  e-mail address, and
              "subj" is the message subject.  If a message has more  than  one
              recipient,  md_graphdefang_log may log an event message for each
              recipient,      depending      on      how      you       called
              md_graphdefang_log_enable.

              Note that md_graphdefang_log should not be used in filter_relay,
              filter_sender or  filter_recipient.   The  global  variables  it
              relies on are not valid in that context.

              If   you   want   to  log  general  text  strings,  do  not  use
              md_graphdefang_log.  Instead, use md_syslog (described next).

       md_syslog($level, $msg)
              Logs the message $msg to syslog, using level $level.  The  level
              is  a  literal  string,  and  should  be  one of ’err’, ’debug’,
              ’warning’, ´emerg’, ’crit’, ’notice’ or ’info’.  (See  syslog(3)
              for details.)

              Note   that  md_syslog  does  not  perform  %-subsitutions  like
              syslog(3) does.  Depending on your Perl installation,  md_syslog
              boils    down    to    a   call   to   Unix::Syslog::syslog   or
              Sys::Syslog::syslog.  See the Unix::Syslog  or  Sys::Syslog  man
              pages for more details.

       md_openlog($tag, $facility)
              Sets the tag used in syslog messages to $tag, and sends the logs
              to the $facility facility.  If you do not call md_openlog before
              you  call  md_syslog, then it is called implicitly with $tag set
              to mimedefang.pl and $facility set to mail.

RBL LOOKUP FUNCTIONS

       mimedefang.pl  includes  the  following  functions  for  lookup  up  IP
       addresses in DNS-based real-time blacklists.

       relay_is_blacklisted($relay, $domain)
              This  checks  a  DNS-based real-time spam blacklist, and returns
              true if the relay host is blacklisted, or false otherwise.   (In
              fact,  the  return  value is whatever the blacklist returns as a
              resolved hostname, such as "127.0.0.4")

              Note that relay_is_blacklisted uses the  built-in  gethostbyname
              function;  this is usually quite inefficient and does not permit
              you to set a timeout on the lookup.  Instead, we recommend using
              one  of the other DNS lookup function described in this section.
              (Note,  though,  that  the  other  functions  require  the  Perl
              Net::DNS module, whereas relay_is_blacklisted does not.)

              Here’s an example of how to use relay_is_blacklisted:

                   if (relay_is_blacklisted($RelayAddr, "rbl.spamhaus.org")) {
                        action_add_header("X-Blacklist-Warning",
                               "Relay $RelayAddr is blacklisted by Spamhaus");
                   }

       relay_is_blacklisted_multi($relay,      $timeout,      $answers_wanted,
       [$domain1, $domain2, ...], $res)
              This function is similar to relay_is_blacklisted, except that it
              takes a timeout argument (specified in seconds) and an array  of
              domains  to check.  The function checks all domains in parallel,
              and is guaranteed to return in $timeout seconds.  (Actually,  it
              may take up to one second longer.)

              The parameters are:

              $relay -- the IP address you want to look up

              $timeout -- a timeout in seconds after which the function should
              return

              $answers_wanted -- the maximum number of  positive  answers  you
              care  about.  For example, if you’re looking up an address in 10
              different RBLs, but are going to bounce it if it is on  four  or
              more, you can set $answers_wanted to 4, and the function returns
              as  soon  as  four  "hits"   are   discovered.    If   you   set
              $answers_wanted  to  zero,  then  the  function  does not return
              early.

              [$domain1, $domain2, ...] -- a reference to an array of strings,
              where each string is an RBL domain.

              $res -- a Net::DNS::Resolver object.  This argument is optional;
              if  you  do  not  supply  it,  then   relay_is_blacklisted_multi
              constructs its own resolver.

              The  return value is a reference to a hash; the keys of the hash
              are the original  domains,  and  the  corresponding  values  are
              either  SERVFAIL, NXDOMAIN, or a list of IP addresses in dotted-
              quad notation.

              Here’s an example:

                  $ans = relay_is_blacklisted_multi($RelayAddr, 8, 0,
                      ["sbl.spamhaus.org", "relays.ordb.org"]);

                  foreach $domain (keys(%$ans)) {
                      $r = $ans->{$domain};
                      if (ref($r) eq "ARRAY") {
                          # It’s an array -- it IS listed in RBL
                          print STDERR "Lookup in $domain yields [ ";
                          foreach $addr (@$r) {
                              print STDERR $addr . " ";
                          }
                          print STDERR "]\n";
                      } else {
                          # It is NOT listed in RBL
                          print STDERR "Lookup in $domain yields "
                                       . $ans->{$domain} . "\n";
                      }
                  }

              You should compare each of  $ans->{$domain}  to  "SERVFAIL"  and
              "NXDOMAIN"  to see if the relay is not listed.  Any other return
              value will be an array of IP addresses indicating that the relay
              is listed.

              Any lookup that does not succeed within $timeout seconds has the
              corresponding return value set to SERVFAIL.

       relay_is_blacklisted_multi_list($relay,   $timeout,    $answers_wanted,
       [$domain1, $domain2, ...], $res)
              This function is similar  to  relay_is_blacklisted_multi  except
              that the return value is simply an array of RBL domains in which
              the relay was listed.

       relay_is_blacklisted_multi_count($relay,   $timeout,   $answers_wanted,
       [$domain1, $domain2, ...], $res)
              This function is similar  to  relay_is_blacklisted_multi  except
              that  the  return  value  is an integer specifying the number of
              domains on which the relay was blacklisted.

TEST FUNCTIONS

       mimedefang.pl includes some "test" functions:

       md_version()
              returns the version of MIMEDefang  as  a  string  (for  example,
              "2.53").

       message_rejected()
              Returns   true  if  any  of  action_tempfail,  action_bounce  or
              action_discard have been called for this message; returns  false
              otherwise.

       If   you   have  the  Mail::SpamAssassin  Perl  module  installed  (see
       http://www.spamassassin.org) you may call any  of  the  spam_assassin_*
       functions.   They should only be called from filter_begin or filter_end
       because they operate on the entire message at once.  Most functions use
       an  optionally  provided  config  file.  If no config file is provided,
       mimedefang.pl  will  look  for  one  of  three   default   SpamAssassin
       preference files.  The first of the following found will be used:

       o      /etc/sa-mimedefang.cf o /etc/mail/sa-mimedefang.cf

       o      /etc/spamassassin/local.cf

       o      /etc/spamassassin.cf

       Important  Note:   MIMEDefang  does  not  permit SpamAssassin to modify
       messages.  If you want to tag spam messages  with  special  headers  or
       alter  the  subject  line,  you must use MIMEDefang functions to do it.
       Setting SpamAssassin configuration options to alter messages  will  not
       work.

       spam_assassin_is_spam([ $config_file ])
              Determine  if  the  current message is SPAM/UCE as determined by
              SpamAssassin.  Compares the score of  the  message  against  the
              threshold  score  (see  below)  and returns true if it is.  Uses
              spam_assassin_check below.

       spam_assassin_check([ $config_file ])
              This function returns a four-element list of  the  form  ($hits,
              $required,  $tests, $report).  $hits is the "score" given to the
              message by SpamAssassin (higher score means more  likely  SPAM).
              $required  is  the  number  of hits required before SpamAssassin
              concludes that the message is SPAM.  $tests is a comma-separated
              list  of  SpamAssassin test names, and $report is text detailing
              which tests triggered and their point  score.   This  gives  you
              insight  into  why  SpamAssassin  concluded  that the message is
              SPAM.  Uses spam_assassin_status below.

       spam_assassin_status([ $config_file ])
              This function returns a Mail::SpamAssasin::PerMsgStatus  object.
              Read  the  SpamAssassin  documentation  for  details  about this
              object.  You are responsible for calling the finish method  when
              you   are   done   with   it.    Uses   spam_assassin_init   and
              spam_assassin_mail below.

       spam_assassin_init([ $config_file ])
              This function returns the new global  Mail::SpamAssassin  object
              with  the  specified or default config (outlined above).  If the
              global object is already defined, returns it -- does not  change
              config   files!   The  object  can  be  used  to  perform  other
              SpamAssassin related functions.

       spam_assassin_mail()
              This function returns a  Mail::SpamAssassin::NoMailAudit  object
              with  the current email message contained in it.  It may be used
              to perform other SpamAssassin related functions.

       md_copy_orig_msg_to_work_dir()
              Normally, virus-scanners are passed only the  unpacked,  decoded
              parts  of  a  MIME  message.   If you want to pass the original,
              undecoded message in as well, call  md_copy_orig_msg_to_work_dir
              prior to calling message_contains_virus.

       md_copy_orig_msg_to_work_dir_as_mbox_file()
              Normally,  virus-scanners  are passed only the unpacked, decoded
              parts of a MIME message.  If you  want  to  pass  the  original,
              undecoded   message   in  as  a  UNIX-style  "mbox"  file,  call
              md_copy_orig_msg_to_work_dir_as_mbox_file   prior   to   calling
              message_contains_virus.    The   only  difference  between  this
              function and md_copy_orig_msg_to_work_dir is that this  function
              prepends  a  "From_"  line to make the message look like a UNIX-
              style mbox file.  This is required for some virus scanners (such
              as Clam AntiVirus) to recognize the file as an e-mail message.

       message_contains_virus()
              This function runs every installed virus-scanner and returns the
              scanner results.  The function should be called in list context;
              the  return  value  is  a  three-element list ($code, $category,
              $action).

              $code is the actual return code from the virus scanner.

              $category is a string categorizing the return code:

              "ok" - no viruses detected.

              "not-installed" - indicated virus scanner is not installed.

              "cannot-execute" - for some reason, the  scanner  could  not  be
              executed.

              "virus" - a virus was found.

              "suspicious" - a "suspicious" file was found.

              "interrupted" - scanning was interrupted.

              "swerr" - an internal scanner software error occurred.

              $action is a string containing the recommended action:

              "ok" - allow the message through unmolested.

              "quarantine" - a virus was detected; quarantine it.

              "tempfail" - something went wrong; tempfail the message.

       message_contains_virus_trend()

       message_contains_virus_nai()

       message_contains_virus_bdc()

       message_contains_virus_nvcc()

       message_contains_virus_csav()

       message_contains_virus_fsav()

       message_contains_virus_hbedv()

       message_contains_virus_vexira()

       message_contains_virus_sophos()

       message_contains_virus_clamav()

       message_contains_virus_avp()

       message_contains_virus_avp5()

       message_contains_virus_filescan()

       message_contains_virus_fprot()

       message_contains_virus_fprotd()

              These  functions should be called in list context.  They use the
              indicated anti-virus software to scan the message  for  viruses.
              These  functions  are intended for use in filter_begin() to make
              an initial scan of the e-mail message.

              The supported virus scanners are:

       nai    NAI "uvscan" - http://www.nai.com/

       Bitdefender "bdc" - http://www.bitdefender.com/

       csav   Command Anti-Virus - http://www.commandsoftware.com/

       fsav   F-Secure Anti-Virus - http://www.f-secure.com/

       hbedv  H+BEDV "AntiVir" - http://www.hbedv.com/

       vexira Vexira "Vexira" - http://www.centralcommand.com/

       sophos Sophos AntiVirus - http://www.sophos.com/

       avp    Kaspersky AVP and aveclient (AVP5) - http://www.avp.ru/

       clamav Clam AntiVirus - http://www.clamav.net/

       f-prot F-RISK F-PROT - http://www.f-prot.com/

       message_contains_virus_openantivirus([$host])
              Connects to the specified host:port (default $OpenAVHost), where
              the  OpenAntiVirus  daemon  is expected to be listening.  Return
              values  are  the  same  as  the   other   message_contains_virus
              functions.

       message_contains_virus_carrier_scan([$host])
              Connects  to  the specified host:port:local_or_nonlocal (default
              $CSSHost), where  the  Symantec  CarrierScan  Server  daemon  is
              expected  to  be  listening.   Return values are the same as the
              other message_contains_virus functions.

       message_contains_virus_sophie([$sophie_sock])
              Connects to the specified socket  (default  $SophieSock),  where
              the  Sophie  daemon  is expected to be listening.  Return values
              are the same as the other message_contains_virus functions.

       message_contains_virus_clamd([$clamd_sock])
              Connects to the specified socket (default $ClamdSock), where the
              clamd daemon is expected to be listening.  Return values are the
              same as the other message_contains_virus functions.

       message_contains_virus_trophie([$trophie_sock])
              Connects to the specified socket (default  $TrophieSock),  where
              the  Trophie  daemon is expected to be listening.  Return values
              are the same as the other message_contains_virus functions.

       entity_contains_virus($entity)

              This function runs  the  specified  MIME::Entity  through  every
              installed  virus-scanner  and  returns the scanner results.  The
              return values are the same as for message_contains_virus().

       entity_contains_virus_trend($entity)

       entity_contains_virus_nai($entity)

       entity_contains_virus_bdc($entity)

       entity_contains_virus_nvcc($entity)

       entity_contains_virus_csav($entity)

       entity_contains_virus_fsav($entity)

       entity_contains_virus_hbedv($entity)

       entity_contains_virus_sophos($entity)

       entity_contains_virus_clamav($entity)

       entity_contains_virus_avp($entity)

       entity_contains_virus_avp5($entity)

       entity_contains_virus_filescan($entity)

       entity_contains_virus_fprot($entity)

       entity_contains_virus_fprotd($entity)
              These functions, meant to be called from filter(),  are  similar
              to  the  message_contains_virus  functions except they scan only
              the current part.  They should be called from list context,  and
              their    return    values    are    as    described    for   the
              message_contains_virus functions.

       entity_contains_virus_openantivirus($entity[, $host])
              Connects to the specified host:port (default $OpenAVHost), where
              the  OpenAntiVirus  daemon  is expected to be listening.  Return
              values  are  the  same  as   the   other   entity_contains_virus
              functions.

       entity_contains_virus_carrier_scan($entity[, $host])
              Connects  to  the specified host:port:local_or_nonlocal (default
              $CSSHost), where  the  Symantec  CarrierScan  Server  daemon  is
              expected  to  be  listening.   Return values are the same as the
              other entity_contains_virus functions.

       entity_contains_virus_sophie($entity[, $sophie_sock])
              Connects to the specified socket  (default  $SophieSock),  where
              the  Sophie  daemon  is expected to be listening.  Return values
              are the same as the other entity_contains_virus functions.

       entity_contains_virus_trophie($entity[, $trophie_sock])
              Connects to the specified socket (default  $TrophieSock),  where
              the  Trophie  daemon is expected to be listening.  Return values
              are the same as the other entity_contains_virus functions.

       entity_contains_virus_clamd($entity[, $clamd_sock])
              Connects to the specified socket (default $ClamdSock), where the
              clamd daemon is expected to be listening.  Return values are the
              same as the other entity_contains_virus functions.

SMTP FLOW

       This section illustrates the flow of messages through MIMEDefang.

       1. INITIAL CONNECTION
              If you invoked mimedefang with the -r option and have defined  a
              filter_relay routine, it is called.

       2. SMTP HELO COMMAND
              The  HELO  string  is stored internally, but no filter functions
              are called.

       3. SMTP MAIL FROM: COMMAND
              If you invoked mimedefang with the -s option and have defined  a
              filter_sender routine, it is called.

       4. SMTP RCPT TO: COMMAND
              If  you invoked mimedefang with the -t option and have defined a
              filter_recipient routine, it is called.

       5. END OF SMTP DATA
              filter_begin is called.  For each MIME part, filter  is  called.
              Then filter_end is called.

PRESERVING RELAY INFORMATION

       Most organizations have more than one machine handling internet e-mail.
       If the primary machine is down, mail  is  routed  to  a  secondary  (or
       tertiary,  etc.)  MX server, which stores the mail until the primary MX
       host comes back up.  Mail is then relayed to the primary MX host.

       Relaying from a secondary to a primary MX host has the unfortunate side
       effect   of   losing  the  original  relay’s  IP  address  information.
       MIMEDefang allows you to preserve this information.  One way around the
       problem  is to run MIMEDefang on all the secondary MX hosts and use the
       same filter.  However, you may not have control over the  secondary  MX
       hosts.  If you can persuade the owners of the secondary MX hosts to run
       MIMEDefang with a simple filter which only preserves relay  information
       and  does  no  other  scanning,  your  primary MX host can obtain relay
       information and make decisions using $RelayAddr and $RelayHostname.

       When you configure MIMEDefang, supply the "--with-ipheader" argument to
       the  ./configure  script.   When  you install MIMEDefang, a file called
       /etc/mimedefang-ip-key will be  created,  which  contains  a  randomly-
       generated  header name.  Copy this file to all of your mail relays.  It
       is important that all of your MX hosts have  the  same  key.   The  key
       should be kept confidential, but it’s not disastrous if it leaks out.

       On your secondary MX hosts, add this line to filter_end:

            add_ip_validation_header();

       Note:   You  should only add the validation header to mail destined for
       one of your other MX hosts!  Otherwise, the validation header will leak
       out.

       When  the  secondary  MX hosts relay to the primary MX host, $RelayAddr
       and $RelayHostname will be set based on the IP validation  header.   If
       MIMEDefang  notices this header, it sets the global variable $WasResent
       to 1.  Since you don’t want to trust the header unless it  was  set  by
       one   of  your  secondary  MX  hosts,  you  should  put  this  code  in
       filter_begin:

            if ($WasResent) {
                 if ($RealRelayAddr ne "ip.of.secondary.mx" and
                     $RealRelayAddr ne "ip.of.tertiary.mx") {
                      $RelayAddr = $RealRelayAddr;
                      $RelayHostname = $RealRelayHostname;
                 }
            }

       This resets the relay address and hostname to the actual relay  address
       and  hostname,  unless  the message is coming from one of your other MX
       hosts.

       On the primary MX host, you should add this in filter_begin:

            delete_ip_validation_header();

       This prevents the validation header from leaking out to recipients.

       Note:  The  IP  validation  header  works  only   in   message-oriented
       functions.  It (obviously) has no effect on filter_relay, filter_sender
       and filter_recipient, because no header information is  available  yet.
       You  must  take  this  into  account when writing your filter; you must
       defer relay-based decisions to the message  filter  for  mail  arriving
       from your other MX hosts.

GLOBAL VARIABLE LIFETIME

       The  following  list describes the lifetime of global variables (thanks
       to Tony Nugent for providing this documentation.)

       If you set a global variable:

       Outside a subroutine in your filter file
              It is available to all functions, all the time.

       In filter_relay, filter_sender or filter_recipient
              Not guaranteed to be available to any other function,  not  even
              from  one  filter_recipient  call  to the next, when receiving a
              multi-recipient email message.

       In filter_begin
              Available to filter_begin, filter and filter_end

       In filter
              Available to filter and filter_end

       In filter_end
              Available within filter_end

       The  "built-in"  globals  like  $Subject,  $Sender,  etc.  are   always
       available to filter_begin, filter and filter_end. Some are available to
       filter_relay, filter_sender or filter_recipient, but you  should  check
       the documentation of the variable above for details.

MAINTAINING STATE

       There are four basic groups of filtering functions:

       1      filter_relay

       2      filter_sender

       3      filter_recipient

       4      filter_begin, filter, filter_multipart, filter_end

       In  general, for a given mail message, these groups of functions may be
       called in completely different Perl processes.  Thus, there is  no  way
       to  maintain  state  inside Perl between groups of functions.  That is,
       you cannot set a variable in filter_relay and expect it to be available
       in filter_sender, because the filter_sender invocation might take place
       in a completely different process.

       However, for a given mail message, the $CWD global variable  holds  the
       message  spool  directory,  and the current working directory is set to
       $CWD.  Therefore, you  can  store  state  in  files  inside  $CWD.   If
       filter_sender  stores data in a file inside $CWD, then filter_recipient
       can retrieve that data.

       Since filter_relay is  called  directly  after  a  mail  connection  is
       established, there is no message context yet, no per-message mimedefang
       spool directory, and the $CWD global is not set. Therefore, it  is  not
       possible  to  share  information  from filter_relay to one of the other
       filter functions. The only thing that filter_relay has in  common  with
       the  other  functions  are  the  values  in  the globals $RelayAddr and
       $RelayHostname.  These  could  be  used   to   access   per-remote-host
       information in some database.

       Inside $CWD, we reserve filenames beginning with upper-case letters for
       internal MIMEDefang use.  If you want to create files to  store  state,
       name  them  beginning  with  a  lower-case letter to avoid clashes with
       future releases of MIMEDefang.

SOCKET MAPS

       If you have Sendmail 8.13 or later,  and  have  compiled  it  with  the
       SOCKETMAP option, then you can use a special map type that communicates
       over a socket with another program (rather than looking up a key  in  a
       Berkeley database, for example.)

       mimedefang-multiplexor  implements  the  Sendmail SOCKETMAP protocol if
       you supply the -N option.  In that case,  you  can  define  a  function
       called  filter_map  to  implement  map  lookups.   filter_map takes two
       arguments:  $mapname is the name of the Sendmail map (as given in the K
       sendmail configuration directive), and $key is the key to be looked up.

       filter_map must return a two-element list: ($code, $val) $code  can  be
       one of:

       OK     The  lookup  was  successful.   In  this  case, $val must be the
              result of the lookup

       NOTFOUND
              The lookup was unsuccessful -- the key was not found.   In  this
              case, $val should be the empty string.

       TEMP   There  was  a  temporary  failure  of some kind.  $val can be an
              explanatory error message.

       TIMEOUT
              There was a timeout of some kind.  $val can  be  an  explanatory
              error message.

       PERM   There  was  a  permanent  failure.   This  is not the same as an
              unsuccessful lookup; it  should  be  used  only  to  indicate  a
              serious misconfiguration.  As before, $val can be an explanatory
              error message.

       Consider this small example.  Here is a minimal Sendmail  configuration
       file:

            V10/Berkeley
            Kmysock socket unix:/var/spool/MIMEDefang/map.sock
            kothersock socket unix:/var/spool/MIMEDefang/map.sock

       If   mimedefang-multiplexor   is   invoked   with   the   arguments  -N
       unix:/var/spool/MIMEDefang/map.sock, and the filter defines  filter_map
       as follows:

            sub filter_map ($$) {
                my($mapname, $key) = @_;
                my $ans;
                if($mapname ne "mysock") {
                    return("PERM", "Unknown map $mapname");
                }
                $ans = reverse($key);
                return ("OK", $ans);
            }

       Then in Sendmail’s testing mode, we see the following:

            > /map mysock testing123
            map_lookup: mysock (testing123) returns 321gnitset (0)
            > /map othersock foo
            map_lookup: othersock (foo) no match (69)

       (The return code of 69 means EX_UNAVAILABLE or Service Unavailable)

       A  real-world  example could do map lookups in an LDAP directory or SQL
       database, or perform other kinds of processing.  You can even implement
       standard Sendmail maps like virtusertable, mailertable, access_db, etc.
       using SOCKETMAP.

TICK REQUESTS

       If you supply the -X option to mimedefang-multiplexor,  then  every  so
       often,  a  "tick"  request  is  sent  to  a free slave.  If your filter
       defines a function called filter_tick, then  this  function  is  called
       with  a  single  argument: the tick type.  If you run multiple parallel
       ticks, then each tick has a type ranging from 0 to n-1, where n is  the
       number  of  parallel  ticks.   If you’re only running one tick request,
       then the argument to filter_tick is always 0.

       You can use this facility to run periodic tasks from within MIMEDefang.
       Note,  however,  that you have no control over which slave is picked to
       run filter_tick.  Also, at most one filter_tick call with a  particular
       "type"  argument  will  be active at any time, and if there are no free
       slaves when a tick would occur, the tick is skipped.

SUPPORTED VIRUS SCANNERS

       The following virus scanners are supported by MIMEDefang:

       o      OpenAntiVirus (http://www.openantivirus.org/)  is  supported  in
              daemon-scanning mode.

       o      Symantec                    CarrierScan                   Server
              (http://www.symantec.com/region/can/eng/product/scs/)

       o      Trend Micro vscan (http://www.antivirus.com/)

       o      Sophos                                                     Sweep
              (http://www.sophos.com/products/antivirus/savunix.html)

       o      H+BEDV AntiVir (http://www.hbedv.com/)

       o      Central Command Vexira (http://www.centralcommand.com/)

       o      NAI uvscan (http://www.nai.com)

       o      Bitdefender bdc (http://www.bitdefender.com)

       o      Norman Virus Control (NVCC) (http://www.norman.no/)

       o      Command csav (http://www.commandsoftware.com)

       o      F-Secure fsav (http://www.f-secure.com)

       o      The clamscan command-line scanner and the clamd daemon from Clam
              AntiVirus (http://www.clamav.net/)

       o      Kaspersky Anti-Virus (AVP) (http://www.kaspersky.com/)

       o      F-Risk F-Prot (http://www.f-prot.com/)

       o      F-Risk FPROTD (daemonized version of F-Prot)

       o      Symantec                   CarrierScan                    Server
              (http://www.symantec.ca/region/can/eng/product/scs/buymenu.html)

       o      The             File::Scan              Perl              module
              (http://freshmeat.net/projects/filescan/)

       o      Sophie   (http://www.vanja.com/tools/sophie/),  which  uses  the
              libsavi library from Sophos,  is  supported  in  daemon-scanning
              mode.

       o      Trophie  (http://www.vanja.com/tools/trophie/),  which  uses the
              libvsapi library from  Trend  Micro,  is  supported  in  daemon-
              scanning mode.

AUTHORS

       mimedefang was written by David F. Skoll <dfs@roaringpenguin.com>.  The
       mimedefang home page is http://www.mimedefang.org/.

SEE ALSO

       mimedefang(8), mimedefang.pl(8)