From: Wietse Venema Date: Sun, 1 Jan 2017 05:00:00 +0000 (-0500) Subject: postfix-3.0.8 X-Git-Tag: v3.0.8^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7362341304dd07c0afbcec48ae83a4420d899321;p=thirdparty%2Fpostfix.git postfix-3.0.8 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index f057cb585..0c5caedf7 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -21762,6 +21762,32 @@ Apologies for any names omitted. Portability: OpenBSD 6.0. Files: makedefs, util/sys_defs.h. +20160618 + + Bugfix (introduced: 20091121): with the introduction of + sender_dependent_default_transport_maps, the SMTP daemon + was not updated. This resulted in false rejects with + sender-dependent "error" transports. Based on a fix by + Russell Yanofsky. Files: global/resolve_clnt.c, + global/resolve_clnt.h, smtpd/smtpd_check.c, smtpd/smtpd_check.h, + smtpd/smtpd_milter.c, smtpd/smtpd_resolve.c, smtpd/smtpd_resolve.h. + +20160717 + + Bugfix (introduced: Postfix 1.1): the virtual(8) delivery + agent discarded the error result from vstream_fseek(). + File: virtual/mailbox.c. + +20160730 + + Bugfix (introduced: 20090614): with concurrent connections + from the same client IP address, and after-220 tests enabled, + postscreen could overwrite the cached "all tests completed" + result of one connection that completed the after-220 tests, + with the "some tests not completed" result of a concurrent + connection where the client hung up later, without completing + the after-220 tests. + 20160819 Bugfix (introduced: Postfix 3.0): the makedefs script ignored @@ -21796,3 +21822,24 @@ Apologies for any names omitted. UTF8-encoded text, specify "option_group = client" in Postfix MySQL configuration files. This will be the default setting with Postfix 3.2 and later. + +20161105 + + Bugfix (introduced: Postfix 1.1): the postsuper command did + not count a successful rename operation after error recovery. + Problem reported by Markus Schönhaber. File: postsuper/postsuper.c. + +20161206 + + Bugfix (introduced: Postfix 3.0): when receiving a MAIL + FROM...SMTPUTF8 command while smtpd_delay_reject=no, enable + SMTPUTF8 support before processing smtpd_sender_restrictions. + Problem reported by Viktor Dukhovni. File: smtpd/smtpd.c. + +20161220 + + Bugfix (introduced: Postfix 2.1.0): the Postfix SMTP daemon + did not query sender_canonical_maps when rejecting unknown + senders with "smtpd_reject_unlisted_recipient = yes" or + with reject_unlisted_sender. Stephen R. van den Berg (Mr. + procmail). Files: smtpd/smtpd.c, smtpd/smtpd_check.c. diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index d1664d5e9..49a683909 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -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 "20161001" -#define MAIL_VERSION_NUMBER "3.0.7" +#define MAIL_RELEASE_DATE "20170101" +#define MAIL_VERSION_NUMBER "3.0.8" #ifdef SNAPSHOT #define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE diff --git a/postfix/src/postscreen/postscreen.c b/postfix/src/postscreen/postscreen.c index e4ea94cb6..6bfd76d8c 100644 --- a/postfix/src/postscreen/postscreen.c +++ b/postfix/src/postscreen/postscreen.c @@ -760,6 +760,7 @@ static void psc_endpt_lookup_done(int endpt_status, * valid. */ if ((state->flags & PSC_STATE_MASK_ANY_FAIL) == 0 + && state->client_info->concurrency == 1 && psc_cache_map != 0 && (stamp_str = psc_cache_lookup(psc_cache_map, state->smtp_client_addr)) != 0) { saved_flags = state->flags; @@ -773,6 +774,13 @@ static void psc_endpt_lookup_done(int endpt_status, psc_conclude(state); return; } + } else if (state->client_info->concurrency > 1) { + saved_flags = state->flags; + psc_todo_tests(state, event_time()); + state->flags |= saved_flags; + if (msg_verbose) + msg_info("%s: new + recent flags: %s", + myname, psc_print_state_flags(state->flags, myname)); } else { saved_flags = state->flags; psc_new_tests(state); @@ -824,6 +832,7 @@ static int psc_cache_validator(const char *client_addr, void *unused_context) { PSC_STATE dummy; + PSC_CLIENT_INFO dummy_client_info; /* * This function is called by the cache cleanup pseudo thread. @@ -833,6 +842,7 @@ static int psc_cache_validator(const char *client_addr, * silly logging we remove the cache entry only after all tests have * expired longer ago than the cache retention time. */ + dummy.client_info = &dummy_client_info; psc_parse_tests(&dummy, stamp_str, event_time() - var_psc_cache_ret); return ((dummy.flags & PSC_STATE_MASK_ANY_TODO) == 0); } diff --git a/postfix/src/postscreen/postscreen.h b/postfix/src/postscreen/postscreen.h index 130b52770..69971072a 100644 --- a/postfix/src/postscreen/postscreen.h +++ b/postfix/src/postscreen/postscreen.h @@ -54,6 +54,15 @@ #define PSC_TINDX_BYTNAME(tname) (PSC_TINDX_ ## tname) + /* + * Per-client shared state. + */ +typedef struct { + int concurrency; /* per-client */ + int pass_new_count; /* per-client */ + time_t expire_time[PSC_TINDX_COUNT]; /* per-test expiration */ +} PSC_CLIENT_INFO; + /* * Per-session state. */ @@ -66,13 +75,12 @@ typedef struct { char *smtp_client_port; /* client port */ char *smtp_server_addr; /* server address */ char *smtp_server_port; /* server port */ - int client_concurrency; /* per-client */ const char *final_reply; /* cause for hanging up */ VSTRING *send_buf; /* pending output */ /* Test context. */ struct timeval start_time; /* start of current test */ const char *test_name; /* name of current test */ - time_t expire_time[PSC_TINDX_COUNT]; /* per-test expiration */ + PSC_CLIENT_INFO *client_info; /* shared client state */ VSTRING *dnsbl_reply; /* dnsbl reject text */ int dnsbl_score; /* saved DNSBL score */ const char *dnsbl_name; /* DNSBL name with largest weight */ @@ -94,11 +102,14 @@ typedef struct { * Emulate legacy ad-hoc variables on top of indexable time stamps. This * avoids massive scar tissue during initial feature development. */ -#define pregr_stamp expire_time[PSC_TINDX_PREGR] -#define dnsbl_stamp expire_time[PSC_TINDX_DNSBL] -#define pipel_stamp expire_time[PSC_TINDX_PIPEL] -#define nsmtp_stamp expire_time[PSC_TINDX_NSMTP] -#define barlf_stamp expire_time[PSC_TINDX_BARLF] +#define pregr_stamp client_info->expire_time[PSC_TINDX_PREGR] +#define dnsbl_stamp client_info->expire_time[PSC_TINDX_DNSBL] +#define pipel_stamp client_info->expire_time[PSC_TINDX_PIPEL] +#define nsmtp_stamp client_info->expire_time[PSC_TINDX_NSMTP] +#define barlf_stamp client_info->expire_time[PSC_TINDX_BARLF] + + /* Minize the patch size for stable releases. */ +#define client_concurrency client_info->concurrency /* * Special expiration time values. @@ -489,17 +500,21 @@ extern int psc_dnsbl_request(const char *, void (*) (int, void *), void *); #define PSC_INIT_TESTS(dst) do { \ time_t *_it_stamp_p; \ (dst)->flags = 0; \ - for (_it_stamp_p = (dst)->expire_time; \ - _it_stamp_p < (dst)->expire_time + PSC_TINDX_COUNT; \ + for (_it_stamp_p = (dst)->client_info->expire_time; \ + _it_stamp_p < (dst)->client_info->expire_time + PSC_TINDX_COUNT; \ _it_stamp_p++) \ *_it_stamp_p = PSC_TIME_STAMP_INVALID; \ } while (0) +#define PSC_INIT_TEST_FLAGS_ONLY(dst) do { \ + (dst)->flags = 0; \ + } while (0) #define PSC_BEGIN_TESTS(state, name) do { \ (state)->test_name = (name); \ GETTIMEOFDAY(&(state)->start_time); \ } while (0) extern void psc_new_tests(PSC_STATE *); extern void psc_parse_tests(PSC_STATE *, const char *, time_t); +extern void psc_todo_tests(PSC_STATE *, time_t); extern char *psc_print_tests(VSTRING *, PSC_STATE *); extern char *psc_print_grey_key(VSTRING *, const char *, const char *, const char *, const char *); diff --git a/postfix/src/postscreen/postscreen_early.c b/postfix/src/postscreen/postscreen_early.c index e46487bcb..267f0825f 100644 --- a/postfix/src/postscreen/postscreen_early.c +++ b/postfix/src/postscreen/postscreen_early.c @@ -87,8 +87,8 @@ static void psc_whitelist_non_dnsbl(PSC_STATE *state) state->flags |= PSC_STATE_FLAG_BYTINDX_PASS(tindx); } /* Update expiration even if the test was completed or disabled. */ - if (state->expire_time[tindx] < now + var_psc_dnsbl_ttl) - state->expire_time[tindx] = now + var_psc_dnsbl_ttl; + if (state->client_info->expire_time[tindx] < now + var_psc_dnsbl_ttl) + state->client_info->expire_time[tindx] = now + var_psc_dnsbl_ttl; } } } diff --git a/postfix/src/postscreen/postscreen_misc.c b/postfix/src/postscreen/postscreen_misc.c index 57a1bb67d..d54b24f9d 100644 --- a/postfix/src/postscreen/postscreen_misc.c +++ b/postfix/src/postscreen/postscreen_misc.c @@ -105,13 +105,17 @@ void psc_conclude(PSC_STATE *state) if ((state->flags & PSC_STATE_MASK_ANY_PASS) != 0 && (state->flags & PSC_STATE_MASK_ANY_PASS) == PSC_STATE_FLAGS_TODO_TO_PASS(state->flags & PSC_STATE_MASK_ANY_TODO)) - msg_info("PASS %s [%s]:%s", (state->flags & PSC_STATE_FLAG_NEW) == 0 ? + msg_info("PASS %s [%s]:%s", (state->flags & PSC_STATE_FLAG_NEW) == 0 + || state->client_info->pass_new_count++ > 0 ? "OLD" : "NEW", PSC_CLIENT_ADDR_PORT(state)); /* * Update the postscreen cache. This still supports a scenario where a * client gets whitelisted in the course of multiple sessions, as long as - * that client does not "fail" any test. + * that client does not "fail" any test. Don't try to optimize away cache + * updates; we want cached information to be up-to-date even if a test + * result is renewed during overlapping SMTP sessions, and even if + * 'postfix reload' happens in the middle of that. */ if ((state->flags & PSC_STATE_MASK_ANY_UPDATE) != 0 && psc_cache_map != 0) { diff --git a/postfix/src/postscreen/postscreen_state.c b/postfix/src/postscreen/postscreen_state.c index 946afd6fa..b84f6656b 100644 --- a/postfix/src/postscreen/postscreen_state.c +++ b/postfix/src/postscreen/postscreen_state.c @@ -61,7 +61,8 @@ /* psc_new_session_state() creates a new session state object /* for the specified client stream, and increments the /* psc_check_queue_length counter. The flags and per-test time -/* stamps are initialized with PSC_INIT_TESTS(). The addr and +/* stamps are initialized with PSC_INIT_TESTS(), or for concurrent +/* sessions, with PSC_INIT_TEST_FLAGS_ONLY(). The addr and /* port arguments are null-terminated strings with the remote /* SMTP client endpoint. The _reply members are set to /* polite "try again" SMTP replies. The protocol member is set @@ -149,10 +150,8 @@ PSC_STATE *psc_new_session_state(VSTREAM *stream, const char *server_port) { PSC_STATE *state; - HTABLE_INFO *ht; state = (PSC_STATE *) mymalloc(sizeof(*state)); - PSC_INIT_TESTS(state); if ((state->smtp_client_stream = stream) != 0) psc_check_queue_length++; state->smtp_server_fd = (-1); @@ -188,10 +187,19 @@ PSC_STATE *psc_new_session_state(VSTREAM *stream, /* * Update the per-client session count. */ - if ((ht = htable_locate(psc_client_concurrency, client_addr)) == 0) - ht = htable_enter(psc_client_concurrency, client_addr, (void *) 0); - ht->value += 1; - state->client_concurrency = CAST_ANY_PTR_TO_INT(ht->value); + if ((state->client_info = (PSC_CLIENT_INFO *) + htable_find(psc_client_concurrency, client_addr)) == 0) { + state->client_info = (PSC_CLIENT_INFO *) + mymalloc(sizeof(state->client_info[0])); + (void) htable_enter(psc_client_concurrency, client_addr, + (void *) state->client_info); + PSC_INIT_TESTS(state); + state->client_info->concurrency = 1; + state->client_info->pass_new_count = 0; + } else { + PSC_INIT_TEST_FLAGS_ONLY(state); + state->client_info->concurrency += 1; + } return (state); } @@ -210,9 +218,8 @@ void psc_free_session_state(PSC_STATE *state) state->smtp_client_addr)) == 0) msg_panic("%s: unknown client address: %s", myname, state->smtp_client_addr); - if (--(ht->value) == 0) - htable_delete(psc_client_concurrency, state->smtp_client_addr, - (void (*) (void *)) 0); + if (--(state->client_info->concurrency) == 0) + htable_delete(psc_client_concurrency, state->smtp_client_addr, myfree); if (state->smtp_client_stream != 0) { event_server_disconnect(state->smtp_client_stream); diff --git a/postfix/src/postscreen/postscreen_tests.c b/postfix/src/postscreen/postscreen_tests.c index 17b7a3926..f8b92a988 100644 --- a/postfix/src/postscreen/postscreen_tests.c +++ b/postfix/src/postscreen/postscreen_tests.c @@ -17,6 +17,11 @@ /* const char *stamp_text; /* time_t time_value; /* +/* void psc_todo_tests(state, time_value) +/* PSC_STATE *state; +/* const char *stamp_text; +/* time_t time_value; +/* /* char *psc_print_tests(buffer, state) /* VSTRING *buffer; /* PSC_STATE *state; @@ -41,13 +46,18 @@ /* zeroes all the flags bits. These values are not meant to /* be stored into the postscreen(8) cache. /* +/* PSC_INIT_TEST_FLAGS_ONLY() zeroes all the flag bits. It +/* should be used when the time stamps are already initialized. +/* /* psc_new_tests() sets all test expiration time stamps to -/* PSC_TIME_STAMP_NEW, and overwrites all flags bits. Only -/* enabled tests are flagged with PSC_STATE_FLAG_TODO; the -/* object is flagged with PSC_STATE_FLAG_NEW. +/* PSC_TIME_STAMP_NEW, and invokes psc_todo_tests(). +/* +/* psc_parse_tests() parses a cache file record and invokes +/* psc_todo_tests(). /* -/* psc_parse_tests() parses a cache file record and overwrites -/* all flags bits. Tests are considered "expired" when they +/* psc_todo_tests() overwrites all per-session flag bits, and +/* populates the flags based on test expiration time stamp +/* information. Tests are considered "expired" when they /* would be expired at the specified time value. Only enabled /* tests are flagged as "expired"; the object is flagged as /* "new" if some enabled tests have "new" time stamps. @@ -124,11 +134,6 @@ void psc_new_tests(PSC_STATE *state) { - /* - * We know this client is brand new. - */ - state->flags = PSC_STATE_FLAG_NEW; - /* * Give all tests a PSC_TIME_STAMP_NEW time stamp, so that we can later * recognize cache entries that haven't passed all enabled tests. When we @@ -142,19 +147,9 @@ void psc_new_tests(PSC_STATE *state) state->barlf_stamp = PSC_TIME_STAMP_NEW; /* - * Don't flag disabled tests as "todo", because there would be no way to - * make those bits go away. + * Determine what tests need to be completed. */ - if (PSC_PREGR_TEST_ENABLE()) - state->flags |= PSC_STATE_FLAG_PREGR_TODO; - if (PSC_DNSBL_TEST_ENABLE()) - state->flags |= PSC_STATE_FLAG_DNSBL_TODO; - if (var_psc_pipel_enable) - state->flags |= PSC_STATE_FLAG_PIPEL_TODO; - if (var_psc_nsmtp_enable) - state->flags |= PSC_STATE_FLAG_NSMTP_TODO; - if (var_psc_barlf_enable) - state->flags |= PSC_STATE_FLAG_BARLF_TODO; + psc_todo_tests(state, PSC_TIME_STAMP_NEW + 1); } /* psc_parse_tests - parse test results from cache */ @@ -165,29 +160,18 @@ void psc_parse_tests(PSC_STATE *state, { const char *start = stamp_str; char *cp; - time_t *time_stamps = state->expire_time; + time_t *time_stamps = state->client_info->expire_time; time_t *sp; - /* - * We don't know what tests have expired or have never passed. - */ - state->flags = 0; - /* * Parse the cache entry, and allow for older postscreen versions that * implemented fewer tests. We pretend that the newer tests were disabled * at the time that the cache entry was written. - * - * Flag the cache entry as "new" when the cache entry has fields for all - * enabled tests, but the remote SMTP client has not yet passed all those - * tests. */ for (sp = time_stamps; sp < time_stamps + PSC_TINDX_COUNT; sp++) { *sp = strtoul(start, &cp, 10); if (*start == 0 || (*cp != '\0' && *cp != ';') || errno == ERANGE) *sp = PSC_TIME_STAMP_DISABLED; - if (*sp == PSC_TIME_STAMP_NEW) - state->flags |= PSC_STATE_FLAG_NEW; if (msg_verbose) msg_info("%s -> %lu", start, (unsigned long) *sp); if (*cp == ';') @@ -196,6 +180,34 @@ void psc_parse_tests(PSC_STATE *state, start = cp; } + /* + * Determine what tests need to be completed. + */ + psc_todo_tests(state, time_value); +} + +/* psc_todo_tests - determine what tests to perform */ + +void psc_todo_tests(PSC_STATE *state, time_t time_value) +{ + time_t *time_stamps = state->client_info->expire_time; + time_t *sp; + + /* + * Reset all per-session flags. + */ + state->flags = 0; + + /* + * Flag the tests as "new" when the cache entry has fields for all + * enabled tests, but the remote SMTP client has not yet passed all those + * tests. + */ + for (sp = time_stamps; sp < time_stamps + PSC_TINDX_COUNT; sp++) { + if (*sp == PSC_TIME_STAMP_NEW) + state->flags |= PSC_STATE_FLAG_NEW; + } + /* * Don't flag disabled tests as "todo", because there would be no way to * make those bits go away. diff --git a/postfix/src/postsuper/postsuper.c b/postfix/src/postsuper/postsuper.c index 0e821367d..49b2b32be 100644 --- a/postfix/src/postsuper/postsuper.c +++ b/postfix/src/postsuper/postsuper.c @@ -430,7 +430,7 @@ static int postrename(const char *old, const char *new) if ((ret = sane_rename(old, new)) < 0) { if (errno != ENOENT || mail_queue_mkdirs(new) < 0 - || sane_rename(old, new) < 0) + || (ret = sane_rename(old, new)) < 0) if (errno != ENOENT) msg_fatal("rename file %s as %s: %m", old, new); } else { diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index 91106b742..afffa5f93 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -533,6 +533,7 @@ smtpd_resolve.o: ../../include/mymalloc.h smtpd_resolve.o: ../../include/nvtable.h smtpd_resolve.o: ../../include/resolve_clnt.h smtpd_resolve.o: ../../include/rewrite_clnt.h +smtpd_resolve.o: ../../include/split_at.h smtpd_resolve.o: ../../include/stringops.h smtpd_resolve.o: ../../include/sys_defs.h smtpd_resolve.o: ../../include/vbuf.h diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index b65ec648c..12360af18 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -1214,6 +1214,7 @@ char *var_rest_classes; int var_strict_rfc821_env; bool var_disable_vrfy_cmd; char *var_canonical_maps; +char *var_send_canon_maps; char *var_rcpt_canon_maps; char *var_virt_alias_maps; char *var_virt_mailbox_maps; @@ -2222,7 +2223,9 @@ static int extract_addr(SMTPD_STATE *state, SMTPD_TOKEN *arg, if ((STR(state->addr_buf)[0] == 0 && !allow_empty_addr) || (strict_rfc821 && STR(state->addr_buf)[0] == '@') || (SMTPD_STAND_ALONE(state) == 0 - && smtpd_check_addr(STR(state->addr_buf), smtputf8) != 0)) { + && smtpd_check_addr(strcmp(state->where, SMTPD_CMD_MAIL) == 0 ? + state->recipient : state->sender, + STR(state->addr_buf), smtputf8) != 0)) { msg_warn("Illegal address syntax from %s in %s command: %s", state->namaddr, state->where, printable(STR(arg->vstrval), '?')); @@ -2272,7 +2275,6 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) char *verp_delims = 0; int rate; int dsn_envid = 0; - int smtputf8 = 0; state->flags &= ~SMTPD_FLAG_SMTPUTF8; state->encoding = 0; @@ -2339,13 +2341,15 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) for (narg = 3; narg < argc; narg++) { arg = argv[narg].strval; if (strcasecmp(arg, "SMTPUTF8") == 0) { /* RFC 6531 */ - smtputf8 = 1; + /* Fix 20161206: allow UTF8 in smtpd_sender_restrictions. */ + state->flags |= SMTPD_FLAG_SMTPUTF8; break; } } } if (extract_addr(state, argv + 2, PERMIT_EMPTY_ADDR, - var_strict_rfc821_env, smtputf8) != 0) { + var_strict_rfc821_env, + state->flags & SMTPD_FLAG_SMTPUTF8) != 0) { state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "501 5.1.7 Bad sender address syntax"); return (-1); @@ -2545,8 +2549,6 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) state->verp_delims = mystrdup(verp_delims); if (dsn_envid) state->dsn_envid = mystrdup(STR(state->dsn_buf)); - if (smtputf8) - state->flags |= SMTPD_FLAG_SMTPUTF8; if (USE_SMTPD_PROXY(state)) state->proxy_mail = mystrdup(STR(state->buffer)); if (var_smtpd_delay_open == 0 && mail_open_stream(state) < 0) { @@ -3519,6 +3521,7 @@ static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) const char *err = 0; int rate; int smtputf8 = 0; + int saved_flags; /* * The SMTP standard (RFC 821) disallows unquoted special characters in @@ -3605,10 +3608,17 @@ static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) } } /* Use state->addr_buf, with the unquoted result from extract_addr() */ - if (SMTPD_STAND_ALONE(state) == 0 - && (err = smtpd_check_rcpt(state, STR(state->addr_buf))) != 0) { - smtpd_chat_reply(state, "%s", err); - return (-1); + if (SMTPD_STAND_ALONE(state) == 0) { + /* Fix 20161206: allow UTF8 in smtpd_recipient_restrictions. */ + saved_flags = state->flags; + if (smtputf8) + state->flags |= SMTPD_FLAG_SMTPUTF8; + err = smtpd_check_rcpt(state, STR(state->addr_buf)); + state->flags = saved_flags; + if (err != 0) { + smtpd_chat_reply(state, "%s", err); + return (-1); + } } /* @@ -5682,6 +5692,7 @@ int main(int argc, char **argv) VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0, VAR_REST_CLASSES, DEF_REST_CLASSES, &var_rest_classes, 0, 0, VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, 0, 0, + VAR_SEND_CANON_MAPS, DEF_SEND_CANON_MAPS, &var_send_canon_maps, 0, 0, VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, 0, 0, VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps, 0, 0, VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0, diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index cafc69d1e..28ee1287e 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -9,7 +9,8 @@ /* /* void smtpd_check_init() /* -/* int smtpd_check_addr(address, smtputf8) +/* int smtpd_check_addr(sender, address, smtputf8) +/* const char *sender; /* const char *address; /* int smtputf8; /* @@ -57,7 +58,9 @@ /* once during the process life time. /* /* smtpd_check_addr() sanity checks an email address and returns -/* non-zero in case of badness. +/* non-zero in case of badness. The sender argument provides sender +/* context for address resolution and caching, or a null pointer +/* if information is unavailable. /* /* smtpd_check_rewrite() should be called before opening a queue /* file or proxy connection, in order to establish the proper @@ -278,6 +281,7 @@ static CTABLE *smtpd_rbl_byte_cache; * trivial-rewrite resolver. */ static MAPS *local_rcpt_maps; +static MAPS *send_canon_maps; static MAPS *rcpt_canon_maps; static MAPS *canonical_maps; static MAPS *virt_alias_maps; @@ -346,7 +350,8 @@ static int generic_checks(SMTPD_STATE *, ARGV *, const char *, const char *, con */ static int check_sender_rcpt_maps(SMTPD_STATE *, const char *); static int check_recipient_rcpt_maps(SMTPD_STATE *, const char *); -static int check_rcpt_maps(SMTPD_STATE *, const char *, const char *); +static int check_rcpt_maps(SMTPD_STATE *, const char *, const char *, + const char *); /* * Tempfail actions; @@ -730,6 +735,9 @@ void smtpd_check_init(void) local_rcpt_maps = maps_create(VAR_LOCAL_RCPT_MAPS, var_local_rcpt_maps, DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST); + send_canon_maps = maps_create(VAR_SEND_CANON_MAPS, var_send_canon_maps, + DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX + | DICT_FLAG_UTF8_REQUEST); rcpt_canon_maps = maps_create(VAR_RCPT_CANON_MAPS, var_rcpt_canon_maps, DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST); @@ -1595,7 +1603,7 @@ static int permit_auth_destination(SMTPD_STATE *state, char *recipient) /* * Resolve the address. */ - reply = smtpd_resolve_addr(recipient); + reply = smtpd_resolve_addr(state->sender, recipient); if (reply->flags & RESOLVE_FLAG_FAIL) reject_dict_retry(state, recipient); @@ -1890,7 +1898,7 @@ static int permit_mx_backup(SMTPD_STATE *state, const char *recipient, /* * Resolve the address. */ - reply = smtpd_resolve_addr(recipient); + reply = smtpd_resolve_addr(state->sender, recipient); if (reply->flags & RESOLVE_FLAG_FAIL) reject_dict_retry(state, recipient); @@ -2078,7 +2086,8 @@ static int reject_unknown_address(SMTPD_STATE *state, const char *addr, /* * Resolve the address. */ - reply = smtpd_resolve_addr(addr); + reply = smtpd_resolve_addr(strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ? + state->recipient : state->sender, addr); if (reply->flags & RESOLVE_FLAG_FAIL) reject_dict_retry(state, addr); @@ -3130,7 +3139,8 @@ static int check_mail_access(SMTPD_STATE *state, const char *table, /* * Resolve the address. */ - reply = smtpd_resolve_addr(addr); + reply = smtpd_resolve_addr(strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ? + state->recipient : state->sender, addr); if (reply->flags & RESOLVE_FLAG_FAIL) reject_dict_retry(state, addr); @@ -3781,7 +3791,7 @@ static int reject_auth_sender_login_mismatch(SMTPD_STATE *state, const char *sen * Reject if the client is logged in and does not own the sender address. */ if (smtpd_sender_login_maps && state->sasl_username) { - reply = smtpd_resolve_addr(sender); + reply = smtpd_resolve_addr(state->recipient, sender); if (reply->flags & RESOLVE_FLAG_FAIL) reject_dict_retry(state, sender); if ((owners = check_mail_addr_find(state, sender, smtpd_sender_login_maps, @@ -3815,7 +3825,7 @@ static int reject_unauth_sender_login_mismatch(SMTPD_STATE *state, const char *s * owner. */ if (smtpd_sender_login_maps && !state->sasl_username) { - reply = smtpd_resolve_addr(sender); + reply = smtpd_resolve_addr(state->recipient, sender); if (reply->flags & RESOLVE_FLAG_FAIL) reject_dict_retry(state, sender); if (check_mail_addr_find(state, sender, smtpd_sender_login_maps, @@ -4627,7 +4637,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, /* smtpd_check_addr - address sanity check */ -int smtpd_check_addr(const char *addr, int smtputf8) +int smtpd_check_addr(const char *sender, const char *addr, int smtputf8) { const RESOLVE_REPLY *resolve_reply; const char *myname = "smtpd_check_addr"; @@ -4643,7 +4653,7 @@ int smtpd_check_addr(const char *addr, int smtputf8) */ if (addr == 0 || *addr == 0) return (0); - resolve_reply = smtpd_resolve_addr(addr); + resolve_reply = smtpd_resolve_addr(sender, addr); if (resolve_reply->flags & RESOLVE_FLAG_ERROR) return (-1); @@ -5053,7 +5063,8 @@ static int check_recipient_rcpt_maps(SMTPD_STATE *state, const char *recipient) if (state->warn_if_reject == 0) /* We really validate the recipient address. */ state->recipient_rcptmap_checked = 1; - return (check_rcpt_maps(state, recipient, SMTPD_NAME_RECIPIENT)); + return (check_rcpt_maps(state, state->sender, recipient, + SMTPD_NAME_RECIPIENT)); } /* check_sender_rcpt_maps - generic_checks() sender table check */ @@ -5072,24 +5083,26 @@ static int check_sender_rcpt_maps(SMTPD_STATE *state, const char *sender) if (state->warn_if_reject == 0) /* We really validate the sender address. */ state->sender_rcptmap_checked = 1; - return (check_rcpt_maps(state, sender, SMTPD_NAME_SENDER)); + return (check_rcpt_maps(state, state->recipient, sender, + SMTPD_NAME_SENDER)); } /* check_rcpt_maps - generic_checks() interface for recipient table check */ -static int check_rcpt_maps(SMTPD_STATE *state, const char *recipient, +static int check_rcpt_maps(SMTPD_STATE *state, const char *sender, + const char *recipient, const char *reply_class) { const RESOLVE_REPLY *reply; DSN_SPLIT dp; if (msg_verbose) - msg_info(">>> CHECKING RECIPIENT MAPS <<<"); + msg_info(">>> CHECKING %s VALIDATION MAPS <<<", reply_class); /* * Resolve the address. */ - reply = smtpd_resolve_addr(recipient); + reply = smtpd_resolve_addr(sender, recipient); if (reply->flags & RESOLVE_FLAG_FAIL) reject_dict_retry(state, recipient); @@ -5110,6 +5123,8 @@ static int check_rcpt_maps(SMTPD_STATE *state, const char *recipient, * domains. */ if (MATCH(rcpt_canon_maps, CONST_STR(reply->recipient)) + || (strcmp(reply_class, SMTPD_NAME_SENDER) == 0 + && MATCH(send_canon_maps, CONST_STR(reply->recipient))) || MATCH(canonical_maps, CONST_STR(reply->recipient)) || MATCH(virt_alias_maps, CONST_STR(reply->recipient))) return (0); @@ -5456,6 +5471,7 @@ char *var_proxy_interfaces; char *var_rcpt_delim; char *var_rest_classes; char *var_alias_maps; +char *var_send_canon_maps; char *var_rcpt_canon_maps; char *var_canonical_maps; char *var_virt_alias_maps; @@ -5506,6 +5522,7 @@ static const STRING_TABLE string_table[] = { VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, VAR_REST_CLASSES, DEF_REST_CLASSES, &var_rest_classes, VAR_ALIAS_MAPS, DEF_ALIAS_MAPS, &var_alias_maps, + VAR_SEND_CANON_MAPS, DEF_SEND_CANON_MAPS, &var_send_canon_maps, VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps, @@ -6057,6 +6074,22 @@ int main(int argc, char **argv) resp = 0; break; } + if (strcasecmp(args->argv[0], VAR_SEND_CANON_MAPS) == 0) { + UPDATE_STRING(var_send_canon_maps, args->argv[1]); + UPDATE_MAPS(send_canon_maps, VAR_SEND_CANON_MAPS, + var_send_canon_maps, DICT_FLAG_LOCK + | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST); + resp = 0; + break; + } + if (strcasecmp(args->argv[0], VAR_RCPT_CANON_MAPS) == 0) { + UPDATE_STRING(var_rcpt_canon_maps, args->argv[1]); + UPDATE_MAPS(rcpt_canon_maps, VAR_RCPT_CANON_MAPS, + var_rcpt_canon_maps, DICT_FLAG_LOCK + | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST); + resp = 0; + break; + } if (strcasecmp(args->argv[0], VAR_RBL_REPLY_MAPS) == 0) { UPDATE_STRING(var_rbl_reply_maps, args->argv[1]); UPDATE_MAPS(rbl_reply_maps, VAR_RBL_REPLY_MAPS, diff --git a/postfix/src/smtpd/smtpd_check.h b/postfix/src/smtpd/smtpd_check.h index a654cd6e0..e7f440145 100644 --- a/postfix/src/smtpd/smtpd_check.h +++ b/postfix/src/smtpd/smtpd_check.h @@ -13,7 +13,7 @@ * External interface. */ extern void smtpd_check_init(void); -extern int smtpd_check_addr(const char *, int); +extern int smtpd_check_addr(const char *, const char *, int); extern char *smtpd_check_rewrite(SMTPD_STATE *); extern char *smtpd_check_client(SMTPD_STATE *); extern char *smtpd_check_helo(SMTPD_STATE *, char *); diff --git a/postfix/src/smtpd/smtpd_milter.c b/postfix/src/smtpd/smtpd_milter.c index 833148a7e..0d46d917f 100644 --- a/postfix/src/smtpd/smtpd_milter.c +++ b/postfix/src/smtpd/smtpd_milter.c @@ -160,7 +160,7 @@ const char *smtpd_milter_eval(const char *name, void *ptr) return (0); if (state->sender[0] == 0) return (""); - reply = smtpd_resolve_addr(state->sender); + reply = smtpd_resolve_addr(state->recipient, state->sender); /* Sendmail 8.13 does not externalize the null string. */ if (STR(reply->recipient)[0]) quote_821_local(state->expand_buf, STR(reply->recipient)); @@ -171,13 +171,13 @@ const char *smtpd_milter_eval(const char *name, void *ptr) if (strcmp(name, S8_MAC_MAIL_HOST) == 0) { if (state->sender == 0) return (0); - reply = smtpd_resolve_addr(state->sender); + reply = smtpd_resolve_addr(state->recipient, state->sender); return (STR(reply->nexthop)); } if (strcmp(name, S8_MAC_MAIL_MAILER) == 0) { if (state->sender == 0) return (0); - reply = smtpd_resolve_addr(state->sender); + reply = smtpd_resolve_addr(state->recipient, state->sender); return (STR(reply->transport)); } @@ -195,7 +195,7 @@ const char *smtpd_milter_eval(const char *name, void *ptr) cp = split_at(STR(state->expand_buf), ' '); return (cp ? split_at(cp, ' ') : cp); } - reply = smtpd_resolve_addr(state->recipient); + reply = smtpd_resolve_addr(state->sender, state->recipient); /* Sendmail 8.13 does not externalize the null string. */ if (STR(reply->recipient)[0]) quote_821_local(state->expand_buf, STR(reply->recipient)); @@ -212,7 +212,7 @@ const char *smtpd_milter_eval(const char *name, void *ptr) (void) split_at(STR(state->expand_buf), ' '); return (STR(state->expand_buf)); } - reply = smtpd_resolve_addr(state->recipient); + reply = smtpd_resolve_addr(state->sender, state->recipient); return (STR(reply->nexthop)); } if (strcmp(name, S8_MAC_RCPT_MAILER) == 0) { @@ -220,7 +220,7 @@ const char *smtpd_milter_eval(const char *name, void *ptr) return (0); if (state->milter_reject_text) return (S8_RCPT_MAILER_ERROR); - reply = smtpd_resolve_addr(state->recipient); + reply = smtpd_resolve_addr(state->sender, state->recipient); return (STR(reply->transport)); } return (0); diff --git a/postfix/src/smtpd/smtpd_resolve.c b/postfix/src/smtpd/smtpd_resolve.c index 7cd8e4cda..0adf6904e 100644 --- a/postfix/src/smtpd/smtpd_resolve.c +++ b/postfix/src/smtpd/smtpd_resolve.c @@ -9,7 +9,8 @@ /* void smtpd_resolve_init(cache_size) /* int cache_size; /* -/* const RESOLVE_REPLY *smtpd_resolve_addr(addr) +/* const RESOLVE_REPLY *smtpd_resolve_addr(sender, addr) +/* const char *sender; /* const char *addr; /* DESCRIPTION /* This module maintains a resolve client cache that persists @@ -26,6 +27,8 @@ /* Arguments: /* .IP cache_size /* The requested cache size. +/* .IP sender +/* The message sender, or null pointer. /* .IP addr /* The address to resolve. /* DIAGNOSTICS @@ -56,6 +59,7 @@ #include #include #include +#include /* Global library. */ @@ -70,20 +74,28 @@ static CTABLE *smtpd_resolve_cache; #define STR(x) vstring_str(x) +#define SENDER_ADDR_JOIN_CHAR '\n' /* resolve_pagein - page in an address resolver result */ -static void *resolve_pagein(const char *addr, void *unused_context) +static void *resolve_pagein(const char *sender_plus_addr, void *unused_context) { + const char myname[] = "resolve_pagein"; static VSTRING *query; + static VSTRING *junk; + static VSTRING *sender_buf; RESOLVE_REPLY *reply; - char *tmp; + const char *sender; + const char *addr; /* * Initialize on the fly. */ - if (query == 0) + if (query == 0) { query = vstring_alloc(10); + junk = vstring_alloc(10); + sender_buf = vstring_alloc(10); + } /* * Initialize. @@ -91,14 +103,22 @@ static void *resolve_pagein(const char *addr, void *unused_context) reply = (RESOLVE_REPLY *) mymalloc(sizeof(*reply)); resolve_clnt_init(reply); + /* + * Split the sender and address. + */ + vstring_strcpy(junk, sender_plus_addr); + sender = STR(junk); + if ((addr = split_at(STR(junk), SENDER_ADDR_JOIN_CHAR)) == 0) + msg_panic("%s: bad search key: \"%s\"", myname, sender_plus_addr); + /* * Resolve the address. */ + rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL, sender, sender_buf); rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL, addr, query); - resolve_clnt_query(STR(query), reply); - tmp = mystrdup(STR(reply->recipient)); - casefold(reply->recipient, tmp); /* XXX */ - myfree(tmp); + resolve_clnt_query_from(STR(sender_buf), STR(query), reply); + vstring_strcpy(junk, STR(reply->recipient)); + casefold(reply->recipient, STR(junk)); /* XXX */ /* * Save the result. @@ -136,10 +156,17 @@ void smtpd_resolve_init(int cache_size) resolve_pageout, (void *) 0); } -/* smtpd_resolve_addr - resolve cached addres */ +/* smtpd_resolve_addr - resolve cached address */ -const RESOLVE_REPLY *smtpd_resolve_addr(const char *addr) +const RESOLVE_REPLY *smtpd_resolve_addr(const char *sender, const char *addr) { + static VSTRING *sender_plus_addr_buf; + + /* + * Initialize on the fly. + */ + if (sender_plus_addr_buf == 0) + sender_plus_addr_buf = vstring_alloc(10); /* * Sanity check. @@ -150,5 +177,9 @@ const RESOLVE_REPLY *smtpd_resolve_addr(const char *addr) /* * Reply from the read-through cache. */ - return (const RESOLVE_REPLY *) ctable_locate(smtpd_resolve_cache, addr); + vstring_sprintf(sender_plus_addr_buf, "%s%c%s", + sender ? sender : RESOLVE_NULL_FROM, + SENDER_ADDR_JOIN_CHAR, addr); + return (const RESOLVE_REPLY *) + ctable_locate(smtpd_resolve_cache, STR(sender_plus_addr_buf)); } diff --git a/postfix/src/smtpd/smtpd_resolve.h b/postfix/src/smtpd/smtpd_resolve.h index bfbc494da..c04c52a7a 100644 --- a/postfix/src/smtpd/smtpd_resolve.h +++ b/postfix/src/smtpd/smtpd_resolve.h @@ -17,7 +17,7 @@ * External interface. */ extern void smtpd_resolve_init(int); -extern const RESOLVE_REPLY *smtpd_resolve_addr(const char *); +extern const RESOLVE_REPLY *smtpd_resolve_addr(const char*, const char *); /* LICENSE /* .ad diff --git a/postfix/src/virtual/mailbox.c b/postfix/src/virtual/mailbox.c index e04c42682..51e646de7 100644 --- a/postfix/src/virtual/mailbox.c +++ b/postfix/src/virtual/mailbox.c @@ -80,7 +80,6 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr) int mail_copy_status; int deliver_status; int copy_flags; - long end; struct stat st; /* @@ -132,7 +131,9 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr) msg_warn("specify \"%s = no\" to ignore mailbox ownership mismatch", VAR_STRICT_MBOX_OWNER); } else { - end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END); + if (vstream_fseek(mp->fp, (off_t) 0, SEEK_END) < 0) + msg_fatal("%s: seek queue file %s: %m", + myname, VSTREAM_PATH(mp->fp)); mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp, copy_flags, "\n", why); }