Man Linux: Main Page and Category List

NAME

       mimedefang-filter - Configuration file for MIMEDefang mail filter.

DESCRIPTION

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

CALLING SEQUENCE

       Incoming messages are scanned 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.  Each part is  represented  internally  as  an  instance  of
       MIME::Entity.

       2)  If  the file /etc/mail/mimedefang-filter.pl defines a Perl function
       called filter_begin, it is called with a single argument consisting  of
       a  MIME::Entity  representing  the  parsed  e-mail message.  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 that
       contains nested parts.  Such a part has no useful body, but you  should
       still  perform  filename checks to check for viruses that 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 and chooses a
       disposition for that part.  (A disposition is selected by  calling  one
       of the following functions from filter and then immediately returning.)
       Available dispositions are:

       action_accept
              The  part  is  passed  through  unchanged.   If  no  disposition
              function is returned, this is the default.

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

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

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

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

       action_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.

       action_bounce
              The  entire  e-mail message is rejected and an error returned to
              the sender.  The intended recipients  are  not  notified.   Note
              that  in  spite of the name, MIMEDefang does not generate and e-
              mail a failure notification.  Rather, it causes the SMTP  server
              to return a 5XX SMTP failure code.

       action_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 HELO

       You can define a function called filter_helo in your filter.  This lets
       you reject connections after the HELO/EHLO SMTP command.  Note that for
       this function to be called, you must use the -H flag with mimedefang.

       filter_helo is passed three arguments: $ip and $name are the IP address
       and name of the sending relay, as in filter_relay.  The third argument,
       $helo, is the argument supplied in the HELO/EHLO command.

       filter_helo must return  a  two-to-five  element  list:  ($code,  $msg,
       $smtp_code,  $smtp_dsn, $delay).  $code is a return code, with the same
       meaning as the $code return from filter_relay.  $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.)

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,  with  the  same
       meaning as the return value from filter_helo.

       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,  that  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 that 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.

       $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 that 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{"HTML::Parser"}  is  1 if HTML::Parser is installed; 0
              otherwise.

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

              $Features{"Virus:FPROTD6"} is currently always 0.  Set it  to  1
              in  your  filter  file  if you have version 6 of 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:SAVSCAN"} is the full path to Sophos savscan 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:FPSCAN"}  is  the full path to F-Risk fpscan 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.

              $Features{"Virus:NOD32"} is the full path to ESET NOD32 nod32cli
              if it is installed; 0 if it is not.

              NOTE:  Perl-module  based  features  such  as  SpamAssassin  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  that
              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 in
              addition to the body filtering functions.

       $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  in  addition  to  the  body
              filtering functions.

       $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 that change a message implicitly call action_rebuild.

       action_add_header($hdr, $val)
              Add  a  header to 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_insert_header($hdr, $val, $index)
              Add  a  header to the message int the specified position $index.
              A position of 0 specifies that the header  should  be  prepended
              before  existing  headers.   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.

       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,  that  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.

       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.

       change_sender($sender)
              This function changes the envelope sender to  $sender.   It  can
              only  be called from filter_begin or any later function.  Please
              note that this function is only supported  with  Sendmail/Milter
              8.14.0  or  newer.   It  has  no  effect if you’re running older
              versions.

       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  looking  up IP
       addresses  in  DNS-based   real-time   blacklists.    Note   that   the
       "relay_is_blacklisted" functions are deprecated and may be removed in a
       future release.  Instead, you should use the module  Net::DNSBL::Client
       from CPAN.

       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.

       md_get_bogus_mx_hosts($domain)
              This function is not really an RBL lookup.  What it does is look
              up  all  the  MX  records for the specified domain, and return a
              list of "bogus" IP addresses found amongst the  MX  records.   A
              "bogus"  IP  address  is  an  IP  address  in  a private network
              (10.0.0.0/8,  172.16.0.0/12,   192.168.0.0/16),   the   loopback
              network      (127.0.0.0/8),     local-link     for     auto-DHCP
              (169.254.0.0/16),  IPv4  multicast  (224.0.0.0/4)  or   reserved
              (240.0.0.0/4).

       Here’s how you might use the function in filter_sender:

       sub filter_sender {
           my ($sender, $ip, $hostname, $helo) = @_;
           if ($sender =~ /@([^>]+)/) {
               my $domain = $1;
               my @bogushosts = md_get_bogus_mx_hosts($domain);
               if (scalar(@bogushosts)) {
                   return(’REJECT’, "Domain $domain contains bogus MX record(s) " .
                          join(’, ’, @bogushosts));
               }
           }
           return (’CONTINUE’, ’ok’);
       }

TEST FUNCTIONS

       mimedefang.pl includes some "test" functions:

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

       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 four 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_fprot()

       message_contains_virus_fpscan()

       message_contains_virus_fprotd()

       message_contains_virus_fprotd_v6()

       message_contains_virus_nod32()

              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/

       nod32cli
              ESET NOD32 - http://www.eset.com/

       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_fprot($entity)

       entity_contains_virus_fpscan($entity)

       entity_contains_virus_fprotd($entity)

       entity_contains_virus_fprotd_v6($entity)

       entity_contains_virus_nod32($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_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 that 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      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 F-Prot v6 (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      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.

       o      ESET NOD32 (http://www.eset.com/)

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)