]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.3-20051120
authorWietse Venema <wietse@porcupine.org>
Sun, 20 Nov 2005 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:31:44 +0000 (06:31 +0000)
15 files changed:
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/html/postconf.5.html
postfix/man/man5/postconf.5
postfix/proto/postconf.proto
postfix/src/bounce/bounce_template.c
postfix/src/bounce/bounce_templates.c
postfix/src/dns/dns.h
postfix/src/dns/dns_rr.c
postfix/src/global/mail_version.h
postfix/src/oqmgr/qmgr_deliver.c
postfix/src/qmgr/qmgr_deliver.c
postfix/src/smtp/smtp_addr.c
postfix/src/smtp/smtp_sasl_proto.c
postfix/src/smtpd/smtpd_check.c

index 915915c9522e85b64ec20b84e0b8dd7dbc8777fc..bc68e68ed43d724b0201abcbe8c793f130f98fa4 100644 (file)
@@ -11405,6 +11405,25 @@ Apologies for any names omitted.
        Bugfix: new bounce template code did not return after
        template syntax error. File: bounce/bounce_template.c
 
+       Safety: permit_mx_backup now requires that the local MTA
+       is not listed as primary MX for the recipient domain. This
+       prevents mail loops when someone points the primary MX
+       record to Postfix.
+
+20051119
+
+       Workaround: some SMTP servers announce multiple but different
+       lists of SASL methods. Postfix now concatenates the lists
+       instead of logging a warning and remembering only one. File:
+       smtp/smtp_sasl_proto.c.
+
+       Bugfix: the queue manager did not write a per-recipient
+       defer logfile record when the delivery agent crashed between
+       receiving a delivery request, and reporting the delivery
+       status to the queue manager.  Found while redesigning the
+       code that handles unavailable transports or destinations.
+       Files: *qmgr/qmgr_deliver.c.
+
 Open problems:
 
        "postsuper -r" no longer resets the message arrival time,
index 1ae66908bffb44a9f37eeeb3986c3211df1e4d2f..a5f0336fd768be1cce897b5216d1eae47d8e8e24 100644 (file)
@@ -17,6 +17,14 @@ Incompatibility with Postfix 2.1 and earlier
 If you upgrade from Postfix 2.1 or earlier, read RELEASE_NOTES-2.2
 before proceeding.
 
+Incompatibility with snapshot 20051120
+======================================
+
+The permit_mx_backup feature now requires that the local MTA is not
+listed as primary MX host for the recipient domain. This prevents
+mail loop problems when someone points the primary MX record at
+Postfix.
+
 Major changes with snapshot 20051113
 ====================================
 
index d3ff4cfdf67d1dc0c7418b413faf0d854848cb5f..242d8643e3c8056453a5319636c2761af978d4eb 100644 (file)
@@ -8305,9 +8305,16 @@ system is the final destination. However, the SMTP server will not
 forward mail with addresses that have sender-specified routing
 information (example: user@elsewhere@domain).  Use the optional
 <a href="postconf.5.html#permit_mx_backup_networks">permit_mx_backup_networks</a> parameter to require that the primary
-MX hosts match a list of network blocks. <br> Note: prior to
+MX hosts match a list of network blocks. <br> NOTE: prior to
 Postfix version 2.0, use of <a href="postconf.5.html#permit_mx_backup">permit_mx_backup</a> is not recommended;
-mail may be rejected in case of a temporary DNS lookup problem. </dd>
+mail may be rejected in case of a temporary DNS lookup problem.
+
+<br> NOTE: as of Postfix version 2.3, <a href="postconf.5.html#permit_mx_backup">permit_mx_backup</a> requires
+that the local MTA is not listed as primary MX for the recipient
+domain.  This is for safety reasons.
+
+<br> NOTE: use of <a href="postconf.5.html#permit_mx_backup">permit_mx_backup</a> is not recommended without
+restricting its use with <a href="postconf.5.html#permit_mx_backup_networks">permit_mx_backup_networks</a>. </dd>
 
 <dt><b><a name="reject_non_fqdn_recipient">reject_non_fqdn_recipient</a></b></dt>
 
