From: Wietse Venema Date: Wed, 21 Dec 2011 05:00:00 +0000 (-0500) Subject: postfix-2.9-20111221 X-Git-Tag: v2.9.0-RC1~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=872acb8b5d85684cca4ecdc31d153fd071046e17;p=thirdparty%2Fpostfix.git postfix-2.9-20111221 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index ea798e676..e68ebd443 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -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. diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 3812da471..9e650de0b 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -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 diff --git a/postfix/src/global/server_acl.c b/postfix/src/global/server_acl.c index 03b602dab..8767fa470 100644 --- a/postfix/src/global/server_acl.c +++ b/postfix/src/global/server_acl.c @@ -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); diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index 95d0ac4f0..2a26b77c1 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -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_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 \ diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 59415c85f..1b3f053c7 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -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. diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index b23c3c168..f5beaf46c 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -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 = ""; - 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 index 000000000..257a89522 --- /dev/null +++ b/postfix/src/smtpd/smtpd_error.in @@ -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 index 000000000..cb2448c39 --- /dev/null +++ b/postfix/src/smtpd/smtpd_error.ref @@ -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: : reject: HELO from localhost[127.0.0.1]: 451 4.3.5 : Helo command rejected: Server configuration error; proto=SMTP helo= +451 4.3.5 : 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: : reject: CONNECT from foo.dunno.com[131.155.210.17]: 451 4.3.5 : Client host rejected: Server configuration error; proto=SMTP helo= +451 4.3.5 : 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: : reject: MAIL from foo.dunno.com[131.155.210.17]: 451 4.3.5 : Sender address rejected: Server configuration error; from= proto=SMTP helo= +451 4.3.5 : 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: : reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.5 : Recipient address rejected: Server configuration error; from= to= proto=SMTP helo= +451 4.3.5 : 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: : reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.0 : Temporary lookup failure; from= to= proto=SMTP helo= +451 4.3.0 : 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: : reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.5 Server configuration error; from= to= proto=SMTP helo= +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: : reject: MAIL from foo.dunno.com[131.155.210.17]: 451 4.3.5 <>: Sender address rejected: Server configuration error; from=<> proto=SMTP helo= +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: : reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.0 : Temporary lookup failure; from=<> to= proto=SMTP helo= +451 4.3.0 : 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: : reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.0 Temporary lookup error; from=<> proto=SMTP helo= +451 4.3.0 Temporary lookup error diff --git a/postfix/src/util/argv.c b/postfix/src/util/argv.c index 5ed42a4d8..4613bc2df 100644 --- a/postfix/src/util/argv.c +++ b/postfix/src/util/argv.c @@ -27,6 +27,11 @@ /* 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: @@ -57,6 +62,15 @@ /* 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 diff --git a/postfix/src/util/argv.h b/postfix/src/util/argv.h index b039fbb72..17f006a39 100644 --- a/postfix/src/util/argv.h +++ b/postfix/src/util/argv.h @@ -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 diff --git a/postfix/src/util/cidr_match.c b/postfix/src/util/cidr_match.c index b72b8db3e..9ca016b95 100644 --- a/postfix/src/util/cidr_match.c +++ b/postfix/src/util/cidr_match.c @@ -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; diff --git a/postfix/src/util/dict_fail.c b/postfix/src/util/dict_fail.c index 197f61ed5..b0ad3f2c5 100644 --- a/postfix/src/util/dict_fail.c +++ b/postfix/src/util/dict_fail.c @@ -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)); } diff --git a/postfix/src/util/match_list.c b/postfix/src/util/match_list.c index b63ac5ccf..6f76dafe7 100644 --- a/postfix/src/util/match_list.c +++ b/postfix/src/util/match_list.c @@ -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); diff --git a/postfix/src/util/match_ops.h b/postfix/src/util/match_ops.h index e8c8142f5..a98b8c089 100644 --- a/postfix/src/util/match_ops.h +++ b/postfix/src/util/match_ops.h @@ -11,15 +11,28 @@ /* 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 *); diff --git a/postfix/src/util/name_mask.c b/postfix/src/util/name_mask.c index 6d11dd3ef..ee4615504 100644 --- a/postfix/src/util/name_mask.c +++ b/postfix/src/util/name_mask.c @@ -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);