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. 20160619 Refinements to the 20160618 fix. For more consistent results with sender address validation, use the recipient address (if available) as the sender-dependent address resolver context. For better caching, pass sender context with all attempts to resolve an email address. File: smtpd/smtpd.c, smtpd/smtpd_check.c, smtpd/smtpd_milter.c. diff -ur --exclude=global /var/tmp/postfix-3.2-20160612/src/smtpd/Makefile.in src/smtpd/Makefile.in --- /var/tmp/postfix-3.2-20160612/src/smtpd/Makefile.in 2016-03-14 19:33:34.000000000 -0400 +++ src/smtpd/Makefile.in 2016-06-18 17:11:11.000000000 -0400 @@ -531,6 +531,7 @@ 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 -ur --exclude=global /var/tmp/postfix-3.2-20160612/src/smtpd/smtpd.c src/smtpd/smtpd.c --- /var/tmp/postfix-3.2-20160612/src/smtpd/smtpd.c 2016-06-11 15:46:04.000000000 -0400 +++ src/smtpd/smtpd.c 2016-06-19 15:29:52.000000000 -0400 @@ -2286,7 +2286,9 @@ 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), '?')); diff -ur --exclude=global /var/tmp/postfix-3.2-20160612/src/smtpd/smtpd_check.c src/smtpd/smtpd_check.c --- /var/tmp/postfix-3.2-20160612/src/smtpd/smtpd_check.c 2016-06-11 19:30:32.000000000 -0400 +++ src/smtpd/smtpd_check.c 2016-06-19 15:42:33.000000000 -0400 @@ -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 @@ -351,7 +354,8 @@ */ 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; @@ -1615,7 +1619,7 @@ /* * 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); @@ -1910,7 +1914,7 @@ /* * 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); @@ -2098,7 +2102,8 @@ /* * 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); @@ -3155,7 +3160,8 @@ /* * 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); @@ -3806,7 +3812,7 @@ * 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, @@ -3840,7 +3846,7 @@ * 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, @@ -4658,7 +4664,7 @@ /* 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"; @@ -4674,7 +4680,7 @@ */ 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); @@ -5084,7 +5090,8 @@ 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 */ @@ -5103,12 +5110,14 @@ 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; @@ -5120,7 +5129,7 @@ /* * 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); diff -ur --exclude=global /var/tmp/postfix-3.2-20160612/src/smtpd/smtpd_check.h src/smtpd/smtpd_check.h --- /var/tmp/postfix-3.2-20160612/src/smtpd/smtpd_check.h 2014-07-15 08:53:48.000000000 -0400 +++ src/smtpd/smtpd_check.h 2016-06-19 15:17:12.000000000 -0400 @@ -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 -ur --exclude=global /var/tmp/postfix-3.2-20160612/src/smtpd/smtpd_milter.c src/smtpd/smtpd_milter.c --- /var/tmp/postfix-3.2-20160612/src/smtpd/smtpd_milter.c 2016-06-11 10:28:58.000000000 -0400 +++ src/smtpd/smtpd_milter.c 2016-06-19 15:21:22.000000000 -0400 @@ -162,7 +162,7 @@ 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)); @@ -173,13 +173,13 @@ 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)); } @@ -197,7 +197,7 @@ 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)); @@ -214,7 +214,7 @@ (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) { @@ -222,7 +222,7 @@ 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 -ur --exclude=global /var/tmp/postfix-3.2-20160612/src/smtpd/smtpd_resolve.c src/smtpd/smtpd_resolve.c --- /var/tmp/postfix-3.2-20160612/src/smtpd/smtpd_resolve.c 2015-01-27 15:19:03.000000000 -0500 +++ src/smtpd/smtpd_resolve.c 2016-06-19 15:46:09.000000000 -0400 @@ -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. @@ -92,13 +104,21 @@ 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 @@ 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 @@ /* * 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 -ur --exclude=global /var/tmp/postfix-3.2-20160612/src/smtpd/smtpd_resolve.h src/smtpd/smtpd_resolve.h --- /var/tmp/postfix-3.2-20160612/src/smtpd/smtpd_resolve.h 2009-04-26 13:52:34.000000000 -0400 +++ src/smtpd/smtpd_resolve.h 2016-06-19 15:20:45.000000000 -0400 @@ -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