]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.9-20111221
authorWietse Venema <wietse@porcupine.org>
Wed, 21 Dec 2011 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:37:49 +0000 (06:37 +0000)
15 files changed:
postfix/HISTORY
postfix/src/global/mail_version.h
postfix/src/global/server_acl.c
postfix/src/smtpd/Makefile.in
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd_check.c
postfix/src/smtpd/smtpd_error.in [new file with mode: 0644]
postfix/src/smtpd/smtpd_error.ref [new file with mode: 0644]
postfix/src/util/argv.c
postfix/src/util/argv.h
postfix/src/util/cidr_match.c
postfix/src/util/dict_fail.c
postfix/src/util/match_list.c
postfix/src/util/match_ops.h
postfix/src/util/name_mask.c

index ea798e67636e994bf535c4ebc9ccb8fe1ea7a0e7..e68ebd443cadd152ced9357df280f917145dd010 100644 (file)
@@ -17394,11 +17394,27 @@ Apologies for any names omitted.
        trivial-rewrite/resolve.c.
 
        Cleanup: a broken relay_domains table would cause many
-       Postfix processes to terminate with fatal error. Postfix
-       now logs a warning instead. File: global/flush_clnt.c.
-
-       Cleanup: the Postfix SMTP server now "catches" some of the
-       errors with implicit database lookups in mynetworks and TLS
-       client certificate tables, and reports "server configuration
-       error" instead of terminating with a fatal error. This is
-       work in progress. Files: smtpd/smtpd.c, smtpd/smtpd_check.c.
+       Postfix processes to terminate with fatal error as they
+       initialized the flush() client (used by defer_append()
+       etc.). Postfix now logs a warning instead.  File:
+       global/flush_clnt.c.
+
+       Cleanup: the Postfix SMTP server now "catches" errors with
+       implicit database lookups in mynetworks, TLS client certificate
+       tables, and local_header_rewrite_clients, and reports "server
+       configuration error" or "table lookup error" instead of
+       terminating with a fatal error. This is work in progress;
+       errors with opening a database may be covered later. Files:
+       smtpd/smtpd.c, smtpd/smtpd_check.c.
+
+20111220
+
+       Cleanup: the Postfix SMTP server now "catches" errors with
+       implicit database lookups in mynetworks, debug_peer_list,
+       smtpd_client_event_limit_exceptions, permit_mx_backup_networks.
+       This continues work started 20111219, and does not cover
+       errors with opening a database.  Files: smtpd/smtpd.c,
+       smtpd/smtpd_checks.c, smtpd/smtpd_error.in, smtpd/smtpd_error.ref.
+
+       Cleanup: memory leak testing of error handling. Files:
+       util/name_mask.c, util/cidr_mask.c.
index 3812da471e5c386082c330facc7c79a727ba2150..9e650de0b0ef961e5a25883056655752d13003c6 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      "20111219"
+#define MAIL_RELEASE_DATE      "20111221"
 #define MAIL_VERSION_NUMBER    "2.9"
 
 #ifdef SNAPSHOT