index e8d4599febaa8371499ae8a9e135ef70c763e834..14fe1e75b4cfa8e307ffd9e4cf5af77aff516f97 100644 (file)
@@ -4777,9 +4777,16 @@ information (example: user@elsewhere@domain).  Use the optional
 permit_mx_backup_networks parameter to require that the primary
 MX hosts match a list of network blocks.
 .br
-Note: prior to
+NOTE: prior to
 Postfix version 2.0, use of permit_mx_backup is not recommended;
 mail may be rejected in case of a temporary DNS lookup problem.
+.br
+NOTE: as of Postfix version 2.3, permit_mx_backup requires
+that the local MTA is not listed as primary MX for the recipient
+domain.  This is for safety reasons.
+.br
+NOTE: use of permit_mx_backup is not recommended without
+restricting its use with permit_mx_backup_networks.
 .IP "\fBreject_non_fqdn_recipient\fR"
 Reject the request when the RCPT TO address is not in
 fully-qualified domain form, as required by the RFC.
index b9b29e345092ca7188bbfd9cc1edd601f369c600..fb3172d14f9a4d5bf411747ce57f57fb0458d0dc 100644 (file)
@@ -5198,9 +5198,16 @@ system is the final destination. However, the SMTP server will not
 forward mail with addresses that have sender-specified routing
 information (example: user@elsewhere@domain).  Use the optional
 permit_mx_backup_networks parameter to require that the primary
-MX hosts match a list of network blocks. <br> Note: prior to
+MX hosts match a list of network blocks. <br> NOTE: prior to
 Postfix version 2.0, use of permit_mx_backup is not recommended;
-mail may be rejected in case of a temporary DNS lookup problem. </dd>
+mail may be rejected in case of a temporary DNS lookup problem.
+
+<br> NOTE: as of Postfix version 2.3, permit_mx_backup requires
+that the local MTA is not listed as primary MX for the recipient
+domain.  This is for safety reasons.
+
+<br> NOTE: use of permit_mx_backup is not recommended without
+restricting its use with permit_mx_backup_networks. </dd>
 
 <dt><b><a name="reject_non_fqdn_recipient">reject_non_fqdn_recipient</a></b></dt>
 
index 90f1e8b07b9a5b9343d7179b6ae0b5efbba7a907..eb2e0167dfa641587e7aac1c810f4e2c77149a55 100644 (file)
@@ -47,7 +47,9 @@
 /*     BOUNCE_TEMPLATE *template;
 /* DESCRIPTION
 /*     This module implements the built-in and external bounce
-/*     message template support.
+/*     message template support. The content of a template are
+/*     private. To access information within a template, use
+/*     the API described in this document.
 /*
 /*     bounce_template_create() creates a template, with the
 /*     specified default settings. The template defaults are not
@@ -81,7 +83,7 @@
 /*     specified stream.
 /*
 /*     The IS_MUMBLE_TEMPLATE() macros are predicates that
-/*     return when the template is of the specified type.
+/*     determine whether the template is of the specified type.
 /* DIAGNOSTICS
 /*     Fatal error: out of memory, undefined macro name in template.
 /* SEE ALSO
   * Ideally, the bounce template processor would strip the _days etc. suffix
   * from the parameter name, and use the parameter name to look up the actual
   * parameter value and its default value (the default value specifies the
-  * default time unit of that parameter (seconds, minutes, etc.), and allows
-  * us to convert the parameter string value into the corresponding number of
-  * seconds). The bounce template processor would then use the _hours etc.
+  * default time unit of that parameter (seconds, minutes, etc.)), and use
+  * this to convert the parameter string value into the corresponding number
+  * of seconds. The bounce template processor would then use the _hours etc.
   * suffix from the bounce template to divide this number by the number of
   * seconds in an hour, etc. and produce the number that is needed for the
   * template.
index 7038e3f2d776d010a49d4d6281cb01685bcfd2d5..292ea04a7324bb03ffba7e16356470ccbce3ac76 100644 (file)
@@ -6,6 +6,15 @@
 /* SYNOPSIS
 /*     #include <bounce_template.h>
 /*
+/*     typedef struct {
+/* .in +4
+/*             BOUNCE_TEMPLATE *failure;
+/*             BOUNCE_TEMPLATE *delay;
+/*             BOUNCE_TEMPLATE *success;
+/*             BOUNCE_TEMPLATE *verify;
+/* .in -4
+/*     } BOUNCE_TEMPLATES;
+/*
 /*     BOUNCE_TEMPLATES *bounce_templates_create(void)
 /*
 /*     void    bounce_templates_free(templates)
index b1db34f3798c71b5f2ada9d811c0868c6d3aef7f..e84ce8abc2248bbdca6d65faaee83cc90742fcb3 100644 (file)
@@ -86,7 +86,7 @@ typedef struct DNS_RR {
     unsigned int ttl;                  /* always */
     unsigned short pref;               /* T_MX only */
     struct DNS_RR *next;               /* linkage */
