mimedefang-filter man page on DragonFly

Man page or keyword search:  
man Server   44335 pages
apropos Keyword Search (all sections)
Output format
DragonFly logo
[printable version]

MIMEDEFANG-FILTER(5)					  MIMEDEFANG-FILTER(5)

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 mimede‐
       fang.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 /usr/local/etc/mimedefang/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	exten‐
       sion, and type, the MIME Content-Type value.  For each non-leaf part of
       the mail message, filter_multipart is called with the same  four	 argu‐
       ments  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 consist‐
       ing  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 dis‐
       position	 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 func‐
	      tion 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/MD-Quarantine	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 five arguments: $hostip is the IP address of the
       relay  host  (for  example, "127.0.0.1"), $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.)

       The remaining three arguments to	 filter_relay  are  $port,  $myip  and
       $myport which contain the client's TCP port, the Sendmail daemon's lis‐
       tening IP address and the Sendmail daemon's listening port.

       filter_relay must return a two-element list: ($code, $msg).  $msg spec‐
       ifies  the text message to use for the SMTP reply, but because of limi‐
       tations 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 six 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.

       The remaining three arguments to	 filter_relay  are  $port,  $myip  and
       $myport which contain the client's TCP port, the Sendmail daemon's lis‐
       tening IP address and the Sendmail daemon's listening port.

       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 Send‐
       mail.  $delay defaults to zero.

       (Note that the delay is implemented in the Milter C code; if you	 spec‐
       ify  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 func‐
       tion  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 argu‐
       ment   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 interpre‐
       tation is the same as for filter_sender.	 Note, however, that  if  fil‐
       ter_recipient returns 'DISCARD', then the entire message for all recip‐
       ients is discarded.  (It doesn't really make sense, but that's how Mil‐
       ter works.)

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

       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.	  How‐
       ever,  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 fil‐
       ter_initialize and not directly from the	 filter,  because  the	multi‐
       plexor closes all open descriptors when it activates a new slave.

       When  a	slave  is about to exit, mimedefang.pl calls the function fil‐
       ter_cleanup (if it is defined) with no arguments.  This function can do
       whatever	 cleanup you like, such as closing file descriptors and clean‐
       ing  up	long-lived  slave  resources.	The  return  value  from  fil‐
       ter_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	catch‐
       ing  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	 argu‐
       ments,  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 result‐
       ing 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 mes‐
       sage 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,  connec‐
	      tion  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_recipi‐
       ent 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 notifica‐
	      tions 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 warn‐
	      ing  are issued.	Mail clients that are not this stupid are Net‐
	      scape 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 $AddAp‐
	      parentlyToForSpamAssassin	 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 possi‐
	      bilites.	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 $Warn‐
	      ingLocation 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_admin‐
	      istrator().   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	admin‐
	      istrator.	 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_con‐
	      tains_virus_sophie  and  entity_contains_virus_sophie  unless  a
	      socket is provided by the calling routine.

       $ClamdSock (default /var/run/clamav/clamd.sock)
	      Socket  used  for	 clamd	daemon	 calls	 within	  message_con‐
	      tains_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_con‐
	      tains_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	 exam‐
       ples  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 docu‐
	      mentation.)

       $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	avail‐
       able  for use in your filter.  All of these variables are always avail‐
       able 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	 func‐
	      tionality	 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	 "ave‐
	      client" 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 deter‐
	      mined at runtime and may change as these are added and  removed.
	      Most  Virus features are predetermined at the time of configura‐
	      tion and do not adapt to runtime availability unless changed  by
	      the filter rules.

       $CWD   This  variable  holds the working directory for the current mes‐
	      sage.  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  fil‐
	      ter_recipient, but not in filter_relay.

       $SuspiciousCharsInHeaders
	      If  this variable is true, then mimedefang has discovered suspi‐
	      cious 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 suspi‐
	      cious 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 avail‐
	      able 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 fil‐
	      tering functions.

	      $Helo The argument given to the SMTP "HELO" command.  This vari‐
	      able 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  in	 addition  to the body filtering func‐
	      tions.

       @Recipients
	      A list of the recipients.	 In filter_recipient, it is set to the
	      single  recipient currently under consideration. Or, after call‐
	      ing  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.	Other‐
	      wise, contains the string "NOQUEUE". This variable is  set  cor‐
	      rectly  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  mes‐
	      sages.   Note  that  this	 variable  is  set  correctly  in fil‐
	      ter_sender and filter_recipient, but it is not available in fil‐
	      ter_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}, ${daemon_port}, ${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}.   In  addition,  ${client_port}  is	 set  to   the
	      client's TCP port.

	      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	 vari‐
	      able  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 sup‐
	      ply  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 sup‐
	      ply 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 con‐
	      tained 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 infor‐
	      mation 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	 argu‐
	      ments: $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	./FIL‐
	      TEROUTPUT.   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 fil‐
	      ter_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 adminis‐
	      trator 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 doc‐
	      umentation  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  dis‐
	      card 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	 prof‐
	      itably  call action_quarantine followed by action_discard if you
	      want to keep a copy of the offending part.  Note that  the  mes‐
	      sage  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 mes‐
	      sages are accumulated into a single e-mail message  --  at  most
	      one notification message is sent per incoming message.  The mes‐
	      sage 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 func‐
	      tions:

		   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  mes‐
	      sage 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 fil‐
	      ter_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 sim‐
	      ply calling $entity->add_part.  The decision process is as  fol‐
	      lows:

       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	gener‐
	      ated,  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.

       action_add_entity($entity [, $offset])
	      This  is	similar	 to  action_add_part  but  takes  a  pre-built
	      MIME::Entity object rather than constructing one based on $type,
	      $encoding, $data, $fname and $disposition arguments.

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 ver‐
	      sions.

       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 fil‐
	      ter(), 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 fil‐
	      ter_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 exam‐
	      ple.)

	      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 fil‐
	      ter_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-sub‐
	      mitted  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-sub‐
	      mitted  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  out‐
	      put  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 identi‐
	      fier.  "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_graphde‐
	      fang_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', 'warn‐
	      ing', ´emerg', 'crit', 'notice' or 'info'.  (See	syslog(3)  for
	      details.)

	      Note  that  md_syslog  does not perform %-subsitutions like sys‐
	      log(3) does.  Depending on  your	Perl  installation,  md_syslog
	      boils  down  to  a  call	to  Unix::Syslog::syslog  or Sys::Sys‐
	      log::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  con‐
	      structs 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 looks up all the  MX  records  for	the  specified
	      domain  (or  A records if there are no MX records) and returns a
	      list of "bogus" IP  addresses  found  amongst  the  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  net‐
	      work  (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.75").

       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      /usr/local/etc/mimedefang/sa-mimedefang.cf

       o      /usr/local/etc/mimedefang/spamassassin/sa-mimedefang.cf

       o      /usr/local/etc/mimedefang/spamassassin/local.cf

       o      /usr/local/etc/mimedefang/spamassassin.cf

       Important Note:	MIMEDefang does not permit SpamAssassin to modify mes‐
       sages.  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_assas‐
	      sin_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  SpamAs‐
	      sassin 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 mes‐
	      sage_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_con‐
	      tains_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 ter‐
       tiary, 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.   MIMEDe‐
       fang allows you to preserve this information.  One way around the prob‐
       lem 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 MIMEDe‐
       fang  with  a  simple  filter that only preserves relay information and
       does no other scanning, your primary MX host can obtain relay  informa‐
       tion 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
       /usr/local/etc/mimedefang/mimedefang-ip-key  will be created which con‐
       tains 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 fil‐
       ter_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	 func‐
       tions.  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	avail‐
       able to filter_begin, filter and filter_end. Some are available to fil‐
       ter_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  fil‐
       ter_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 estab‐
       lished,	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  informa‐
       tion 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 SOCK‐
       ETMAP  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 argu‐
       ments:  $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 seri‐
	      ous 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.syman‐
	      tec.com/region/can/eng/product/scs/)

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

       o      Sophos   Sweep   (http://www.sophos.com/products/antivirus/savu‐
	      nix.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.syman‐
	      tec.ca/region/can/eng/product/scs/buymenu.html)

       o      Sophie (http://www.vanja.com/tools/sophie/), which uses the lib‐
	      savi 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-scan‐
	      ning 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)

4th Berkeley Distribution	8 February 2005		  MIMEDEFANG-FILTER(5)
[top]

List of man pages available for DragonFly

Copyright (c) for man pages and the logo by the respective OS vendor.

For those who want to learn more, the polarhome community provides shell access and support.

[legal] [privacy] [GNU] [policy] [cookies] [netiquette] [sponsors] [FAQ]
Tweet
Polarhome, production since 1999.
Member of Polarhome portal.
Based on Fawad Halim's script.
....................................................................
Vote for polarhome
Free Shell Accounts :: the biggest list on the net