]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
snapshot-20010520
authorWietse Venema <wietse@porcupine.org>
Sun, 20 May 2001 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:27:16 +0000 (06:27 +0000)
33 files changed:
postfix/HISTORY
postfix/conf/main.cf
postfix/conf/sample-misc.cf
postfix/html/faq.html
postfix/html/sendmail.1.html
postfix/man/man1/sendmail.1
postfix/src/bounce/bounce_notify_service.c
postfix/src/cleanup/cleanup_message.c
postfix/src/global/Makefile.in
postfix/src/global/is_header.c
postfix/src/global/mail_params.c
postfix/src/global/mail_params.h
postfix/src/global/mail_queue.c
postfix/src/global/mail_version.h
postfix/src/global/post_mail.c
postfix/src/global/post_mail.h
postfix/src/global/smtp_stream.c
postfix/src/global/tok822.h
postfix/src/global/tok822_node.c
postfix/src/global/tok822_parse.c
postfix/src/global/tok822_parse.ref
postfix/src/lmtp/lmtp.c
postfix/src/lmtp/lmtp_chat.c
postfix/src/postsuper/Makefile.in
postfix/src/postsuper/postsuper.c
postfix/src/sendmail/sendmail.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp_addr.c
postfix/src/smtp/smtp_chat.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd_chat.c
postfix/src/smtpd/smtpd_check.c

index 408259629979caf481c061c8544075c2eb8985c2..8182a3e17a66a63cdee57e2699991cc9d4d69c5b 100644 (file)
@@ -5125,3 +5125,45 @@ Apologies for any names omitted.
        Code cleanup: in order to make postsuper -d more usable,
        the showq command was extended to safely list the possibly
        world-writable maildrop directory.  File:  showq/showq.c.
+
+20010505
+
+       RFC 2821 feature: an SMTP server must accept a recipient
+       address of "postmaster" without domain name. File:
+       smtpd/smtpd_check.c.
+
+       RFC 2821 recommendation: reply with 503 to commands sent
+       after 554 greeting. File:  smtpd/smtpd.c.
+
+       RFC 2821 recommendation: if VRFY is enabled, list it in
+       the EHLO response.
+
+20010507
+
+       Bugfix: with soft_bounce=yes, the SMTP server would log
+       5xx replies even though it would send 4xx replies to the
+       client (Phil Howard, ipal.net). File: smtpd/smtpd_check.c.
+
+20010515
+
+       Compatibility: Microsoft sends "AUTH=MBS_BASIC LOGIN".
+       Updated the parsing code in smtp/smtp_proto.c.  Problem
+       reported by Ralf Tessmann, Godot GmbH.
+
+20010520
+
+       Standard: deleted the "via" portion from Received: headers
+       generated by Postfix bounce or other notification processes.
+       File: global/post_mail.c.
+
+       Robustness: eliminated stack-based recursion from the RFC
+       822 address parser. File: global/tok822_parse.c.
+
+       Standard: annotated the source code with comments based on
+       RFC 2821 and 2822. Not all the changes make sense.
+
+       Cleanup: moved ownership of the debug_peer parameters from
+       the applications to the library, so that a Postfix shared
+       library does not suffer from undefined references.  Files:
+       smtp/smtp.c, lmtp/lmtp.c, smtpd/smtpd.c, global/mail_params.c.
+       LaMont Jones, for Debian.
index 03406031852d1d46955fd7b5bac2b33c1b6fa58e..1612b1d45463b8873979af14eb6539b5179be1cd 100644 (file)
@@ -98,8 +98,10 @@ mail_owner = postfix
 #inet_interfaces = $myhostname, localhost
 
 # The mydestination parameter specifies the list of domains that this
-# machine considers itself the final destination for. That does not
-# include domains that are hosted on this machine. Those domains are
+# machine considers itself the final destination for. That includes
+# Sendmail-style virtual domains hosted on this machine.
+#
+# Do not include Postfix-style virtual domains - those domains are
 # specified elsewhere (see sample-virtual.cf, and sample-transport.cf).
 #
 # The default is $myhostname + localhost.$mydomain.  On a mail domain
index 6de9867251e057ff823fa9e8129943ac2bd60206..16ca0d37f40022cd89610a8875d280ca3f5406a9 100644 (file)
@@ -165,7 +165,11 @@ max_idle = 100s
 max_use = 100
 
 # The mydestination parameter specifies the list of domains that this
-# machine considers itself the final destination for.
+# machine considers itself the final destination for. That includes
+# Sendmail-style virtual domains hosted on this machine.
+#
+# Do not include Postfix-style virtual domains - those domains are
+# specified elsewhere (see sample-virtual.cf, and sample-transport.cf).
 #
 # The default is $myhostname + localhost.$mydomain.  On a mail domain
 # gateway, you should also include $mydomain. Do not specify the
index 0f2764acae70dba07eddd83c7dc6c13f988e43a6..47f4d9ec53056dabfa190c4041ea89f378f3d6ec 100644 (file)
@@ -1366,8 +1366,9 @@ record, and that this one PTR record needs a matching A record.
 Some people read the RFCs such that one IP address can have multiple
 PTR records, but that makes PTR records even less useful than they
 already are. And in any case, having multiple names per IP address
-would only worsen the problem of finding out the "official name"
-of a machine's IP address.
+only worsens the problem of finding out the SMTP client hostname.
+
+<hr>
 
 <a name="open_relay"><h3>Help! Postfix is an open relay</h3>
 
index 43b48ba14262bf4ef2b150b58e3a58a324e3fb8f..704fae3083a89333a20e9d22a01798abf143cedf 100644 (file)
@@ -43,14 +43,14 @@ SENDMAIL(1)                                           SENDMAIL(1)
               daemon.
 
        <b>newaliases</b>
-              Initialize the alias database. If no alias database
-              type is specified, the program uses the type speci-
-              fied  in the <b>database</b><i>_</i><b>type</b> configuration parameter;
-              if no input file is  specified,  the  program  pro-
-              cesses    the    file(s)    specified    with   the
-              <b>alias</b><i>_</i><b>database</b> configuration parameter.  This  mode
-              of  operation is implemented by running the <b>postal-</b>
-              <b>ias</b>(1) command.
+              Initialize the alias database.  If no input file is
+              specified (with the <b>-oA</b>  option,  see  below),  the
+              program  processes  the  file(s) specified with the
+              <b>alias</b><i>_</i><b>database</b>  configuration  parameter.   If   no
+              alias  database type is specified, the program uses
+              the type specified with the <b>database</b><i>_</i><b>type</b>  configu-
+              ration parameter.  This mode of operation is imple-
+              mented by running the <a href="postalias.1.html"><b>postalias</b>(1)</a> command.
 
               Note: it may take a minute or so  before  an  alias
               database  update  becomes  visible. Use the <b>postfix</b>