-    size_t data_len;                   /* actual data size */
+    size_t  data_len;                  /* actual data size */
     char    data[1];                   /* actually a bunch of data */
 } DNS_RR;
 
@@ -111,6 +111,7 @@ extern void dns_rr_free(DNS_RR *);
 extern DNS_RR *dns_rr_copy(DNS_RR *);
 extern DNS_RR *dns_rr_append(DNS_RR *, DNS_RR *);
 extern DNS_RR *dns_rr_sort(DNS_RR *, int (*) (DNS_RR *, DNS_RR *));
+extern int dns_rr_compare_pref(DNS_RR *, DNS_RR *);
 extern DNS_RR *dns_rr_shuffle(DNS_RR *);
 extern DNS_RR *dns_rr_remove(DNS_RR *, DNS_RR *);
 
index 01732d0ddaa297f61aa6ca89c49252c63fc8a5e2..0063a201e1b823db717dad50bee3a95bd92451ff 100644 (file)
 /*     DNS_RR  *list
 /*     int     (*compar)(DNS_RR *, DNS_RR *);
 /*
+/*     int     dns_rr_compare_pref(DNS_RR *a, DNS_RR *b)
+/*     DNS_RR  *list
+/*     DNS_RR  *list
+/*
 /*     DNS_RR  *dns_rr_shuffle(list)
 /*     DNS_RR  *list;
 /*
@@ -58,6 +62,9 @@
 /*     order according to a user-specified criterion. The result is the
 /*     sorted list.
 /*
+/*     dns_rr_compare_pref() is a dns_rr_sort() helper to sort records
+/*     by their MX preference.
+/*
 /*     dns_rr_shuffle() randomly permutes a list of resource records.
 /*
 /*     dns_rr_remove() removes the specified record from the specified list.
@@ -151,6 +158,23 @@ DNS_RR *dns_rr_append(DNS_RR *list, DNS_RR *rr)
     return (list);
 }
 
+/* dns_rr_compare_pref - compare resource records by preference */
+
+int     dns_rr_compare_pref(DNS_RR *a, DNS_RR *b)
+{
+    if (a->pref != b->pref)
+       return (a->pref - b->pref);
+#ifdef HAS_IPV6
+    if (a->type == b->type)                    /* 200412 */
+       return 0;
+    if (a->type == T_AAAA)
+       return (-1);
+    if (b->type == T_AAAA)
+       return (+1);
+#endif
+    return 0;
+}
+
 /* dns_rr_sort_callback - glue function */
 
 static int (*dns_rr_sort_user) (DNS_RR *, DNS_RR *);
index a530b409b68dc97f49bcdcc36854bf5eae62a9ae..95a6c3009b832eebe16db83c2900028b0c7986d0 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20051118"
+#define MAIL_RELEASE_DATE      "20051120"
 #define MAIL_VERSION_NUMBER    "2.3"
 
 #ifdef SNAPSHOT
index b3e4cd65685638a176c7de803ee4e50e9f563cf4..7f392d319f00c5af06b5fcb5ef9d8dd584953ffb 100644 (file)
@@ -219,6 +219,8 @@ static void qmgr_deliver_update(int unused_event, char *context)
     static DSN_BUF *dsb;
     int     status;
     DSN     dsn;
