Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
MIMEDEFANG-FILTER(5)	      File Formats Manual	  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.  Within filter_end, you can  call	 func-
       tions that modify the message headers body.

       5) After	filter_end returns, the	function filter_wrapup is called if it
       has been	defined.  It is	passed a single	 argument  consisting  of  the
       (possibly  modified) MIME::Entity object	representing the message about
       to be  delivered,  including  any  modifications	 made  in  filter_end.
       Within  filter_wrapup,  you can not call	functions that modify the mes-
       sage body, but you can still add	or modify message headers.

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.	 (You should therefore
       ensure that filter_cleanup returns an integer suitable  for  a  process
       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.78").

       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.

       For a given mail	message, it is always the case that filter_begin, fil-
       ter,  filter_multipart  and  filter_end	are  called  in	 the same Perl
       process.	 Therefore, you	can use	global variables to carry state	 among
       those  functions.   You should be very careful to initialize such vari-
       ables in	filter_begin to	ensure no  data	 leaks	from  one  message  to
       another.

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

       Since filter_relay is called directly after a mail connection is	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 Dianne 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)

NAME | DESCRIPTION | CALLING SEQUENCE | DISPOSITION | CONTROLLING RELAYING | FILTERING BY HELO | FILTERING BY SENDER | FILTERING BY RECIPIENT | INITIALIZATION AND CLEANUP | CONTROLLING PARSING | EXTENDING MIMEDEFANG | REJECTING UNKNOWN USERS EARLY | GLOBAL VARIABLES YOU CAN SET | FILTER | GLOBAL VARIABLES SET BY MIMEDEFANG.PL | ACTIONS | USEFUL ROUTINES | LOGGING | RBL LOOKUP FUNCTIONS | TEST FUNCTIONS | SMTP FLOW | PRESERVING RELAY INFORMATION | GLOBAL VARIABLE LIFETIME | MAINTAINING STATE | SOCKET MAPS | TICK REQUESTS | SUPPORTED VIRUS SCANNERS | AUTHORS | SEE ALSO

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=mimedefang-filter&sektion=5&manpath=FreeBSD+12.0-RELEASE+and+Ports>

home | help