From: Wietse Venema Date: Sat, 25 Dec 1999 05:00:00 +0000 (-0500) Subject: snapshot-19991225 X-Git-Tag: v20010228~77 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9005adcaca5d48ddd3534f795e89c16e3af4c455;p=thirdparty%2Fpostfix.git snapshot-19991225 --- diff --git a/postfix/BEWARE b/postfix/BEWARE new file mode 100644 index 000000000..89cf9f8a0 --- /dev/null +++ b/postfix/BEWARE @@ -0,0 +1,50 @@ +LINUX SYSLOGD PERFORMANCE +========================= + +LINUX syslogd uses synchronous writes by default, which is very +expensive. For services such a mail it is recommended that you +disable synchronous logfile writes by prepending a - to the logfile +name: + + mail.* -/var/log/mail.log + +SPAM BLOCKING SOURCE ROUTED ADDRESSES +===================================== + +If you are responsible for a backup MX host for some domain (either +your own domain or the domain of some other organization) it is +prudent to block addresses with multiple address operators at the +SMTP port, such as: + + user@elsewhere@some.domain + user%elsewhere@some.domain + elsewhere!user@some.domain + +The problem is that the primary MX host for some.domain may forward +the above to user@elsewhere. This can happen because the primary +MX host somehow "trusts" your 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 involves +a primary MX host that perhaps is not under your control. + +The simplest solution is to install a regular expression filter: + + /etc/postfix/main.cf: + smtpd_recipient_restrictions = + regexp:/etc/postfix/regexp_access + ...other restrictions... + + /etc/postfix/regexp_access: + /[%!@].*[%!@]/ 550 Sender specified routing is not supported here. + +For the local domain, Postfix will do the right thing with: + + user@elsewhere@my.own.domain + user%elsewhere@my.own.domain + elsewhere!user@my.own.domain + +That is, it bounces the first form because "user@elsewhere" is not +a valid local user, and it accepts the second and third forms only +when user@elsewhere is a valid relay destination. diff --git a/postfix/HISTORY b/postfix/HISTORY index 224a62968..a76f7cd03 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -3471,3 +3471,8 @@ Apologies for any names omitted. to change Postfix into an open relay. File: smtpd/smtpd_check.c. Retraction: null-length inet_interfaces is too confusing. + +19991224 + + Bugfix: the relative symlink code in INSTALL.sh computed + the ../ segments from the wrong pathname. diff --git a/postfix/INSTALL.sh b/postfix/INSTALL.sh index 4bd312967..4fceb90d3 100644 --- a/postfix/INSTALL.sh +++ b/postfix/INSTALL.sh @@ -58,18 +58,22 @@ compare_or_replace() { compare_or_symlink() { cmp $1 $2 >/dev/null 2>&1 || { rm -f $tempdir/junk || exit 1 - target=`echo $1 | sed ' + dest=`echo $1 | sed ' + s;^'$install_root';; + s;/\./;/;g + s;//*;/;g + s;^/;; + '` + link=`echo $2 | sed ' s;^'$install_root';; s;/\./;/;g s;//*;/;g s;^/;; - H s;/[^/]*$;/; s;[^/]*/;../;g - G - s/\n// + s;$;'$dest'; '` - ln -s $target $tempdir/junk || exit 1 + ln -s $link $tempdir/junk || exit 1 mv -f $tempdir/junk $2 || { echo Error: your mv command is unable to rename symlinks. 1>&2 echo If you run Linux, upgrade to GNU fileutils-4.0 or better, 1>&2 diff --git a/postfix/global/mail_version.h b/postfix/global/mail_version.h index 24dbfb450..f4ada0836 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-19991223" +#define DEF_MAIL_VERSION "Snapshot-19991225" extern char *var_mail_version; /* LICENSE diff --git a/postfix/global/quote_822_local.c b/postfix/global/quote_822_local.c index f32ca696a..138b46634 100644 --- a/postfix/global/quote_822_local.c +++ b/postfix/global/quote_822_local.c @@ -93,7 +93,7 @@ static int is_822_dot_string(const char *local_part, const char *end) return (NO); if (ch == '(' || ch == ')' || ch == '<' || ch == '>' - || ch == '@' || ch == ',' + /* || ch == '@' */ || ch == ',' || ch == ';' || ch == ':' || ch == '\\' || ch == '"' || ch == '[' || ch == ']') diff --git a/postfix/global/resolve_clnt.c b/postfix/global/resolve_clnt.c index f8978da7b..fc86c798d 100644 --- a/postfix/global/resolve_clnt.c +++ b/postfix/global/resolve_clnt.c @@ -11,6 +11,7 @@ /* VSTRING *transport; /* VSTRING *nexthop /* VSTRING *recipient; +/* int flags; /* .in -4 /* } RESOLVE_REPLY; /* @@ -35,6 +36,17 @@ /* transport name, next_hop host name, and internal-form recipient /* address. In case of communication failure the program keeps trying /* until the mail system goes down. +/* +/* In the resolver reply, the flags member is the bit-wise OR of +/* zero or more of the following: +/* .IP RESOLVE_FLAG_FINAL +/* The recipient address resolves to a mail transport that performs +/* final delivery. The destination is local or corresponds to a hosted +/* domain that is handled by the local machine. This flag is currently +/* not used. +/* .IP RESOLVE_FLAG_ROUTED +/* The recipient address contains routing information, so the +/* destination domain is not necessarily the final destination. /* DIAGNOSTICS /* Warnings: communication failure. Fatal error: mail system is down. /* SEE ALSO @@ -90,6 +102,7 @@ void resolve_clnt_init(RESOLVE_REPLY *reply) reply->transport = vstring_alloc(100); reply->nexthop = vstring_alloc(100); reply->recipient = vstring_alloc(100); + reply->flags = 0; } /* resolve_clnt_query - resolve address to (transport, next hop, recipient) */ @@ -123,6 +136,7 @@ void resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply) vstring_strcpy(reply->transport, STR(last_reply.transport)); vstring_strcpy(reply->nexthop, STR(last_reply.nexthop)); vstring_strcpy(reply->recipient, STR(last_reply.recipient)); + reply->flags = last_reply.flags; if (msg_verbose) msg_info("%s: cached: `%s' -> t=`%s' h=`%s' r=`%s'", myname, addr, STR(reply->transport), @@ -145,8 +159,9 @@ void resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply) || vstream_fflush(stream)) { if (msg_verbose || (errno != EPIPE && errno != ENOENT)) msg_warn("%s: bad write: %m", myname); - } else if (mail_scan(stream, "%s %s %s", reply->transport, - reply->nexthop, reply->recipient) != 3) { + } else if (mail_scan(stream, "%s %s %s %d", + reply->transport, reply->nexthop, + reply->recipient, &reply->flags) != 4) { if (msg_verbose || (errno != EPIPE && errno != ENOENT)) msg_warn("%s: bad read: %m", myname); } else { @@ -172,6 +187,7 @@ void resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply) vstring_strcpy(last_reply.transport, STR(reply->transport)); vstring_strcpy(last_reply.nexthop, STR(reply->nexthop)); vstring_strcpy(last_reply.recipient, STR(reply->recipient)); + last_reply.flags = reply->flags; } /* resolve_clnt_free - destroy reply */ diff --git a/postfix/global/resolve_clnt.h b/postfix/global/resolve_clnt.h index 308e5a8c7..af55d1f4e 100644 --- a/postfix/global/resolve_clnt.h +++ b/postfix/global/resolve_clnt.h @@ -21,10 +21,14 @@ */ #define RESOLVE_ADDR "resolve" +#define RESOLVE_FLAG_FINAL (1<<0) /* final delivery */ +#define RESOLVE_FLAG_ROUTED (1<<1) /* routed destination */ + typedef struct RESOLVE_REPLY { VSTRING *transport; VSTRING *nexthop; VSTRING *recipient; + int flags; } RESOLVE_REPLY; extern void resolve_clnt_init(RESOLVE_REPLY *); diff --git a/postfix/html/faq.html b/postfix/html/faq.html index 57063f189..f0ec41caf 100644 --- a/postfix/html/faq.html +++ b/postfix/html/faq.html @@ -721,18 +721,37 @@ users.

-However, there will be a problem when you are backup MX host for -a domain that runs Sendmail, because many Sendmail configurations -will forward the above mail to test@some.other.site. The -bad news is that your machine will be put on the black list because -it accepted the mail, even though the problem is with the configuration -of a Sendmail machine that is not under your control. +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:

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

+    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.

@@ -1060,7 +1079,7 @@ parameter:

-    /etc/postfix/main.cf
+    /etc/postfix/main.cf:
 	local_recipient_maps = $alias_maps, unix:passwd.byname
 
@@ -1447,8 +1466,8 @@ sense to make it moderated. Delivering mail to a command is a security-sensitive operation, because the command must be executed with the right privileges. -Only root-privileged software such as the Postfix delivery -agent can set the privileges for a command. +Only root-privileged software such as the Postfix local +delivery agent can set the privileges for a command.

@@ -1560,13 +1579,6 @@ domain name: virtual.domain whatever -

- -

  • Verify that the smtpd_recipient_restrictions -parameter contains a restriction that depends on relay_domains. This is the default setting. -

    diff --git a/postfix/html/index.html b/postfix/html/index.html index 6482cfbde..5cacb4f37 100644 --- a/postfix/html/index.html +++ b/postfix/html/index.html @@ -31,9 +31,9 @@ First of all, thank you for your interest in the Postfix project. What is Postfix? It is Wietse Venema's attempt to provide an alternative to the widely-used Sendmail program. Sendmail -is responsible for an estimated 70% of all e-mail delivered on the -Internet. With an estimated 100 million users, that's billions of -messages daily. A stunning number. +is responsible for most of the e-mail delivered on the Internet. +With an estimated 100 million users, that's billions of messages +daily. A stunning number.

    diff --git a/postfix/html/uce.html b/postfix/html/uce.html index 3050f536c..857dcd193 100644 --- a/postfix/html/uce.html +++ b/postfix/html/uce.html @@ -634,9 +634,9 @@ reject_unauth_destination

    Note: you must specify at least one of the following -restrictions: reject, check_relay_domains or -reject_unauth_destination. Postfix will refuse to -receive mail otherwise. +restrictions: reject, check_relay_domains or +reject_unauth_destination. Postfix will refuse to receive +mail otherwise.

    @@ -755,16 +755,6 @@ response code to rejected requests (default: 504).

    -

    permit_recipient_map maptype:mapname
    -Permit the request when the recipient address matches the named -table. Table lookup is done as with the virtual and canonical tables. This also produces -useful results with the aliases and -unix:passwd.byname maps. - -

    -

    reject_unknown_sender_domain
    reject_non_fqdn_sender diff --git a/postfix/smtp/quote_821_local.c b/postfix/smtp/quote_821_local.c index 0ae67e469..d4522b210 100644 --- a/postfix/smtp/quote_821_local.c +++ b/postfix/smtp/quote_821_local.c @@ -81,7 +81,7 @@ static int is_821_dot_string(char *local_part, char *end) || ch == '[' || ch == ']' || ch == '\\' || ch == ',' || ch == ';' || ch == ':' - || ch == '@' || ch == '"') + /* || ch == '@' */ || ch == '"') return (NO); } if (cp[-1] == '.') diff --git a/postfix/smtpd/smtpd_check.c b/postfix/smtpd/smtpd_check.c index a19165d28..c3265c260 100644 --- a/postfix/smtpd/smtpd_check.c +++ b/postfix/smtpd/smtpd_check.c @@ -741,6 +741,7 @@ static int check_relay_domains(SMTPD_STATE *state, char *recipient, { char *myname = "check_relay_domains"; char *domain; + static int permit_auth_destination(char *recipient); if (msg_verbose) msg_info("%s: %s", myname, recipient); @@ -752,27 +753,9 @@ static int check_relay_domains(SMTPD_STATE *state, char *recipient, return (SMTPD_CHECK_OK); /* - * Resolve the address. - */ - canon_addr_internal(query, recipient); - resolve_clnt_query(STR(query), &reply); - - /* - * Permit if destination is local. That is, the destination matches - * mydestination or virtual_maps, or it resolves to any transport that - * delivers locally. - */ - if ((domain = strrchr(STR(reply.recipient), '@')) == 0) - return (SMTPD_CHECK_OK); - domain += 1; - if (resolve_local(domain) - || (*var_virtual_maps && maps_find(virtual_maps, domain, 0))) - return (SMTPD_CHECK_OK); - - /* - * Permit if the destination matches the relay_domains list. + * Permit authorized destinations. */ - if (domain_list_match(relay_domains, domain)) + if (permit_auth_destination(recipient) == SMTPD_CHECK_OK) return (SMTPD_CHECK_OK); /* @@ -800,25 +783,28 @@ static int permit_auth_destination(char *recipient) resolve_clnt_query(STR(query), &reply); /* - * Permit if destination is local. That is, the destination matches - * mydestination or virtual_maps, or it resolves to any transport that - * delivers locally. + * Handle special case that is not supposed to happen. */ - if ((domain = strrchr(STR(reply.recipient), '@')) == 0) + if ((domain = split_at_right(STR(reply.recipient), '@')) == 0) return (SMTPD_CHECK_OK); - 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_OK); /* - * Permit if the destination matches the relay_domains list. + * Permit non-routed mail to a destination on the relay_domains list. */ - if (domain_list_match(relay_domains, domain)) + if ((reply.flags & RESOLVE_FLAG_ROUTED) == 0 + && domain_list_match(relay_domains, domain)) return (SMTPD_CHECK_OK); /* - * Skip when not matched + * Something else. */ return (SMTPD_CHECK_DUNNO); } @@ -834,31 +820,13 @@ static int reject_unauth_destination(SMTPD_STATE *state, char *recipient) msg_info("%s: %s", myname, recipient); /* - * Resolve the address. - */ - canon_addr_internal(query, recipient); - resolve_clnt_query(STR(query), &reply); - - /* - * Permit if destination is local. That is, the destination matches - * mydestination or virtual_maps, or it resolves to any transport that - * delivers locally. - */ - if ((domain = strrchr(STR(reply.recipient), '@')) == 0) - return (SMTPD_CHECK_DUNNO); - domain += 1; - if (resolve_local(domain) - || (*var_virtual_maps && maps_find(virtual_maps, domain, 0))) - return (SMTPD_CHECK_DUNNO); - - /* - * Pass if the destination matches the relay_domains list. + * Permit authorized destination. */ - if (domain_list_match(relay_domains, domain)) + if (permit_auth_destination(recipient) == SMTPD_CHECK_OK) return (SMTPD_CHECK_DUNNO); /* - * Reject relaying to sites that are not listed in relay_domains. + * Reject unauthorized destination. */ return (smtpd_check_reject(state, MAIL_ERROR_POLICY, "%d <%s>: Relay access denied", diff --git a/postfix/trivial-rewrite/resolve.c b/postfix/trivial-rewrite/resolve.c index cc32a0f5b..47f9a6b96 100644 --- a/postfix/trivial-rewrite/resolve.c +++ b/postfix/trivial-rewrite/resolve.c @@ -83,13 +83,15 @@ /* resolve_addr - resolve address according to rule set */ void resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop, - VSTRING *nextrcpt) + VSTRING *nextrcpt, int *flags) { VSTRING *addr_buf = vstring_alloc(100); TOK822 *tree; TOK822 *saved_domain = 0; TOK822 *domain = 0; + *flags = 0; + /* * The address is in internalized (unquoted) form, so we must externalize * it first before we can parse it. @@ -135,21 +137,35 @@ void resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop, } /* - * Replace foo%bar by foo@bar, site!user by user@site, rewrite to - * canonical form, and retry. + * After stripping the local domain, replace foo%bar by foo@bar, + * site!user by user@site, rewrite to canonical form, and retry. + * Otherwise we're done. */ - 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 { - domain = 0; - break; + 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 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. + */ + if (domain && domain->prev) + if (tok822_rfind_type(domain->prev, '@') != 0 + || tok822_rfind_type(domain->prev, '!') != 0 + || tok822_rfind_type(domain->prev, '%') != 0) + *flags |= RESOLVE_FLAG_ROUTED; + /* * Make sure the resolved envelope recipient has the user@domain form. If * no domain was specified in the address, assume the local machine. See @@ -220,16 +236,19 @@ static VSTRING *query; int resolve_proto(VSTREAM *stream) { + int flags; + if (mail_scan(stream, "%s", query) != 1) return (-1); - resolve_addr(STR(query), channel, nexthop, nextrcpt); + resolve_addr(STR(query), channel, nexthop, nextrcpt, &flags); if (msg_verbose) - msg_info("%s -> (`%s' `%s' `%s')", STR(query), STR(channel), - STR(nexthop), STR(nextrcpt)); + msg_info("%s -> (`%s' `%s' `%s' `%d')", STR(query), STR(channel), + STR(nexthop), STR(nextrcpt), flags); - mail_print(stream, "%s %s %s", STR(channel), STR(nexthop), STR(nextrcpt)); + mail_print(stream, "%s %s %s %d", + STR(channel), STR(nexthop), STR(nextrcpt), flags); if (vstream_fflush(stream) != 0) { msg_warn("write resolver reply: %m"); diff --git a/postfix/trivial-rewrite/rewrite.c b/postfix/trivial-rewrite/rewrite.c index b798a5c3c..85e2face5 100644 --- a/postfix/trivial-rewrite/rewrite.c +++ b/postfix/trivial-rewrite/rewrite.c @@ -122,26 +122,38 @@ void rewrite_tree(char *unused_ruleset, TOK822 *tree) tok822_free_tree(tok822_sub_keep_after(tree, colon)); /* - * Swap domain!user to user@domain. + * Optionally, transform address forms without @. */ - if (var_swap_bangpath != 0 - && (domain = tok822_rfind_type(tree->tail, '@')) == 0 - && (bang = tok822_find_type(tree->head, '!')) != 0) { - tok822_sub_keep_before(tree, bang); - local = tok822_cut_after(bang); - tok822_free(bang); - tok822_sub_prepend(tree, tok822_alloc('@', (char *) 0)); - if (local) - tok822_sub_prepend(tree, local); - } - - /* - * Append missing @origin - */ - if (var_append_at_myorigin != 0 - && (domain = tok822_rfind_type(tree->tail, '@')) == 0) { - domain = tok822_sub_append(tree, tok822_alloc('@', (char *) 0)); - tok822_sub_append(tree, tok822_scan(var_myorigin, (TOK822 **) 0)); + if ((domain = tok822_rfind_type(tree->tail, '@')) == 0) { + + /* + * Swap domain!user to user@domain. + */ + if (var_swap_bangpath != 0 + && (bang = tok822_find_type(tree->head, '!')) != 0) { + tok822_sub_keep_before(tree, bang); + local = tok822_cut_after(bang); + tok822_free(bang); + tok822_sub_prepend(tree, tok822_alloc('@', (char *) 0)); + if (local) + tok822_sub_prepend(tree, local); + } + + /* + * Promote user%domain to user@domain. + */ + else if (var_percent_hack != 0 + && (domain = tok822_rfind_type(tree->tail, '%')) != 0) { + domain->type = '@'; + } + + /* + * Append missing @origin. + */ + else if (var_append_at_myorigin != 0) { + domain = tok822_sub_append(tree, tok822_alloc('@', (char *) 0)); + tok822_sub_append(tree, tok822_scan(var_myorigin, (TOK822 **) 0)); + } } /* diff --git a/postfix/trivial-rewrite/trivial-rewrite.h b/postfix/trivial-rewrite/trivial-rewrite.h index da5ef96ee..2a13de62f 100644 --- a/postfix/trivial-rewrite/trivial-rewrite.h +++ b/postfix/trivial-rewrite/trivial-rewrite.h @@ -32,7 +32,7 @@ extern void rewrite_tree(char *, TOK822 *); */ extern void resolve_init(void); extern int resolve_proto(VSTREAM *); -extern void resolve_addr(char *, VSTRING *, VSTRING *, VSTRING *); +extern void resolve_addr(char *, VSTRING *, VSTRING *, VSTRING *, int *); /* LICENSE /* .ad