index 51fee8715040711c9871e24a2f087e2604c1b943..b7dade23f183bb15a713b2fc395023f6b0368b2f 100644 (file)
@@ -40,12 +40,13 @@ be delivered.  If mail could not be delivered upon the last attempt,
 the reason for failure is shown. This mode of operation is implemented
 by connecting to the \fBshowq\fR(8) daemon.
 .IP \fBnewaliases\fR
-Initialize the alias database. If no alias database type is
-specified, the program uses the type specified in the
-\fBdatabase_type\fR configuration parameter; if no input file
-is specified, the program processes the file(s) specified with the
-\fBalias_database\fR configuration parameter. This mode of operation
-is implemented by running the \fBpostalias\fR(1) command.
+Initialize the alias database.  If no input file is specified (with
+the \fB-oA\fR option, see below), the program processes the file(s)
+specified with the \fBalias_database\fR configuration parameter.
+If no alias database type is specified, the program uses the type
+specified with the \fBdatabase_type\fR configuration parameter.
+This mode of operation is implemented by running the \fBpostalias\fR(1)
+command.
 .sp
 Note: it may take a minute or so before an alias database update
 becomes visible. Use the \fBpostfix reload\fR command to eliminate
index 35e10a45cb9ff74a5176deed7546fc6caf6ab4ee..284b6468ee578248108a4c7a26cdda3336209de3 100644 (file)
@@ -138,8 +138,7 @@ int     bounce_notify_service(char *service, char *queue_name,
            postmaster = flush ? var_2bounce_rcpt : var_delay_rcpt;
            if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
                                                 postmaster,
-                                                NULL_CLEANUP_FLAGS,
-                                                "BOUNCE")) != 0) {
+                                                NULL_CLEANUP_FLAGS)) != 0) {
 
                /*
                 * Double bounce to Postmaster. This is the last opportunity
@@ -163,8 +162,7 @@ int     bounce_notify_service(char *service, char *queue_name,
      */
     else {
        if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient,
-                                            NULL_CLEANUP_FLAGS,
-                                            "BOUNCE")) != 0) {
+                                            NULL_CLEANUP_FLAGS)) != 0) {
 
            /*
             * Send the bounce message header, some boilerplate text that
@@ -203,8 +201,7 @@ int     bounce_notify_service(char *service, char *queue_name,
            postmaster = flush ? var_bounce_rcpt : var_delay_rcpt;
            if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
                                                 postmaster,
-                                                NULL_CLEANUP_FLAGS,
-                                                "BOUNCE")) != 0) {
+                                                NULL_CLEANUP_FLAGS)) != 0) {
                if (bounce_header(bounce, bounce_info, postmaster) == 0
                    && bounce_diagnostic_log(bounce, bounce_info) == 0
                    && bounce_header_dsn(bounce, bounce_info) == 0
index 20a4c1cf5a2b073d8dd85a9ccc5fdb2a9e2a69e1..2c84ff60c63e09c68ee33733cbf6676d0678cfde 100644 (file)
@@ -287,6 +287,29 @@ static void cleanup_header(CLEANUP_STATE *state)
      * we should do with this header: delete, count, rewrite. Note that we
      * should examine headers even when they will be deleted from the output,
      * because the addresses in those headers might be needed elsewhere.
+     * 
+     * XXX 2821: Return-path breakage.
+     * 
+     * RFC 821 specifies: When the receiver-SMTP makes the "final delivery" of a
+     * message it inserts at the beginning of the mail data a return path
+     * line.  The return path line preserves the information in the
+     * <reverse-path> from the MAIL command.  Here, final delivery means the
+     * message leaves the SMTP world.  Normally, this would mean it has been
+     * delivered to the destination user, but in some cases it may be further
+     * processed and transmitted by another mail system.
+     * 
+     * And that is what Postfix implements. Delivery agents prepend
+     * Return-Path:. In order to avoid cluttering up the message with
+     * possibly inconsistent Return-Path: information (the sender can change
+     * as the result of mail forwarding or mailing list delivery), Postfix
+     * removes any existing Return-Path: headers.
+     * 
+     * RFC 2821 Section 4.4 specifies:    A message-originating SMTP system
+     * SHOULD NOT send a message that already contains a Return-path header.
+     * SMTP servers performing a relay function MUST NOT inspect the message
+     * data, and especially not to the extent needed to determine if
+     * Return-path headers are present. SMTP servers making final delivery
+     * MAY remove Return-path headers before adding their own.
      */
     else {
        state->headers_seen |= (1 << hdr_opts->type);
@@ -324,6 +347,11 @@ static void cleanup_missing_headers(CLEANUP_STATE *state)
     /*
      * Add a missing (Resent-)Message-Id: header. The message ID gives the
      * time in GMT units, plus the local queue ID.
+     * 
+     * XXX Message-Id is not a required message header (RFC 822 and RFC 2822).
+     * 
+     * XXX It is the queue ID non-inode bits that prevent messages from getting
+     * the same Message-Id within the same second.
      */
     if ((state->headers_seen & (1 << (state->resent[0] ?
                           HDR_RESENT_MESSAGE_ID : HDR_MESSAGE_ID))) == 0) {
@@ -365,6 +393,29 @@ static void cleanup_missing_headers(CLEANUP_STATE *state)
        CLEANUP_OUT_BUF(state, REC_TYPE_NORM, state->temp2);
     }
 
+    /*
+     * XXX 2821: Appendix B: The return address in the MAIL command SHOULD,
+     * if possible, be derived from the system's identity for the submitting
+     * (local) user, and the "From:" header field otherwise.  If there is a
+     * system identity available, it SHOULD also be copied to the Sender
+     * header field if it is different from the address in the From header
+     * field.  (Any Sender field that was already there SHOULD be removed.)
+     * Similar wording appears in RFC 2822 section 3.6.2.
+     * 
+     * Postfix presently does not insert a Sender: header if envelope and From:
+     * address differ. Older Postfix versions assumed that the envelope
+     * sender address specifies the system identity and inserted Sender:
+     * whenever envelope and From: differed. This was wrong with relayed
+     * mail, and was often not even desirable with original submissions.
+     * 
+     * XXX 2822 Section 3.6.2, as well as RFC 822 Section 4.1: FROM headers can
+     * contain multiple addresses. If this is the case, then a Sender: header
+     * must be provided with a single address.
+     * 
+     * Postfix does not count the number of addresses in a From: header
+     * (although doing so is trivial, once the address is parsed).
+     */
+
     /*
      * Add a missing destination header.
      */
index c7f777ef40e3808bff461a1025ac71263c53f04a..053ea4e9251b14be94cd63fec06c4b87d8142e44 100644 (file)
@@ -12,7 +12,7 @@ SRCS  = been_here.c bounce.c canon_addr.c cleanup_strerror.c clnt_stream.c \
        mail_scan_dir.c mail_stream.c mail_task.c mail_trigger.c maps.c \
        mark_corrupt.c mkmap_db.c mkmap_dbm.c mkmap_open.c mynetworks.c \
        mypwd.c namadr_list.c off_cvt.c opened.c own_inet_addr.c \
-       peer_name.c pipe_command.c post_mail.c quote_821_local.c \
+       pipe_command.c post_mail.c quote_821_local.c \
        quote_822_local.c rec_streamlf.c rec_type.c recipient_list.c \
        record.c remove.c resolve_clnt.c resolve_local.c rewrite_clnt.c \
        sent.c smtp_stream.c split_addr.c string_list.c sys_exits.c \
@@ -32,7 +32,7 @@ OBJS  = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
        mail_scan_dir.o mail_stream.o mail_task.o mail_trigger.o maps.o \
        mark_corrupt.o mkmap_db.o mkmap_dbm.o mkmap_open.o mynetworks.o \
        mypwd.o namadr_list.o off_cvt.o opened.o own_inet_addr.o \
-       peer_name.o pipe_command.o post_mail.o quote_821_local.o \
+       pipe_command.o post_mail.o quote_821_local.o \
        quote_822_local.o rec_streamlf.o rec_type.o recipient_list.o \
        record.o remove.o resolve_clnt.o resolve_local.o rewrite_clnt.o \
        sent.o smtp_stream.o split_addr.o string_list.o sys_exits.o \
@@ -49,7 +49,7 @@ HDRS  = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
        mail_proto.h mail_queue.h mail_run.h mail_scan_dir.h mail_stream.h \
        mail_task.h mail_version.h maps.h mark_corrupt.h mkmap.h \
        mynetworks.h mypwd.h namadr_list.h off_cvt.h opened.h \
-       own_inet_addr.h peer_name.h pipe_command.h post_mail.h \
+       own_inet_addr.h pipe_command.h post_mail.h \
        quote_821_local.h quote_822_local.h rec_streamlf.h rec_type.h \
        recipient_list.h record.h resolve_clnt.h resolve_local.h \
        rewrite_clnt.h sent.h smtp_stream.h split_addr.h string_list.h \
@@ -65,7 +65,7 @@ INCL  =
 LIB    = libglobal.a
 TESTPROG= domain_list dot_lockfile mail_addr_crunch mail_addr_find \
        mail_addr_map mail_date maps mynetworks mypwd namadr_list \
-       off_cvt peer_name quote_822_local rec2stream recdump resolve_clnt \
+       off_cvt quote_822_local rec2stream recdump resolve_clnt \
        resolve_local rewrite_clnt stream2rec string_list tok822_parse \
        quote_821_local mail_conf_time
 
index 0cd3e93c2d5f1d8c5f43d8720908011561d02280..5ed88fadd6eedb63aa927d6cbf65b5859632632b 100644 (file)
@@ -41,6 +41,13 @@ int     is_header(const char *str)
     const char *cp;
     int     c;
 
+    /*
+     * XXX RFC 2822 Section 4.5.2, Obsolete header fields: whitespace may
+     * appear between header label and ":" (see: RFC 822, Section 3.4.2.).
+     * 
+     * The code below allows no such whitespace. This has never been a problem,
+     * and therefore we're not inclined to add code for it.
+     */
     for (cp = str; (c = *(unsigned char *) cp) != 0; cp++) {
        if (c == ':')
            return (cp > str);
index 82db3bd84385fb03146be49c4e9cd1f17b8d3b16..830e9b1d934bca19326a658bed2bd491b58ba6aa 100644 (file)
@@ -65,6 +65,8 @@
 /*
 /*     char    *var_import_environ;
 /*     char    *var_export_environ;
+/*     char    *var_debug_peer_list;
+/*     int     var_debug_peer_level;
 /*
 /*     void    mail_params_init()
 /* DESCRIPTION
@@ -181,6 +183,8 @@ char   *var_mynetworks_style;
 
 char   *var_import_environ;
 char   *var_export_environ;
+char   *var_debug_peer_list;
+int     var_debug_peer_level;
 
 /* check_myhostname - lookup hostname and validate */
 
@@ -298,6 +302,7 @@ void    mail_params_init()
        VAR_IMPORT_ENVIRON, DEF_IMPORT_ENVIRON, &var_import_environ, 0, 0,
        VAR_DEF_TRANSPORT, DEF_DEF_TRANSPORT, &var_def_transport, 0, 0,
        VAR_MYNETWORKS_STYLE, DEF_MYNETWORKS_STYLE, &var_mynetworks_style, 1, 0,
+       VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0,
        0,
     };
     static CONFIG_STR_FN_TABLE function_str_defaults_2[] = {
@@ -312,6 +317,7 @@ void    mail_params_init()
        VAR_HASH_QUEUE_DEPTH, DEF_HASH_QUEUE_DEPTH, &var_hash_queue_depth, 1, 0,
        VAR_FORK_TRIES, DEF_FORK_TRIES, &var_fork_tries, 1, 0,
        VAR_FLOCK_TRIES, DEF_FLOCK_TRIES, &var_flock_tries, 1, 0,
+       VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0,
        0,
     };
     static CONFIG_TIME_TABLE time_defaults[] = {
index caea36103d220c274a37a75421a8d49aef236bfe..452fc443cbfb9f716418f1c16c7f358ebac5d48e 100644 (file)
@@ -224,6 +224,10 @@ extern char *var_always_bcc;
 
  /*
   * What to put in the To: header when no recipients were disclosed.
+  * 
+  * XXX 2822: When no recipient headers remain, a system should insert a Bcc:
+  * header without additional information. That is not so great given that
+  * MTAs routinely strip Bcc: headers from message headers.
   */
 #define VAR_RCPT_WITHELD       "undisclosed_recipients_header"
 #define DEF_RCPT_WITHELD       "To: undisclosed-recipients:;"
@@ -634,6 +638,9 @@ extern int var_hash_queue_depth;
   * determines how many recipient addresses the SMTP client sends along with
   * each message. Unfortunately, some mailers misbehave and disconnect (smap)
   * when given more recipients than they are willing to handle.
+  * 
+  * XXX 2821: A mail system is supposed to use EHLO instead of HELO, and to fall
+  * back to HELO if EHLO is not supported.
   */
 #define VAR_BESTMX_TRANSP      "best_mx_transport"
 #define DEF_BESTMX_TRANSP      ""
@@ -688,7 +695,11 @@ extern bool var_ign_mx_lookup_err;
 extern bool var_skip_quit_resp;
 
 #define VAR_SMTP_ALWAYS_EHLO   "smtp_always_send_ehlo"
+#ifdef RFC821_SYNTAX
 #define DEF_SMTP_ALWAYS_EHLO   0
+#else
+#define DEF_SMTP_ALWAYS_EHLO   1
+#endif
 extern bool var_smtp_always_ehlo;
 
 #define VAR_SMTP_NEVER_EHLO    "smtp_never_send_ehlo"
index 5fc18640ec38c02b2ebfc3529f58c25dc68cae84..d58bade6c585361138d5d8ff91fc6bfcac7f5543 100644 (file)
@@ -378,6 +378,13 @@ VSTREAM *mail_queue_enter(const char *queue_name, int mode)
     file_id = get_file_id(fd);
     GETTIMEOFDAY(&tv);
 
+    /*
+     * XXX Some systems seem to have clocks that correlate with process
+     * scheduling or something. Unfortunately, we cannot add random
+     * quantities to the time, because the non-inode part of a queue ID must
+     * not repeat within the same second. The queue ID is the sole thing that
+     * prevents multiple messages from getting the same Message-ID value.
+     */
     for (count = 0;; count++) {
        vstring_sprintf(id_buf, "%05X%s", (int) tv.tv_usec, file_id);
        mail_queue_path(path_buf, queue_name, STR(id_buf));
index bb1b805ad6b15319bd469fdcbc711040d9001ea7..1d8829a49570298a87ae49cfac664411363008ca 100644 (file)
@@ -15,7 +15,7 @@
   * Version of this program.
   */
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "Snapshot-20010502"
+#define DEF_MAIL_VERSION       "Snapshot-20010520"
 extern char *var_mail_version;
 
 /* LICENSE
index c3673243f5c65f7932abe7275fb248b1be68c451..91f5a608ef9896848a2f198473e19dddfe843b90 100644 (file)
@@ -6,17 +6,15 @@
 /* SYNOPSIS
 /*     #include <post_mail.h>
 /*
-/*     VSTREAM *post_mail_fopen(sender, recipient, flags, via)
+/*     VSTREAM *post_mail_fopen(sender, recipient, flags)
 /*     const char *sender;
 /*     const char *recipient;
 /*     int     flags;
-/*     const char *via;
 /*
-/*     VSTREAM *post_mail_fopen_nowait(sender, recipient, flags, via)
+/*     VSTREAM *post_mail_fopen_nowait(sender, recipient, flags)
 /*     const char *sender;
 /*     const char *recipient;
 /*     int     flags;
-/*     const char *via;
 /*
 /*     int     post_mail_fprintf(stream, format, ...)
 /*     VSTREAM *stream;
 /* post_mail_init - initial negotiations */
 
 static void post_mail_init(VSTREAM *stream, const char *sender,
-                         const char *recipient, int flags, const char *via)
+                                  const char *recipient, int flags)
 {
     VSTRING *id = vstring_alloc(100);
     long    now = time((time_t *) 0);
@@ -158,8 +156,8 @@ static void post_mail_init(VSTREAM *stream, const char *sender,
      * Do the Received: and Date: header lines. This allows us to shave a few
      * cycles by using the expensive date conversion result for both.
      */
-    post_mail_fprintf(stream, "Received: by %s (%s) via %s",
-                     var_myhostname, var_mail_name, via);
+    post_mail_fprintf(stream, "Received: by %s (%s)",
+                     var_myhostname, var_mail_name);
     post_mail_fprintf(stream, "\tid %s; %s", vstring_str(id), date);
     post_mail_fprintf(stream, "Date: %s", date);
     vstring_free(id);
@@ -167,26 +165,25 @@ static void post_mail_init(VSTREAM *stream, const char *sender,
 
 /* post_mail_fopen - prepare for posting a message */
 
-VSTREAM *post_mail_fopen(const char *sender, const char *recipient,
-                                int flags, const char *via)
+VSTREAM *post_mail_fopen(const char *sender, const char *recipient, int flags)
 {
     VSTREAM *stream;
 
     stream = mail_connect_wait(MAIL_CLASS_PRIVATE, MAIL_SERVICE_CLEANUP);
-    post_mail_init(stream, sender, recipient, flags, via);
+    post_mail_init(stream, sender, recipient, flags);
     return (stream);
 }
 
 /* post_mail_fopen_nowait - prepare for posting a message */
 
 VSTREAM *post_mail_fopen_nowait(const char *sender, const char *recipient,
-                                       int flags, const char *via)
+                                       int flags)
 {
     VSTREAM *stream;
 
     if ((stream = mail_connect(MAIL_CLASS_PRIVATE, MAIL_SERVICE_CLEANUP,
                               BLOCKING)) != 0)
-       post_mail_init(stream, sender, recipient, flags, via);
+       post_mail_init(stream, sender, recipient, flags);
     return (stream);
 }
 
index 8fa5a80bf3bdadae8b46954522070c53f057ec93..264afc77bfffda24b16f437dd7ca5adf72f154cc 100644 (file)
@@ -24,9 +24,8 @@
  /*
   * External interface.
   */
-extern VSTREAM *post_mail_fopen(const char *, const char *, int, const char *);
-extern VSTREAM *post_mail_fopen_nowait(const char *, const char *,
-                                              int, const char *);
+extern VSTREAM *post_mail_fopen(const char *, const char *, int);
+extern VSTREAM *post_mail_fopen_nowait(const char *, const char *, int);
 extern int PRINTFLIKE(2, 3) post_mail_fprintf(VSTREAM *, const char *,...);
 extern int post_mail_fputs(VSTREAM *, const char *);
 extern int post_mail_buffer(VSTREAM *, const char *, int);
index 606ffb65fc0258ad80b228ac765e9b7c708d6371..b919cfaa89a13d8473d45a562cb759e24a1799f3 100644 (file)
@@ -200,6 +200,9 @@ int     smtp_get(VSTRING *vp, VSTREAM *stream, int bound)
      * Allow for partial long lines (we will read the remainder later) and
      * allow for lines ending in bare LF. The idea is to be liberal in what
      * we accept, strict in what we send.
+     * 
+     * XXX 2821: Section 4.1.1.4 says that an SMTP server must not recognize
+     * bare LF as record terminator.
      */
     smtp_timeout_reset(stream);
     last_char = (bound == 0 ? vstring_get(vp, stream) :
index c0dd10f5c58947070511ff1ef292be9180f905ef..316dfb19821c18370559f561214a51800d0fa8cb 100644 (file)
@@ -45,8 +45,7 @@ typedef struct TOK822 {
 #define        TOK822_DOMLIT   259             /* stuff between [] not nesting */
 #define        TOK822_ADDR     260             /* actually a token group */
 #define TOK822_STARTGRP        261             /* start of named group */
-#define        TOK822_COMMENT_TEXT 262         /* comment text */
-#define TOK822_MAXTOK  262
+#define TOK822_MAXTOK  261
 
  /*
   * tok822_node.c
index 797deb3424e060638650046bf4189775a19b0291..d39bf15b94f3b79e6a0357812d58eeee577ef3c6 100644 (file)
@@ -57,7 +57,7 @@ TOK822 *tok822_alloc(int type, const char *strval)
     TOK822 *tp;
 
 #define CONTAINER_TOKEN(x) \
-       ((x) == TOK822_ADDR || (x) == TOK822_COMMENT || (x) == TOK822_STARTGRP)
+       ((x) == TOK822_ADDR || (x) == TOK822_STARTGRP)
 
     tp = (TOK822 *) mymalloc(sizeof(*tp));
     tp->type = type;
index 7fd66830adc9846a38ce569d2249b8d215ea409c..4bb54dc5d0164d8856474306825773f50781b255 100644 (file)
@@ -192,12 +192,7 @@ VSTRING *tok822_internalize(VSTRING *vp, TOK822 *tree, int flags)
            tok822_internalize(vp, tp->head, TOK822_STR_NONE);
            break;
        case TOK822_COMMENT:
-           VSTRING_ADDCH(vp, '(');
-           tok822_internalize(vp, tp->head, TOK822_STR_NONE);
-           VSTRING_ADDCH(vp, ')');
-           break;
        case TOK822_ATOM:
-       case TOK822_COMMENT_TEXT:
        case TOK822_QSTRING:
            vstring_strcat(vp, vstring_str(tp->vstr));
            break;
@@ -244,15 +239,8 @@ VSTRING *tok822_externalize(VSTRING *vp, TOK822 *tree, int flags)
            tok822_externalize(vp, tp->head, TOK822_STR_NONE);
            break;
        case TOK822_ATOM:
-           vstring_strcat(vp, vstring_str(tp->vstr));
-           break;
        case TOK822_COMMENT:
-           VSTRING_ADDCH(vp, '(');
-           tok822_externalize(vp, tp->head, TOK822_STR_NONE);
-           VSTRING_ADDCH(vp, ')');
-           break;
-       case TOK822_COMMENT_TEXT:
-           tok822_copy_quoted(vp, vstring_str(tp->vstr), "()\\");
+           vstring_strcat(vp, vstring_str(tp->vstr));
            break;
        case TOK822_QSTRING:
            VSTRING_ADDCH(vp, '"');
@@ -321,6 +309,13 @@ TOK822 *tok822_scan(const char *str, TOK822 **tailp)
     TOK822 *tp;
     int     ch;
 
+    /*
+     * XXX 2822 new feature: Section 4.1 allows "." to appear in a phrase (to
+     * allow for forms such as: Johnny B. Goode <johhny@domain.org>. I cannot
+     * handle that at the tokenizer level - it is not context sensitive. And
+     * to fix this at the parser level requires radical changes to preserve
+     * white space as part of the token stream. Thanks a lot, people.
+     */
     while ((ch = *(unsigned char *) str++) != 0) {
        if (ISSPACE(ch))
            continue;
@@ -466,36 +461,32 @@ static void tok822_quote_atom(TOK822 *tp)
 
 static const char *tok822_comment(TOK822 *tp, const char *str)
 {
-    TOK822 *tc = 0;
+    int     level = 1;
     int     ch;
 
-#define COMMENT_TEXT_TOKEN(t) ((t) && (t)->type == TOK822_COMMENT_TEXT)
-
-#define APPEND_NEW_TOKEN(tp, type, strval) \
-       tok822_sub_append(tp, tok822_alloc(type, strval))
+    /*
+     * XXX We cheat by storing comments in their external form. Otherwise it
+     * would be a royal pain to preserve \ before (. That would require a
+     * recursive parser, which could consume unreasonable amounts of memory.
+     */
+    VSTRING_ADDCH(tp->vstr, '(');
 
     while ((ch = *(unsigned char *) str) != 0) {
+       VSTRING_ADDCH(tp->vstr, ch);
        str++;
        if (ch == '(') {                        /* comments can nest! */
-           if (COMMENT_TEXT_TOKEN(tc))
-               VSTRING_TERMINATE(tc->vstr);
-           tc = APPEND_NEW_TOKEN(tp, TOK822_COMMENT, (char *) 0);
-           str = tok822_comment(tc, str);
+           level++;
        } else if (ch == ')') {
-           break;
-       } else {
-           if (ch == '\\') {
-               if ((ch = *(unsigned char *) str) == 0)
-                   break;
-               str++;
-           }
-           if (!COMMENT_TEXT_TOKEN(tc))
-               tc = APPEND_NEW_TOKEN(tp, TOK822_COMMENT_TEXT, (char *) 0);
-           VSTRING_ADDCH(tc->vstr, ch);
+           if (--level == 0)
+               break;
+       } else if (ch == '\\') {
+           if ((ch = *(unsigned char *) str) == 0)
+               break;
+           VSTRING_ADDCH(tp->vstr, ch);
+           str++;
        }
     }
-    if (COMMENT_TEXT_TOKEN(tc))
-       VSTRING_TERMINATE(tc->vstr);
+    VSTRING_TERMINATE(tp->vstr);
     return (str);
 }
 
@@ -554,14 +545,11 @@ static void tok822_print(TOK822 *list, int indent)
        } else if (tp->type == TOK822_ADDR) {
            vstream_printf("%*s %s\n", indent, "", "address");
            tok822_print(tp->head, indent + 2);
-       } else if (tp->type == TOK822_COMMENT) {
-           vstream_printf("%*s %s\n", indent, "", "comment");
-           tok822_print(tp->head, indent + 2);
        } else if (tp->type == TOK822_STARTGRP) {
            vstream_printf("%*s %s\n", indent, "", "group \":\"");
        } else {
            vstream_printf("%*s %s \"%s\"\n", indent, "",
-                          tp->type == TOK822_COMMENT_TEXT ? "text" :
+                          tp->type == TOK822_COMMENT ? "comment" :
                           tp->type == TOK822_ATOM ? "atom" :
                           tp->type == TOK822_QSTRING ? "quoted string" :
                           tp->type == TOK822_DOMLIT ? "domain literal" :
index dc35bff57b728bddf15b034f00f989fe7ed99990..169957ac40e1798dc9cef581f35f5b1d7703e9a4 100644 (file)
@@ -86,8 +86,7 @@ Parse tree:
  OP ","
  address
    atom "venema"
- comment
-   text ""wietse "
+ comment "("wietse )"
  OP ","
  address
    quoted string ")"
@@ -135,11 +134,7 @@ Parse tree:
    OP "."
    atom "org"
    OP ")"
- comment
-   text " "
-   comment
-     text ""wietse "
-   text " venema""
+ comment "( ("wietse ) venema")"
 
 Internalized:
 wietse venema@porcupine.org) ( ("wietse ) venema")
@@ -272,9 +267,8 @@ Parse tree:
    atom "wietse"
    OP "@"
    atom "foo"
- comment
-   text "wietse
-       venema"
+ comment "(wietse
+       venema)"
 
 Internalized:
 wietse@foo (wietse
index 49b89f403bd0b8770cdc5ed59e8393c1f30e22af..af74d8dd0a754732455cae69a0f4f42a8daf2f57 100644 (file)
@@ -269,8 +269,6 @@ int     var_lmtp_data0_tmout;
 int     var_lmtp_data1_tmout;
 int     var_lmtp_data2_tmout;
 int     var_lmtp_quit_tmout;
-char   *var_debug_peer_list;
-int     var_debug_peer_level;
 int     var_lmtp_cache_conn;
 int     var_lmtp_skip_quit_resp;
 char   *var_notify_classes;
@@ -505,7 +503,6 @@ static void pre_accept(char *unused_name, char **unused_argv)
 int     main(int argc, char **argv)
 {
     static CONFIG_STR_TABLE str_table[] = {
-       VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0,
        VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
        VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
        VAR_LMTP_SASL_PASSWD, DEF_LMTP_SASL_PASSWD, &var_lmtp_sasl_passwd, 0, 0,
@@ -514,7 +511,6 @@ int     main(int argc, char **argv)
     };
     static CONFIG_INT_TABLE int_table[] = {
        VAR_LMTP_TCP_PORT, DEF_LMTP_TCP_PORT, &var_lmtp_tcp_port, 0, 0,
-       VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0,
        0,
     };
     static CONFIG_TIME_TABLE time_table[] = {
index 19b37cc03c4b1698577604fe6a3a362845f13072..40f5947165a5cd60a587e41fbfd8a1879296949e 100644 (file)
@@ -268,7 +268,7 @@ void    lmtp_chat_notify(LMTP_STATE *state)
 
     notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
                                    var_error_rcpt,
-                                   NULL_CLEANUP_FLAGS, "NOTICE");
+                                   NULL_CLEANUP_FLAGS);
     if (notice == 0) {
        msg_warn("postmaster notify: %m");
        return;
index 3ff67a4d3df161ca8bb3475b3fcc89d3d0bfdb1b..c42db2a892dca9f83987ad0fd20f22ce457b6766 100644 (file)
@@ -66,7 +66,9 @@ postsuper.o: ../../include/vstring.h
 postsuper.o: ../../include/safe.h
 postsuper.o: ../../include/set_ugid.h
 postsuper.o: ../../include/argv.h
+postsuper.o: ../../include/vstring_vstream.h
 postsuper.o: ../../include/mail_task.h
 postsuper.o: ../../include/mail_conf.h
 postsuper.o: ../../include/mail_params.h
 postsuper.o: ../../include/mail_queue.h
+postsuper.o: ../../include/mail_open_ok.h
index f4fd84517a200fd05237e3adac5cd8a682cc4753..d7c071691b615d1f2cb6597ca33bf916a5edd203 100644 (file)
@@ -170,29 +170,43 @@ static int delete_one(const char *queue_id)
        MAIL_QUEUE_ACTIVE,              /* foolproof but adequate */
        0,
     };
+    const char *log_queue_names[] = {
+       MAIL_QUEUE_BOUNCE,
+       MAIL_QUEUE_DEFER,
+       0,
+    };
     struct stat st;
-    const char **cpp;
-    const char *path;
+    const char **msg_qpp;
+    const char **log_qpp;
+    const char *msg_path;
+    VSTRING *log_path_buf = vstring_alloc(100);
     int     found = 0;
 
     /*
-     * Do not delete defer or bounce logfiles, because we could lose a race
-     * and delete a defer/bounce logfile from a message that reuses the queue
-     * ID.
+     * Delete defer or bounce logfiles before deleting the corresponding
+     * message file, and only if the message file exists. This minimizes but
+     * does not eliminate a race condition with queue ID reuse which results
+     * in deleting the wrong files.
      */
-    for (cpp = msg_queue_names; *cpp != 0; cpp++) {
-       if (!mail_open_ok(*cpp, queue_id, &st, &path)) {
+    for (msg_qpp = msg_queue_names; *msg_qpp != 0; msg_qpp++) {
+       if (!mail_open_ok(*msg_qpp, queue_id, &st, &msg_path))
            continue;
-       } else if (unlink(path) == 0) {
+       for (log_qpp = log_queue_names; *log_qpp != 0; log_qpp++)
+           (void) mail_queue_path(log_path_buf, *log_qpp, queue_id);
+       if (unlink(STR(log_path_buf)) < 0 && errno != ENOENT)
+           msg_warn("remove file %s: %m", STR(log_path_buf));
+       if (unlink(msg_path) == 0) {
            found = 1;
-           msg_info("removed file %s", path);
+           msg_info("removed file %s", msg_path);
            break;
-       } else if (errno != ENOENT) {
-           msg_warn("remove file %s: %m", path);
+       }
+       if (errno != ENOENT) {
+           msg_warn("remove file %s: %m", msg_path);
        } else if (msg_verbose) {
-           msg_info("remove file %s: %m", path);
+           msg_info("remove file %s: %m", msg_path);
        }
     }
+    vstring_free(log_path_buf);
     return (found);
 }
 
index 978ff14b07730ed22ef91d9a53e2e6f11d943f92..f3324d2f3d05f115e27cfa359d5c206e684b6746 100644 (file)
 /*     the reason for failure is shown. This mode of operation is implemented
 /*     by connecting to the \fBshowq\fR(8) daemon.
 /* .IP \fBnewaliases\fR
-/*     Initialize the alias database. If no alias database type is
-/*     specified, the program uses the type specified in the
-/*     \fBdatabase_type\fR configuration parameter; if no input file
-/*     is specified, the program processes the file(s) specified with the
-/*     \fBalias_database\fR configuration parameter. This mode of operation
-/*     is implemented by running the \fBpostalias\fR(1) command.
+/*     Initialize the alias database.  If no input file is specified (with
+/*     the \fB-oA\fR option, see below), the program processes the file(s)
+/*     specified with the \fBalias_database\fR configuration parameter.
+/*     If no alias database type is specified, the program uses the type
+/*     specified with the \fBdatabase_type\fR configuration parameter.
+/*     This mode of operation is implemented by running the \fBpostalias\fR(1)
+/*     command.
 /* .sp
 /*     Note: it may take a minute or so before an alias database update
 /*     becomes visible. Use the \fBpostfix reload\fR command to eliminate
index 2adb776f84dfcfcf77697b134c4318a71817b389..ab541accee9c4ec6aa53284151aa7bbfcc6aad72 100644 (file)
@@ -234,8 +234,6 @@ int     var_smtp_data1_tmout;
 int     var_smtp_data2_tmout;
 int     var_smtp_quit_tmout;
 char   *var_inet_interfaces;
-char   *var_debug_peer_list;
-int     var_debug_peer_level;
 char   *var_notify_classes;
 int     var_smtp_skip_4xx_greeting;
 int     var_smtp_skip_5xx_greeting;
@@ -395,7 +393,6 @@ static void pre_exit(void)
 int     main(int argc, char **argv)
 {
     static CONFIG_STR_TABLE str_table[] = {
-       VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0,
        VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
        VAR_FALLBACK_RELAY, DEF_FALLBACK_RELAY, &var_fallback_relay, 0, 0,
        VAR_BESTMX_TRANSP, DEF_BESTMX_TRANSP, &var_bestmx_transp, 0, 0,
@@ -417,7 +414,6 @@ int     main(int argc, char **argv)
        0,
     };
     static CONFIG_INT_TABLE int_table[] = {
-       VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0,
        0,
     };
     static CONFIG_BOOL_TABLE bool_table[] = {
index 223e70db599928a474e458a6ea1994baa9ad7e05..f04fcacbd48a288c2c65e3729219da5c0107b006 100644 (file)
@@ -207,6 +207,11 @@ static DNS_RR *smtp_addr_list(DNS_RR *mx_names, VSTRING *why)
     /*
      * As long as we are able to look up any host address, we ignore problems
      * with DNS lookups.
+     * 
+     * XXX 2821: update smtp_errno (0->FAIL upon unrecoverable lookup error,
+     * any->RETRY upon temporary lookup error) so that we can correctly
+     * handle the case of no resolvable MX host. Currently this is always
+     * treated as a soft error. RFC 2821 wants a more precise response.
      */
     for (rr = mx_names; rr; rr = rr->next) {
        if (rr->type != T_MX)
@@ -320,6 +325,19 @@ DNS_RR *smtp_domain_addr(char *name, VSTRING *why, int *found_myself)
      * as we're looking up all the hosts, it would be better to look up the
      * least preferred host first, so that DNS lookup error messages make
      * more sense.
+     * 
+     * XXX 2821: RFC 2821 says that the sender must shuffle equal-preference MX
+     * hosts, whereas multiple A records per hostname must be used in the
+     * order as received. They make the bogus assumption that a hostname with
+     * multiple A records corresponds to one machine with multiple network
+     * interfaces.
+     * 
+     * XXX 2821: Postfix recognizes the local machine by looking for its own IP
+     * address in the list of mail exchangers. RFC 2821 says one has to look
+     * at the mail exchanger hostname as well, making the bogus assumption
+     * that an IP address is listed only under one hostname. However, looking
+     * at hostnames provides a partial solution for MX hosts behind a NAT
+     * gateway.
      */
     switch (dns_lookup(name, T_MX, 0, &mx_names, (VSTRING *) 0, why)) {
     default:
index 62c0de64f3f4cf84442a582970f5aa3fe0d79fc2..d33a90e4e0454931d72d45fe401dd557d9788f23 100644 (file)
@@ -252,7 +252,7 @@ void    smtp_chat_notify(SMTP_STATE *state)
 
     notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
                                    var_error_rcpt,
-                                   NULL_CLEANUP_FLAGS, "NOTICE");
+                                   NULL_CLEANUP_FLAGS);
     if (notice == 0) {
        msg_warn("postmaster notify: %m");
        return;
index c9b0a54e85844833ff271b1fd36744e5b2c299bb..230c7a07afb7c4fdf3eb5d74feda56e2d0c8feb0 100644 (file)
@@ -213,10 +213,13 @@ int     smtp_helo(SMTP_STATE *state)
      * overflow detection, ignore the message size limit advertised by the
      * SMTP server. Otherwise, we might do the wrong thing when the server
      * advertises a really huge message size limit.
+     * 
+     * XXX Allow for "code (SP|-) ehlo-keyword (SP|=) ehlo-param...", because
+     * MicroSoft implemented AUTH based on an old draft.
      */
     lines = resp->str;
     while ((words = mystrtok(&lines, "\n")) != 0) {
-       if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t")) != 0) {
+       if (mystrtok(&words, "- =") && (word = mystrtok(&words, " \t")) != 0) {
            if (strcasecmp(word, "8BITMIME") == 0)
                state->features |= SMTP_FEATURE_8BITMIME;
            else if (strcasecmp(word, "PIPELINING") == 0)
@@ -226,8 +229,6 @@ int     smtp_helo(SMTP_STATE *state)
 #ifdef USE_SASL_AUTH
            else if (var_smtp_sasl_enable && strcasecmp(word, "AUTH") == 0)
                smtp_sasl_helo_auth(state, words);
-           else if (var_smtp_sasl_enable && strncasecmp(word, "AUTH=", 5) == 0)
-               smtp_sasl_helo_auth(state, word + 5);
 #endif
            else if (strcasecmp(word, var_myhostname) == 0) {
                msg_warn("host %s replied to HELO/EHLO with my own hostname %s",
@@ -480,9 +481,16 @@ int     smtp_xfer(SMTP_STATE *state)
                     * rejected, ignore RCPT TO responses: all recipients are
                     * dead already. When all recipients are rejected the
                     * receiver may apply a course correction.
+                    * 
+                    * XXX 2821: Section 4.5.3.1 says that a 552 RCPT TO reply
+                    * must be treated as if the server replied with 452.
                     */
                case SMTP_STATE_RCPT:
                    if (!mail_from_rejected) {
+#ifndef RFC821_SYNTAX
+                       if (resp->code == 552)
+                           resp->code = 452;
+#endif
                        if (resp->code / 100 == 2) {
                            ++nrcpt;
                        } else {
index 48f8c82e871342d909929d0550eb3a8fa0b8e81d..1fc3877e3b8ed84f667f6df000dd013a4dace3ba 100644 (file)
@@ -311,8 +311,6 @@ int     var_smtpd_soft_erlim;
 int     var_smtpd_hard_erlim;
 int     var_queue_minfree;             /* XXX use off_t */
 char   *var_smtpd_banner;
-char   *var_debug_peer_list;
-int     var_debug_peer_level;
 char   *var_notify_classes;
 char   *var_client_checks;
 char   *var_helo_checks;
@@ -416,6 +414,11 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
 {
     char   *err;
 
+    /*
+     * XXX 2821 new feature: Section 4.1.4 specifies that a server must clear
+     * all buffers and reset the state exactly as if a RSET command had been
+     * issued.
+     */
     if (argc < 2) {
        state->error_mask |= MAIL_ERROR_PROTOCOL;
        smtpd_chat_reply(state, "501 Syntax: EHLO hostname");
@@ -423,7 +426,7 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
     }
     if (state->helo_name != 0)
        helo_reset(state);
-#if 0
+#ifndef RFC821_SYNTAX
     mail_reset(state);
     rcpt_reset(state);
 #endif
@@ -444,6 +447,8 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
                         (unsigned long) var_message_limit);    /* XXX */
     else
        smtpd_chat_reply(state, "250-SIZE");
+    if (var_disable_vrfy_cmd == 0)
+       smtpd_chat_reply(state, "250-VRFY");
     smtpd_chat_reply(state, "250-ETRN");
 #ifdef USE_SASL_AUTH
     if (var_smtpd_sasl_enable) {
@@ -471,6 +476,18 @@ static void mail_open_stream(SMTPD_STATE *state)
 {
     char   *postdrop_command;
 
+    /*
+     * XXX 2821: An SMTP server is not allowed to "clean up" mail except in
+     * the case of original submissions. Presently, Postfix always runs all
+     * mail through the cleanup server.
+     * 
+     * We could approximate the RFC as follows: Postfix rewrites mail if it
+     * comes from a source that we are willing to relay for. This way, we
+     * avoid rewriting most mail that comes from elsewhere. However, that
+     * requires moving functionality away from the cleanup daemon elsewhere,
+     * such as virtual address expansion, and header/body pattern matching.
+     */
+
     /*
      * If running from the master or from inetd, connect to the cleanup
      * service.
@@ -613,6 +630,12 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
     /*
      * Sanity checks. XXX Ignore bad SIZE= values until we can reliably and
      * portably detect overflows while converting from string to off_t.
+     * 
+     * XXX 2821 pedantism: Section 4.1.2 says that SMTP servers that receive a
+     * command in which invalid character codes have been employed, and for
+     * which there are no other reasons for rejection, MUST reject that
+     * command with a 501 response. So much for the principle of "be liberal
+     * in what you accept, be strict in what you send".
      */
     if (var_helo_required && state->helo_name == 0) {
        state->error_mask |= MAIL_ERROR_POLICY;
@@ -746,6 +769,12 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
 
     /*
      * Sanity checks.
+     * 
+     * XXX 2821 pedantism: Section 4.1.2 says that SMTP servers that receive a
+     * command in which invalid character codes have been employed, and for
+     * which there are no other reasons for rejection, MUST reject that
+     * command with a 501 response. So much for the principle of "be liberal
+     * in what you accept, be strict in what you send".
      */
     if (state->cleanup == 0) {
        state->error_mask |= MAIL_ERROR_PROTOCOL;
@@ -1023,6 +1052,15 @@ static int rset_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
 static int noop_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
 {
 
+    /*
+     * XXX 2821 incompatibility: Section 4.1.1.9 says that NOOP can have a
+     * parameter string which is to be ignored. NOOP instructions with
+     * parameters? Go figure.
+     * 
+     * RFC 2821 violates RFC 821, which says that NOOP takes no parameters.
+     */
+#ifdef RFC821_SYNTAX
+
     /*
      * Sanity checks.
      */
@@ -1031,6 +1069,7 @@ static int noop_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
        smtpd_chat_reply(state, "501 Syntax: NOOP");
        return (-1);
     }
+#endif
     smtpd_chat_reply(state, "250 Ok");
     return (0);
 }
@@ -1051,6 +1090,17 @@ static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
      * address forms. Therefore we must parse out the address, or we must
      * stop doing recipient restriction checks and lose the opportunity to
      * say "user unknown" at the SMTP port.
+     * 
+     * XXX 2821 incompatibility and brain damage: Section 4.5.1 requires that
+     * VRFY is implemented. RFC 821 specifies that VRFY is optional. It gets
+     * even worse: section 3.5.3 says that a 502 (command recognized but not
+     * implemented) reply is not fully compliant.
+     * 
+     * Thus, an RFC 2821 compliant implementation cannot refuse to supply
+     * information in reply to VRFY queries. That is simply bogus. The only
+     * reply we could supply is a generic 252 reply. This causes spammers to
+     * add tons of bogus addresses to their mailing lists (spam harvesting by
+     * trying out large lists of potential recipient names with VRFY).
      */
 #define SLOPPY 0
 
@@ -1076,7 +1126,17 @@ static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        smtpd_chat_reply(state, "%s", err);
        return (-1);
     }
-    smtpd_chat_reply(state, "252 <%s>", argv[1].strval);
+
+    /*
+     * XXX 2821 new feature: Section 3.5.1 requires that the VRFY response is
+     * either "full name <user@domain>" or "user@domain". Postfix replies
+     * with the address that was provided by the client, whether or not it is
+     * in fully qualified domain form or not.
+     * 
+     * Reply code 250 is reserved for the case where the address is verified;
+     * reply code 252 should be used when no definitive certainty exists.
+     */
+    smtpd_chat_reply(state, "252 %s", argv[1].strval);
     return (0);
 }
 
@@ -1256,7 +1316,8 @@ static void smtpd_proto(SMTPD_STATE *state)
                continue;
            }
            if (state->access_denied && cmdp->action != quit_cmd) {
-               smtpd_chat_reply(state, "%s", state->access_denied);
+               smtpd_chat_reply(state, "503 Error: access denied for %s",
+                                state->namaddr);       /* RFC 2821 Sec 3.1 */
                state->error_count++;
                continue;
            }
@@ -1445,7 +1506,6 @@ int     main(int argc, char **argv)
        VAR_SMTPD_SOFT_ERLIM, DEF_SMTPD_SOFT_ERLIM, &var_smtpd_soft_erlim, 1, 0,
        VAR_SMTPD_HARD_ERLIM, DEF_SMTPD_HARD_ERLIM, &var_smtpd_hard_erlim, 1, 0,
        VAR_QUEUE_MINFREE, DEF_QUEUE_MINFREE, &var_queue_minfree, 0, 0,
-       VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0,
        VAR_UNK_CLIENT_CODE, DEF_UNK_CLIENT_CODE, &var_unk_client_code, 0, 0,
        VAR_BAD_NAME_CODE, DEF_BAD_NAME_CODE, &var_bad_name_code, 0, 0,
        VAR_UNK_NAME_CODE, DEF_UNK_NAME_CODE, &var_unk_name_code, 0, 0,
@@ -1475,7 +1535,6 @@ int     main(int argc, char **argv)
     };
     static CONFIG_STR_TABLE str_table[] = {
        VAR_SMTPD_BANNER, DEF_SMTPD_BANNER, &var_smtpd_banner, 1, 0,
-       VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0,
        VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
        VAR_CLIENT_CHECKS, DEF_CLIENT_CHECKS, &var_client_checks, 0, 0,
        VAR_HELO_CHECKS, DEF_HELO_CHECKS, &var_helo_checks, 0, 0,
index 2d1f8772672be9f998b6a0f0d1582ca2d1876e95..13dd756a30ed0a5164b562a46b968868c53ade76 100644 (file)
@@ -207,7 +207,7 @@ void    smtpd_chat_notify(SMTPD_STATE *state)
 
     notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
                                    var_error_rcpt,
-                                   NULL_CLEANUP_FLAGS, "NOTICE");
+                                   NULL_CLEANUP_FLAGS);
     if (notice == 0) {
        msg_warn("postmaster notify: %m");
        return;
index 656a652ba66721d6521911fe285127f752252036..397f00cf89324130f13666206605c10a6adb6997 100644 (file)
@@ -551,6 +551,26 @@ 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
+     * 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.
+     * 
+     * Implementing the soft_bounce safety net in the SMTP server reply output
+     * routine has the advantage that it covers all 5xx replies, including
+     * SMTP protocol or syntax errors, which makes soft_bounce great for
+     * non-destructive tests (especially by people who are paranoid about
+     * losing mail).
+     * 
+     * We could eliminate the code duplication and implement the soft_bounce
+     * safety net only in the code below. But then the safety net would cover
+     * the UCE restrictions only. This would be at odds with the documentation
+     * which says soft_bounce changes all 5xx replies into 4xx ones.
+     */
+    if (var_soft_bounce && STR(error_text)[0] == '5')
+       STR(error_text)[0] = '4';
+
     /*
      * Log what is happening. When the sysadmin discards policy violation
      * postmaster notices, this may be the only trace left that service was
@@ -1898,6 +1918,13 @@ char   *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
     if (recipient == 0)
        return (0);
 
+    /*
+     * XXX 2821: Section 3.6 requires that "postmaster" be accepted even when
+     * specified without a fully qualified domain name.
+     */
+    if (strcasecmp(recipient, "postmaster") == 0)
+       return (0);
+
     /*
      * Minor kluge so that we can delegate work to the generic routine and so
      * that we can syslog the recipient with the reject messages.