]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.5.8 v2.5.8
authorWietse Venema <wietse@porcupine.org>
Wed, 26 Aug 2009 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Sat, 10 Feb 2018 19:57:40 +0000 (14:57 -0500)
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/src/global/mail_version.h
postfix/src/milter/milter8.c
postfix/src/smtpd/smtpd_check.c

index 12dd4e802ba36e6d3f288bfae216c95845060b2a..27512e5352c128414dae7bd3e36ee8b809ea4da6 100644 (file)
@@ -14514,3 +14514,47 @@ Apologies for any names omitted.
        Bugfix: don't disable MIME parsing with smtp_header_checks,
        smtp_mime_header_checks, smtp_nested_header_checks or with
        smtp_body_checks. Bug reported by Victor. File: smtp/smtp_proto.c.
+
+20090710
+
+       Bugfix (introduced Postfix 2.3): Postfix got out of sync
+       with a Milter application after the application sent a
+       "quarantine" request at end-of-message time. The milter
+       application would still be in the end-of-message state,
+       while Postfix would already be working on the next SMTP
+       event (typically, QUIT or MAIL FROM).  Problem diagnosed
+       with help from Alban Deniz. File: milter/milter8.c.
+
+20090805
+
+       Bugfix: don't panic when an unexpected smtpd access map is
+       specified. File: smtpd/smtpd_check.c.
+
+20090807
+
+       Workaround: NS record lookups for certain domains always
+       fail, while other queries for those domains always succeed
+       (and even return replies with NS records as additional
+       information).
+
+       This inconsistency in DNS lookup results would allow spammers
+       to circumvent the Postfix check_{client,helo,sender,etc}_ns_access
+       restrictions, because those restrictions have effect only
+       for NS records that can be looked up in the DNS.
+
+       To address this inconsistency, check_{client,etc}_ns_access
+       now require that a known-in-DNS domain name (or parent
+       thereof) always resolves to at least one name server IP
+       address.
+
+       For consistency, check_{client,etc}_mx_access now require
+       that a known-in-DNS domain name always resolves to at least
+       one mail server IP address.
+
+       These measures merely raise the difficulty level for spammers.
+       The IP address information thus obtained is not necessarily
+       "correct".  There is little to stop an uncooperative DNS
+       server from lying, especially when the owner of the domain
+       has no desire to receive email.  File: smtpd/smtpd_check.c.
+
+       Problem reported by MXTools.com.
index 14fd19aa1704ef93af484ed48faef99645572fdc..50acb06c9cc2ceb935dfb2d8b06d487369e302b1 100644 (file)
@@ -11,6 +11,28 @@ instead, a new snapshot is released.
 The mail_release_date configuration parameter (format: yyyymmdd)
 specifies the release date of a stable release or snapshot release.
 
+Incompatibility with Postfix 2.5.8
+==================================
+
+With some domain names, NS record lookups always fail while other
+lookups always succeed (and may even return NS records as additional
+information).  This anomaly could be used by evil elements to skip
+Postfix check_{client,helo,sender,recipient}_ns_access checks,
+because these apply only to NS records that are found in the DNS.
+
+To address this specific problem, check_{client,etc}_ns_access now
+requires that a known-in-DNS domain name (or parent thereof) always
+resolves to at least one name server IP address.
+
+For consistency, check_{client,etc}_mx_access now requires that a
+known-in-DNS domain name always resolves to at least one mail server
+IP address.
+
+These measures provide no hard assurances that the IP address
+information thus obtained is correct. There is little to stop an
+uncooperative DNS server from lying, especially when the owner of
+the domain has no desire to receive email.
+
 Incompatibility with Postfix 2.5.3
 ==================================
 
index e7b69aef73d80353015070e3c76a39d285d385fb..242d2feafb270d3588c0feff9d810e76f9fc97ca 100644 (file)
@@ -20,8 +20,8 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20090512"
-#define MAIL_VERSION_NUMBER    "2.5.7"
+#define MAIL_RELEASE_DATE      "20090826"
+#define MAIL_VERSION_NUMBER    "2.5.8"
 
 #ifdef SNAPSHOT
 # define MAIL_VERSION_DATE     "-" MAIL_RELEASE_DATE
