]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-1.1.11-20020905
authorWietse Venema <wietse@porcupine.org>
Thu, 5 Sep 2002 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:28:12 +0000 (06:28 +0000)
24 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/auxiliary/rmail/rmail
postfix/html/smtpd.8.html
postfix/man/Makefile.in
postfix/man/man1/qmqp-sink.1 [new file with mode: 0644]
postfix/man/man1/qmqp-source.1 [new file with mode: 0644]
postfix/man/man1/smtp-sink.1 [new file with mode: 0644]
postfix/man/man1/smtp-source.1 [new file with mode: 0644]
postfix/man/man8/smtpd.8
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/nqmgr/qmgr.c
postfix/src/nqmgr/qmgr_active.c
postfix/src/qmgr/qmgr.c
postfix/src/qmgr/qmgr_active.c
postfix/src/qmqpd/qmqpd.c
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd.h
postfix/src/smtpd/smtpd_check.c
postfix/src/smtpd/smtpd_check.h
postfix/src/smtpd/smtpd_state.c
postfix/src/util/dict_ldap.c

index 0f9bb2644d89302559676a45e7eb6573cf7eecb6..4c60e4c34e6e08f87c89e56be26ef574441b477d 100644 (file)
 -TSINK_COMMAND
 -TSINK_STATE
 -TSMTPD_CMD
+-TSMTPD_DEFER
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index 4f496021f38f36a29a9b738e7dfc813c19beaf56..6d46badad63945f3a9e6662094829bd9e68ac770 100644 (file)
@@ -6888,14 +6888,40 @@ Apologies for any names omitted.
        Feature: "FILTER transport:nexthop" is now also available
        in SMTPD access tables.
 
