[Mimedefang] [PATCH] filter_data implementation

Martin Blapp mbr at freebsd.org
Wed May 27 06:10:51 EDT 2009


Hi all,

And here the patch again, this time with examples and parts
of the manpage.

--
Martin

--- mimedefang.c	2009-05-24 07:40:40.000000000 +0200
+++ mimedefang.c	2009-05-24 06:27:35.000000000 +0200
@@ -233,6 +233,9 @@
 /* Do recipient check? */
 static int doRecipientCheck = 0;
 
+/* Do precontent check */
+static int doPreContentCheck = 0;
+
 /* Keep directories around if multiplexor fails? */
 static int keepFailedDirectories = 0;
 
@@ -978,12 +981,67 @@
 *%RETURNS:
 * Standard milter reply code
 *%DESCRIPTION:
-* Does a post-DATA callback
+* Does a post-DATA callback before any content is submitted
 ***********************************************************************/
 #ifdef MILTER_BUILDLIB_HAS_DATA
 static sfsistat mf_data(SMFICTX *ctx)
 {
-    return SMFIS_CONTINUE;
+    struct privdata *data = DATA;
+    char ans[SMALLBUF];
+    sfsistat retcode = SMFIS_CONTINUE;
+    int i;
+
+    DEBUG_ENTER("mf_data");
+    if (!data) {
+	syslog(LOG_WARNING, "postdata: Unable to obtain private data from milter
context");
+	DEBUG_EXIT("mf_data", "SMFIS_TEMPFAIL");
+	return SMFIS_TEMPFAIL;
+    }
+
+    /* Post data check if enabled */
+    if (doPreContentCheck) {
+	int n;
+
+	n = MXDataOK(MultiplexorSocketName, ans, data->sender, data->hostip,
+			  data->hostname, data->firstRecip, data->heloArg,
+			  data->dir, data->qid);
+
+	if (n == MD_REJECT) {
+	    /* Reject this mail with all recipients */
+	    set_dsn(ctx, ans, 5);
+
+	    DEBUG_EXIT("mf_data", "SMFIS_REJECT");
+	    return SMFIS_REJECT;
+	}
+	if (n <= MD_TEMPFAIL) {
+	    /* Tempfail this mail with all recipients */
+	    set_dsn(ctx, ans, 4);
+
+	    DEBUG_EXIT("mf_data", "SMFIS_TEMPFAIL");
+	    return SMFIS_TEMPFAIL;
+	}
+	if (n == MD_ACCEPT_AND_NO_MORE_FILTERING) {
+	    /* Called in case we don't need content filtering */
+	    set_dsn(ctx, ans, 2);
+	    cleanup(ctx);
+	    DEBUG_EXIT("mf_data", "SMFIS_ACCEPT");
+	    return SMFIS_ACCEPT;
+	}
+	if (n == MD_DISCARD) {
+	    set_dsn(ctx, ans, 2);
+
+	    cleanup(ctx);
+	    DEBUG_EXIT("mf_data", "SMFIS_DISCARD");
+	    return SMFIS_DISCARD;
+	}
+	if (n == MD_CONTINUE) {
+	    /* Called only in case we need to delay */
+	    set_dsn(ctx, ans, 2);
+    	    return SMFIS_CONTINUE;
+	}
+    }
+    DEBUG_EXIT("mf_data", "SMFIS_CONTINUE");
+    return retcode;
 }
 #endif
 
@@ -2092,6 +2150,7 @@
     fprintf(stderr, "  -r                -- Do relay check before
processing body\n");
     fprintf(stderr, "  -s                -- Do sender check before
processing body\n");
     fprintf(stderr, "  -t                -- Do recipient checks before
processing body\n");
+    fprintf(stderr, "  -A                -- Do pre content check for
processing body\n");
     fprintf(stderr, "  -q                -- Allow new connections to be
queued by multiplexor\n");
     fprintf(stderr, "  -P file           -- Write process-ID of daemon to
specified file\n");
     fprintf(stderr, "  -T                -- Log filter times to syslog\n");
@@ -2189,7 +2248,7 @@
     }
 
     /* Process command line options */
-    while ((c = getopt(argc, argv,
"NCDHL:MP:R:S:TU:Xa:b:cdhkm:p:qrstvx:z:")) != -1) {
+    while ((c = getopt(argc, argv,
"ANCDHL:MP:R:S:TU:Xa:b:cdhkm:p:qrstvx:z:")) != -1) {
 	switch (c) {
 	case 'N':
 #ifdef MILTER_BUILDLIB_HAS_NEGOTIATE
@@ -2346,6 +2405,9 @@
 	case 't':
 	    doRecipientCheck = 1;
 	    break;
+	case 'A':
+	    doPreContentCheck = 1;
+	    break;
 	case 'h':
 	    usage();
 	    break;
--- mimedefang.h	2009-05-24 07:40:40.000000000 +0200
+++ mimedefang.h	2009-05-24 06:26:27.000000000 +0200
@@ -40,6 +40,10 @@
 			 char const *dir, char const *qid,
 			 char const *rcpt_mailer, char const *rcpt_host,
 			 char const *rcpt_addr);
+extern int MXDataOK(char const *sockname, char *msg,
+			 char const *sender, char const *ip, char const *name,
+			 char const *firstRecip, char const *helo,
+			 char const *dir, char const *qid);
 
 extern int safeWriteHeader(int fd, char *str);
 extern void split_on_space(char *buf, char **first, char **rest);
--- mimedefang.pl.in	2009-05-24 07:41:08.000000000 +0200
+++ mimedefang.pl.in	2009-05-24 07:10:42.000000000 +0200
@@ -5645,6 +5645,21 @@
 	    chdir($Features{'Path:SPOOLDIR'});
 	    next;
 	}
+	if ($_ =~ /^dataok (\S*)\s+(\S*)\s+(\S*)\s+(\S*)\s+(\S*)\s+(\S*)\s+(\S*)/)
{
+	    $sender = percent_decode($1);
+	    $ip = percent_decode($2);
+	    $name = percent_decode($3);
+	    $firstRecip = percent_decode($4);
+	    $helo = percent_decode($5);
+	    $CWD = percent_decode($6);
+	    $QueueID = percent_decode($7);
+	    $MsgID = $QueueID;
+
+	    chdir($CWD);
+	    data_ok($sender, $ip, $name, $firstRecip, $helo);
+	    chdir($Features{'Path:SPOOLDIR'});
+	    next;
+	}
 
 	# If "filter_unknown_cmd" is defined, call it
 	if (defined(&filter_unknown_cmd)) {
@@ -7074,6 +7089,39 @@
 }
 
 #***********************************************************************
+# %PROCEDURE: data_ok
+# %ARGUMENTS:
+#  sender -- e-mail address of sender
+#  ip -- IP address of relay host
+#  name -- name of relay host
+#  firstRecip -- first recipient of message
+#  helo -- arg to SMTP HELO command
+# %RETURNS:
+#  Nothing, but prints "ok 1" if we accept the message,
+# "ok 0" if not.
+#***********************************************************************
+sub data_ok ($$$$$) {
+    my($sender, $ip, $name, $firstRecip, $helo) = @_;
+    if (!defined(&filter_data)) {
+	send_filter_answer('CONTINUE', "ok",
+			   "filter_data", "data");
+	return;
+    }
+
+    # Set up globals
+    $Sender        = $sender;
+    $RelayAddr     = $ip;
+    $RelayHostname = $name;
+    $Helo          = $helo;
+    my($ok, $msg, $code, $dsn, $delay) =
+	filter_data($sender, $ip, $name,
+			 $firstRecip, $helo);
+    send_filter_answer($ok, $msg,
+		       "filter_data", "data",
+		       $code, $dsn, $delay);
+}
+
+#***********************************************************************
 # %PROCEDURE: print_message_structure
 # %ARGUMENTS:
 #  None
--- utils.c	2009-05-24 07:40:40.000000000 +0200
+++ utils.c	2009-05-24 06:29:06.000000000 +0200
@@ -801,6 +801,69 @@
 }
 
 /**********************************************************************
+* %FUNCTION: MXDataOK
+* %ARGUMENTS:
+*  sockname -- multiplexor socket name
+*  msg -- buffer of at least SMALLBUF size for error messages
+*  sender -- sender's e-mail address
+*  ip -- sending relay's IP address
+*  name -- sending relay's host name
+*  firstRecip -- first recipient of the message
+*  helo -- argument to "HELO/EHLO" (may be NULL)
+*  dir -- MIMEDefang working directory
+*  qid -- Sendmail queue identifier
+* %RETURNS:
+*  1 if it's OK to accept this message; 0 if not, -1 if error.
+***********************************************************************/
+int
+MXDataOK(char const *sockname,
+	      char *msg,
+	      char const *sender,
+	      char const *ip,
+	      char const *name,
+	      char const *firstRecip,
+	      char const *helo,
+	      char const *dir,
+	      char const *qid)
+{
+    char cmd[SMALLBUF];
+    char ans[SMALLBUF];
+    int i, l, l2;
+
+    *msg = 0;
+
+    if (!sender || !*sender) {
+	sender = "UNKNOWN";
+    }
+
+    if (!ip || !*ip) {
+	ip = "UNKNOWN";
+    }
+    if (!name || !*name) {
+	name = ip;
+    }
+
+    if (!firstRecip || !*firstRecip) {
+	firstRecip = "UNKNOWN";
+    }
+    if (!helo) {
+	helo = "UNKNOWN";
+    }
+
+    if (percent_encode_command(0, cmd, sizeof(cmd),
+			       "dataok", sender, ip, name, firstRecip,
+			       helo, dir, qid, NULL) < 0) {
+	return MD_TEMPFAIL;
+    }
+
+    /* Add newline */
+    strcat(cmd, "\n");
+
+    if (MXCommand(sockname, cmd, ans, SMALLBUF-1) < 0) return MD_TEMPFAIL;
+    return munch_mx_return(ans, msg);
+}
+
+/**********************************************************************
 * %FUNCTION: writen
 * %ARGUMENTS:
 *  fd -- file to write to
--- examples/init-script.in	2008-03-07 21:59:28.000000000 +0100
+++ examples/init-script.in	2009-05-24 08:06:00.000000000 +0200
@@ -61,6 +61,9 @@
 # "yes" turns on the multiplexor recipient checking function
 # MX_RECIPIENT_CHECK=no
 
+# "yes" turns on the multiplexor data checking function
+# MX_DATA_CHECK=no
+
 # Set to yes if you want the multiplexor to log events to syslog
 MX_LOG=yes
 
@@ -268,6 +271,7 @@
 	`[ "$MX_HELO_CHECK" = "yes" ] && echo "-H"` \
 	`[ "$MX_SENDER_CHECK" = "yes" ] && echo "-s"` \
 	`[ "$MX_RECIPIENT_CHECK" = "yes" ] && echo "-t"` \
+	`[ "$MX_DATA_CHECK" = "yes" ] && echo "-A"` \
 	`[ "$KEEP_FAILED_DIRECTORIES" = "yes" ] && echo "-k"` \
 	`[ "$MD_EXTRA" != "" ] && echo $MD_EXTRA` \
 	`[ "$MD_SKIP_BAD_RCPTS" = "yes" ] && echo "-N"` \
--- redhat/mimedefang-init.in	2008-08-15 20:03:41.000000000 +0200
+++ redhat/mimedefang-init.in	2009-05-24 08:06:31.000000000 +0200
@@ -141,6 +141,7 @@
 	$([ "$MX_HELO_CHECK" = "yes" ] && echo "-H") \
 	$([ "$MX_SENDER_CHECK" = "yes" ] && echo "-s") \
 	$([ "$MX_RECIPIENT_CHECK" = "yes" ] && echo "-t") \
+	$([ "$MX_DATA_CHECK" = "yes" ] && echo "-A") \
 	$([ "$KEEP_FAILED_DIRECTORIES" = "yes" ] && echo "-k") \
 	$([ -n "$MD_EXTRA" ] && echo "$MD_EXTRA") \
 	$([ "$ALLOW_NEW_CONNECTIONS_TO_QUEUE" = "yes" ] && echo "-q") \
--- redhat/mimedefang-sysconfig.in	2008-03-07 21:59:28.000000000 +0100
+++ redhat/mimedefang-sysconfig.in	2009-05-24 08:07:22.000000000 +0200
@@ -145,6 +145,9 @@
 # If "yes", turn on the multiplexor recipient checking function
 # MX_RECIPIENT_CHECK=no
 
+# If "yes", turn on the multiplexor post data checking function
+# MX_DATA_CHECK=no
+
 # Ask for filter_tick to be called every 60 seconds
 # MX_TICK_REQUEST=60
 
--- mimedefang-filter.5.in	2009-01-05 16:06:45.000000000 +0100
+++ mimedefang-filter.5.in	2009-05-24 08:18:35.000000000 +0200
@@ -811,21 +811,21 @@
 The host name of the relay.  This is the name of the host that is
attempting
 to send e-mail to your host.  May be "undef" if the host name could not be
 determined.  This variable is available in \fBfilter_relay\fR,
-\fBfilter_sender\fR and \fBfilter_recipient\fR.
+\fBfilter_sender\fR, \fBfilter_recipient\fR and \fBfilter_data\fR.
 
 .TP
 .B $RelayAddr
 The IP address of the sending relay (as a string consisting of four
 dot-separated decimal numbers.)  One potential use of \fB$RelayAddr\fR
 is to limit mailing to certain lists to people within your organization.
-This variable is available in \fBfilter_relay\fR, \fBfilter_sender\fR
-and \fBfilter_recipient\fR.
+This variable is available in \fBfilter_relay\fR, \fBfilter_sender\fR,
+\fBfilter_recipient\fR and \fBfilter_data\fR.
 
 .TP
 .B $Helo
 The argument given to the SMTP "HELO" command.  This variable is
 available in \fBfilter_sender\fR and \fBfilter_recipient\fR,
-but \fInot\fR in \fBfilter_relay\fR.
+\fBfilter_data\fR, but \fInot\fR in \fBfilter_relay\fR.
 
 .TP
 .B $Subject
@@ -833,8 +833,8 @@
 
 .TP
 .B $Sender
-The sender of the e-mail.  This variable is set in \fBfilter_sender\fR
-and \fBfilter_recipient\fR.
+The sender of the e-mail.  This variable is set in \fBfilter_sender\fR,
+\fBfilter_recipient\fR and \fBfilter_data\fR.
 
 .TP
 .B @Recipients
@@ -856,16 +856,16 @@
 .B $QueueID
 The Sendmail queue identifier if it could be determined.  Otherwise,
 contains the string "NOQUEUE". This variable \fIis\fR set correctly
-in \fBfilter_sender\fR and \fBfilter_recipient\fR, but it is \fInot\fR
-available in \fBfilter_relay\fR.
+in \fBfilter_sender\fR,\fBfilter_recipient\fR and \fBfilter_data\fR,
+but it is \fInot\fR available in \fBfilter_relay\fR.
 
 .TP
 .B $MsgID
 Set to $QueueID if the queue ID could be determined; otherwise, set
 to $MessageID.  This identifier should be used in logging, because it
 matches the identifier used by Sendmail to log messages.  Note that this
-variable \fIis\fR set correctly in \fBfilter_sender\fR
-and \fBfilter_recipient\fR, but it is \fInot\fR available in
+variable \fIis\fR set correctly in \fBfilter_sender\fR,
+\fBfilter_recipient\fR and \fBfilter_data\fR, but it is \fInot\fR available
in
 \fBfilter_relay\fR.
 
 .TP
@@ -1396,16 +1396,16 @@
 
 .TP
 .B read_commands_file()
-This function should only be called from \fBfilter_sender\fR and
-\fBfilter_recipient\fR. This will read the \fBCOMMANDS\fR 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.
+This function should only be called from \fBfilter_sender\fR,
+\fBfilter_recipient\fR and \fBfilter_data\fR. This will read the
+\fBCOMMANDS\fR file (as described in mimedefang-protocol(7)),
+and will fill or update the following global variables: $Sender,
+ at Recipients, %RecipientMailers, $RelayAddr, $RealRelayAddr,
+$RelayHostname, $RealRelayHostname, $QueueID, $Helo, %SendmailMacros.
 
 If you do not call \fBread_commands_file\fR, then the only information
-available in \fBfilter_sender\fR and \fBfilter_recipient\fR is that
-which is passed as an argument to the function.
+available in \fBfilter_sender\fR, \fBfilter_recipient\fR or
\fBfilter_data\fR
+is that which is passed as an argument to the function.
 
 .TP
 .B stream_by_domain()
@@ -2008,6 +2008,12 @@
 defined a filter_recipient routine, it is called.
 
 .TP
+.B 4. SMTP DATA: COMMAND
+If you invoked \fBmimedefang\fR with the \fB\-A\fR option and have
+defined a filter_data routine, it is called. At this point, no body
+data have been received by the filter.
+
+.TP
 .B 5. END OF SMTP DATA
 filter_begin is called.  For each MIME part, filter is called.  Then
 filter_end is called.
@@ -2087,7 +2093,7 @@
 .PP
 \fINote\fR: The IP validation header works only in message-oriented
 functions.  It (obviously) has no effect on \fBfilter_relay\fR,
-\fBfilter_sender\fR and \fBfilter_recipient\fR, because no header
+\fBfilter_sender\fR, \fBfilter_recipient\fR and \fBfilter_data\fR, 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.
@@ -2104,7 +2110,7 @@
 It is available to all functions, all the time.
 
 .TP
-.B In filter_relay, filter_sender or filter_recipient
+.B In filter_relay, filter_sender, filter_recipient or filter_data
 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.
@@ -2124,8 +2130,8 @@
 .PP
 The "built-in" globals like $Subject, $Sender, etc. are always available
 to filter_begin, filter and filter_end. Some are available to filter_relay,
-filter_sender or filter_recipient, but you should check the documentation
-of the variable above for details.
+filter_sender, filter_recipient or filter_data, but you should check the
+documentation of the variable above for details.
 
 .SH MAINTAINING STATE
 
@@ -2146,6 +2152,10 @@
 
 .TP
 .B 4
+filter_data
+
+.TP
+.B 5
 filter_begin, filter, filter_multipart, filter_end
 
 .PP
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: patch-filter_data.txt
URL: <https://lists.mimedefang.org/pipermail/mimedefang_lists.mimedefang.org/attachments/20090527/6ad344cb/attachment.txt>


More information about the MIMEDefang mailing list