index 4a3abb96d849f7628d8e30054a3b17f82b6f6b4e..72190df72d9e27082f6be5644245e9060e3c2d58 100644 (file)
@@ -1292,7 +1292,8 @@ static const char *milter8_event(MILTER8 *milter, int event,
            /*
             * Decision: quarantine. In Sendmail 8.13 this does not imply a
             * transition in the receiver state (reply, reject, tempfail,
-            * accept, discard).
+            * accept, discard). We should not transition, either, otherwise
+            * we get out of sync.
             */
        case SMFIR_QUARANTINE:
            /* XXX What to do with the "reason" text? */
@@ -1300,7 +1301,8 @@ static const char *milter8_event(MILTER8 *milter, int event,
                                  MILTER8_DATA_BUFFER, milter->buf,
                                  MILTER8_DATA_END) != 0)
                MILTER8_EVENT_BREAK(milter->def_reply);
-           MILTER8_EVENT_BREAK("H");
+           milter8_def_reply(milter, "H");
+           continue;
 
            /*
             * Decision: skip further events of this type.
index 6cfb704704022ac0e4d90ba5ba8b6727c07248ed..ccc01dc55b635f9e6f40681628ab9e2760015d6d 100644 (file)
@@ -2295,8 +2295,13 @@ static int check_access(SMTPD_STATE *state, const char *table, const char *name,
     if (msg_verbose)
        msg_info("%s: %s", myname, name);
 
-    if ((dict = dict_handle(table)) == 0)
-       msg_panic("%s: dictionary not found: %s", myname, table);
+    if ((dict = dict_handle(table)) == 0) {
+       msg_warn("%s: unexpected dictionary: %s", myname, table);
+       value = "451 4.3.5 Server configuration error";
+       CHK_ACCESS_RETURN(check_table_result(state, table, value, name,
+                                            reply_name, reply_class,
+                                            def_acl), FOUND);
+    }
     if (flags == 0 || (flags & dict->flags) != 0) {
        if ((value = dict_get(dict, name)) != 0)
            CHK_ACCESS_RETURN(check_table_result(state, table, value, name,
@@ -2340,8 +2345,13 @@ static int check_domain_access(SMTPD_STATE *state, const char *table,
      */
 #define CHK_DOMAIN_RETURN(x,y) { *found = y; return(x); }
 