+20020901
+
+       Cleanup: postfix-install no longer installs all the manual
+       pages under $POSTFIXSOURCE/man, so we can generate manual
+       pages for smtp-sink etc.  File: man/Makefile.in.
+
+20020903
+
+       Bugfix: the rmail script should have been updated when
+       Postfix sendmail was changed to recognize `.' as the end
+       of input.  Problem fix by Christian Kratzer, cksoft.de.
+       File:  auxiliary/rmail/rmail.
+
+20020904
+
+       Bugfix: qmail compatibility: qmqpd should support any
+       character at the end of the VERP prefix in prefix@host-@[].
+       Based on a patch by LaMont Jones, HP.
+
+20020905
+
+       Feature: "smtpd_data_restrictions = reject_unauth_pipelining"
+       blocks mail from SMTP clients that send message content
+       before Postfix has replied to the DATA command.  File:
+       smtpd/smtpd.c, smtpd/smtpd_check.c.
+
+       Bugfix: the LDAP client dumped core in verbose mode.
+       Reported by Will Day and others.  File: util/dict_ldap.c.
+
 Open problems:
 
        Low: smtpd should log queue ID with reject/warn/hold/discard
        actions.
 
-       Medium: should permit_mx_backup defer delivery if DNS has
-       some error of some kind?
-
        Low: revise other local delivery agent duplicate filters.
 
        Low: all table lookups should consistently use internalized
index 47bdd6777a4bcf10b5b5cec8b3aad9a3d0e97ba0..3d27318b14926ab3a0f340ecf25efb5920816058 100644 (file)
@@ -12,20 +12,28 @@ snapshot release).  Patches change the patchlevel and the release
 date. Snapshots change only the release date, unless they include
 the same bugfixes as a patch release.
 
-Major changes with Postfix snapshot 1.1.11-20020823
+Major changes with Postfix snapshot 1.1.11-20020XXX
 ===================================================
 
 More sophisticated handling of UCE-related DNS lookup errors.
 These cause Postfix to not give up so easily, so that some deliveries
 will not have to be deferred after all.  This affects the following
-restrictions:  permit_mx_backup (defer the request if any subsequent
-restriction would cause the request to be rejected, accept the
-request if any subsequent restriction would cause the request to
-be accepted); reject_unknown_hostname, reject_unknown_sender_domain
-and reject_unknown_recipient_domain (defer the request if any
-subsequent restriction would cause the request to be accepted,
-reject the request if any subsequent restriction would cause the
-request to be rejected).
+restrictions:
+
+- permit_mx_backup (defer the request if a subsequent restriction
+would cause the request to be rejected, accept the request if a
+subsequent restriction would cause the request to be accepted
+anyway);
+
+- reject_unknown_hostname, reject_unknown_sender_domain and
+reject_unknown_recipient_domain (defer the request if a subsequent
+restriction would cause the request to be accepted, reject the
+request if a subsequent restriction would cause the request to be
+rejected anyway).
+
+Specify "smtpd_data_restrictions = reject_unauth_pipelining" to
+block mail from SMTP clients that send message content before
+Postfix has replied to the DATA command.
 
 Incompatible changes with Postfix snapshot 1.1.11-20020819
 ==========================================================
index eb35bf1c24c7636e2fca94c0c0af2b53cd81344d..ab1573c5f0cb86ca342bfe82e663fccf725cad10 100755 (executable)
@@ -10,4 +10,4 @@ case "$from" in
       *) from="$from@$relay";;
 esac
 
-exec $SENDMAIL -f "$from" -- "$@"
+exec $SENDMAIL -i -f "$from" -- "$@"
index 96dbad7a1cebbfc52aabf161a2986c1ba5bcd10b..14e79e9d86f4f3769a0e5bffd2f72bb434cc8155 100644 (file)
@@ -254,6 +254,11 @@ SMTPD(8)                                                 SMTPD(8)
               Restrict what domain names can be used in <b>ETRN</b> com-
               mands, and what clients may issue <b>ETRN</b> commands.
 
+       <b>smtpd</b><i>_</i><b>data</b><i>_</i><b>restrictions</b>
+              Restrictions  on  the  <b>DATA</b> command. Currently, the
+              only  restriction  that   makes   sense   here   is
+              <b>reject</b><i>_</i><b>unauth</b><i>_</i><b>pipelining</b>.
+
        <b>allow</b><i>_</i><b>untrusted</b><i>_</i><b>routing</b>
               Allow  untrusted  clients to specify addresses with
               sender-specified routing.  Enabling this  opens  up
index f1461025a454c6ca0a8b4f3cfff19c22d9b4bc90..279950201b53a7a18b63030d4163dfdfe924b49d 100644 (file)
@@ -12,8 +12,10 @@ COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
        man1/postqueue.1 man1/postsuper.1
 CONFIG = man5/access.5 man5/aliases.5 man5/canonical.5 man5/relocated.5 \
        man5/transport.5 man5/virtual.5 man5/pcre_table.5 man5/regexp_table.5
+TOOLS  = man1/smtp-sink.1 man1/smtp-source.1 man1/qmqp-sink.1 \
+       man1/qmqp-source.1
 
-update:        $(DAEMONS) $(COMMANDS) $(CONFIG)
+update:        $(DAEMONS) $(COMMANDS) $(CONFIG) $(TOOLS)
 
 Makefile: Makefile.in
        (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../src/makedefs; cat $?) >$@
@@ -151,3 +153,15 @@ man5/transport.5: ../proto/transport
 
 man5/virtual.5: ../proto/virtual
        ../mantools/srctoman - $? >$@
+
+man1/smtp-sink.1: ../src/smtpstone/smtp-sink.c
+       ../mantools/srctoman $? >$@
+
+man1/smtp-source.1: ../src/smtpstone/smtp-source.c
+       ../mantools/srctoman $? >$@
+
+man1/qmqp-sink.1: ../src/smtpstone/qmqp-sink.c
+       ../mantools/srctoman $? >$@
+
+man1/qmqp-source.1: ../src/smtpstone/qmqp-source.c
+       ../mantools/srctoman $? >$@
diff --git a/postfix/man/man1/qmqp-sink.1 b/postfix/man/man1/qmqp-sink.1
new file mode 100644 (file)
index 0000000..6bd71a7
--- /dev/null
@@ -0,0 +1,52 @@
+.TH QMQP-SINK 8 
+.ad
+.fi
+.SH NAME
+qmqp-sink
+\-
+multi-threaded QMQP test server
+.SH SYNOPSIS
+.na
+.nf
+.fi
+\fBqmqp-sink\fR [\fB-cv\fR] [\fB-x \fItime\fR]
+[\fBinet:\fR][\fIhost\fR]:\fIport\fR \fIbacklog\fR
+
+\fBqmqp-sink\fR [\fB-cv\fR] [\fB-x \fItime\fR]
+\fBunix:\fR\fIpathname\fR \fIbacklog\fR
+.SH DESCRIPTION
+.ad
+.fi
+\fIqmqp-sink\fR listens on the named host (or address) and port.
+It receives messages from the network and throws them away.
+The purpose is to measure QMQP client performance, not protocol
+compliance.
+Connections can be accepted on IPV4 endpoints or UNIX-domain sockets.
+IPV4 is the default.
+This program is the complement of the \fIqmqp-source\fR program.
+.IP \fB-c\fR
+Display a running counter that is updated whenever a delivery
+is completed.
+.IP \fB-v\fR
+Increase verbosity. Specify \fB-v -v\fR to see some of the QMQP
+conversation.
+.IP "\fB-x \fItime\fR
+Terminate after \fItime\fR seconds. This is to facilitate memory
+leak testing.
+.SH SEE ALSO
+.na
+.nf
+qmqp-source, QMQP test message generator
+.SH LICENSE
+.na
+.nf
+.ad
+.fi
+The Secure Mailer license must be distributed with this software.
+.SH AUTHOR(S)
+.na
+.nf
+Wietse Venema
+IBM T.J. Watson Research
+P.O. Box 704
+Yorktown Heights, NY 10598, USA
diff --git a/postfix/man/man1/qmqp-source.1 b/postfix/man/man1/qmqp-source.1
new file mode 100644 (file)
index 0000000..db13a54
--- /dev/null
@@ -0,0 +1,66 @@
+.TH QMQP-SOURCE 8 
+.ad
+.fi
+.SH NAME
+qmqp-source
+\-
+multi-threaded QMQP test generator
+.SH SYNOPSIS
+.na
+.nf
+.fi
+\fBqmqp-source\fR [\fIoptions\fR] [\fBinet:\fR]\fIhost\fR[:\fIport\fR]
+
+\fBqmqp-source\fR [\fIoptions\fR] \fBunix:\fIpathname\fR
+.SH DESCRIPTION
+.ad
+.fi
+qmqp-source connects to the named host and TCP port (default 628)
+and sends one or more messages to it, either sequentially
+or in parallel. The program speaks the QMQP protocol.
+Connections can be made to UNIX-domain and IPV4 servers.
+IPV4 is the default.
+
+Options:
+.IP -c
+Display a running counter that is incremented each time
+a delivery completes.
+.IP "-C count"
+When a host sends RESET instead of SYN|ACK, try \fIcount\fR times
+before giving up. The default count is 1. Specify a larger count in
+order to work around a problem with TCP/IP stacks that send RESET
+when the listen queue is full.
+.IP "-f from"
+Use the specified sender address (default: <foo@myhostname>).
+.IP "-l length"
+Send \fIlength\fR bytes as message payload. The length
+includes the message headers.
+.IP "-m message_count"
+Send the specified number of messages (default: 1).
+.IP "-r recipient_count"
+Send the specified number of recipients per transaction (default: 1).
+Recipient names are generated by prepending a number to the
+recipient address.
+.IP "-s session_count"
+Run the specified number of QMQP sessions in parallel (default: 1).
+.IP "-t to"
+Use the specified recipient address (default: <foo@myhostname>).
+.IP "-R interval"
+Wait for a random period of time 0 <= n <= interval between messages.
+Suspending one thread does not affect other delivery threads.
+.IP "-w interval"
+Wait a fixed time between messages.
+Suspending one thread does not affect other delivery threads.
+.SH LICENSE
+.na
+.nf
+.ad
+.fi
+The Secure Mailer license must be distributed with this software.
+.SH AUTHOR(S)
+.na
+.nf
+Wietse Venema
+IBM T.J. Watson Research
+P.O. Box 704
+Yorktown Heights, NY 10598, USA
diff --git a/postfix/man/man1/smtp-sink.1 b/postfix/man/man1/smtp-sink.1
new file mode 100644 (file)
index 0000000..3335f07
--- /dev/null
@@ -0,0 +1,82 @@
+.TH SMTP-SINK 8 
+.ad
+.fi
+.SH NAME
+smtp-sink
+\-
+multi-threaded SMTP/LMTP test server
+.SH SYNOPSIS
+.na
+.nf
+.fi
+\fBsmtp-sink\fR [\fIoptions\fR] [\fBinet:\fR][\fIhost\fR]:\fIport\fR
+\fIbacklog\fR
+
+\fBsmtp-sink\fR [\fIoptions\fR] \fBunix:\fR\fIpathname\fR \fIbacklog\fR
+.SH DESCRIPTION
+.ad
+.fi
+\fIsmtp-sink\fR listens on the named host (or address) and port.
+It takes SMTP messages from the network and throws them away.
+The purpose is to measure SMTP client performance, not protocol
+compliance.
+Connections can be accepted on IPV4 endpoints or UNIX-domain sockets.
+IPV4 is the default.
+This program is the complement of the \fIsmtp-source\fR program.
+
+Arguments:
+.IP \fB-c\fR
+Display a running counter that is updated whenever an SMTP
+QUIT command is executed.
+.IP \fB-e\fR
+Disable ESMTP support.
+.IP \fB-h\fI hostname\fR
+Use \fIhostname\fR in the SMTP greeting, in the HELO response,
+and in the EHLO response. The default hostname is "smtp-sink".
+.IP \fB-L\fR
+Enable LMTP rather than SMTP.
+.IP "\fB-n \fIcount\fR"
+Terminate after \fIcount\fR sessions. This is for testing purposes.
+.IP \fB-p\fR
+Disable ESMTP command pipelining.
+.IP \fB-P\fR
+Change the server greeting so that it appears to come through
+a CISCO PIX system.
+.IP "\fB-s \fIcommand,command,...\fR"
+Log the named commands to syslogd.
+Examples of commands that can be logged are HELO, EHLO, LHLO, MAIL,
+RCPT, VRFY, RSET, NOOP, and QUIT. Separate command names by white
+space or commas, and use quotes to protect white space from the
+shell. Command names are case-insensitive.
+.IP \fB-v\fR
+Show the SMTP conversations.
+.IP "\fB-w \fIdelay\fR"
+Wait \fIdelay\fR seconds before responding to a DATA command.
+.IP \fB-8\fR
+Disable 8BITMIME support.
+.IP [\fBinet:\fR][\fIhost\fR]:\fIport\fR
+Listen on network interface \fIhost\fR (default: any interface)
+TCP port \fIport\fR. Both \fIhost\fR and \fIport\fR may be
+specified in numeric or symbolic form.
+.IP \fBunix:\fR\fIpathname\fR
+Listen on the UNIX-domain socket at \fIpathname\fR.
+.IP \fIbacklog\fR
+The maximum length the queue of pending connections,
+as defined by the listen(2) call.
+.SH SEE ALSO
+.na
+.nf
+smtp-source, SMTP/LMTP test message generator
+.SH LICENSE
+.na
+.nf
+.ad
+.fi
+The Secure Mailer license must be distributed with this software.
+.SH AUTHOR(S)
+.na
+.nf
+Wietse Venema
+IBM T.J. Watson Research
+P.O. Box 704
+Yorktown Heights, NY 10598, USA
diff --git a/postfix/man/man1/smtp-source.1 b/postfix/man/man1/smtp-source.1
new file mode 100644 (file)
index 0000000..0bd3f7a
--- /dev/null
@@ -0,0 +1,85 @@
+.TH SMTP-SOURCE 8 
+.ad
+.fi
+.SH NAME
+smtp-source
+\-
+multi-threaded SMTP test generator
+.SH SYNOPSIS
+.na
+.nf
+.fi
+\fBsmtp-source\fR [\fIoptions\fR] [\fBinet:\fR]\fIhost\fR[:\fIport\fR]
+
+\fBsmtp-source\fR [\fIoptions\fR] \fBunix:\fIpathname\fR
+.SH DESCRIPTION
+.ad
+.fi
+smtp-source connects to the named \fIhost\fR and TCP \fIport\fR
+(default: port 25)
+and sends one or more messages to it, either sequentially
+or in parallel. The program speaks either SMTP (default) or
+LMTP. Connections can be made to UNIX-domain and IPV4 servers.
+IPV4 is the default.
+
+Arguments:
+.IP \fB-c\fR
+Display a running counter that is incremented each time
+an SMTP DATA command completes.
+.IP "\fB-C \fIcount\fR"
+When a host sends RESET instead of SYN|ACK, try \fIcount\fR times
+before giving up. The default count is 1. Specify a larger count in
+order to work around a problem with TCP/IP stacks that send RESET
+when the listen queue is full.
+.IP \fB-d\fR
+Don't disconnect after sending a message; send the next
+message over the same connection.
+.IP "\fB-f \fIfrom\fR"
+Use the specified sender address (default: <foo@myhostname>).
+.IP \fB-o\fR
+Old mode: don't send HELO, and don't send message headers.
+.IP "\fB-l \fIlength\fR"
+Send \fIlength\fR bytes as message payload. The length does not
+include message headers.
+.IP \fB-L\fR
+Speak LMTP rather than SMTP.
+.IP "\fB-m \fImessage_count\fR"
+Send the specified number of messages (default: 1).
+.IP "\fB-r \fIrecipient_count\fR"
+Send the specified number of recipients per transaction (default: 1).
+Recipient names are generated by prepending a number to the
+recipient address.
+.IP "\fB-s \fIsession_count\fR"
+Run the specified number of SMTP sessions in parallel (default: 1).
+.IP "\fB-S \fIsubject\fR"
+Send mail with the named subject line (default: none).
+.IP "\fB-t \fIto\fR"
+Use the specified recipient address (default: <foo@myhostname>).
+.IP "\fB-R \fIinterval\fR"
+Wait for a random period of time 0 <= n <= interval between messages.
+Suspending one thread does not affect other delivery threads.
+.IP "\fB-w \fIinterval\fR"
+Wait a fixed time between messages.
+Suspending one thread does not affect other delivery threads.
+.IP [\fBinet:\fR]\fIhost\fR[:\fIport\fR]
+Connect via TCP to \fIhost\fR port \fIport\fR. The default
+port is \fBsmtp\fR.
+.IP \fBunix:\fIpathname\fR
+Connect to the UNIX-domain socket at \fIpathname\fR.
+.SH BUGS
+.ad
+.fi
+No SMTP command pipelining support.
+.SH LICENSE
+.na
+.nf
+.ad
+.fi
+The Secure Mailer license must be distributed with this software.
+.SH AUTHOR(S)
+.na
+.nf
+Wietse Venema
+IBM T.J. Watson Research
+P.O. Box 704
+Yorktown Heights, NY 10598, USA
index 6b02a0e3b79b968d6b115763d8c85d1baafee0f8..3fbdab4262605dc880d4a1c5288aa67eaa85f329 100644 (file)
@@ -212,6 +212,9 @@ Restrict what recipient addresses are allowed in \fBRCPT TO\fR commands.
 .IP \fBsmtpd_etrn_restrictions\fR
 Restrict what domain names can be used in \fBETRN\fR commands,
 and what clients may issue \fBETRN\fR commands.
+.IP \fBsmtpd_data_restrictions\fR
+Restrictions on the \fBDATA\fR command. Currently, the only restriction
+that makes sense here is \fBreject_unauth_pipelining\fR.
 .IP \fBallow_untrusted_routing\fR
 Allow untrusted clients to specify addresses with sender-specified
 routing.  Enabling this opens up nasty relay loopholes involving
index 71f78bd20039df2800d019a49c777790702a7ddc..25fa510ded96874216525a4da7f89bd72f99564a 100644 (file)
@@ -1116,6 +1116,10 @@ extern char *var_rcpt_checks;
 #define DEF_ETRN_CHECKS                ""
 extern char *var_etrn_checks;
 
+#define VAR_DATA_CHECKS                "smtpd_data_restrictions"
+#define DEF_DATA_CHECKS                ""
+extern char *var_data_checks;
+
 #define VAR_REST_CLASSES       "smtpd_restriction_classes"
 #define DEF_REST_CLASSES       ""
 extern char *var_rest_classes;
index af88095e0c4e476881d942ed8e459c5e4c97572a..4373cc45ae114abd437a90e6061ef23f5f660539 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change the patchlevel and the release date. Snapshots change the
   * release date only, unless they include the same bugfix as a patch release.
   */
-#define MAIL_RELEASE_DATE      "20020827"
+#define MAIL_RELEASE_DATE      "20020905"
 
 #define VAR_MAIL_VERSION       "mail_version"
 #define DEF_MAIL_VERSION       "1.1.11-" MAIL_RELEASE_DATE
index 57f65cac4ad417f05fab6845190b2a6b61911763..0d1603d756f562552239bcbe933edca784ecadc0 100644 (file)
@@ -553,7 +553,7 @@ int     main(int argc, char **argv)
        VAR_QUEUE_RUN_DELAY, DEF_QUEUE_RUN_DELAY, &var_queue_run_delay, 1, 0,
        VAR_MIN_BACKOFF_TIME, DEF_MIN_BACKOFF_TIME, &var_min_backoff_time, 1, 0,
        VAR_MAX_BACKOFF_TIME, DEF_MAX_BACKOFF_TIME, &var_max_backoff_time, 1, 0,
-       VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 1, 8640000,
+       VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 0, 8640000,
        VAR_XPORT_RETRY_TIME, DEF_XPORT_RETRY_TIME, &var_transport_retry_time, 1, 0,
        VAR_QMGR_CLOG_WARN_TIME, DEF_QMGR_CLOG_WARN_TIME, &var_qmgr_clog_warn_time, 0, 0,
        0,
index b4b7f9c480bbf838ae31e16cb4b69e5719672b1d..dd0044b4c7b90bbf59eaee3ff002f3571f600b9d 100644 (file)
@@ -365,7 +365,7 @@ static void qmgr_active_done_2_generic(QMGR_MESSAGE *message)
      * daemon waits for the qmgr to accept the "new mail" trigger.
      */
     if (message->flags) {
-       if (event_time() > message->arrival_time + var_max_queue_time) {
+       if (event_time() >= message->arrival_time + var_max_queue_time) {
            msg_info("%s: from=<%s>, status=expired, returned to sender",
                     message->queue_id, message->sender);
            if (message->verp_delims == 0 || var_verp_bounce_off)
index 87d75dd822b82d77613f2c70d6f1a7531359b780..d09a646500eddc8f2582542931cf927db1423e23 100644 (file)
@@ -505,7 +505,7 @@ int     main(int argc, char **argv)
        VAR_QUEUE_RUN_DELAY, DEF_QUEUE_RUN_DELAY, &var_queue_run_delay, 1, 0,
        VAR_MIN_BACKOFF_TIME, DEF_MIN_BACKOFF_TIME, &var_min_backoff_time, 1, 0,
        VAR_MAX_BACKOFF_TIME, DEF_MAX_BACKOFF_TIME, &var_max_backoff_time, 1, 0,
-       VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 1, 8640000,
+       VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 0, 8640000,
        VAR_XPORT_RETRY_TIME, DEF_XPORT_RETRY_TIME, &var_transport_retry_time, 1, 0,
        VAR_QMGR_CLOG_WARN_TIME, DEF_QMGR_CLOG_WARN_TIME, &var_qmgr_clog_warn_time, 0, 0,
        0,
index b4b7f9c480bbf838ae31e16cb4b69e5719672b1d..dd0044b4c7b90bbf59eaee3ff002f3571f600b9d 100644 (file)
@@ -365,7 +365,7 @@ static void qmgr_active_done_2_generic(QMGR_MESSAGE *message)
      * daemon waits for the qmgr to accept the "new mail" trigger.
      */
     if (message->flags) {
-       if (event_time() > message->arrival_time + var_max_queue_time) {
+       if (event_time() >= message->arrival_time + var_max_queue_time) {
            msg_info("%s: from=<%s>, status=expired, returned to sender",
                     message->queue_id, message->sender);
            if (message->verp_delims == 0 || var_verp_bounce_off)
index dbcfcb4f0c5fa47f835cb7b27a2922173db4e314..ff331c355704c4ce14b9b45a26f40a8fe2a019e6 100644 (file)
@@ -217,23 +217,27 @@ static void qmqpd_copy_sender(QMQPD_STATE *state)
     char   *end_prefix;
     char   *end_origin;
     int     verp_requested;
+    static char verp_chars[] = "-=";
 
     /*
-     * If the sender address looks like prefix-@origin-@[], then request
+     * If the sender address looks like prefix@origin-@[], then request
      * variable envelope return path delivery, with an envelope sender
-     * address of prefix@origin, and with VERP delimiters of - and =. This
+     * address of prefi@origin, and with VERP delimiters of x and =. This
      * way, the recipients will see envelope sender addresses that look like:
-     * prefix-user=domain@origin.
+     * prefixuser=domain@origin.
      */
     state->where = "receiving sender address";
     netstring_get(state->client, state->buf, var_line_limit);
     VSTRING_TERMINATE(state->buf);
-    verp_requested = ((end_prefix = strstr(STR(state->buf), "-@")) != 0
-                     && (end_origin = strstr(end_prefix + 2, "-@")) != 0
-                     && strncmp(end_origin + 2, "[]", 2) == 0
-                     && vstring_end(state->buf) == end_origin + 4);
+    verp_requested =
+       ((end_origin = vstring_end(state->buf) - 4) > STR(state->buf)
+        && strcmp(end_origin, "-@[]") == 0
+        && (end_prefix = strchr(STR(state->buf), '@')) != 0    /* XXX */
+        && --end_prefix < end_origin - 2       /* non-null origin */
+        && end_prefix > STR(state->buf));      /* non-null prefix */
     if (verp_requested) {
-       memcpy(end_prefix, end_prefix + 1, end_origin - end_prefix - 1);
+       verp_chars[0] = end_prefix[0];
+       memmove(end_prefix, end_prefix + 1, end_origin - end_prefix - 1);
        vstring_truncate(state->buf, end_origin - STR(state->buf) - 1);
     }
     if (state->err == CLEANUP_STAT_OK
@@ -241,7 +245,7 @@ static void qmqpd_copy_sender(QMQPD_STATE *state)
        state->err = CLEANUP_STAT_WRITE;
     if (verp_requested)
        if (state->err == CLEANUP_STAT_OK
-           && rec_put(state->cleanup, REC_TYPE_VERP, "-=", 2) < 0)
+           && rec_put(state->cleanup, REC_TYPE_VERP, verp_chars, 2) < 0)
            state->err = CLEANUP_STAT_WRITE;
     state->sender = mystrndup(STR(state->buf), LEN(state->buf));
 }
index ca31431ffa44fa9e91d288f70b4fca8bc953f162..66f4a97d0cc745ed323364225aba5567275647ba 100644 (file)
 /* .IP \fBsmtpd_etrn_restrictions\fR
 /*     Restrict what domain names can be used in \fBETRN\fR commands,
 /*     and what clients may issue \fBETRN\fR commands.
+/* .IP \fBsmtpd_data_restrictions\fR
+/*     Restrictions on the \fBDATA\fR command. Currently, the only restriction
+/*     that makes sense here is \fBreject_unauth_pipelining\fR.
 /* .IP \fBallow_untrusted_routing\fR
 /*     Allow untrusted clients to specify addresses with sender-specified
 /*     routing.  Enabling this opens up nasty relay loopholes involving
@@ -350,6 +353,7 @@ char   *var_helo_checks;
 char   *var_mail_checks;
 char   *var_rcpt_checks;
 char   *var_etrn_checks;
+char   *var_data_checks;
 int     var_unk_client_code;
 int     var_bad_name_code;
 int     var_unk_name_code;
@@ -925,6 +929,7 @@ static void rcpt_reset(SMTPD_STATE *state)
 
 static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
 {
+    char   *err;
     char   *start;
     int     len;
     int     curr_rec_type;
@@ -951,6 +956,10 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
        smtpd_chat_reply(state, "501 Syntax: DATA");
        return (-1);
     }
+    if (SMTPD_STAND_ALONE(state) == 0 && (err = smtpd_check_data(state)) != 0) {
+       smtpd_chat_reply(state, "%s", err);
+       return (-1);
+    }
 
     /*
      * Terminate the message envelope segment. Start the message content
@@ -1609,6 +1618,7 @@ int     main(int argc, char **argv)
        VAR_MAIL_CHECKS, DEF_MAIL_CHECKS, &var_mail_checks, 0, 0,
        VAR_RCPT_CHECKS, DEF_RCPT_CHECKS, &var_rcpt_checks, 0, 0,
        VAR_ETRN_CHECKS, DEF_ETRN_CHECKS, &var_etrn_checks, 0, 0,
+       VAR_DATA_CHECKS, DEF_DATA_CHECKS, &var_data_checks, 0, 0,
        VAR_MAPS_RBL_DOMAINS, DEF_MAPS_RBL_DOMAINS, &var_maps_rbl_domains, 0, 0,
        VAR_ALWAYS_BCC, DEF_ALWAYS_BCC, &var_always_bcc, 0, 0,
        VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
index 9f04b72e68ab698bd09ce99a72bfbb3170899603..5cb9f19ec13381f4c34f3c7d71997adc0bbb921e 100644 (file)
   * some of this has to be global anyway, so that the run-time error handler
   * can clean up in case of a fatal error deep down in some library routine.
   */
+typedef struct SMTPD_DEFER {
+    int     active;                    /* is this active */
+    VSTRING *reason;                   /* reason for deferral */
+    int     class;                     /* error notification class */
+} SMTPD_DEFER;
+
 typedef struct SMTPD_STATE {
     int     err;
     VSTREAM *client;
@@ -80,11 +86,9 @@ typedef struct SMTPD_STATE {
     VSTRING *sasl_encoded;
     VSTRING *sasl_decoded;
 #endif
-    int     warn_if_reject;
-    int     defer_if_reject;           /* force reject into deferral */
-    int     defer_if_permit;           /* force permit into deferral */
-    VSTRING *defer_reason;             /* reason why we force deferral */
-    int     defer_class;               /* forced deferral error class */
+    int     warn_if_reject;            /* force reject into warning */
+    SMTPD_DEFER defer_if_reject;       /* force reject into deferral */
+    SMTPD_DEFER defer_if_permit;       /* force permit into deferral */
 } SMTPD_STATE;
 
 extern void smtpd_state_init(SMTPD_STATE *, VSTREAM *);
index 6dd9a206ea382f100708435c71d8874b5f3c3ae3..a426ab4ac30f19e8dd604c523cad505dd9ad6b20 100644 (file)
@@ -31,6 +31,9 @@
 /*     char    *smtpd_check_etrn(state, destination)
 /*     SMTPD_STATE *state;
 /*     char    *destination;
+/*
+/*     char    *smtpd_check_data(state)
+/*     SMTPD_STATE *state;
 /* DESCRIPTION
 /*     This module implements additional checks on SMTP client requests.
 /*     A client request is validated in the context of the session state.
 /* .IP reject_unauth_pipelining
 /*     Reject the request when the client has already sent the next request
 /*     without being told that the server implements SMTP command pipelining.
+/*     Reject the DATA command when the client sends message content before
+/*     Postfix has sent the DATA command reply.
 /* .IP permit_mx_backup
 /*     Allow the request when all primary MX hosts for the recipient
 /*     are in the networks specified with the $permit_mx_backup_networks
@@ -359,6 +364,7 @@ static ARGV *helo_restrctions;
 static ARGV *mail_restrctions;
 static ARGV *rcpt_restrctions;
 static ARGV *etrn_restrctions;
+static ARGV *data_restrctions;
 
 static HTABLE *smtpd_rest_classes;
 
@@ -375,6 +381,7 @@ static int generic_checks(SMTPD_STATE *, ARGV *, const char *, const char *, con
 #define SMTPD_NAME_SENDER      "Sender address"
 #define SMTPD_NAME_RECIPIENT   "Recipient address"
 #define SMTPD_NAME_ETRN                "Etrn command"
+#define SMTPD_NAME_DATA                "Data command"
 
  /*
   * YASLM.
@@ -384,11 +391,28 @@ static int generic_checks(SMTPD_STATE *, ARGV *, const char *, const char *, con
 
  /*
   * If some decision can't be made due to a temporary error, then change
-  * other decisions in to deferrals.
+  * other decisions into deferrals.
+  * 
+  * XXX Deferrals can be postponed only with restrictions that are based on
+  * client-specified information: this restricts their use to parameters
+  * given in HELO, MAIL FROM, RCPT TO commands.
+  * 
+  * XXX Deferrals must not be postponed after client hostname lookup failure.
+  * The reason is that the effect of access tables may depend on whether a
+  * client hostname is available or not. Thus, the reject_unknown_client
+  * restriction must defer immediately when lookup fails, otherwise incorrect
+  * results happen with:
+  * 
+  * reject_unknown_client, hostname-based white-list, reject
   */
-static void PRINTFLIKE(3, 4) defer_if_reject(SMTPD_STATE *, int, const char *, ...);
-static void PRINTFLIKE(3, 4) defer_if_permit(SMTPD_STATE *, int, const char *, ...);
-
+static void PRINTFLIKE(3, 4) defer_if(SMTPD_DEFER *, int, const char *,...);
+
+#define DEFER_IF_REJECT2(state, class, fmt, a1, a2) \
+    defer_if(&(state)->defer_if_reject, (class), (fmt), (a1), (a2))
+#define DEFER_IF_REJECT3(state, class, fmt, a1, a2, a3) \
+    defer_if(&(state)->defer_if_reject, (class), (fmt), (a1), (a2), (a3))
+#define DEFER_IF_PERMIT2(state, class, fmt, a1, a2) \
+    defer_if(&(state)->defer_if_permit, (class), (fmt), (a1), (a2))
 /* resolve_pagein - page in an address resolver result */
 
 static void *resolve_pagein(const char *addr, void *unused_context)
@@ -584,6 +608,7 @@ void    smtpd_check_init(void)
     mail_restrctions = smtpd_check_parse(var_mail_checks);
     rcpt_restrctions = smtpd_check_parse(var_rcpt_checks);
     etrn_restrctions = smtpd_check_parse(var_etrn_checks);
+    data_restrctions = smtpd_check_parse(var_data_checks);
 
     /*
      * Parse the pre-defined restriction classes.
@@ -656,6 +681,21 @@ static int smtpd_check_reject(SMTPD_STATE *state, int error_class,
     int     warn_if_reject;
     const char *whatsup;
 
+    /*
+     * defer_if_whatever has precedence over warn_if_reject, so as to
+     * minimize confusion. Bummer. There goes transparency.
+     */
+    if (state->warn_if_reject && state->defer_if_reject.active) {
+       state->warn_if_reject = state->defer_if_reject.active = 0;
+       return (smtpd_check_reject(state, state->defer_if_reject.class,
+                                "%s", STR(state->defer_if_reject.reason)));
+    }
+    if (state->warn_if_reject && state->defer_if_permit.active) {
+       state->warn_if_reject = state->defer_if_permit.active = 0;
+       return (smtpd_check_reject(state, state->defer_if_permit.class,
+                                "%s", STR(state->defer_if_permit.reason)));
+    }
+
     /*
      * Do not reject mail if we were asked to warn only. However,
      * configuration errors cannot be converted into warnings.
@@ -691,7 +731,20 @@ static int smtpd_check_reject(SMTPD_STATE *state, int error_class,
     printable(STR(error_text), ' ');
 
     /*
-     * XXX The code below also appears in the SMTP server reply output
+     * Force this rejection into deferral because of some earlier temporary
+     * error that may have prevented us from accepting mail, and report the
+     * earlier problem instead.
+     */
+    if (!warn_if_reject && state->defer_if_reject.active && STR(error_text)[0] == '5') {
+       state->warn_if_reject = state->defer_if_reject.active = 0;
+       return (smtpd_check_reject(state, state->defer_if_reject.class,
+                                "%s", STR(state->defer_if_reject.reason)));
+    }
+
+    /*
+     * Soft bounce safety net.
+     * 
+     * XXX The code below also appears in the Postfix SMTP server reply output
      * routine. It is duplicated here in order to avoid discrepancies between
      * the reply codes that are shown in "reject" logging and the reply codes
      * that are actually sent to the SMTP client.
@@ -707,15 +760,8 @@ static int smtpd_check_reject(SMTPD_STATE *state, int error_class,
      * the UCE restrictions only. This would be at odds with documentation
      * which says soft_bounce changes all 5xx replies into 4xx ones.
      */
-    if (STR(error_text)[0] == '5') {
-       if (state->defer_if_reject) {
-           state->defer_if_reject = 0;
-           return (smtpd_check_reject(state, state->defer_class,
-                                      "%s", STR(state->defer_reason)));
-       }
-       if (var_soft_bounce)
-           STR(error_text)[0] = '4';
-    }
+    if (var_soft_bounce && STR(error_text)[0] == '5')
+       STR(error_text)[0] = '4';
 
     /*
      * Log what is happening. When the sysadmin discards policy violation
@@ -727,36 +773,25 @@ static int smtpd_check_reject(SMTPD_STATE *state, int error_class,
     return (warn_if_reject ? 0 : SMTPD_CHECK_REJECT);
 }
 
-/* defer_if_reject - prepare to change our mind */
-
-static void defer_if_reject(SMTPD_STATE *state, int error_class,
-                                   const char *fmt,...)
-{
-    va_list ap;
-
-    if (state->defer_reason == 0)
-       state->defer_reason = vstring_alloc(10);
-    state->defer_class = error_class;
-    va_start(ap, fmt);
-    vstring_vsprintf(state->defer_reason, fmt, ap);
-    va_end(ap);
-    state->defer_if_reject = 1;
-}
-
-/* defer_if_permit - prepare to change our mind */
+/* defer_if - prepare to change our mind */
 
-static void defer_if_permit(SMTPD_STATE *state, int error_class,
-                                   const char *fmt,...)
+static void defer_if(SMTPD_DEFER *defer, int error_class, const char *fmt,...)
 {
     va_list ap;
 
-    if (state->defer_reason == 0)
-       state->defer_reason = vstring_alloc(10);
-    state->defer_class = error_class;
-    va_start(ap, fmt);
-    vstring_vsprintf(state->defer_reason, fmt, ap);
-    va_end(ap);
-    state->defer_if_permit = 1;
+    /*
+     * Keep the first reason for this type of deferral, to minimize
+     * confusion.
+     */
+    if (defer->active == 0) {
+       defer->active = 1;
+       defer->class = error_class;
+       if (defer->reason == 0)
+           defer->reason = vstring_alloc(10);
+       va_start(ap, fmt);
+       vstring_vsprintf(defer->reason, fmt, ap);
+       va_end(ap);
+    }
 }
 
 /* reject_dict_retry - reject with temporary failure if dict lookup fails */
@@ -1032,9 +1067,9 @@ static int reject_unknown_hostname(SMTPD_STATE *state, char *name,
                                   var_unk_name_code,
                                   reply_name, reply_class));
     else if (dns_status != DNS_OK)
-       defer_if_permit(state, MAIL_ERROR_POLICY,
-                       "450 <%s>: %s rejected: Host not found",
-                       reply_name, reply_class);
+       DEFER_IF_PERMIT2(state, MAIL_ERROR_POLICY,
+                        "450 <%s>: %s rejected: Host not found",
+                        reply_name, reply_class);
     return (SMTPD_CHECK_DUNNO);
 }
 
@@ -1057,9 +1092,9 @@ static int reject_unknown_mailhost(SMTPD_STATE *state, const char *name,
                                   var_unk_addr_code,
                                   reply_name, reply_class));
     else if (dns_status != DNS_OK)
-       defer_if_permit(state, MAIL_ERROR_POLICY,
-                       "450 <%s>: %s rejected: Domain not found",
-                       reply_name, reply_class);
+       DEFER_IF_PERMIT2(state, MAIL_ERROR_POLICY,
+                        "450 <%s>: %s rejected: Domain not found",
+                        reply_name, reply_class);
     return (SMTPD_CHECK_DUNNO);
 }
 
@@ -1169,7 +1204,8 @@ static int reject_unauth_destination(SMTPD_STATE *state, char *recipient)
 
 /* reject_unauth_pipelining - reject improper use of SMTP command pipelining */
 
-static int reject_unauth_pipelining(SMTPD_STATE *state)
+static int reject_unauth_pipelining(SMTPD_STATE *state,
+                           const char *reply_name, const char *reply_class)
 {
     char   *myname = "reject_unauth_pipelining";
 
@@ -1179,16 +1215,19 @@ static int reject_unauth_pipelining(SMTPD_STATE *state)
     if (state->client != 0
        && SMTPD_STAND_ALONE(state) == 0
        && vstream_peek(state->client) > 0
-       && strcasecmp(state->protocol, "ESMTP") != 0) {
+       && (strcasecmp(state->protocol, "ESMTP") != 0
+           || strcasecmp(state->where, "DATA") == 0)) {
        return (smtpd_check_reject(state, MAIL_ERROR_PROTOCOL,
-                           "503 Improper use of SMTP command pipelining"));
+          "503 <%s>: %s rejected: Improper use of SMTP command pipelining",
+                                  reply_name, reply_class));
     }
     return (SMTPD_CHECK_DUNNO);
 }
 
 /* all_auth_mx_addr - match host addresses against permit_mx_backup_networks */
 
-static int all_auth_mx_addr(SMTPD_STATE *state, char *host)
+static int all_auth_mx_addr(SMTPD_STATE *state, char *host,
+                           const char *reply_name, const char *reply_class)
 {
     char   *myname = "all_auth_mx_addr";
     struct in_addr addr;
@@ -1210,9 +1249,9 @@ static int all_auth_mx_addr(SMTPD_STATE *state, char *host)
      */
     dns_status = dns_lookup(host, T_A, 0, &addr_list, (VSTRING *) 0, (VSTRING *) 0);
     if (dns_status != DNS_OK) {
-       defer_if_reject(state, MAIL_ERROR_POLICY,
-                     "450 Unable to look up host %s as mail exchanger: %s",
-                       host, dns_strerror(h_errno));
+       DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
+       "450 <%s>: %s rejected: Unable to look up host %s as mail exchanger",
+                        reply_name, reply_class, host);
        return (NOPE);
     }
     for (rr = addr_list; rr != 0; rr = rr->next) {
@@ -1244,7 +1283,8 @@ static int all_auth_mx_addr(SMTPD_STATE *state, char *host)
 
 /* has_my_addr - see if this host name lists one of my network addresses */
 
-static int has_my_addr(SMTPD_STATE *state, const char *host)
+static int has_my_addr(SMTPD_STATE *state, const char *host,
+                           const char *reply_name, const char *reply_class)
 {
     char   *myname = "has_my_addr";
     struct in_addr addr;
@@ -1261,9 +1301,9 @@ static int has_my_addr(SMTPD_STATE *state, const char *host)
 #define NOPE   0
 
     if ((hp = gethostbyname(host)) == 0) {
-       defer_if_reject(state, MAIL_ERROR_POLICY,
-                     "450 Unable to look up host %s as mail exchanger: %s",
-                       host, dns_strerror(h_errno));
+       DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
+         "450 <%s>: %s rejected: Unable to look up mail exchanger host %s",
+                        reply_name, reply_class, host);
        return (NOPE);
     }
     if (hp->h_addrtype != AF_INET || hp->h_length != sizeof(addr)) {
@@ -1286,7 +1326,8 @@ static int has_my_addr(SMTPD_STATE *state, const char *host)
 
 /* i_am_mx - is this machine listed as MX relay */
 
-static int i_am_mx(SMTPD_STATE *state, DNS_RR *mx_list)
+static int i_am_mx(SMTPD_STATE *state, DNS_RR *mx_list,
+                          const char *reply_name, const char *reply_class)
 {
     const char *myname = "permit_mx_backup";
     DNS_RR *mx;
@@ -1308,7 +1349,7 @@ static int i_am_mx(SMTPD_STATE *state, DNS_RR *mx_list)
     for (mx = mx_list; mx != 0; mx = mx->next) {
        if (msg_verbose)
            msg_info("%s: address lookup: %s", myname, (char *) mx->data);
-       if (has_my_addr(state, (char *) mx->data))
+       if (has_my_addr(state, (char *) mx->data, reply_name, reply_class))
            return (YUP);
     }
 
@@ -1322,7 +1363,8 @@ static int i_am_mx(SMTPD_STATE *state, DNS_RR *mx_list)
 
 /* permit_mx_primary - authorize primary MX relays */
 
-static int permit_mx_primary(SMTPD_STATE *state, DNS_RR *mx_list)
+static int permit_mx_primary(SMTPD_STATE *state, DNS_RR *mx_list,
+                           const char *reply_name, const char *reply_class)
 {
     DNS_RR *mx;
     unsigned int best_pref;
@@ -1341,7 +1383,7 @@ static int permit_mx_primary(SMTPD_STATE *state, DNS_RR *mx_list)
     for (mx = mx_list; mx != 0; mx = mx->next) {
        if (mx->pref != best_pref)
            continue;
-       if (!all_auth_mx_addr(state, (char *) mx->data))
+       if (!all_auth_mx_addr(state, (char *) mx->data, reply_name, reply_class))
            return (NOPE);
     }
 
@@ -1349,12 +1391,13 @@ static int permit_mx_primary(SMTPD_STATE *state, DNS_RR *mx_list)
      * All IP addresses of the best MX hosts are within
      * permit_mx_backup_networks.
      */
-    return (mx_list ? YUP : NOPE);
+    return (YUP);
 }
 
 /* permit_mx_backup - permit use of me as MX backup for recipient domain */
 
-static int permit_mx_backup(SMTPD_STATE *state, const char *recipient)
+static int permit_mx_backup(SMTPD_STATE *state, const char *recipient,
+                           const char *reply_name, const char *reply_class)
 {
     char   *myname = "permit_mx_backup";
     const RESOLVE_REPLY *reply;
@@ -1411,18 +1454,19 @@ static int permit_mx_backup(SMTPD_STATE *state, const char *recipient)
     dns_status = dns_lookup(domain, T_MX, 0, &mx_list,
                            (VSTRING *) 0, (VSTRING *) 0);
     if (dns_status == DNS_NOTFOUND)
-       return (has_my_addr(state, domain) ? SMTPD_CHECK_OK : SMTPD_CHECK_DUNNO);
+       return (has_my_addr(state, domain, reply_name, reply_class) ?
+               SMTPD_CHECK_OK : SMTPD_CHECK_DUNNO);
     if (dns_status != DNS_OK) {
-       defer_if_reject(state, MAIL_ERROR_POLICY,
-                    "450 Unable to look up mail exchanger information: %s",
-                       dns_strerror(h_errno));
+       DEFER_IF_REJECT2(state, MAIL_ERROR_POLICY,
+                        "450 <%s>: %s rejected: Unable to look up mail exchanger information",
+                        reply_name, reply_class);
        return (SMTPD_CHECK_DUNNO);
     }
 
     /*
      * First, see if we match any of the MX host names listed.
      */
-    if (!i_am_mx(state, mx_list)) {
+    if (!i_am_mx(state, mx_list, reply_name, reply_class)) {
        dns_rr_free(mx_list);
        return (SMTPD_CHECK_DUNNO);
     }
@@ -1431,7 +1475,8 @@ static int permit_mx_backup(SMTPD_STATE *state, const char *recipient)
      * Optionally, see if the primary MX hosts are in a restricted list of
      * networks.
      */
-    if (*var_perm_mx_networks && !permit_mx_primary(state, mx_list)) {
+    if (*var_perm_mx_networks
+       && !permit_mx_primary(state, mx_list, reply_name, reply_class)) {
        dns_rr_free(mx_list);
        return (SMTPD_CHECK_DUNNO);
     }
@@ -1569,18 +1614,24 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
      */
 #define FILTER_LEN     (sizeof("FILTER") - 1)
 
-    if (strncasecmp(value, "FILTER", FILTER_LEN) == 0
-       && (value[FILTER_LEN] == 0 || ISSPACE(value[FILTER_LEN]))) {
-       value += FILTER_LEN;
-       while (ISSPACE(*value))
-           value++;
-       vstring_sprintf(error_text, "<%s>: %s triggers FILTER %s",
-                       reply_name, reply_class, value);
-       log_whatsup(state, "hold", STR(error_text));
+    if (strncasecmp(value, "FILTER", FILTER_LEN) == 0) {
+       if (value[FILTER_LEN] == 0) {
+           msg_warn("access map %s entry %s has FILTER entry without value",
+                    table, datum);
+           return (SMTPD_CHECK_DUNNO);
+       }
+       if (ISSPACE(value[FILTER_LEN])) {
+           value += FILTER_LEN;
+           while (ISSPACE(*value))
+               value++;
+           vstring_sprintf(error_text, "<%s>: %s triggers FILTER %s",
+                           reply_name, reply_class, value);
+           log_whatsup(state, "filter", STR(error_text));
 #ifndef TEST
-       rec_fprintf(state->dest->stream, REC_TYPE_FILT, "%s", value);
+           rec_fprintf(state->dest->stream, REC_TYPE_FILT, "%s", value);
 #endif
-       return (SMTPD_CHECK_DUNNO);
+           return (SMTPD_CHECK_DUNNO);
+       }
     }
 
     /*
@@ -2164,7 +2215,16 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
         * Spoof the is_map_command() routine, so that we do not have to make
         * special cases for the implicit short-hand access map notation.
         */
+#define NO_DEF_ACL     0
+
        if (strchr(name, ':') != 0) {
+           if (def_acl == NO_DEF_ACL) {
+               msg_warn("specify one of (%s, %s, %s, %s, %s) before restriction \"%s\"",
+                        CHECK_CLIENT_ACL, CHECK_HELO_ACL, CHECK_SENDER_ACL,
+                        CHECK_RECIP_ACL, CHECK_ETRN_ACL, name);
+               longjmp(smtpd_check_buf, smtpd_check_reject(state,
+                   MAIL_ERROR_SOFTWARE, "451 Server configuration error"));
+           }
            name = def_acl;
            cpp -= 1;
        }
@@ -2192,7 +2252,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
                msg_warn("restriction `%s' after `%s' is ignored",
                         cpp[1], REJECT_ALL);
        } else if (strcasecmp(name, REJECT_UNAUTH_PIPE) == 0) {
-           status = reject_unauth_pipelining(state);
+           status = reject_unauth_pipelining(state, reply_name, reply_class);
        }
 
        /*
@@ -2295,7 +2355,8 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
                                           SMTPD_NAME_RECIPIENT, def_acl);
        } else if (strcasecmp(name, PERMIT_MX_BACKUP) == 0) {
            if (state->recipient)
-               status = permit_mx_backup(state, state->recipient);
+               status = permit_mx_backup(state, state->recipient,
+                                   state->recipient, SMTPD_NAME_RECIPIENT);
        } else if (strcasecmp(name, PERMIT_AUTH_DEST) == 0) {
            if (state->recipient)
                status = permit_auth_destination(state, state->recipient);
@@ -2361,16 +2422,25 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
 
        if (status != 0)
            break;
+
+       if (state->defer_if_permit.active && state->defer_if_reject.active)
+           break;
     }
     if (msg_verbose && name == 0)
        msg_info("%s: END", myname);
 
     state->recursion = saved_recursion;
 
-    if (status == SMTPD_CHECK_OK || status == SMTPD_CHECK_DUNNO)
-       if (state->defer_if_permit)
-           status = smtpd_check_reject(state, state->defer_class,
-                                       "%s", STR(state->defer_reason));
+    /*
+     * Force this permission into deferral because of some earlier temporary
+     * error that may have prevented us from rejecting mail, and report the
+     * earlier problem instead.
+     */
+    if (status == SMTPD_CHECK_OK || status == SMTPD_CHECK_DUNNO) {
+       if (state->defer_if_permit.active)
+           status = smtpd_check_reject(state, state->defer_if_permit.class,
+                                 "%s", STR(state->defer_if_permit.reason));
+    }
     return (status);
 }
 
