diff --git a/postfix/HISTORY b/postfix/HISTORY index a76f7cd03..b87f5c7b9 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -3475,4 +3475,24 @@ Apologies for any names omitted. 19991224 Bugfix: the relative symlink code in INSTALL.sh computed - the ../ segments from the wrong pathname. + the ../ prefix from the wrong pathname. + +1999122[56] + + Feature: "allow_routed_relaying = no" (default) disallows + forwarding of mail with sender-specified routing (example: + user%domain2@domain1, user@domain2@domain1, etc.). This + plugs an "open relay" loophole where a backup MX host would + forward junk mail to a primary MX host which would forward + it to the Internet. Files: global/quote_822_local.c, + smtp/quote_821_local.c, trivial-rewrite/rewrite.c, + trivial-rewrite/resolve.c, smtp/smtpd_check.c. + + In order to make this possible, the resolver now passes a + status back to the client that says if the result is a + routed address. + + Side effect from the above change: from now on, an address + with @ in the recipient localpart no longer bounces with + "user unknown" but instead is rejected with "relay access + denied" or "source-routed relay access denied". diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 016de3965..57de19125 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -1,6 +1,20 @@ -Incompatible changes with snapshot 19991223 +Incompatible changes with snapshot 19991226 =========================================== +- The SMTP server by default no longer forwards mail to non-local +destinations with sender-specified routing (stuff[@%!]stuff[@%!]stuff). +This closes an open relay loophole with primary and secondary MX +hosts. To get old behavior, specify "allow_routed_relaying = yes". + +- In order to support the above, the data structure and protocol +of the trivial-rewrite service was changed. This means you must +re-compile and re-link existing software that uses the Postfix +resolve_clnt interface. + +- As a side effect of the above, an address with @ in the localpart +(user@there@here) no longer bounces with "user unknown" but instead +is rejected with "relay access denied". + - The experimental permit_recipient_map and local_transports features are gone. They were never part of an official release. Both are replaced by a "local_recipient_map" parameter that allows the SMTP @@ -26,7 +40,7 @@ transport maps, it is better to always have explicit entries for all domain names you have in $mydestination. See the html/faq.html sections for firewalls and intranets. -Major changes with snapshot 19991223 +Major changes with snapshot 19991226 ==================================== - It is now much more difficult to configure Postfix as an open @@ -35,6 +49,13 @@ contains at least one restriction that by default refuses mail (as is the default). There were too many accidents with changes to the UCE restrictions. +- An "open relay" loophole is now plugged where a backup MX host +would forward stuff[@%!]stuff[@%!]stuff to a primary MX host which +would then spam it out to the world. To get the old behavior, +specify "allow_routed_relaying = yes". The old behavior is safe +only for non-MX hosts, and for primary MX hosts of domains that +have no backup MX hosts. + - The relay_domains parameter no longer needs to contain $virtual_maps. - Overhauled FAQ (html/faq.html) with many more examples. diff --git a/postfix/conf/sample-smtpd.cf b/postfix/conf/sample-smtpd.cf index 1f77a4290..22dac53d9 100644 --- a/postfix/conf/sample-smtpd.cf +++ b/postfix/conf/sample-smtpd.cf @@ -254,6 +254,16 @@ smtpd_recipient_restrictions = permit_mynetworks,check_relay_domains # ADDITIONAL UCE CONTROLS # +# The allow_routed_relaying parameter controls whether the host will +# forward addresses with sender-specified routing. This is disabled +# by default, in order to close a nasty open relay loophole where a +# backup MX host can be tricked into forwarding mail to a primary MX +# host which then spams it out to the world. Don't change this if +# this system is backup MX host for any domain, or if this system +# receives mail from any backup MX host. +# +allow_routed_relaying = no + # The maps_rbl_domains parameter specifies an optional list of DNS # domains that publish the network addresses of blacklisted hosts. # diff --git a/postfix/global/mail_params.h b/postfix/global/mail_params.h index f3a9797eb..81194ed53 100644 --- a/postfix/global/mail_params.h +++ b/postfix/global/mail_params.h @@ -748,6 +748,10 @@ extern char *var_etrn_checks; #define DEF_REST_CLASSES "" extern char *var_rest_classes; +#define VAR_ALLOW_ROUTED_RELAY "allow_routed_relaying" +#define DEF_ALLOW_ROUTED_RELAY 0 +extern bool var_allow_routed_relay; + /* * Names of specific restrictions, and the corresponding configuration * parameters that control the status codes sent in response to rejected diff --git a/postfix/global/mail_version.h b/postfix/global/mail_version.h index f4ada0836..35757105b 100644 --- a/postfix/global/mail_version.h +++ b/postfix/global/mail_version.h @@ -15,7 +15,7 @@ * Version of this program. */ #define VAR_MAIL_VERSION "mail_version" -#define DEF_MAIL_VERSION "Snapshot-19991225" +#define DEF_MAIL_VERSION "Snapshot-19991226" extern char *var_mail_version; /* LICENSE diff --git a/postfix/html/faq.html b/postfix/html/faq.html index f0ec41caf..df99aa277 100644 --- a/postfix/html/faq.html +++ b/postfix/html/faq.html @@ -697,7 +697,7 @@ mail for arbitrary non-local destinations:
     >>> MAIL FROM:<someone@some.where>
     <<< 250 Ok