index 03b602dab2ade8f2568b5acf5bf62428a4178f04..8767fa47051d14ad7ca3a1c26e90f51937f18513 100644 (file)
@@ -157,8 +157,6 @@ int     server_acl_eval(const char *client_addr, SERVER_ACL * intern_acl,
     const char *acl;
     const char *dict_val;
     int     ret;
-    ARGV    fake_argv;
-    const char *fake_args[2];
     int     rc;
 
     for (cpp = intern_acl->argv; (acl = *cpp) != 0; cpp++) {
@@ -184,11 +182,9 @@ int     server_acl_eval(const char *client_addr, SERVER_ACL * intern_acl,
            if ((dict_val = dict_get(dict, client_addr)) != 0) {
                /* Fake up an ARGV to avoid lots of mallocs and frees. */
                if (dict_val[strcspn(dict_val, ":" SERVER_ACL_SEPARATORS)] == 0) {
-                   fake_args[0] = dict_val;
-                   fake_args[1] = 0;
-                   fake_argv.argv = (char **) fake_args;
-                   fake_argv.argc = fake_argv.len = 1;
+                   ARGV_FAKE_BEGIN(fake_argv, dict_val);
                    ret = server_acl_eval(client_addr, &fake_argv, acl);
+                   ARGV_FAKE_END;
                } else {
                    argv = server_acl_parse(dict_val, acl);
                    ret = server_acl_eval(client_addr, argv, acl);
index 95d0ac4f0c23917a857ff8ef4fc315a76bff9ed4..2a26b77c155f37e5815422b6aea5f54ab1e989cf 100644 (file)
@@ -68,7 +68,7 @@ tidy: clean
 
 tests: smtpd_check_test smtpd_check_test2 smtpd_acl_test smtpd_exp_test \
        smtpd_token_test smtpd_check_test4 smtpd_check_dsn_test \
-       smtpd_check_backup_test smtpd_dnswl_test
+       smtpd_check_backup_test smtpd_dnswl_test smtpd_error_test
 
 root_tests:
 
@@ -133,6 +133,11 @@ smtpd_dnswl_test: smtpd_check smtpd_dnswl.in smtpd_dnswl.ref
        diff smtpd_dnswl.ref smtpd_dnswl.tmp
        rm -f smtpd_dnswl.tmp
 
+smtpd_error_test: smtpd_check smtpd_error.in smtpd_error.ref
+       ./smtpd_check <smtpd_error.in >smtpd_check.tmp 2>&1
+       diff smtpd_error.ref smtpd_check.tmp
+       rm -f smtpd_check.tmp
+
 depend: $(MAKES)
        (sed '1,/^# do not edit/!d' Makefile.in; \
        set -e; for i in [a-z][a-z0-9]*.c; do \
index 59415c85f994aa3cf54c03c38441c465ddcf0b94..1b3f053c76cd869435d8f7bbc1ef098157d23f15 100644 (file)
@@ -4890,7 +4890,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
     verp_clients = namadr_list_init(MATCH_FLAG_NONE, var_verp_clients);
     xclient_hosts = namadr_list_init(MATCH_FLAG_NONE, var_xclient_hosts);
     xforward_hosts = namadr_list_init(MATCH_FLAG_NONE, var_xforward_hosts);
-    hogger_list = namadr_list_init(MATCH_FLAG_NONE, var_smtpd_hoggers);
+    hogger_list = namadr_list_init(MATCH_FLAG_RETURN, var_smtpd_hoggers);
 
     /*
      * Open maps before dropping privileges so we can read passwords etc.
index b23c3c168e2860db33cc163ad378730f00f4419e..f5beaf46c0349541170a2a723e2826980ea370fc 100644 (file)
@@ -572,13 +572,14 @@ void    smtpd_check_init(void)
      * Pre-open access control lists before going to jail.
      */
     mynetworks =
-       namadr_list_init(match_parent_style(VAR_MYNETWORKS),
+       namadr_list_init(MATCH_FLAG_RETURN | match_parent_style(VAR_MYNETWORKS),
                         var_mynetworks);
     relay_domains =
        domain_list_init(match_parent_style(VAR_RELAY_DOMAINS),
                         var_relay_domains);
     perm_mx_networks =
-       namadr_list_init(match_parent_style(VAR_PERM_MX_NETWORKS),
+       namadr_list_init(MATCH_FLAG_RETURN
+                        | match_parent_style(VAR_PERM_MX_NETWORKS),
                         var_perm_mx_networks);
 #ifdef USE_TLS
     relay_ccerts = maps_create(VAR_RELAY_CCERTS, var_smtpd_relay_ccerts,
@@ -771,7 +772,8 @@ static int smtpd_check_reject(SMTPD_STATE *state, int error_class,
      * Do not reject mail if we were asked to warn only. However,
      * configuration errors cannot be converted into warnings.
      */
-    if (state->warn_if_reject && error_class != MAIL_ERROR_SOFTWARE) {
+    if (state->warn_if_reject && error_class != MAIL_ERROR_SOFTWARE
+       && error_class != MAIL_ERROR_RESOURCE) {
        warn_if_reject = 1;
        whatsup = "reject_warning";
     } else {
@@ -894,7 +896,7 @@ static int defer_if(SMTPD_DEFER *defer, int error_class,
 
 /* reject_dict_retry - reject with temporary failure if dict lookup fails */
 
-static void reject_dict_retry(SMTPD_STATE *state, const char *reply_name)
+static NORETURN reject_dict_retry(SMTPD_STATE *state, const char *reply_name)
 {
     longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_RESOURCE,
                                                451, "4.3.0",
@@ -902,6 +904,15 @@ static void reject_dict_retry(SMTPD_STATE *state, const char *reply_name)
                                                reply_name));
 }
 
+/* reject_server_error - reject with temporary failure after non-dict error */
+
+static NORETURN reject_server_error(SMTPD_STATE *state)
+{
+    longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
+                                               451, "4.3.5",
+                                            "Server configuration error"));
+}
+
 /* check_mail_addr_find - reject with temporary failure if dict lookup fails */
 
 static const char *check_mail_addr_find(SMTPD_STATE *state,
@@ -912,10 +923,12 @@ static const char *check_mail_addr_find(SMTPD_STATE *state,
     const char *result;
 
     dict_errno = 0;
-    if ((result = mail_addr_find(maps, key, ext)) == 0
-       && dict_errno == DICT_ERR_RETRY)
+    if ((result = mail_addr_find(maps, key, ext)) != 0 || dict_errno == 0)
+       return (result);
+    if (dict_errno == DICT_ERR_RETRY)
        reject_dict_retry(state, reply_name);
-    return (result);
+    else
+       reject_server_error(state);
 }
 
 /* reject_unknown_reverse_name - fail if reverse client hostname is unknown */
@@ -991,13 +1004,17 @@ static int permit_inet_interfaces(SMTPD_STATE *state)
 static int permit_mynetworks(SMTPD_STATE *state)
 {
     const char *myname = "permit_mynetworks";
+    int     rc;
 
     if (msg_verbose)
        msg_info("%s: %s %s", myname, state->name, state->addr);
 
-    if (namadr_list_match(mynetworks, state->name, state->addr))
+    if ((rc = namadr_list_match(mynetworks, state->name, state->addr)) > 0)
        return (SMTPD_CHECK_OK);
-    return (SMTPD_CHECK_DUNNO);
+    else if (rc == 0)
+       return (SMTPD_CHECK_DUNNO);
+    else
+       return (SMTPD_CHECK_ERROR);
 }
 
 /* dup_if_truncate - save hostname and truncate if it ends in dot */
@@ -1255,9 +1272,15 @@ static int permit_tls_clientcerts(SMTPD_STATE *state, int permit_all_certs)
            if (msg_verbose)
                msg_info("Relaying allowed for certified client: %s", found);
            return (SMTPD_CHECK_OK);
-       } else if (msg_verbose)
-           msg_info("relay_clientcerts: No match for fingerprint '%s', "
+       } else if (dict_errno != 0) {
+           msg_warn("relay_clientcerts: lookup error for fingerprint '%s', "
                     "pkey fingerprint %s", prints[0], prints[1]);
+           return (SMTPD_CHECK_ERROR);
+       } else {
+           if (msg_verbose)
+               msg_info("relay_clientcerts: No match for fingerprint '%s', "
+                        "pkey fingerprint %s", prints[0], prints[1]);
+       }
     }
 #else
     dict_errno = 0;
@@ -1408,6 +1431,7 @@ static int all_auth_mx_addr(SMTPD_STATE *state, char *host,
     DNS_RR *rr;
     DNS_RR *addr_list;
     int     dns_status;
+    int     rc;
 
     if (msg_verbose)
        msg_info("%s: host %s", myname, host);
@@ -1439,7 +1463,8 @@ static int all_auth_mx_addr(SMTPD_STATE *state, char *host,
        if (msg_verbose)
            msg_info("%s: checking: %s", myname, hostaddr.buf);
 
-       if (!namadr_list_match(perm_mx_networks, host, hostaddr.buf)) {
+       rc = namadr_list_match(perm_mx_networks, host, hostaddr.buf);
+       if (rc == 0) {
 
            /*
             * Reject: at least one IP address is not listed in
@@ -1450,6 +1475,14 @@ static int all_auth_mx_addr(SMTPD_STATE *state, char *host,
                         myname, hostaddr.buf, host, VAR_PERM_MX_NETWORKS);
            dns_rr_free(addr_list);
            return (NOPE);
+       } else if (rc < 0) {
+           msg_warn("%s: %s lookup error for address %s for %s",
+                    myname, VAR_PERM_MX_NETWORKS, hostaddr.buf, host);
+           DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
+                            450, "4.4.4",
+           "<%s>: %s rejected: Unable to verify host %s as mail exchanger",
+                            reply_name, reply_class, host);
+           return (NOPE);
        }
     }
     dns_rr_free(addr_list);
@@ -2259,9 +2292,7 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
                 table, value);
        msg_warn("do not specify lookup tables inside SMTPD access maps");
        msg_warn("define a restriction class and specify its name instead.");
-       longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
-                                                   451, "4.3.5",
-                                            "Server configuration error"));
+       reject_server_error(state);
     }
 
     /*
@@ -2270,9 +2301,7 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
     if (state->recursion > 100) {
        msg_warn("access table %s entry %s causes unreasonable recursion",
                 table, value);
-       longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
-                                                   451, "4.3.5",
-                                            "Server configuration error"));
+       reject_server_error(state);
     }
 
     /*
@@ -3555,9 +3584,7 @@ static int is_map_command(SMTPD_STATE *state, const char *name,
     } else if (*(*argp + 1) == 0 || strchr(*(*argp += 1), ':') == 0) {
        msg_warn("restriction %s: bad argument \"%s\": need maptype:mapname",
                 command, **argp);
-       longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
-                                                   451, "4.3.5",
-                                            "Server configuration error"));
+       reject_server_error(state);
     } else {
        return (1);
     }
@@ -3572,9 +3599,7 @@ static void forbid_whitelist(SMTPD_STATE *state, const char *name,
        msg_warn("restriction %s returns OK for %s", name, target);
        msg_warn("this is not allowed for security reasons");
        msg_warn("use DUNNO instead of OK if you want to make an exception");
-       longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
-                                                   451, "4.3.5",
-                                            "Server configuration error"));
+       reject_server_error(state);
     }
 }
 
@@ -3624,10 +3649,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
                msg_warn("specify one of (%s, %s, %s, %s, %s, %s) before %s restriction \"%s\"",
                         CHECK_CLIENT_ACL, CHECK_REVERSE_CLIENT_ACL, CHECK_HELO_ACL, CHECK_SENDER_ACL,
                         CHECK_RECIP_ACL, CHECK_ETRN_ACL, reply_class, name);
-               longjmp(smtpd_check_buf,
-                       smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
-                                          451, "4.3.5",
-                                          "Server configuration error"));
+               reject_server_error(state);
            }
            name = def_acl;
            cpp -= 1;
@@ -3663,10 +3685,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
            if (cpp[1] == 0 || strchr(cpp[1], ':') == 0) {
                msg_warn("restriction %s must be followed by transport:server",
                         CHECK_POLICY_SERVICE);
-               longjmp(smtpd_check_buf,
-                       smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
-                                          451, "4.3.5",
-                                          "Server configuration error"));
+               reject_server_error(state);
            } else
                status = check_policy_service(state, *++cpp, reply_name,
                                              reply_class, def_acl);
@@ -3683,10 +3702,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
        } else if (strcasecmp(name, SLEEP) == 0) {
            if (cpp[1] == 0 || alldig(cpp[1]) == 0) {
                msg_warn("restriction %s must be followed by number", SLEEP);
-               longjmp(smtpd_check_buf,
-                       smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
-                                          451, "4.3.5",
-                                          "Server configuration error"));
+               reject_server_error(state);
            } else
                sleep(atoi(*++cpp));
        } else if (strcasecmp(name, REJECT_PLAINTEXT_SESSION) == 0) {
@@ -3972,12 +3988,8 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
 #endif
        } else if (strcasecmp(name, PERMIT_TLS_ALL_CLIENTCERTS) == 0) {
            status = permit_tls_clientcerts(state, 1);
-           if (dict_errno != 0)
-               reject_dict_retry(state, reply_name);
        } else if (strcasecmp(name, PERMIT_TLS_CLIENTCERTS) == 0) {
            status = permit_tls_clientcerts(state, 0);
-           if (dict_errno != 0)
-               reject_dict_retry(state, reply_name);
        } else if (strcasecmp(name, REJECT_UNKNOWN_RCPTDOM) == 0) {
            if (state->recipient)
                status = reject_unknown_address(state, state->recipient,
@@ -4052,14 +4064,17 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
         */
        else {
            msg_warn("unknown smtpd restriction: \"%s\"", name);
-           longjmp(smtpd_check_buf,
-                   smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
-                                      451, "4.3.5",
-                                      "Server configuration error"));
+           reject_server_error(state);
        }
        if (msg_verbose)
            msg_info("%s: name=%s status=%d", myname, name, status);
 
+       if (status == SMTPD_CHECK_ERROR) {
+           if (dict_errno == DICT_ERR_RETRY)
+               reject_dict_retry(state, reply_name);
+           else
+               reject_server_error(state);
+       }
        if (state->warn_if_reject >= state->recursion)
            state->warn_if_reject = 0;
 
@@ -4124,10 +4139,8 @@ char   *smtpd_check_rewrite(SMTPD_STATE *state)
        }
        if (strcasecmp(name, PERMIT_INET_INTERFACES) == 0) {
            status = permit_inet_interfaces(state);
-           /* dict errors are fatal */
        } else if (strcasecmp(name, PERMIT_MYNETWORKS) == 0) {
            status = permit_mynetworks(state);
-           /* dict errors are fatal */
        } else if (is_map_command(state, name, CHECK_ADDR_MAP, &cpp)) {
            if ((dict = dict_handle(*cpp)) == 0)
                msg_panic("%s: dictionary not found: %s", myname, *cpp);
@@ -4146,24 +4159,25 @@ char   *smtpd_check_rewrite(SMTPD_STATE *state)
 #endif
        } else if (strcasecmp(name, PERMIT_TLS_ALL_CLIENTCERTS) == 0) {
            status = permit_tls_clientcerts(state, 1);
-#ifdef USE_TLS
-           if (dict_errno != 0)
-               status = SMTPD_CHECK_ERROR;
-#endif
        } else if (strcasecmp(name, PERMIT_TLS_CLIENTCERTS) == 0) {
            status = permit_tls_clientcerts(state, 0);
-#ifdef USE_TLS
-           if (dict_errno != 0)
-               status = SMTPD_CHECK_ERROR;
-#endif
        } else {
            msg_warn("parameter %s: invalid request: %s",
                     VAR_LOC_RWR_CLIENTS, name);
            continue;
        }
-       if (status < 0) {
-           state->error_mask |= MAIL_ERROR_RESOURCE;
-           return ("451 4.3.5 Server configuration error");
+       if (status == SMTPD_CHECK_ERROR) {
+           if (dict_errno == DICT_ERR_RETRY) {
+               state->error_mask |= MAIL_ERROR_RESOURCE;
+               log_whatsup(state, "reject",
+                           "451 4.3.0 Temporary lookup error");
+               return ("451 4.3.0 Temporary lookup error");
+           } else {
+               state->error_mask |= MAIL_ERROR_SOFTWARE;
+               log_whatsup(state, "reject",
+                           "451 4.3.5 Server configuration error");
+               return ("451 4.3.5 Server configuration error");
+           }
        }
        if (status == SMTPD_CHECK_OK) {
            state->rewrite_context = MAIL_ATTR_RWR_LOCAL;
@@ -5278,11 +5292,10 @@ int     main(int argc, char **argv)
     int_init();
     smtpd_check_init();
     smtpd_expand_init();
+    proto_info = inet_proto_init(argv[0], INET_PROTO_NAME_IPV4);
     smtpd_state_init(&state, VSTREAM_IN, "smtpd");
     state.queue_id = "<queue id>";
 
-    proto_info = inet_proto_init(argv[0], INET_PROTO_NAME_ALL);
-
     /*
      * Main loop: update config parameters or test the client, helo, sender
      * and recipient restrictions.
@@ -5316,8 +5329,17 @@ int     main(int argc, char **argv)
             * Emtpy line.
             */
        case 0:
+           argv_free(args);
            continue;
 
+           /*
+            * Special case: rewrite context.
+            */
+       case 1:
+           if (strcasecmp(args->argv[0], "rewrite") == 0)
+               resp = smtpd_check_rewrite(&state);
+           break;
+
            /*
             * Special case: client identity.
             */
@@ -5423,7 +5445,8 @@ int     main(int argc, char **argv)
                /* NOT: UPDATE_STRING */
                namadr_list_free(mynetworks);
                mynetworks =
-                   namadr_list_init(match_parent_style(VAR_MYNETWORKS),
+                   namadr_list_init(MATCH_FLAG_RETURN
+                                    | match_parent_style(VAR_MYNETWORKS),
                                     args->argv[1]);
                resp = 0;
                break;
@@ -5441,16 +5464,32 @@ int     main(int argc, char **argv)
                UPDATE_STRING(var_perm_mx_networks, args->argv[1]);
                domain_list_free(perm_mx_networks);
                perm_mx_networks =
-                   namadr_list_init(match_parent_style(VAR_PERM_MX_NETWORKS),
+                   namadr_list_init(MATCH_FLAG_RETURN
+                                | match_parent_style(VAR_PERM_MX_NETWORKS),
                                     args->argv[1]);
                resp = 0;
                break;
            }
+#ifdef USE_TLS
+           if (strcasecmp(args->argv[0], VAR_RELAY_CCERTS) == 0) {
+               UPDATE_STRING(var_smtpd_relay_ccerts, args->argv[1]);
+               UPDATE_MAPS(relay_ccerts, VAR_RELAY_CCERTS,
+                           var_smtpd_relay_ccerts, DICT_FLAG_LOCK
+                           | DICT_FLAG_FOLD_FIX);
+               resp = 0;
+           }
+#endif
            if (strcasecmp(args->argv[0], "restriction_class") == 0) {
                rest_class(args->argv[1]);
                resp = 0;
                break;
            }
+           if (strcasecmp(args->argv[0], VAR_LOC_RWR_CLIENTS) == 0) {
+               UPDATE_STRING(var_local_rwr_clients, args->argv[1]);
+               argv_free(local_rewrite_clients);
+               local_rewrite_clients = smtpd_check_parse(SMTPD_CHECK_PARSE_MAPS,
+                                                    var_local_rwr_clients);
+           }
            if (int_update(args->argv)
                || string_update(args->argv)
                || rest_update(args->argv)) {
@@ -5483,6 +5522,24 @@ int     main(int argc, char **argv)
                state.where = "RCPT";
                TRIM_ADDR(args->argv[1], addr);
                resp = smtpd_check_rcpt(&state, addr);
+#ifdef USE_TLS
+           } else if (strcasecmp(args->argv[0], "fingerprint") == 0) {
+               if (state.tls_context == 0) {
+                   state.tls_context =
+                       (TLS_SESS_STATE *) mymalloc(sizeof(*state.tls_context));
+                   memset((char *) state.tls_context, 0,
+                          sizeof(*state.tls_context));
+                   state.tls_context->peer_fingerprint =
+                       state.tls_context->peer_pkey_fprint = 0;
+               }
+               state.tls_context->peer_status |= TLS_CERT_FLAG_PRESENT;
+               UPDATE_STRING(state.tls_context->peer_fingerprint,
+                             args->argv[1]);
+               state.tls_context->peer_pkey_fprint =
+                   state.tls_context->peer_fingerprint;
+               resp = "OK";
+               break;
+#endif
            }
            break;
 
@@ -5520,6 +5577,10 @@ int     main(int argc, char **argv)
 #define FREE_STRING(s) { if (s) myfree(s); }
     FREE_STRING(state.helo_name);
     FREE_STRING(state.sender);
+    if (state.tls_context) {
+       FREE_STRING(state.tls_context->peer_fingerprint);
+       myfree((char *) state.tls_context);
+    }
     exit(0);
 }
 
diff --git a/postfix/src/smtpd/smtpd_error.in b/postfix/src/smtpd/smtpd_error.in
new file mode 100644 (file)
index 0000000..257a895
--- /dev/null
@@ -0,0 +1,67 @@
+#
+# Initialize
+#
+smtpd_delay_reject 0
+#
+# Test check_domain_access()
+#
+helo_restrictions fail:1_helo_access
+# Expect: REJECT (temporary lookup failure)
+helo foobar
+#
+# Test check_namadr_access()
+#
+client_restrictions fail:1_client_access
+# Expect: REJECT (temporary lookup failure)
+client foo.dunno.com 131.155.210.17
+#
+# Test check_mail_access()
+#
+sender_restrictions fail:1_sender_access
+# Expect: REJECT (temporary lookup failure)
+mail reject@dunno.domain
+#
+# Test check_rcpt_access()
+#
+recipient_restrictions fail:1_rcpt_access
+# Expect: REJECT (temporary lookup failure)
+rcpt reject@dunno.domain
+# Expect: OK
+rcpt postmaster
+#
+# Test mynetworks in generic_checks().
+#
+mynetworks fail:1_mynetworks
+#
+# Expect REJECT (temporary lookup failure)
+#
+recipient_restrictions permit_mynetworks
+rcpt reject@dunno.domain
+# 
+# Test mynetworks. 
+#
+mynetworks 168.100.189.1/27
+#
+# Expect REJECT (server configuration error)
+#
+rcpt reject@dunno.domain
+#
+# check_sender_access specific
+#
+smtpd_null_access_lookup_key <> 
+mail <>
+#
+# Test permit_tls_client_certs in generic_restrictions
+#
+relay_clientcerts fail:1_certs
+fingerprint abcdef
+recipient_restrictions permit_tls_clientcerts
+rcpt reject@dunno.domain
+#
+# Test smtpd_check_rewrite().
+#
+local_header_rewrite_clients fail:1_rewrite
+#
+# Expect: REJECT (temporary lookup failure)
+#
+rewrite
diff --git a/postfix/src/smtpd/smtpd_error.ref b/postfix/src/smtpd/smtpd_error.ref
new file mode 100644 (file)
index 0000000..cb2448c
--- /dev/null
@@ -0,0 +1,108 @@
+>>> #
+>>> # Initialize
+>>> #
+>>> smtpd_delay_reject 0
+OK
+>>> #
+>>> # Test check_domain_access()
+>>> #
+>>> helo_restrictions fail:1_helo_access
+OK
+>>> # Expect: REJECT (temporary lookup failure)
+>>> helo foobar
+./smtpd_check: warning: fail:1_helo_access: table lookup problem
+./smtpd_check: <queue id>: reject: HELO from localhost[127.0.0.1]: 451 4.3.5 <foobar>: Helo command rejected: Server configuration error; proto=SMTP helo=<foobar>
+451 4.3.5 <foobar>: Helo command rejected: Server configuration error
+>>> #
+>>> # Test check_namadr_access()
+>>> #
+>>> client_restrictions fail:1_client_access
+OK
+>>> # Expect: REJECT (temporary lookup failure)
+>>> client foo.dunno.com 131.155.210.17
+./smtpd_check: warning: fail:1_client_access: table lookup problem
+./smtpd_check: <queue id>: reject: CONNECT from foo.dunno.com[131.155.210.17]: 451 4.3.5 <foo.dunno.com[131.155.210.17]>: Client host rejected: Server configuration error; proto=SMTP helo=<foobar>
+451 4.3.5 <foo.dunno.com[131.155.210.17]>: Client host rejected: Server configuration error
+>>> #
+>>> # Test check_mail_access()
+>>> #
+>>> sender_restrictions fail:1_sender_access
+OK
+>>> # Expect: REJECT (temporary lookup failure)
+>>> mail reject@dunno.domain
+./smtpd_check: warning: fail:1_sender_access: table lookup problem
+./smtpd_check: <queue id>: reject: MAIL from foo.dunno.com[131.155.210.17]: 451 4.3.5 <reject@dunno.domain>: Sender address rejected: Server configuration error; from=<reject@dunno.domain> proto=SMTP helo=<foobar>
+451 4.3.5 <reject@dunno.domain>: Sender address rejected: Server configuration error
+>>> #
+>>> # Test check_rcpt_access()
+>>> #
+>>> recipient_restrictions fail:1_rcpt_access
+OK
+>>> # Expect: REJECT (temporary lookup failure)
+>>> rcpt reject@dunno.domain
+./smtpd_check: warning: fail:1_rcpt_access: table lookup problem
+./smtpd_check: <queue id>: reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.5 <reject@dunno.domain>: Recipient address rejected: Server configuration error; from=<reject@dunno.domain> to=<reject@dunno.domain> proto=SMTP helo=<foobar>
+451 4.3.5 <reject@dunno.domain>: Recipient address rejected: Server configuration error
+>>> # Expect: OK
+>>> rcpt postmaster
+OK
+>>> #
+>>> # Test mynetworks in generic_checks().
+>>> #
+>>> mynetworks fail:1_mynetworks
+OK
+>>> #
+>>> # Expect REJECT (temporary lookup failure)
+>>> #
+>>> recipient_restrictions permit_mynetworks
+OK
+>>> rcpt reject@dunno.domain
+./smtpd_check: warning: fail:1_mynetworks(0,lock|fold_fix): table lookup problem
+./smtpd_check: <queue id>: reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.0 <reject@dunno.domain>: Temporary lookup failure; from=<reject@dunno.domain> to=<reject@dunno.domain> proto=SMTP helo=<foobar>
+451 4.3.0 <reject@dunno.domain>: Temporary lookup failure
+>>> # 
+>>> # Test mynetworks. 
+>>> #
+>>> mynetworks 168.100.189.1/27
+OK
+>>> #
+>>> # Expect REJECT (server configuration error)
+>>> #
+>>> rcpt reject@dunno.domain
+./smtpd_check: warning: non-null host address bits in "168.100.189.1/27", perhaps you should use "168.100.189.0/27" instead
+./smtpd_check: <queue id>: reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.5 Server configuration error; from=<reject@dunno.domain> to=<reject@dunno.domain> proto=SMTP helo=<foobar>
+451 4.3.5 Server configuration error
+>>> #
+>>> # check_sender_access specific
+>>> #
+>>> smtpd_null_access_lookup_key <> 
+OK
+>>> mail <>
+./smtpd_check: warning: fail:1_sender_access: table lookup problem
+./smtpd_check: <queue id>: reject: MAIL from foo.dunno.com[131.155.210.17]: 451 4.3.5 <>: Sender address rejected: Server configuration error; from=<> proto=SMTP helo=<foobar>
+451 4.3.5 <>: Sender address rejected: Server configuration error
+>>> #
+>>> # Test permit_tls_client_certs in generic_restrictions
+>>> #
+>>> relay_clientcerts fail:1_certs
+OK
+>>> fingerprint abcdef
+OK
+>>> recipient_restrictions permit_tls_clientcerts
+OK
+>>> rcpt reject@dunno.domain
+./smtpd_check: warning: relay_clientcerts: lookup error for fingerprint 'abcdef', pkey fingerprint abcdef
+./smtpd_check: <queue id>: reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.0 <reject@dunno.domain>: Temporary lookup failure; from=<> to=<reject@dunno.domain> proto=SMTP helo=<foobar>
+451 4.3.0 <reject@dunno.domain>: Temporary lookup failure
+>>> #
+>>> # Test smtpd_check_rewrite().
+>>> #
+>>> local_header_rewrite_clients fail:1_rewrite
+OK
+>>> #
+>>> # Expect: REJECT (temporary lookup failure)
+>>> #
+>>> rewrite
+./smtpd_check: warning: local_header_rewrite_clients: fail:1_rewrite: lookup error
+./smtpd_check: <queue id>: reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.0 Temporary lookup error; from=<> proto=SMTP helo=<foobar>
+451 4.3.0 Temporary lookup error
index 5ed42a4d8909a00b0ac0a2dfd063e4d37d7753bb..4613bc2df7a1cdfa1060b002f96876e755277424 100644 (file)
 /*     void    argv_truncate(argvp, len);
 /*     ARGV    *argvp;
 /*     ssize_t len;
+/*
+/*     void    ARGV_FAKE_BEGIN(argv, arg)
+/*     const char *arg;
+/*
+/*     void    ARGV_FAKE_END
 /* DESCRIPTION
 /*     The functions in this module manipulate arrays of string
 /*     pointers. An ARGV structure contains the following members:
 /*     argv_truncate() trucates its argument to the specified
 /*     number of entries, but does not reallocate memory. The
 /*     result is null-terminated.
+/*
+/*     ARGV_FAKE_BEGIN/END are an optimization for the case where
+/*     a single string needs to be passed into an ARGV-based
+/*     interface.  ARGV_FAKE_BEGIN() opens a statement block and
+/*     allocates a stack-based ARGV structure named after the first
+/*     argument, that encapsulates the second argument.  This
+/*     implementation allocates no heap memory and creates no copy
+/*     of the second argument.  ARGV_FAKE_END closes the statement
+/*     block and thereby releases storage.
 /* SEE ALSO
 /*     msg(3) diagnostics interface
 /* DIAGNOSTICS
index b039fbb72d3e97a8e04286761b392b8fdc4c8c3b..17f006a39427700967ff1f510673cd8ff484a84c 100644 (file)
@@ -31,6 +31,16 @@ extern ARGV *argv_split(const char *, const char *);
 extern ARGV *argv_split_count(const char *, const char *, ssize_t);
 extern ARGV *argv_split_append(ARGV *, const char *, const char *);
 
+#define ARGV_FAKE_BEGIN(fake_argv, arg) { \
+       ARGV fake_argv; \
+       char *__fake_argv_args__[2]; \
+       __fake_argv_args__[0] = (char *) (arg); \
+       __fake_argv_args__[1] = 0; \
+       fake_argv.argv = __fake_argv_args__; \
+       fake_argv.argc = fake_argv.len = 1;
+
+#define ARGV_FAKE_END  }
+
 #define ARGV_END       ((char *) 0)
 
 /* LICENSE
index b72b8db3e1555845d4497c040500a8c3d82d1527..9ca016b957eb318c43b61e65080f6115947248e8 100644 (file)
@@ -140,6 +140,10 @@ VSTRING *cidr_match_parse(CIDR_MATCH *ip, char *pattern, VSTRING *why)
     MAI_HOSTADDR_STR hostaddr;
     unsigned char *np;
     unsigned char *mp;
+    static VSTRING *buf;
+
+#define WHY_OR_BUF (why ? why : buf ? (why = buf) : \
+                   (why = buf = vstring_alloc(20)))
 
     /*
      * Strip [] from [addr/len] or [addr]/len, destroying the pattern. CIDR
@@ -150,13 +154,12 @@ VSTRING *cidr_match_parse(CIDR_MATCH *ip, char *pattern, VSTRING *why)
     if (*pattern == '[') {
        pattern++;
        if ((mask_search = split_at(pattern, ']')) == 0) {
-           vstring_sprintf(why ? why : (why = vstring_alloc(20)),
+           vstring_sprintf(WHY_OR_BUF,
                            "missing ']' character after \"[%s\"", pattern);
            return (why);
        } else if (*mask_search != '/') {
            if (*mask_search != 0) {
-               vstring_sprintf(why ? why : (why = vstring_alloc(20)),
-                               "garbage after \"[%s]\"", pattern);
+               vstring_sprintf(WHY_OR_BUF, "garbage after \"[%s]\"", pattern);
                return (why);
            }
            mask_search = pattern;
@@ -174,7 +177,7 @@ VSTRING *cidr_match_parse(CIDR_MATCH *ip, char *pattern, VSTRING *why)
        if (!alldig(mask)
            || (ip->mask_shift = atoi(mask)) > ip->addr_bit_count
            || inet_pton(ip->addr_family, pattern, ip->net_bytes) != 1) {
-           vstring_sprintf(why ? why : (why = vstring_alloc(20)),
+           vstring_sprintf(WHY_OR_BUF,
                          "bad net/mask pattern: \"%s/%s\"", pattern, mask);
            return (why);
        }
@@ -195,7 +198,7 @@ VSTRING *cidr_match_parse(CIDR_MATCH *ip, char *pattern, VSTRING *why)
                if (inet_ntop(ip->addr_family, ip->net_bytes, hostaddr.buf,
                              sizeof(hostaddr.buf)) == 0)
                    msg_fatal("inet_ntop: %m");
-               vstring_sprintf(why ? why : (why = vstring_alloc(20)),
+               vstring_sprintf(WHY_OR_BUF,
                                "non-null host address bits in \"%s/%s\", "
                                "perhaps you should use \"%s/%d\" instead",
                                pattern, mask, hostaddr.buf, ip->mask_shift);
@@ -212,8 +215,7 @@ VSTRING *cidr_match_parse(CIDR_MATCH *ip, char *pattern, VSTRING *why)
        ip->addr_bit_count = CIDR_MATCH_ADDR_BIT_COUNT(ip->addr_family);
        ip->addr_byte_count = CIDR_MATCH_ADDR_BYTE_COUNT(ip->addr_family);
        if (inet_pton(ip->addr_family, pattern, ip->net_bytes) != 1) {
-           vstring_sprintf(why ? why : (why = vstring_alloc(20)),
-                           "bad address pattern: \"%s\"", pattern);
+           vstring_sprintf(WHY_OR_BUF, "bad address pattern: \"%s\"", pattern);
            return (why);
        }
        ip->mask_shift = ip->addr_bit_count;
index 197f61ed5e815fc04fbe79bc4bd01a1edc72ef7b..b0ad3f2c573eedcb089fcf02a6c1ae06965e0d33 100644 (file)
@@ -109,6 +109,8 @@ DICT   *dict_fail_open(const char *name, int open_flags, int dict_flags)
     dp->dict.close = dict_fail_close;
     dp->dict.flags = dict_flags | DICT_FLAG_PATTERN;
     dp->dict_errno = atoi(name);
+    if (dp->dict_errno == 0)
+       dp->dict_errno = 1;
     dp->dict.owner.status = DICT_OWNER_TRUSTED;
     return (DICT_DEBUG (&dp->dict));
 }
index b63ac5ccf0897c06fabe63d868ed974b00a0a170..6f76dafe77c3fd5ba920d89bdf49eae5a75925ed 100644 (file)
@@ -209,12 +209,13 @@ int     match_list_match(MATCH_LIST *list,...)
        list->match_args[i] = va_arg(ap, const char *);
     va_end(ap);
 
+    dict_errno = 0;
     for (cpp = list->patterns->argv; (pat = *cpp) != 0; cpp++) {
        for (match = 1; *pat == '!'; pat++)
            match = !match;
        for (i = 0; i < list->match_count; i++)
            if ((rc = list->match_func[i] (list->flags,
-                                           list->match_args[i], pat)) > 0)
+                                          list->match_args[i], pat)) > 0)
                return (match);
            else if (rc < 0)
                return (rc);
index e8c8142f597593ff66aa80d7d60e592d91d02de3..a98b8c08903c4cb4cf7d45231622f61bbb766acf 100644 (file)
 /* DESCRIPTION
 /* .nf
 
- /* External interface. */
+ /*
+  * External interface.
+  */
 
+ /*
+  * This is what the caller specifies.
+  */
 #define MATCH_FLAG_NONE                0
 #define MATCH_FLAG_PARENT      (1<<0)
 #define MATCH_FLAG_RETURN      (1<<1)
+
+ /*
+  * This is for internal use.
+  */
 #define MATCH_FLAG_ALL         (MATCH_FLAG_PARENT | MATCH_FLAG_RETURN)
 
-#define MATCH_ERR_TEMP         (-1)    /* temporary error, e.g., database */
-#define MATCH_ERR_PERM         (-2)    /* permanent error, e.g., syntax */
+ /*
+  * Some errors cannot be signaled as (result == 0, dict_errno > 0).
+  * Therefore we signal all errors as (result < 0).
+  */
+#define MATCH_ERR_TEMP         (-1)    /* e.g., database is down */
+#define MATCH_ERR_PERM         (-2)    /* e.g., net/mask syntax */
 
 extern int match_string(int, const char *, const char *);
 extern int match_hostname(int, const char *, const char *);
index 6d11dd3ef20578b8d2d3259942428a94702202fa..ee4615504bcaa22b367da93a53b80480e32b7a97 100644 (file)
@@ -240,7 +240,8 @@ int     name_mask_delim_opt(const char *context, const NAME_MASK *table,
                } else if (flags & NAME_MASK_RETURN) {
                    msg_warn("unknown %s value \"%s\" in \"%s\"",
                             context, name, names);
-                   return (0);
+                   result = 0;
+                   break;
                } else if (flags & NAME_MASK_WARN) {
                    msg_warn("unknown %s value \"%s\" in \"%s\"",
                             context, name, names);