+    RECIPIENT *recipient;
+    int     nrcpt;
 
     if (dsb == 0)
        dsb = dsb_create();
@@ -254,6 +256,21 @@ static void qmgr_deliver_update(int unused_event, char *context)
                                         "unknown mail transport error"));
        msg_warn("transport %s failure -- see a previous warning/fatal/panic logfile record for the problem description",
                 transport->name);
+
+       /*
+        * Assume the worst and write a defer logfile record for each
+        * recipient. This omission was already present in the first queue
+        * manager implementation of 199703, and was fixed 200511.
+        * 
+        * Don't move this queue entry back to the todo queue so that
+        * qmgr_defer_transport() can update the defer log. The queue entry
+        * is still hot, and making it cold would involve duplicating most
+        * but not all code at the end of this routine. That's too tricky.
+        */
+       for (nrcpt = 0; nrcpt < entry->rcpt_list.len; nrcpt++) {
+           recipient = entry->rcpt_list.info + nrcpt;
+           qmgr_defer_recipient(message, recipient, &dsn);
+       }
        qmgr_defer_transport(transport, &dsn);
     }
 
@@ -287,7 +304,7 @@ static void qmgr_deliver_update(int unused_event, char *context)
      * No problems detected. Mark the transport and queue as alive. The queue
      * itself won't go away before we dispose of the current queue entry.
      */
-    if (VSTRING_LEN(dsb->reason) == 0) {
+    if (status != DELIVER_STAT_CRASH && VSTRING_LEN(dsb->reason) == 0) {
        qmgr_transport_unthrottle(transport);
        qmgr_queue_unthrottle(queue);
     }
index 28f0f2c46c05cdd81ce262ce85966a4a78716e2f..a2d96f511eccdf5bdcff7aa0e32fd58314c19a1b 100644 (file)
@@ -224,6 +224,8 @@ static void qmgr_deliver_update(int unused_event, char *context)
     static DSN_BUF *dsb;
     int     status;
     DSN     dsn;
+    RECIPIENT *recipient;
+    int     nrcpt;
 
     if (dsb == 0)
        dsb = dsb_create();
@@ -259,6 +261,21 @@ static void qmgr_deliver_update(int unused_event, char *context)
                                         "unknown mail transport error"));
        msg_warn("transport %s failure -- see a previous warning/fatal/panic logfile record for the problem description",
                 transport->name);
+
+       /*
+        * Assume the worst and write a defer logfile record for each
+        * recipient. This omission was already present in the first queue
+        * manager implementation of 199703, and was fixed 200511.
+        * 
+        * Don't move this queue entry back to the todo queue so that
+        * qmgr_defer_transport() can update the defer log. The queue entry
+        * is still hot, and making it cold would involve duplicating most
+        * but not all code at the end of this routine. That's too tricky.
+        */
+       for (nrcpt = 0; nrcpt < entry->rcpt_list.len; nrcpt++) {
+           recipient = entry->rcpt_list.info + nrcpt;
+           qmgr_defer_recipient(message, recipient, &dsn);
+       }
        qmgr_defer_transport(transport, &dsn);
     }
 
@@ -292,7 +309,7 @@ static void qmgr_deliver_update(int unused_event, char *context)
      * No problems detected. Mark the transport and queue as alive. The queue
      * itself won't go away before we dispose of the current queue entry.
      */
-    if (VSTRING_LEN(dsb->reason) == 0) {
+    if (status != DELIVER_STAT_CRASH && VSTRING_LEN(dsb->reason) == 0) {
        qmgr_transport_unthrottle(transport);
        qmgr_queue_unthrottle(queue);
     }
index 855007efcaeaebef101fabcc02a505065b55e518..ddc06c87eea03c2f6a7a3c6e7a46e8adefa32398 100644 (file)
@@ -338,23 +338,6 @@ static DNS_RR *smtp_truncate_self(DNS_RR *addr_list, unsigned pref)
     return (addr_list);
 }
 