-    >>> RCPT TO:<test@some.other.site@your.site>
+    >>> RCPT TO:<test@some.other.site@some.site>
     <<< 250 Ok
     >>> DATA
     <<< 354 End data with <CR><LF>.<CR><LF>
@@ -708,62 +708,15 @@ mail for arbitrary non-local destinations:
 
 

-Don't Panic! +Don't Panic! Upgrade to a Postfix version of 19991226 or later.

-If the mail for domain your.site is handled by a Postfix -machine, the mail bounces because test@some.other.site is -not a known user in domain your.site. In fact, the above -mail is rejected immediately when the Postfix SMTP server is -configured to reject mail for unknown local -users. - -

- -However, problems lurk when you are responsible for a backup MX -host, either for your own domain or for the domain of some other -organization. Especially troublesome address forms are: - -

- -

-    user@else.where@some.domain
-    user%else.where@some.domain
-    elsewhere!user@some.domain
-
- -

- -The problem is that the primary MX host may forward such mail to -user@else.where, either because the primary MX host somehow "trusts" -yor backup MX host, or because the primary MX host is badly -configured. - -

- -The bad news is that your backup MX machine can end up on a black -list because it accepted the mail, even though the problem could -be with the configuration of a primary MX machine that is not even -under your control. - -

- -So, if you're backup MX relay it is prudent to block addresses with -multiple address operators at the SMTP port, even though you would -also block legitimate addresses. - -

- -