@@ -2386,13 +2456,17 @@ char   *smtpd_check_client(SMTPD_STATE *state)
     if (state->name == 0 || state->addr == 0)
        return (0);
 
+#define SMTPD_CHECK_RESET() { \
+       state->recursion = 1; \
+       state->warn_if_reject = 0; \
+       state->defer_if_reject.active = 0; \
+       state->defer_if_permit.active = 0; \
+    }
+
     /*
      * Apply restrictions in the order as specified.
      */
-    state->recursion = 1;
-    state->warn_if_reject = 0;
-    state->defer_if_reject = 0;
-    state->defer_if_permit = 0;
+    SMTPD_CHECK_RESET();
     status = setjmp(smtpd_check_buf);
     if (status == 0 && client_restrctions->argc)
        status = generic_checks(state, client_restrctions, state->namaddr,
@@ -2420,11 +2494,11 @@ char   *smtpd_check_helo(SMTPD_STATE *state, char *helohost)
      */
 #define SMTPD_CHECK_PUSH(backup, current, new) { \
        backup = current; \
-       current = mystrdup(new); \
+       current = (new ? mystrdup(new) : new); \
     }
 
 #define SMTPD_CHECK_POP(current, backup) { \
-       myfree(current); \
+       if (current) myfree(current); \
        current = backup; \
     }
 
