diff -ur /var/tmp/postfix-3.1-20150721/HISTORY ./HISTORY --- /var/tmp/postfix-3.1-20150721/HISTORY 2015-07-21 19:14:48.000000000 -0400 +++ ./HISTORY 2015-07-25 19:21:20.000000000 -0400 @@ -21852,3 +21852,12 @@ SSLv2 or SSLv3. See the RELEASE_NOTES file for how to get the old settings back. Files: global/mail_params.h, proto/postconf.proto, and files derived from those. + +20150725 + + Feature: the Postfix SMTP server now supports a sequence + of access maps, specified as {type1:name1, ..., typeN:nameN} + where historically only one access map is expected. The + sequence is queried in the specified order until a result + is found. The {...} syntax is also supported for lookup + tables in local_header_rewrite_clients. File: smtpd/smtpd_check.c. diff -ur /var/tmp/postfix-3.1-20150721/src/smtpd/smtpd_check.c ./src/smtpd/smtpd_check.c --- /var/tmp/postfix-3.1-20150721/src/smtpd/smtpd_check.c 2015-07-08 09:44:58.000000000 -0400 +++ ./src/smtpd/smtpd_check.c 2015-07-25 19:37:41.000000000 -0400 @@ -580,6 +580,41 @@ } } +/* register_maps_byname - register maps handle by name */ + +static HTABLE *maps_byname = 0; + +static void register_maps_byname(const char *title, const char *name, + int dict_flags) +{ + char *saved_name = 0; + char *map_names; + char *bp; + char *err; + + if (maps_byname == 0) + maps_byname = htable_create(1); + if (name[0] == CHARS_BRACE[0]) { + saved_name = bp = mystrdup(name); + if ((err = extpar(&bp, CHARS_BRACE, EXTPAR_FLAG_STRIP)) != 0) + msg_fatal("access map syntax error: %s", err); + map_names = bp; + } else { + map_names = name; + } + (void) htable_enter(maps_byname, name, + maps_create(title, map_names, dict_flags)); + if (saved_name) + myfree(saved_name); +} + +/* find_maps_byname - look up maps handle by name */ + +static MAPS *find_maps_byname(const char *name) +{ + return (MAPS *) (maps_byname ? htable_find(maps_byname, name) : 0); +} + /* smtpd_check_parse - pre-parse restrictions */ static ARGV *smtpd_check_parse(int flags, const char *checks) @@ -606,9 +641,9 @@ policy_client_register(name); else if ((flags & SMTPD_CHECK_PARSE_MAPS) && strchr(name, ':') && dict_handle(name) == 0) { - dict_register(name, dict_open(name, O_RDONLY, DICT_FLAG_LOCK - | DICT_FLAG_FOLD_FIX - | DICT_FLAG_UTF8_REQUEST)); + register_maps_byname(name, name, DICT_FLAG_LOCK + | DICT_FLAG_FOLD_FIX + | DICT_FLAG_UTF8_REQUEST); } last = name; } @@ -2659,7 +2694,7 @@ { const char *myname = "check_access"; const char *value; - DICT *dict; + MAPS *maps; #define CHK_ACCESS_RETURN(x,y) \ { *found = y; return(x); } @@ -2671,25 +2706,22 @@ if (msg_verbose) msg_info("%s: %s", myname, name); - if ((dict = dict_handle(table)) == 0) { + if ((maps = find_maps_byname(table)) == 0) { msg_warn("%s: unexpected dictionary: %s", myname, table); value = "451 4.3.5 Server configuration error"; CHK_ACCESS_RETURN(check_table_result(state, table, value, name, reply_name, reply_class, def_acl), FOUND); } - if (flags == 0 || (flags & dict->flags) != 0) { - if ((value = dict_get(dict, name)) != 0) - CHK_ACCESS_RETURN(check_table_result(state, table, value, name, - reply_name, reply_class, - def_acl), FOUND); - if (dict->error != 0) { - msg_warn("%s: table lookup problem", table); - value = "451 4.3.5 Server configuration error"; - CHK_ACCESS_RETURN(check_table_result(state, table, value, name, - reply_name, reply_class, - def_acl), FOUND); - } + if ((value = maps_find(maps, name, flags)) != 0) + CHK_ACCESS_RETURN(check_table_result(state, table, value, name, + reply_name, reply_class, + def_acl), FOUND); + if (maps->error != 0) { + value = "451 4.3.5 Server configuration error"; + CHK_ACCESS_RETURN(check_table_result(state, table, value, name, + reply_name, reply_class, + def_acl), FOUND); } CHK_ACCESS_RETURN(SMTPD_CHECK_DUNNO, MISSED); } @@ -2706,7 +2738,7 @@ const char *name; const char *next; const char *value; - DICT *dict; + MAPS *maps; int maybe_numerical = 1; if (msg_verbose) @@ -2721,7 +2753,7 @@ */ #define CHK_DOMAIN_RETURN(x,y) { *found = y; return(x); } - if ((dict = dict_handle(table)) == 0) { + if ((maps = find_maps_byname(table)) == 0) { msg_warn("%s: unexpected dictionary: %s", myname, table); value = "451 4.3.5 Server configuration error"; CHK_DOMAIN_RETURN(check_table_result(state, table, value, @@ -2729,18 +2761,15 @@ def_acl), FOUND); } for (name = domain; *name != 0; name = next) { - if (flags == 0 || (flags & dict->flags) != 0) { - if ((value = dict_get(dict, name)) != 0) - CHK_DOMAIN_RETURN(check_table_result(state, table, value, + if ((value = maps_find(maps, name, flags)) != 0) + CHK_DOMAIN_RETURN(check_table_result(state, table, value, domain, reply_name, reply_class, - def_acl), FOUND); - if (dict->error != 0) { - msg_warn("%s: table lookup problem", table); - value = "451 4.3.5 Server configuration error"; - CHK_DOMAIN_RETURN(check_table_result(state, table, value, + def_acl), FOUND); + if (maps->error != 0) { + value = "451 4.3.5 Server configuration error"; + CHK_DOMAIN_RETURN(check_table_result(state, table, value, domain, reply_name, reply_class, - def_acl), FOUND); - } + def_acl), FOUND); } /* Don't apply subdomain magic to numerical hostnames. */ if (maybe_numerical @@ -2766,7 +2795,7 @@ const char *myname = "check_addr_access"; char *addr; const char *value; - DICT *dict; + MAPS *maps; int delim; if (msg_verbose) @@ -2785,7 +2814,7 @@ #endif delim = '.'; - if ((dict = dict_handle(table)) == 0) { + if ((maps = find_maps_byname(table)) == 0) { msg_warn("%s: unexpected dictionary: %s", myname, table); value = "451 4.3.5 Server configuration error"; CHK_ADDR_RETURN(check_table_result(state, table, value, address, @@ -2793,18 +2822,15 @@ def_acl), FOUND); } do { - if (flags == 0 || (flags & dict->flags) != 0) { - if ((value = dict_get(dict, addr)) != 0) - CHK_ADDR_RETURN(check_table_result(state, table, value, address, - reply_name, reply_class, - def_acl), FOUND); - if (dict->error != 0) { - msg_warn("%s: table lookup problem", table); - value = "451 4.3.5 Server configuration error"; - CHK_ADDR_RETURN(check_table_result(state, table, value, address, - reply_name, reply_class, - def_acl), FOUND); - } + if ((value = maps_find(maps, addr, flags)) != 0) + CHK_ADDR_RETURN(check_table_result(state, table, value, address, + reply_name, reply_class, + def_acl), FOUND); + if (maps->error != 0) { + value = "451 4.3.5 Server configuration error"; + CHK_ADDR_RETURN(check_table_result(state, table, value, address, + reply_name, reply_class, + def_acl), FOUND); } flags = PARTIAL; } while (split_at_right(addr, delim)); @@ -4671,7 +4697,7 @@ const char *myname = "smtpd_check_rewrite"; int status; char **cpp; - DICT *dict; + MAPS *maps; char *name; /* @@ -4691,13 +4717,13 @@ } else if (strcasecmp(name, PERMIT_MYNETWORKS) == 0) { status = permit_mynetworks(state); } else if (is_map_command(state, name, CHECK_ADDR_MAP, &cpp)) { - if ((dict = dict_handle(*cpp)) == 0) + if ((maps = find_maps_byname(*cpp)) == 0) msg_panic("%s: dictionary not found: %s", myname, *cpp); - if (dict_get(dict, state->addr) != 0) + if (maps_find(maps, state->addr, FULL) != 0) status = SMTPD_CHECK_OK; - else if (dict->error != 0) { + else if (maps->error != 0) { msg_warn("%s: %s: lookup error", VAR_LOC_RWR_CLIENTS, *cpp); - status = dict->error; + status = maps->error; } } else if (strcasecmp(name, PERMIT_SASL_AUTH) == 0) { #ifdef USE_SASL_AUTH diff -ur /var/tmp/postfix-3.1-20150721/src/smtpd/smtpd_error.in ./src/smtpd/smtpd_error.in --- /var/tmp/postfix-3.1-20150721/src/smtpd/smtpd_error.in 2011-12-22 20:20:49.000000000 -0500 +++ ./src/smtpd/smtpd_error.in 2015-07-25 19:39:25.000000000 -0400 @@ -5,25 +5,25 @@ # # Test check_domain_access() # -helo_restrictions fail:1_helo_access +helo_restrictions {fail:1_helo_access} # Expect: REJECT (temporary lookup failure) helo foobar # # Test check_namadr_access() # -client_restrictions fail:1_client_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 +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 +recipient_restrictions {fail:1_rcpt_access} # Expect: REJECT (temporary lookup failure) rcpt reject@dunno.domain # Expect: OK diff -ur /var/tmp/postfix-3.1-20150721/src/smtpd/smtpd_error.ref ./src/smtpd/smtpd_error.ref --- /var/tmp/postfix-3.1-20150721/src/smtpd/smtpd_error.ref 2015-01-21 15:27:04.000000000 -0500 +++ ./src/smtpd/smtpd_error.ref 2015-07-25 19:39:26.000000000 -0400 @@ -6,41 +6,41 @@ >>> # >>> # Test check_domain_access() >>> # ->>> helo_restrictions fail:1_helo_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: warning: fail:1_helo_access lookup error for "foobar" ./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 +>>> 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: warning: fail:1_client_access lookup error for "foo.dunno.com" ./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 +>>> 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: warning: fail:1_sender_access lookup error for "reject@dunno.domain" ./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 +>>> 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: warning: fail:1_rcpt_access lookup error for "reject@dunno.domain" ./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 @@ -78,7 +78,7 @@ >>> smtpd_null_access_lookup_key <> OK >>> mail <> -./smtpd_check: warning: fail:1_sender_access: table lookup problem +./smtpd_check: warning: fail:1_sender_access lookup error for "<>" ./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 >>> # @@ -104,6 +104,7 @@ >>> # Expect: REJECT (temporary lookup failure) >>> # >>> rewrite +./smtpd_check: warning: fail:1_rewrite lookup error for "131.155.210.17" ./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