-    /etc/postfix/main.cf: 
-        smtpd_recipient_restrictions = 
-                regexp:/etc/postfix/regexp_access
-                ...other UCE restrictions...
-
-    /etc/postfix/regexp_access:
-        /[%!@].*[%!@]/ 550 Sender specified routing is not supported here.
-
+Older Postfix versions would either bounce the mail because +"test@some.other.site" is not a known local username (which is +good), or they would forward the mail to a primary MX host for +"some.site" which would then spam it into the Internet (which is +bad).
diff --git a/postfix/smtpd/smtpd.c b/postfix/smtpd/smtpd.c index 818e080d9..ceb1ba681 100644 --- a/postfix/smtpd/smtpd.c +++ b/postfix/smtpd/smtpd.c @@ -141,6 +141,10 @@ /* .IP \fBsmtpd_etrn_restrictions\fR /* Restrict what domain names can be used in \fBETRN\fR commands, /* and what clients may issue \fBETRN\fR commands. +/* .IP \fBallow_routed_relaying\fR +/* Allow the relaying of addresses with sender-specified routing. +/* Enabling this opens up nasty relay loopholes if your domain has +/* primary and backup MX hosts. /* .IP \fBrestriction_classes\fR /* Declares the name of zero or more parameters that contain a /* list of UCE restrictions. The names of these parameters can @@ -300,6 +304,7 @@ char *var_rcpt_canon_maps; char *var_virtual_maps; char *var_alias_maps; char *var_local_rcpt_maps; +bool var_allow_routed_relay; /* * Global state, for stand-alone mode queue file cleanup. When this is @@ -1322,6 +1327,7 @@ int main(int argc, char **argv) VAR_SMTPD_DELAY_REJECT, DEF_SMTPD_DELAY_REJECT, &var_smtpd_delay_reject, VAR_STRICT_RFC821_ENV, DEF_STRICT_RFC821_ENV, &var_strict_rfc821_env, VAR_DISABLE_VRFY_CMD, DEF_DISABLE_VRFY_CMD, &var_disable_vrfy_cmd, + VAR_ALLOW_ROUTED_RELAY, DEF_ALLOW_ROUTED_RELAY, &var_allow_routed_relay, 0, }; static CONFIG_STR_TABLE str_table[] = { diff --git a/postfix/smtpd/smtpd_check.c b/postfix/smtpd/smtpd_check.c index c3265c260..c5ae37d8d 100644 --- a/postfix/smtpd/smtpd_check.c +++ b/postfix/smtpd/smtpd_check.c @@ -450,7 +450,9 @@ void smtpd_check_init(void) * People screw up the relay restrictions too often. Require that they * list at least one restriction that rejects mail by default. */ +#ifndef TEST check_required(VAR_RCPT_CHECKS, rcpt_restrctions, rcpt_required); +#endif /* * Parse the pre-defined restriction classes. @@ -740,7 +742,6 @@ static int check_relay_domains(SMTPD_STATE *state, char *recipient, char *reply_name, char *reply_class) { char *myname = "check_relay_domains"; - char *domain; static int permit_auth_destination(char *recipient); if (msg_verbose) @@ -785,8 +786,9 @@ static int permit_auth_destination(char *recipient) /* * Handle special case that is not supposed to happen. */ - if ((domain = split_at_right(STR(reply.recipient), '@')) == 0) + if ((domain = strrchr(STR(reply.recipient), '@')) == 0) return (SMTPD_CHECK_OK); + domain += 1; /* * Permit final delivery: the destination matches mydestination or @@ -797,14 +799,13 @@ static int permit_auth_destination(char *recipient) return (SMTPD_CHECK_OK); /* - * Permit non-routed mail to a destination on the relay_domains list. + * Permit if the destination matches the relay_domains list. */ - if ((reply.flags & RESOLVE_FLAG_ROUTED) == 0 - && domain_list_match(relay_domains, domain)) + if (domain_list_match(relay_domains, domain)) return (SMTPD_CHECK_OK); /* - * Something else. + * Skip when not matched */ return (SMTPD_CHECK_DUNNO); } @@ -814,7 +815,6 @@ static int permit_auth_destination(char *recipient) static int reject_unauth_destination(SMTPD_STATE *state, char *recipient) { char *myname = "reject_unauth_destination"; - char *domain; if (msg_verbose) msg_info("%s: %s", myname, recipient); @@ -826,7 +826,7 @@ static int reject_unauth_destination(SMTPD_STATE *state, char *recipient) return (SMTPD_CHECK_DUNNO); /* - * Reject unauthorized destination. + * Reject relaying to sites that are not listed in relay_domains. */ return (smtpd_check_reject(state, MAIL_ERROR_POLICY, "%d <%s>: Relay access denied", @@ -852,6 +852,52 @@ static int reject_unauth_pipelining(SMTPD_STATE *state) return (SMTPD_CHECK_DUNNO); } +/* reject_routed_relay - FAIL for relaying via sender-specified route */ + +static int reject_routed_relay(SMTPD_STATE *state, char *recipient, + char *reply_name, char *reply_class) +{ + char *myname = "reject_routed_relay"; + char *domain; + + if (msg_verbose) + msg_info("%s: %s", myname, recipient); + + /* + * Resolve the address. + */ + canon_addr_internal(query, recipient); + resolve_clnt_query(STR(query), &reply); + + /* + * Handle special case that is not supposed to happen. + */ + if ((domain = strrchr(STR(reply.recipient), '@')) == 0) + return (SMTPD_CHECK_DUNNO); + domain += 1; + + /* + * Permit final delivery: the destination matches mydestination or + * virtual_maps. + */ + if (resolve_local(domain) + || (*var_virtual_maps && maps_find(virtual_maps, domain, 0))) + return (SMTPD_CHECK_DUNNO); + + /* + * Reject source-routed mail to a non-local destination. + */ + if ((reply.flags & RESOLVE_FLAG_ROUTED) != 0) + return (smtpd_check_reject(state, MAIL_ERROR_POLICY, + "%d <%s>: %s rejected: Source-routed relay access denied", + var_relay_code, reply_name, reply_class)); + + /* + * Something else. + */ + return (SMTPD_CHECK_DUNNO); +} + /* has_my_addr - see if this host name lists one of my network addresses */ static int has_my_addr(char *host) @@ -1801,10 +1847,13 @@ char *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient) */ state->recursion = 0; status = setjmp(smtpd_check_buf); - if (status == 0 && rcpt_restrctions->argc) + if (status == 0 && rcpt_restrctions->argc) { status = generic_checks(state, rcpt_restrctions, recipient, SMTPD_NAME_RECIPIENT, CHECK_RECIP_ACL); - + if (var_allow_routed_relay == 0 && status != SMTPD_CHECK_REJECT) + status = reject_routed_relay(state, recipient, + recipient, SMTPD_NAME_RECIPIENT); + } SMTPD_CHECK_RCPT_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0); } @@ -1994,7 +2043,11 @@ char *var_maps_rbl_domains; char *var_mydest; char *var_inet_interfaces; char *var_rest_classes; -char *var_local_transports; +char *var_alias_maps; +char *var_rcpt_canon_maps; +char *var_canonical_maps; +char *var_virtual_maps; +char *var_local_rcpt_maps; typedef struct { char *name; @@ -2007,7 +2060,11 @@ static STRING_TABLE string_table[] = { VAR_MYDEST, DEF_MYDEST, &var_mydest, VAR_INET_INTERFACES, DEF_INET_INTERFACES, &var_inet_interfaces, VAR_REST_CLASSES, DEF_REST_CLASSES, &var_rest_classes, - VAR_LOCAL_TRANSP, DEF_LOCAL_TRANSP, &var_local_transports, + VAR_ALIAS_MAPS, DEF_ALIAS_MAPS, &var_alias_maps, + VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, + VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, + VAR_VIRTUAL_MAPS, DEF_VIRTUAL_MAPS, &var_virtual_maps, + VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, }; @@ -2057,6 +2114,7 @@ int var_access_map_code; int var_reject_code; int var_non_fqdn_code; int var_smtpd_delay_reject; +int var_allow_routed_relay; static INT_TABLE int_table[] = { "msg_verbose", 0, &msg_verbose, @@ -2070,6 +2128,7 @@ static INT_TABLE int_table[] = { VAR_REJECT_CODE, DEF_REJECT_CODE, &var_reject_code, VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code, VAR_SMTPD_DELAY_REJECT, DEF_SMTPD_DELAY_REJECT, &var_smtpd_delay_reject, + VAR_ALLOW_ROUTED_RELAY, DEF_ALLOW_ROUTED_RELAY, &var_allow_routed_relay, 0, }; @@ -2106,7 +2165,7 @@ static int int_update(char **argv) typedef struct { char *name; ARGV **target; -} REST_TABLE; +} REST_TABLE; static REST_TABLE rest_table[] = { "client_restrictions", &client_restrctions, diff --git a/postfix/smtpd/smtpd_check.in b/postfix/smtpd/smtpd_check.in index fd827324b..02e11e9e9 100644 --- a/postfix/smtpd/smtpd_check.in +++ b/postfix/smtpd/smtpd_check.in @@ -9,7 +9,7 @@ relay_domains porcupine.org # # Test the client restrictions. # -client_restrictions permit_mynetworks,reject_unknown_client,dbm:./smtpd_check_access +client_restrictions permit_mynetworks,reject_unknown_client,hash:./smtpd_check_access client unknown 131.155.210.17 client unknown 168.100.189.13 client random.bad.domain 123.123.123.123 @@ -21,14 +21,14 @@ client_restrictions permit_mynetworks # # Test the helo restrictions # -helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,reject_unknown_hostname,dbm:./smtpd_check_access +helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,reject_unknown_hostname,hash:./smtpd_check_access client unknown 131.155.210.17 helo foo. client foo 123.123.123.123 helo foo. helo foo helo spike.porcupine.org -helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,dbm:./smtpd_check_access +helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,hash:./smtpd_check_access helo random.bad.domain helo friend.bad.domain helo_restrictions reject_invalid_hostname,reject_unknown_hostname @@ -48,7 +48,7 @@ mail foo@watson.ibm.com sender_restrictions reject_unknown_address mail foo@watson.ibm.com mail foo@bad.domain -sender_restrictions dbm:./smtpd_check_access +sender_restrictions hash:./smtpd_check_access mail bad-sender@any.domain mail bad-sender@good.domain mail reject@this.address @@ -75,7 +75,7 @@ rcpt foo@porcupine.org client foo 123.123.123.123 rcpt foo@watson.ibm.com rcpt foo@porcupine.org -recipient_restrictions dbm:./smtpd_check_access +recipient_restrictions hash:./smtpd_check_access mail bad-sender@any.domain mail bad-sender@good.domain mail reject@this.address @@ -94,16 +94,16 @@ client foo 127.0.0.2 recipient_restrictions check_relay_domains client foo 131.155.210.17 rcpt foo@watson.ibm.com -recipient_restrictions check_client_access,dbm:./smtpd_check_access,check_relay_domains +recipient_restrictions check_client_access,hash:./smtpd_check_access,check_relay_domains client foo 131.155.210.17 rcpt foo@porcupine.org -helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,dbm:./smtpd_check_access -recipient_restrictions check_helo_access,dbm:./smtpd_check_access,check_relay_domains +helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,hash:./smtpd_check_access +recipient_restrictions check_helo_access,hash:./smtpd_check_access,check_relay_domains helo bad.domain rcpt foo@porcupine.org helo 131.155.210.17 rcpt foo@porcupine.org -recipient_restrictions check_sender_access,dbm:./smtpd_check_access,check_relay_domains +recipient_restrictions check_sender_access,hash:./smtpd_check_access,check_relay_domains mail foo@bad.domain rcpt foo@porcupine.org mail foo@friend.bad.domain @@ -123,7 +123,7 @@ rcpt wietse@porcupine.org client_restrictions permit helo_restrictions permit sender_restrictions permit -recipient_restrictions check_helo_access,dbm:./smtpd_check_access,check_sender_access,dbm:./smtpd_check_access +recipient_restrictions check_helo_access,hash:./smtpd_check_access,check_sender_access,hash:./smtpd_check_access helo bad.domain mail foo@good.domain rcpt foo@porcupine.org diff --git a/postfix/smtpd/smtpd_check.in2 b/postfix/smtpd/smtpd_check.in2 index 9dbfd36f7..0eaf8c02b 100644 --- a/postfix/smtpd/smtpd_check.in2 +++ b/postfix/smtpd/smtpd_check.in2 @@ -9,7 +9,7 @@ relay_domains porcupine.org # # Test the client restrictions. # -client_restrictions permit_mynetworks,reject_unknown_client,check_client_access,dbm:./smtpd_check_access +client_restrictions permit_mynetworks,reject_unknown_client,check_client_access,hash:./smtpd_check_access client unknown 131.155.210.17 client unknown 168.100.189.13 client random.bad.domain 123.123.123.123 @@ -21,14 +21,14 @@ client_restrictions permit_mynetworks # # Test the helo restrictions # -helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,reject_unknown_hostname,check_helo_access,dbm:./smtpd_check_access +helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,reject_unknown_hostname,check_helo_access,hash:./smtpd_check_access client unknown 131.155.210.17 helo foo. client foo 123.123.123.123 helo foo. helo foo helo spike.porcupine.org -helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,check_helo_access,dbm:./smtpd_check_access +helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,check_helo_access,hash:./smtpd_check_access helo random.bad.domain helo friend.bad.domain # @@ -44,7 +44,7 @@ mail foo@watson.ibm.com sender_restrictions reject_unknown_address mail foo@watson.ibm.com mail foo@bad.domain -sender_restrictions check_sender_access,dbm:./smtpd_check_access +sender_restrictions check_sender_access,hash:./smtpd_check_access mail bad-sender@any.domain mail bad-sender@good.domain mail reject@this.address @@ -71,7 +71,7 @@ rcpt foo@porcupine.org client foo 123.123.123.123 rcpt foo@watson.ibm.com rcpt foo@porcupine.org -recipient_restrictions check_recipient_access,dbm:./smtpd_check_access +recipient_restrictions check_recipient_access,hash:./smtpd_check_access mail bad-sender@any.domain mail bad-sender@good.domain mail reject@this.address diff --git a/postfix/smtpd/smtpd_check.in3 b/postfix/smtpd/smtpd_check.in3 new file mode 100644 index 000000000..e69de29bb diff --git a/postfix/smtpd/smtpd_check.ref b/postfix/smtpd/smtpd_check.ref index 6e9e1b351..29103605a 100644 --- a/postfix/smtpd/smtpd_check.ref +++ b/postfix/smtpd/smtpd_check.ref @@ -12,7 +12,7 @@ OK >>> # >>> # Test the client restrictions. >>> # ->>> client_restrictions permit_mynetworks,reject_unknown_client,dbm:./smtpd_check_access +>>> client_restrictions permit_mynetworks,reject_unknown_client,hash:./smtpd_check_access OK >>> client unknown 131.155.210.17 ./smtpd_check: reject: CONNECT from unknown[131.155.210.17]: 450 Client host rejected: cannot find your hostname, [131.155.210.17] @@ -37,7 +37,7 @@ OK >>> # >>> # Test the helo restrictions >>> # ->>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,reject_unknown_hostname,dbm:./smtpd_check_access +>>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,reject_unknown_hostname,hash:./smtpd_check_access OK >>> client unknown 131.155.210.17 OK @@ -54,7 +54,7 @@ OK 450 : Helo command rejected: Host not found >>> helo spike.porcupine.org OK ->>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,dbm:./smtpd_check_access +>>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,hash:./smtpd_check_access OK >>> helo random.bad.domain ./smtpd_check: reject: HELO from foo[123.123.123.123]: 554 : Helo command rejected: match bad.domain @@ -96,7 +96,7 @@ OK >>> mail foo@bad.domain ./smtpd_check: reject: MAIL from foo[123.123.123.123]: 450 : Sender address rejected: Domain not found; from= 450 : Sender address rejected: Domain not found ->>> sender_restrictions dbm:./smtpd_check_access +>>> sender_restrictions hash:./smtpd_check_access OK >>> mail bad-sender@any.domain ./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 : Sender address rejected: match bad-sender@; from= @@ -156,7 +156,7 @@ OK 554 : Recipient address rejected: Relay access denied >>> rcpt foo@porcupine.org OK ->>> recipient_restrictions dbm:./smtpd_check_access +>>> recipient_restrictions hash:./smtpd_check_access OK >>> mail bad-sender@any.domain ./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 : Sender address rejected: match bad-sender@; from= @@ -182,8 +182,8 @@ OK >>> client spike.porcupine.org 168.100.189.2 OK >>> client foo 127.0.0.2 -./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: EBlackholed - see ; from= -554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: EBlackholed - see +./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: Blackholed - see ; from= +554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: Blackholed - see >>> # >>> # Hybrids >>> # @@ -194,15 +194,15 @@ OK >>> rcpt foo@watson.ibm.com ./smtpd_check: reject: RCPT from foo[131.155.210.17]: 554 : Recipient address rejected: Relay access denied; from= to= 554 : Recipient address rejected: Relay access denied ->>> recipient_restrictions check_client_access,dbm:./smtpd_check_access,check_relay_domains +>>> recipient_restrictions check_client_access,hash:./smtpd_check_access,check_relay_domains OK >>> client foo 131.155.210.17 OK >>> rcpt foo@porcupine.org OK ->>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,dbm:./smtpd_check_access +>>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,hash:./smtpd_check_access OK ->>> recipient_restrictions check_helo_access,dbm:./smtpd_check_access,check_relay_domains +>>> recipient_restrictions check_helo_access,hash:./smtpd_check_access,check_relay_domains OK >>> helo bad.domain ./smtpd_check: reject: HELO from foo[131.155.210.17]: 554 : Helo command rejected: match bad.domain; from= @@ -215,7 +215,7 @@ OK OK >>> rcpt foo@porcupine.org OK ->>> recipient_restrictions check_sender_access,dbm:./smtpd_check_access,check_relay_domains +>>> recipient_restrictions check_sender_access,hash:./smtpd_check_access,check_relay_domains OK >>> mail foo@bad.domain ./smtpd_check: reject: MAIL from foo[131.155.210.17]: 554 : Sender address rejected: match bad.domain; from= @@ -252,7 +252,7 @@ OK OK >>> sender_restrictions permit OK ->>> recipient_restrictions check_helo_access,dbm:./smtpd_check_access,check_sender_access,dbm:./smtpd_check_access +>>> recipient_restrictions check_helo_access,hash:./smtpd_check_access,check_sender_access,hash:./smtpd_check_access OK >>> helo bad.domain OK diff --git a/postfix/smtpd/smtpd_check.ref2 b/postfix/smtpd/smtpd_check.ref2 index 17573ff4e..8a7347673 100644 --- a/postfix/smtpd/smtpd_check.ref2 +++ b/postfix/smtpd/smtpd_check.ref2 @@ -12,7 +12,7 @@ OK >>> # >>> # Test the client restrictions. >>> # ->>> client_restrictions permit_mynetworks,reject_unknown_client,check_client_access,dbm:./smtpd_check_access +>>> client_restrictions permit_mynetworks,reject_unknown_client,check_client_access,hash:./smtpd_check_access OK >>> client unknown 131.155.210.17 ./smtpd_check: reject: CONNECT from unknown[131.155.210.17]: 450 Client host rejected: cannot find your hostname, [131.155.210.17] @@ -37,7 +37,7 @@ OK >>> # >>> # Test the helo restrictions >>> # ->>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,reject_unknown_hostname,check_helo_access,dbm:./smtpd_check_access +>>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,reject_unknown_hostname,check_helo_access,hash:./smtpd_check_access OK >>> client unknown 131.155.210.17 OK @@ -54,7 +54,7 @@ OK 450 : Helo command rejected: Host not found >>> helo spike.porcupine.org OK ->>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,check_helo_access,dbm:./smtpd_check_access +>>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,check_helo_access,hash:./smtpd_check_access OK >>> helo random.bad.domain ./smtpd_check: reject: HELO from foo[123.123.123.123]: 554 : Helo command rejected: match bad.domain @@ -86,7 +86,7 @@ OK >>> mail foo@bad.domain ./smtpd_check: reject: MAIL from foo[123.123.123.123]: 450 : Sender address rejected: Domain not found; from= 450 : Sender address rejected: Domain not found ->>> sender_restrictions check_sender_access,dbm:./smtpd_check_access +>>> sender_restrictions check_sender_access,hash:./smtpd_check_access OK >>> mail bad-sender@any.domain ./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 : Sender address rejected: match bad-sender@; from= @@ -146,7 +146,7 @@ OK 554 : Recipient address rejected: Relay access denied >>> rcpt foo@porcupine.org OK ->>> recipient_restrictions check_recipient_access,dbm:./smtpd_check_access +>>> recipient_restrictions check_recipient_access,hash:./smtpd_check_access OK >>> mail bad-sender@any.domain ./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 : Sender address rejected: match bad-sender@; from= @@ -172,8 +172,8 @@ OK >>> client spike.porcupine.org 168.100.189.2 OK >>> client foo 127.0.0.2 -./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: EBlackholed - see ; from= -554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: EBlackholed - see +./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: Blackholed - see ; from= +554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: Blackholed - see >>> # >>> # unknown sender/recipient domain >>> # diff --git a/postfix/smtpd/smtpd_check.ref3 b/postfix/smtpd/smtpd_check.ref3 new file mode 100644 index 000000000..e69de29bb diff --git a/postfix/trivial-rewrite/resolve.c b/postfix/trivial-rewrite/resolve.c index 47f9a6b96..3d0324bfd 100644 --- a/postfix/trivial-rewrite/resolve.c +++ b/postfix/trivial-rewrite/resolve.c @@ -122,6 +122,7 @@ void resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop, && VSTRING_LEN(tree->head->vstr) == 0) { tok822_free(tree->head); tree->head = tok822_scan(MAIL_ADDR_POSTMASTER, &tree->tail); + rewrite_tree(REWRITE_CANON, tree); } /* @@ -137,28 +138,33 @@ void resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop, } /* - * After stripping the local domain, replace foo%bar by foo@bar, - * site!user by user@site, rewrite to canonical form, and retry. + * After stripping the local domain, if any, replace foo%bar by + * foo@bar, site!user by user@site, rewrite to canonical form, and + * retry. Recognize routing operators in the address localpart. This + * is needed to prevent primary MX hosts from relaying third-party + * destinations from backup MX hosts, otherwise the primary could end + * up on black lists. + * * Otherwise we're done. */ - if ((domain = tok822_rfind_type(tree->tail, '@')) == 0) { - if (var_swap_bangpath && tok822_rfind_type(tree->tail, '!') != 0) { - rewrite_tree(REWRITE_CANON, tree); - } else if (var_percent_hack - && (domain = tok822_rfind_type(tree->tail, '%')) != 0) { - domain->type = '@'; - rewrite_tree(REWRITE_CANON, tree); - } else { - break; - } + if (tok822_rfind_type(tree->tail, '@') + || (var_swap_bangpath && tok822_rfind_type(tree->tail, '!')) + || (var_percent_hack && tok822_rfind_type(tree->tail, '%'))) { + *flags |= RESOLVE_FLAG_ROUTED; + rewrite_tree(REWRITE_CANON, tree); + } else { + domain = 0; + break; } } /* * If the destination is non-local, recognize routing operators in the - * address localpart. This is needed to protect backup hosts against - * relaying by primary hosts, because the backup host would end up on - * black lists. + * address localpart. This is needed to prevent backup MX hosts from + * relaying third-party destinations through primary MX hosts, otherwise + * the backup host could end up on black lists. Ignore local + * swap_bangpath and percent_hack settings because we can't know how the + * primary MX host is set up. */ if (domain && domain->prev) if (tok822_rfind_type(domain->prev, '@') != 0 diff --git a/postfix/trivial-rewrite/rewrite.c b/postfix/trivial-rewrite/rewrite.c index 85e2face5..80ab11c25 100644 --- a/postfix/trivial-rewrite/rewrite.c +++ b/postfix/trivial-rewrite/rewrite.c @@ -148,7 +148,7 @@ void rewrite_tree(char *unused_ruleset, TOK822 *tree) } /* - * Append missing @origin. + * Append missing @origin */ else if (var_append_at_myorigin != 0) { domain = tok822_sub_append(tree, tok822_alloc('@', (char *) 0));