@@ -2438,10 +2512,7 @@ char   *smtpd_check_helo(SMTPD_STATE *state, char *helohost)
     /*
      * Apply restrictions in the order as specified.
      */
-    state->recursion = 1;
-    state->warn_if_reject = 0;
-    state->defer_if_reject = 0;
-    state->defer_if_permit = 0;
+    SMTPD_CHECK_RESET();
     status = setjmp(smtpd_check_buf);
     if (status == 0 && helo_restrctions->argc)
        status = generic_checks(state, helo_restrctions, state->helo_name,
@@ -2477,10 +2548,7 @@ char   *smtpd_check_mail(SMTPD_STATE *state, char *sender)
     /*
      * Apply restrictions in the order as specified.
      */
-    state->recursion = 1;
-    state->warn_if_reject = 0;
-    state->defer_if_reject = 0;
-    state->defer_if_permit = 0;
+    SMTPD_CHECK_RESET();
     status = setjmp(smtpd_check_buf);
     if (status == 0 && mail_restrctions->argc)
        status = generic_checks(state, mail_restrctions, sender,
@@ -2534,10 +2602,7 @@ char   *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
     /*
      * Apply restrictions in the order as specified.
      */
-    state->recursion = 1;
-    state->warn_if_reject = 0;
-    state->defer_if_reject = 0;
-    state->defer_if_permit = 0;
+    SMTPD_CHECK_RESET();
     status = setjmp(smtpd_check_buf);
     if (status == 0 && rcpt_restrctions->argc)
        status = generic_checks(state, rcpt_restrctions,
@@ -2582,10 +2647,7 @@ char   *smtpd_check_etrn(SMTPD_STATE *state, char *domain)
     /*
      * Apply restrictions in the order as specified.
      */
-    state->recursion = 1;
-    state->warn_if_reject = 0;
-    state->defer_if_reject = 0;
-    state->defer_if_permit = 0;
+    SMTPD_CHECK_RESET();
     status = setjmp(smtpd_check_buf);
     if (status == 0 && etrn_restrctions->argc)
        status = generic_checks(state, etrn_restrctions, domain,
@@ -2747,6 +2809,34 @@ char   *smtpd_check_size(SMTPD_STATE *state, off_t size)
     return (0);
 }
 
+/* smtpd_check_data - check DATA command */
+
+char   *smtpd_check_data(SMTPD_STATE *state)
+{
+    int     status;
+    char   *saved_recipient;
+
+    /*
+     * Minor kluge so that we can delegate work to the generic routine. We
+     * provide no recipient information, because this restriction applies to
+     * all recipients alike. Picking a specific recipient would be wrong.
+     */
+    SMTPD_CHECK_PUSH(saved_recipient, state->recipient, 0);
+
+    /*
+     * Apply restrictions in the order as specified.
+     * 
+     * XXX We cannot specify a default target for a bare access map.
+     */
+    SMTPD_CHECK_RESET();
+    status = setjmp(smtpd_check_buf);
+    if (status == 0 && data_restrctions->argc)
+       status = generic_checks(state, data_restrctions,
+                               "DATA", SMTPD_NAME_DATA, NO_DEF_ACL);
+
+    SMTPD_CHECK_RCPT_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
+}
+
 #ifdef TEST
 
  /*
@@ -2772,6 +2862,7 @@ char   *var_helo_checks = "";
 char   *var_mail_checks = "";
 char   *var_rcpt_checks = "";
 char   *var_etrn_checks = "";
+char   *var_data_checks = "";
 char   *var_relay_domains = "";
 char   *var_mynetworks = "";
 char   *var_notify_classes = "";
index 00f923a8fdec77144a4d3c08d7f894227aaf09d5..60348c40d9a3db247a0a325f3d0b549112c05101 100644 (file)
@@ -20,6 +20,7 @@ extern char *smtpd_check_rcptmap(SMTPD_STATE *, char *);
 extern char *smtpd_check_size(SMTPD_STATE *, off_t);
 extern char *smtpd_check_rcpt(SMTPD_STATE *, char *);
 extern char *smtpd_check_etrn(SMTPD_STATE *, char *);
+extern char *smtpd_check_data(SMTPD_STATE *);
 
 /* LICENSE
 /* .ad
index cc07eeeaf0e5e55765f4594f26dbdca686d23d67..5139d1b1c4bf60e7547181c8997659d54e0732ef 100644 (file)
@@ -91,7 +91,8 @@ void    smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream)
     state->recursion = 0;
     state->msg_size = 0;
     state->junk_cmds = 0;
-    state->defer_reason = 0;
+    state->defer_if_reject.reason = 0;
+    state->defer_if_permit.reason = 0;
 
 #ifdef USE_SASL_AUTH
     if (SMTPD_STAND_ALONE(state))
@@ -124,8 +125,10 @@ void    smtpd_state_reset(SMTPD_STATE *state)
     if (state->buffer)
        vstring_free(state->buffer);
     smtpd_peer_reset(state);
-    if (state->defer_reason)
-       vstring_free(state->defer_reason);
+    if (state->defer_if_permit.reason)
+       vstring_free(state->defer_if_permit.reason);
+    if (state->defer_if_reject.reason)
+       vstring_free(state->defer_if_reject.reason);
 
 #ifdef USE_SASL_AUTH
     if (var_smtpd_sasl_enable)
index 9eafc6613ed54bcc25ab6618de0a3590c0ded924..7b2333b6b0673e3c18ef2366c8a5be273a0f004c 100644 (file)
@@ -302,10 +302,15 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
                        &dict_ldap->version) != LDAP_OPT_SUCCESS)
        msg_warn("%s: Unable to set LDAP protocol version", myname);
 
-    if (msg_verbose)
-       msg_warn("%s: Actual Protocol version used was %d.",
-                myname, ldap_get_option(dict_ldap->ld,
-                   LDAP_OPT_PROTOCOL_VERSION, (int *) dict_ldap->version));
+    if (msg_verbose) {
+       if (ldap_get_option(dict_ldap->ld,
+                           LDAP_OPT_PROTOCOL_VERSION,
+                           &dict_ldap->version) != LDAP_OPT_SUCCESS)
+           msg_warn("%s: Unable to get LDAP protocol version", myname);
+       else
+           msg_warn("%s: Actual Protocol version used was %d.",
+                    myname, dict_ldap->version);
+    }
 #endif
 
     /*