-    if ((dict = dict_handle(table)) == 0)
-       msg_panic("%s: dictionary not found: %s", myname, table);
+    if ((dict = dict_handle(table)) == 0) {
+       msg_warn("%s: unexpected dictionary: %s", myname, table);
+       value = "451 4.3.5 Server configuration error";
+       CHK_DOMAIN_RETURN(check_table_result(state, table, value,
+                                            domain, reply_name, reply_class,
+                                            def_acl), FOUND);
+    }
     for (name = domain; *name != 0; name = next) {
        if (flags == 0 || (flags & dict->flags) != 0) {
            if ((value = dict_get(dict, name)) != 0)
@@ -2399,8 +2409,13 @@ static int check_addr_access(SMTPD_STATE *state, const char *table,
 #endif
        delim = '.';
 
-    if ((dict = dict_handle(table)) == 0)
-       msg_panic("%s: dictionary not found: %s", myname, table);
+    if ((dict = dict_handle(table)) == 0) {
+       msg_warn("%s: unexpected dictionary: %s", myname, table);
+       value = "451 4.3.5 Server configuration error";
+       CHK_ADDR_RETURN(check_table_result(state, table, value, address,
+                                          reply_name, reply_class,
+                                          def_acl), FOUND);
+    }
     do {
        if (flags == 0 || (flags & dict->flags) != 0) {
            if ((value = dict_get(dict, addr)) != 0)
@@ -2480,6 +2495,10 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
     struct addrinfo *res;
     int     status;
     INET_PROTO_INFO *proto_info;
+    const char *saved_domain;
+    int     non_err, soft_err;
+    int     known_name_in_dns;
+    int     ping_status;
 
     /*
      * Sanity check.
@@ -2534,15 +2553,26 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
      * 
      * If the domain name exists but no NS record exists, look up parent domain
      * NS records.
+     * 
+     * After the initial lookup fails, do one final DNS sanity check. Reject
+     * mail when the name exists, but MX lookup produces no valid response or
+     * NS lookup fails for any reason. Beware, this sanity check provides no
+     * hard assurance. An uncooperative DNS server may lie about everything,
+     * including non-existence.
      */
+#define SOME_DNS_RR_EXISTS(stat, herr) \
+       ((stat) == DNS_OK || (stat) == DNS_INVAL || (herr) == NO_DATA)
+
+    saved_domain = domain;
     dns_status = dns_lookup(domain, type, 0, &server_list,
                            (VSTRING *) 0, (VSTRING *) 0);
-    if (dns_status == DNS_NOTFOUND && h_errno == NO_DATA) {
+    known_name_in_dns = SOME_DNS_RR_EXISTS(dns_status, h_errno);
+    if (dns_status == DNS_NOTFOUND /* Not: h_errno == NO_DATA */ ) {
        if (type == T_MX) {
            server_list = dns_rr_create(domain, domain, type, C_IN, 0, 0,
                                        domain, strlen(domain) + 1);
            dns_status = DNS_OK;
-       } else if (type == T_NS) {
+       } else if (type == T_NS && h_errno == NO_DATA) {
            while ((domain = strchr(domain, '.')) != 0 && domain[1]) {
                domain += 1;
                dns_status = dns_lookup(domain, type, 0, &server_list,
@@ -2552,9 +2582,31 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
            }
        }
     }
+
+#ifndef VAR_MAP_DEFER_CODE
+#define var_map_reject_code var_reject_code
+#define var_map_defer_code var_defer_code
+#endif
+
     if (dns_status != DNS_OK) {
        msg_warn("Unable to look up %s host for %s: %s", dns_strtype(type),
                 domain && domain[1] ? domain : name, dns_strerror(h_errno));
+       if (known_name_in_dns == 0) {
+           /* With hostile DNS, an address query is more likely to work. */
+           ping_status = dns_lookup_l(saved_domain, 0, (DNS_RR **) 0,
+                                      (VSTRING *) 0, (VSTRING *) 0,
+                                      DNS_REQ_FLAG_STOP_OK,
+                                      RR_ADDR_TYPES, 0);
+           known_name_in_dns = SOME_DNS_RR_EXISTS(ping_status, h_errno);
+       }
+       if (known_name_in_dns)
+           return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
+                                      dns_status == DNS_RETRY ?
+                                  var_map_defer_code : var_map_reject_code,
+                                      smtpd_dsn_fix("4.1.8", reply_class),
+                                      "<%s>: %s rejected: %s",
+                                      reply_name, reply_class,
+                                      "Domain not found"));
        return (SMTPD_CHECK_DUNNO);
     }
 
@@ -2567,10 +2619,19 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
      * Check the hostnames first, then the addresses.
      */
     proto_info = inet_proto_info();
+    non_err = soft_err = 0;
     for (server = server_list; server != 0; server = server->next) {
        if (msg_verbose)
            msg_info("%s: %s hostname check: %s",
                     myname, dns_strtype(type), (char *) server->data);
+       if (valid_hostaddr((char *) server->data, DONT_GRIPE)) {
+           non_err = 1;
+           if ((status = check_addr_access(state, table, (char *) server->data,
+                                     FULL, &found, reply_name, reply_class,
+                                           def_acl)) != 0 || found)
+               CHECK_SERVER_RETURN(status);
+           continue;
+       }
        if ((status = check_domain_access(state, table, (char *) server->data,
                                      FULL, &found, reply_name, reply_class,
                                          def_acl)) != 0 || found)
@@ -2580,8 +2641,11 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
            msg_warn("Unable to look up %s host %s for %s %s: %s",
                     dns_strtype(type), (char *) server->data,
                     reply_class, reply_name, MAI_STRERROR(aierr));
+           if (aierr == EAI_AGAIN || aierr == EAI_SYSTEM)
+               soft_err = 1;
            continue;
        }
+       non_err = 1;
        /* Now we must also free the addrinfo result. */
        if (msg_verbose)
            msg_info("%s: %s host address check: %s",
@@ -2605,7 +2669,15 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
        }
        freeaddrinfo(res0);                     /* 200412 */
     }
-    CHECK_SERVER_RETURN(SMTPD_CHECK_DUNNO);
+    status = non_err ? SMTPD_CHECK_DUNNO :
+       smtpd_check_reject(state, MAIL_ERROR_POLICY,
+                          soft_err ? var_map_defer_code :
+                          var_map_reject_code,
+                          smtpd_dsn_fix("4.1.8", reply_class),
+                          "<%s>: %s rejected: %s",
+                          reply_name, reply_class,
+                          "Domain not found");
+    CHECK_SERVER_RETURN(status);
 }
 
 /* check_ccert_access - access for TLS clients by certificate fingerprint */