-/* smtp_compare_pref - compare resource records by preference */
-
-static int smtp_compare_pref(DNS_RR *a, DNS_RR *b)
-{
-    if (a->pref != b->pref)
-       return (a->pref - b->pref);
-#ifdef HAS_IPV6
-    if (a->type == b->type)                    /* 200412 */
-       return 0;
-    if (a->type == T_AAAA)
-       return (-1);
-    if (b->type == T_AAAA)
-       return (+1);
-#endif
-    return 0;
-}
-
 /* smtp_domain_addr - mail exchanger address lookup */
 
 DNS_RR *smtp_domain_addr(char *name, int misc_flags, DSN_BUF *why,
@@ -437,7 +420,7 @@ DNS_RR *smtp_domain_addr(char *name, int misc_flags, DSN_BUF *why,
            addr_list = smtp_host_addr(name, misc_flags, why);
        break;
     case DNS_OK:
-       mx_names = dns_rr_sort(mx_names, smtp_compare_pref);
+       mx_names = dns_rr_sort(mx_names, dns_rr_compare_pref);
        best_pref = (mx_names ? mx_names->pref : IMPOSSIBLE_PREFERENCE);
        addr_list = smtp_addr_list(mx_names, why);
        dns_rr_free(mx_names);
@@ -472,7 +455,7 @@ DNS_RR *smtp_domain_addr(char *name, int misc_flags, DSN_BUF *why,
        }
        if (addr_list && addr_list->next && var_smtp_rand_addr) {
            addr_list = dns_rr_shuffle(addr_list);
-           addr_list = dns_rr_sort(addr_list, smtp_compare_pref);
+           addr_list = dns_rr_sort(addr_list, dns_rr_compare_pref);
        }
        break;
     case DNS_INVAL:
@@ -521,7 +504,7 @@ DNS_RR *smtp_host_addr(char *host, int misc_flags, DSN_BUF *why)
            addr_list = dns_rr_shuffle(addr_list);
        /* The following changes the order of equal-preference hosts. */
        if (inet_proto_info()->ai_family_list[1] != 0)
-           addr_list = dns_rr_sort(addr_list, smtp_compare_pref);
+           addr_list = dns_rr_sort(addr_list, dns_rr_compare_pref);
     }
     if (msg_verbose)
        smtp_print_addr(host, addr_list);
index 87b0491295253ab02e082b2c612dab591111d4f4..7b8ed12f07f9eb82e6ec5b7315577eae2b745b0b 100644 (file)
@@ -115,18 +115,25 @@ static const char *smtp_sasl_compat_mechs(const char *words)
 void    smtp_sasl_helo_auth(SMTP_SESSION *session, const char *words)
 {
     const char *mech_list = smtp_sasl_compat_mechs(words);
+    char   *junk;
 
     /*
      * XXX If the server offers no compatible authentication mechanisms, then
      * pretend that the server doesn't support SASL authentication.
+     * 
+     * XXX If the server offers multiple different lists, concatenate them. Let
+     * the SASL library worry about duplicates.
      */
     if (session->sasl_mechanism_list) {
-       if (strcasecmp(session->sasl_mechanism_list, mech_list) == 0)
-           return;
-       myfree(session->sasl_mechanism_list);
-       msg_warn("%s offered AUTH option multiple times", session->namaddr);
-       session->sasl_mechanism_list = 0;
-       session->features &= ~SMTP_FEATURE_AUTH;
+       if (strcasecmp(session->sasl_mechanism_list, mech_list) != 0
+           && strlen(mech_list) > 0
+           && strlen(session->sasl_mechanism_list) < var_line_limit) {
+           junk = concatenate(session->sasl_mechanism_list, " ", mech_list,
+                              (char *) 0);
+           myfree(session->sasl_mechanism_list);
+           session->sasl_mechanism_list = junk;
+       }
+       return;
     }
     if (strlen(mech_list) > 0) {
        session->sasl_mechanism_list = mystrdup(mech_list);
index a95685d2ac43394503babc2a6e1ce6228999055c..0d9b1c6fa921c59a7781a562d51344a2cf29c9b8 100644 (file)
@@ -1515,25 +1515,15 @@ static int permit_mx_primary(SMTPD_STATE *state, DNS_RR *mx_list,
 {
     const char *myname = "permit_mx_primary";
     DNS_RR *mx;
-    unsigned int best_pref;
 
     if (msg_verbose)
        msg_info("%s", myname);
 
-    /*
-     * Find the preference of the primary MX hosts.
-     */
-    for (best_pref = 0xffff, mx = mx_list; mx != 0; mx = mx->next)
-       if (mx->pref < best_pref)
-           best_pref = mx->pref;
-
     /*
      * See if each best MX host has all IP addresses in
      * permit_mx_backup_networks.
      */
     for (mx = mx_list; mx != 0; mx = mx->next) {
-       if (mx->pref != best_pref)
-           continue;
        if (!all_auth_mx_addr(state, (char *) mx->data, reply_name, reply_class))
            return (NOPE);
     }
@@ -1553,8 +1543,9 @@ static int permit_mx_backup(SMTPD_STATE *state, const char *recipient,
     char   *myname = "permit_mx_backup";
     const RESOLVE_REPLY *reply;
     const char *domain;
-
     DNS_RR *mx_list;
+    DNS_RR *middle;
+    DNS_RR *rest;
     int     dns_status;
 
     if (msg_verbose)
@@ -1607,9 +1598,11 @@ 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 0
     if (dns_status == DNS_NOTFOUND)
        return (has_my_addr(state, domain, reply_name, reply_class) ?
                SMTPD_CHECK_OK : SMTPD_CHECK_DUNNO);
+#endif
     if (dns_status != DNS_OK) {                        /* incl. DNS_INVAL */
        if (dns_status == DNS_RETRY)
            DEFER_IF_REJECT2(state, MAIL_ERROR_POLICY,
@@ -1620,28 +1613,50 @@ static int permit_mx_backup(SMTPD_STATE *state, const char *recipient,
     }
 
     /*
-     * First, see if we match any of the MX host names listed.
+     * Separate MX list into primaries and backups.
      */
-    if (!i_am_mx(state, mx_list, reply_name, reply_class)) {
-       dns_rr_free(mx_list);
-       return (SMTPD_CHECK_DUNNO);
+    mx_list = dns_rr_sort(mx_list, dns_rr_compare_pref);
+    for (middle = mx_list; /* see below */ ; middle = rest) {
+       rest = middle->next; 
+       if (rest == 0)
+           break;
+       if (rest->pref != mx_list->pref) {
+           middle->next = 0;
+           break;
+       }
     }
+    /* postcondition: middle->next = 0, rest may be 0. */
+
+#define PERMIT_MX_BACKUP_RETURN(x) do { \
+       middle->next = rest; \
+       dns_rr_free(mx_list); \
+       return (x); \
+   } while (0)
+
+    /*
+     * First, see if we match any of the primary MX servers.
+     */
+    if (i_am_mx(state, mx_list, reply_name, reply_class))
+       PERMIT_MX_BACKUP_RETURN(SMTPD_CHECK_DUNNO);
+
+    /*
+     * Then, see if we match any of the backup MX servers.
+     */
+    if (rest && !i_am_mx(state, rest, reply_name, reply_class))
+       PERMIT_MX_BACKUP_RETURN(SMTPD_CHECK_DUNNO);
 
     /*
      * 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, reply_name, reply_class)) {
-       dns_rr_free(mx_list);
-       return (SMTPD_CHECK_DUNNO);
-    }
+       && !permit_mx_primary(state, mx_list, reply_name, reply_class))
+       PERMIT_MX_BACKUP_RETURN(SMTPD_CHECK_DUNNO);
 
     /*
      * The destination passed all requirements.
      */
-    dns_rr_free(mx_list);
-    return (SMTPD_CHECK_OK);
+    PERMIT_MX_BACKUP_RETURN(SMTPD_CHECK_OK);
 }
 
 /* reject_non_fqdn_address - fail if address is not in fqdn form */