From: Wietse Venema Date: Tue, 19 Oct 2004 05:00:00 +0000 (-0500) Subject: postfix-2.2-20041019 X-Git-Tag: v2.2.0-RC1~36 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a203330d1d90f94a493964cc2b8297c670fd224b;p=thirdparty%2Fpostfix.git postfix-2.2-20041019 --- diff --git a/postfix/.indent.pro b/postfix/.indent.pro index d58f4db3f..42fe93c4d 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -143,6 +143,7 @@ -TRESPONSE -TREST_TABLE -TRES_CONTEXT +-TRWR_CONTEXT -TSCACHE -TSCACHE_CLNT -TSCACHE_MULTI diff --git a/postfix/HISTORY b/postfix/HISTORY index de4fe1935..640ded713 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -9774,6 +9774,45 @@ Apologies for any names omitted. Portability: AIX 5.1/GCC. +20041014-19 + + Message header address rewriting contexts, so that spam + from badly written software won't look like it came from + a local user. + + The default "local" rewriting context appends "@$myorigin" + or ".$mydomain" to incomplete message header addresses, + just like Postfix has always done. + + The new "invalid" address context appends "domain.invalid" + instead (or whatever domain name is specified with the + invalid_rewrite_context_domain parameter). + + The new "none" address rewriting context does not modify + message header addresses at all. + + Postfix uses the "local" rewriting context for mail from + the machine itself, from clients listed with the + local_rewrite_context_clients parameter (default: + $inet_interfaces $mynetworks) and from SASL authenticated + clients. + + The context specified with remote_rewrite_context_name is + used for all other clients. The default setting is backwards + compatible to avoid surprises. + + Postfix always uses the "local" rewriting context to update + incomplete envelope addresses. + +20041018 + + The NIS+ module by Geoff Gibbs is now part of Postfix. + Files: util/dict_nisplus.c, proto/nisplus_table. + +20041019 + + Support for Errors-To: is permanently removed. + Open problems: Low: should the Delivered-To: test in local(8) be configurable? diff --git a/postfix/README_FILES/BASIC_CONFIGURATION_README b/postfix/README_FILES/BASIC_CONFIGURATION_README index 9883e6567..d56b703d1 100644 --- a/postfix/README_FILES/BASIC_CONFIGURATION_README +++ b/postfix/README_FILES/BASIC_CONFIGURATION_README @@ -210,10 +210,10 @@ the patterns in the main.cf file. WWhhaatt ddeessttiinnaattiioonnss ttoo rreellaayy mmaaiill ttoo By default, Postfix will forward mail from strangers (clients outside -authorized networks) to authorized destinations only. Authorized destinations -are defined with the relay_domains configuration parameter. The default is to -authorize all domains (and subdomains) of the domains listed with the -mydestination parameter. +authorized networks) to authorized remote destinations only. Authorized remote +destinations are defined with the relay_domains configuration parameter. The +default is to authorize all domains (and subdomains) of the domains listed with +the mydestination parameter. Examples (specify only one of the following): @@ -240,7 +240,8 @@ Examples (specify only one of the following): relayhost = [mail.isp.tld] (deliver via provider mailhub) The form enclosed with [] eliminates DNS MX lookups. Don't worry if you don't -know what that means. +know what that means. Just be sure to specify the [] around the mailhub +hostname that your ISP gave to you, otherwise mail may be mis-delivered. The STANDARD_CONFIGURATION_README file has more hints and tips for firewalled and/or dial-up networks. diff --git a/postfix/README_FILES/DATABASE_README b/postfix/README_FILES/DATABASE_README index 3c080e5d3..5d1fb8b9c 100644 --- a/postfix/README_FILES/DATABASE_README +++ b/postfix/README_FILES/DATABASE_README @@ -201,6 +201,13 @@ To find out what database types your Postfix system supports, use the "postconf mmyyssqqll (read-only) Perform MySQL database lookups. Configuration details are given in mysql_table(5). + nneettiinnffoo (read-only) + Perform Netinfo database lookups. + nniiss (read-only) + Perform NIS database lookups. + nniisspplluuss (read-only) + Perform NIS+ database lookups. Configuration details are given in + nisplus_table(5). ppccrree (read-only) A lookup table based on Perl Compatible Regular Expressions. The file format is described in pcre_table(5). The lookup table name as used in diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 9b3e75a7e..86a10ec85 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -7,6 +7,52 @@ snapshot release). Patches are issued for the official release and change the patchlevel and the release date. Patches are never issued for snapshot releases. +Incompatible changes with snapshot Postfix-2.2-20041019 +======================================================= + +Support for return addresses in the non-standard Errors-To: message +headers is removed. It was already disabled by default with Postfix +version 2.1. + +Major changes with snapshot Postfix-2.2-20041019 +================================================ + +The NIS+ client by Geoff Gibbs is now part of the Postfix source +tree. Details are given in the nisplus_table(5) manual page. + +Message header address rewriting contexts. These control what +domains are appended to incomplete addresses in message headers, +and whether headers are rewritten at all. + +- "local": Append the domain names in myorigin or mydomain to + incomplete addresses in message headers. + +- "invalid": append "domain.invalid" (or whatever is specified + with the invalid_header_rewrite_context_domain parameter) to + incomplete addresses in message headers, + +- "none": disable header address rewriting (don't even do canonical + mapping or address masquerading). + +The "local" address rewriting context is used for mail submitted +with the Postfix sendmail command, for mail from clients that match +$local_header_rewrite_context_clients (default: $inet_interfaces +$mynetworks), and for mail from SASL authenticated clients. It is +not automatically used for pop-before-smtp clients; you'll have to +specify their lookup table via the local_header_rewrite_context_clients +parameter. + +The smtpd_remote_header_rewrite_context parameter specifies the +address +rewriting context for remote mail. The backwards compatible default +is "local". Purists will specify "none", so that Postfix does not +modify headers (not even with canonical mappings or address +masquerading). + +Postix always uses the "local" context for envelope addresses, +because an unqualified address is effectively local when someone +attempts to reply to it. + Incompatible changes with snapshot Postfix-2.2-20041009 ======================================================= diff --git a/postfix/conf/postfix-files b/postfix/conf/postfix-files index b125f4d8d..d477ba474 100644 --- a/postfix/conf/postfix-files +++ b/postfix/conf/postfix-files @@ -144,6 +144,7 @@ $manpage_directory/man5/header_checks.5:f:root:-:644 $manpage_directory/man5/ldap_table.5:f:root:-:644 $manpage_directory/man5/master.5:f:root:-:644 $manpage_directory/man5/mysql_table.5:f:root:-:644 +$manpage_directory/man5/nisplus_table.5:f:root:-:644 $manpage_directory/man5/pcre_table.5:f:root:-:644 $manpage_directory/man5/pgsql_table.5:f:root:-:644 $manpage_directory/man5/postconf.5:f:root:-:644 @@ -313,6 +314,7 @@ $html_directory/mailq.1.html:f:root:-:644 $html_directory/master.5.html:f:root:-:644 $html_directory/master.8.html:f:root:-:644 $html_directory/mysql_table.5.html:f:root:-:644 +$html_directory/nisplus_table.5.html:f:root:-:644 $html_directory/newaliases.1.html:f:root:-:644 $html_directory/oqmgr.8.html:f:root:-:644 $html_directory/pcre_table.5.html:f:root:-:644 diff --git a/postfix/html/BASIC_CONFIGURATION_README.html b/postfix/html/BASIC_CONFIGURATION_README.html index cee197662..c204ba66d 100644 --- a/postfix/html/BASIC_CONFIGURATION_README.html +++ b/postfix/html/BASIC_CONFIGURATION_README.html @@ -315,7 +315,8 @@ of listing the patterns in the main.cf file.

What destinations to relay mail to

By default, Postfix will forward mail from strangers (clients outside -authorized networks) to authorized destinations only. Authorized +authorized networks) to authorized remote destinations only. +Authorized remote destinations are defined with the relay_domains configuration parameter. The default is to authorize all domains (and subdomains) of the domains listed with the mydestination parameter.

@@ -355,7 +356,9 @@ via a relay host.

The form enclosed with [] eliminates DNS MX lookups. -Don't worry if you don't know what that means.

+Don't worry if you don't know what that means. Just be sure to +specify the [] around the mailhub hostname that your ISP +gave to you, otherwise mail may be mis-delivered.

The STANDARD_CONFIGURATION_README file has more hints and tips for firewalled and/or dial-up networks.

diff --git a/postfix/html/DATABASE_README.html b/postfix/html/DATABASE_README.html index e879a983c..09f93d7e7 100644 --- a/postfix/html/DATABASE_README.html +++ b/postfix/html/DATABASE_README.html @@ -297,6 +297,19 @@ are given in the ldap_table(5).
Perform MySQL database lookups. Configuration details are given in mysql_table(5).
+
netinfo (read-only)
+ +
Perform Netinfo database lookups.
+ +
nis (read-only)
+ +
Perform NIS database lookups.
+ +
nisplus (read-only)
+ +
Perform NIS+ database lookups. Configuration details are given +in nisplus_table(5).
+
pcre (read-only)
A lookup table based on Perl Compatible Regular Expressions. diff --git a/postfix/html/Makefile.in b/postfix/html/Makefile.in index 1b44044bc..514370806 100644 --- a/postfix/html/Makefile.in +++ b/postfix/html/Makefile.in @@ -18,7 +18,7 @@ CONFIG = access.5.html aliases.5.html canonical.5.html relocated.5.html \ transport.5.html virtual.5.html pcre_table.5.html regexp_table.5.html \ cidr_table.5.html tcp_table.5.html header_checks.5.html \ ldap_table.5.html mysql_table.5.html pgsql_table.5.html \ - master.5.html + master.5.html nisplus_table.5.html OTHER = postfix-manuals.html AWK = awk '{ print; if (NR == 2) print ".pl 9999\n.ll 65" }' MAN2HTML = man2html -t "Postfix manual - `IFS=.; set \`echo $@\`; echo \"$$1($$2)\"`" @@ -249,6 +249,10 @@ mysql_table.5.html: ../proto/mysql_table PATH=../mantools:$$PATH; \ srctoman - $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@ +nisplus_table.5.html: ../proto/nisplus_table + PATH=../mantools:$$PATH; \ + srctoman - $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@ + pcre_table.5.html: ../proto/pcre_table PATH=../mantools:$$PATH; \ srctoman - $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@ diff --git a/postfix/html/cidr_table.5.html b/postfix/html/cidr_table.5.html index b766b892e..96f701bbc 100644 --- a/postfix/html/cidr_table.5.html +++ b/postfix/html/cidr_table.5.html @@ -15,10 +15,10 @@ CIDR_TABLE(5) CIDR_TABLE(5) postmap -q - cidr:/etc/postfix/filename <inputfile DESCRIPTION - The Postfix mail system uses optional access control - tables. These tables are usually in dbm or db format. - Alternatively, access control tables can be specified in - CIDR (Classless Inter-Domain Routing) form. + The Postfix mail system uses optional lookup tables. + These tables are usually in dbm or db format. Alterna- + tively, lookup tables can be specified in CIDR (Classless + Inter-Domain Routing) form. To find out what types of lookup tables your Postfix sys- tem supports use the postconf -m command. diff --git a/postfix/html/cleanup.8.html b/postfix/html/cleanup.8.html index 235967ba4..f45cc39ff 100644 --- a/postfix/html/cleanup.8.html +++ b/postfix/html/cleanup.8.html @@ -84,11 +84,6 @@ CLEANUP(8) CLEANUP(8) Available in Postfix version 2.1 and later: - enable_errors_to (no) - Report mail delivery errors to the address speci- - fied with the non-standard Errors-To: message - header, instead of the envelope sender address. - BUILT-IN CONTENT FILTERING CONTROLS Postfix built-in content filtering is meant to stop a flood of worms or viruses. It is not a general content diff --git a/postfix/html/nisplus_table.5.html b/postfix/html/nisplus_table.5.html new file mode 100644 index 000000000..e258e4fa3 --- /dev/null +++ b/postfix/html/nisplus_table.5.html @@ -0,0 +1,88 @@ + + + + Postfix manual - nisplus_table(5) +
+NISPLUS_TABLE(5)                                 NISPLUS_TABLE(5)
+
+NAME
+       nisplus_table - Postfix NIS+ client
+
+SYNOPSIS
+       postmap -q "string" "nisplus:[name=%s];name.name."
+
+       postmap -q - "nisplus:[name=%s];name.name." <inputfile
+
+DESCRIPTION
+       The  Postfix  mail  system  uses  optional  lookup tables.
+       These tables are usually in dbm or  db  format.   Alterna-
+       tively,  lookup tables can be specified as NIS+ databases.
+
+       To find out what types of lookup tables your Postfix  sys-
+       tem supports use the "postconf -m" command.
+
+       To  test  Postfix NIS+ lookup tables, use the postmap com-
+       mand as described in the SYNOPSIS above.
+
+QUERY SYNTAX
+       Most of the NIS+ query is specified via the NIS+ map name.
+       The  general  format of a Postfix NIS+ map name is as fol-
+       lows:
+
+           nisplus:[name=%s];name.name.name.:column
+
+       Postfix NIS+ map names differ from what one normally would
+       use with commands such as niscat:
+
+       o      With  each NIS+ table lookup, "%s" is replaced by a
+              version of the lookup string.  There  can  be  only
+              one "%s" instance in a Postfix NIS+ map name.
+
+       o      Postfix  NIS+  map  names  use  ";" instead of ",",
+              because the latter  character  is  special  in  the
+              Postfix main.cf file.  Postfix replaces ";" charac-
+              ters in the map name  by  ","  before  making  NIS+
+              queries.
+
+       o      The ":column" part in the NIS+ map name is not part
+              of the actual NIS+ query. Instead, it specifies the
+              number of the table column that provides the lookup
+              result. When no ":column" is  specified  the  first
+              column (1) is used.
+
+EXAMPLE
+       A NIS+ aliases map might be queried as follows:
+
+           alias_maps = dbm:/etc/mail/aliases,
+                 nisplus:[alias=%s];mail_aliases.org_dir.$mydomain.:1
+
+       This  queries the local aliases file before the NIS+ file.
+
+SEE ALSO
+       postmap(1), Postfix lookup table manager
+
+README FILES
+       DATABASE_README, Postfix lookup table overview
+
+LICENSE
+       The  Secure  Mailer  license must be distributed with this
+       software.
+
+AUTHOR(S)
+       Geoff Gibbs
+       UK-HGMP-RC
+       Hinxton
+       Cambridge
+       CB10 1SB, UK
+
+       Based on the NIS client code:
+
+       Adopted and adapted by:
+       Wietse Venema
+       IBM T.J. Watson Research
+       P.O. Box 704
+       Yorktown Heights, NY 10598, USA
+
+                                                 NISPLUS_TABLE(5)
+
diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 9884581f8..91dc67b4d 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -670,8 +670,9 @@ The default time unit is s (seconds). (default: yes)

-Append the string "@$myorigin" to mail addresses without domain -information. +With locally submitted mail, append the string "@$myorigin" to mail +addresses without domain information. With remotely submitted mail, +append the string "@$invalid_domain" instead.

@@ -686,8 +687,9 @@ Postfix does not support domain-less addresses. (default: yes)

-Append the string ".$mydomain" to addresses that have no ".domain" -information. +With locally submitted mail, append the string ".$mydomain" to +addresses that have no ".domain" information. With remotely submitted +mail, append the string ".$invalid_domain" instead.

@@ -2569,6 +2571,17 @@ block all mail to a site.

+
+ +
invalid_header_rewrite_context_domain +(default: domain.invalid)
+ +

Append this domain to incomplete message header addresses from +remote clients, when $remote_header_rewrite_context_name is set to +"invalid". This is one way to avoid appending your own domain to +addresses in spam from poorly written software.

+ +
invalid_hostname_reject_code @@ -3067,6 +3080,29 @@ the entry in the master.cf file.

into concurrency per domain.

+ + +
local_header_rewrite_context_clients +(default: $inet_interfaces +$mynetworks)
+ +

Append the domain names in $myorigin and $mydomain to incomplete +message header addresses from these clients.

+ +

Specify a list of network addresses or network/netmask patterns, +separated by comma or whitespace. The list is matched left to right, +and the search stops on the first match. Specify !address or +!network/netmask to exclude an address or network block from the +list. A network mask specifies the number of bits in the network +part of a host address. Continue long lines by starting the next +line with whitespace.

+ +

You can also specify "/file/name" or "type:table" patterns. +A "/file/name" pattern is replaced by its contents; a "type:table" +lookup table is matched when a client name or address matches a +lookup key (the lookup result is ignored).

+ +
local_recipient_maps @@ -4579,7 +4615,7 @@ configure or operate a specific Postfix subsystem or feature. (default: empty)

Enable or disable recipient validation, built-in content -filtering, or address rewriting. Typically, these are specified in +filtering, or address mapping. Typically, these are specified in master.cf as command-line arguments for the smtpd(8), qmqpd(8) or pickup(8) daemons.

@@ -4977,6 +5013,40 @@ Examples: +
+ +
remote_header_rewrite_context_name +(default: local)
+ +

The address rewriting context that should be used for incomplete +mail header addresses from remote clients.

+ +
    + +
  • local Append the domains specified with $myorigin +or $mydomain to incomplete message header addresses from remote +clients.

    + +
  • invalid Append the domain specified with +$invalid_header_rewrite_context_domain to incomplete message header +addresses from remote clients. This is one way to avoid appending +your own domain to addresses in spam from poorly written software. +This is a safe choice for gateways that have no control over +address rewriting by down-stream systems. +

    + +
  • none Don't modify message headers from remote +clients at all. This is another way to avoid appending your own +domain to addresses in spam from poorly written software. This +is the preferred choice for purists.

    + +
+ +

Note: Postfix always appends the domains specified with $myorigin +or $mydomain to incomplete envelope addresses, because those +addresses are effectively equivalent to local addresses.

+ +
require_home_directory diff --git a/postfix/html/postfix-manuals.html b/postfix/html/postfix-manuals.html index e286b3f18..6956125a5 100644 --- a/postfix/html/postfix-manuals.html +++ b/postfix/html/postfix-manuals.html @@ -49,9 +49,9 @@ overview

Each Postfix manual page is numbered after a section of the UNIX manual: examples are mailq(1) or access(5). Unfortunately, -the organization of manual pages depends on the UNIX version being -used. Postfix documentation assumes the following convention: -

+there is no single universal method to organize manual pages; each +UNIX flavor appears to be different. Postfix documentation assumes +the following convention:

@@ -141,6 +141,8 @@ used. Postfix documentation assumes the following convention:
  • mysql_table(5), Postfix MYSQL client +
  • nisplus_table(5), Postfix NIS+ client +
  • pcre_table(5), Associate PCRE pattern with value
  • pgsql_table(5), Postfix PostgreSQL client diff --git a/postfix/html/postfix.1.html b/postfix/html/postfix.1.html index 255a872b4..c71d72f8a 100644 --- a/postfix/html/postfix.1.html +++ b/postfix/html/postfix.1.html @@ -222,6 +222,7 @@ POSTFIX(1) POSTFIX(1) cidr_table(5), Associate CIDR pattern with value ldap_table(5), Postfix LDAP client mysql_table(5), Postfix MYSQL client + nisplus_table(5), Postfix NIS+ client pcre_table(5), Associate PCRE pattern with value pgsql_table(5), Postfix PostgreSQL client regexp_table(5), Associate POSIX regexp pattern with value diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index 98026c336..ebb5c37b4 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -103,6 +103,32 @@ SMTPD(8) SMTPD(8) What SMTP clients Postfix will not offer AUTH sup- port to. +ADDRESS REWRITING CONTROLS + receive_override_options (empty) + Enable or disable recipient validation, built-in + content filtering, or address mapping. + + Available in Postfix version 2.2 and later: + + local_header_rewrite_context_clients ($inet_interfaces + $mynetworks) + Append the domain names in $myorigin and $mydomain + to incomplete message header addresses from these + clients. + + remote_header_rewrite_context_name (local) + The address rewriting context that should be used + for incomplete mail header addresses from remote + clients. + + Implemented by the trivial-rewrite(8) server: + + invalid_header_rewrite_context_domain (domain.invalid) + Append this domain to incomplete message header + addresses from remote clients, when + $remote_header_rewrite_context_name is set to + "invalid". + AFTER QUEUE EXTERNAL CONTENT INSPECTION CONTROLS As of version 1.0, Postfix can be configured to send new mail to an external content filter AFTER the mail is @@ -142,7 +168,7 @@ SMTPD(8) SMTPD(8) receive_override_options (empty) Enable or disable recipient validation, built-in - content filtering, or address rewriting. + content filtering, or address mapping. EXTERNAL CONTENT INSPECTION CONTROLS The following parameters are applicable for both before- diff --git a/postfix/html/trivial-rewrite.8.html b/postfix/html/trivial-rewrite.8.html index 8b24af669..36022a14a 100644 --- a/postfix/html/trivial-rewrite.8.html +++ b/postfix/html/trivial-rewrite.8.html @@ -17,52 +17,71 @@ TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8) The trivial-rewrite daemon processes three types of client service requests: - rewrite - Rewrite an address to standard form. The trivial- - rewrite daemon by default appends local domain - information to unqualified addresses, swaps bang - paths to domain form, and strips source routing - information. This process is under control of sev- - eral configuration parameters (see below). - - resolve + rewrite context address + Rewrite an address to standard form, according to + the address rewriting context: + + local + + none Append the domain names specified with $myo- + rigin or $mydomain to incomplete addresses; + do swap_bangpath and allow_percent_hack pro- + cessing as described below, and strip source + routed addresses (@site,@site:user@domain) + to user@domain form. + + invalid + Append the domain name specified with + $invalid_header_rewrite_context_domain to + incomplete addresses. Otherwise the result + is identical to that of the local address + rewriting context. This prevents Postfix + from appending the local domain to spam from + poorly written remote clients. + + resolve address Resolve an address to a (transport, nexthop, recip- - ient) triple. The meaning of the results is as fol- - lows: + ient, flags) quadruple. The meaning of the results + is as follows: transport The delivery agent to use. This is the first field of an entry in the master.cf file. nexthop - The host to send to and optional delivery + The host to send to and optional delivery method information. recipient - The envelope recipient address that is + The envelope recipient address that is passed on to nexthop. - verify Resolve an address for address verification pur- + flags The address class, whether the address + requires relaying, whether the address has + problems, and whether the request failed. + + verify address + Resolve an address for address verification pur- poses. SERVER PROCESS MANAGEMENT The trivial-rewrite servers run under control by the Post- fix master server. Each server can handle multiple simul- - taneous connections. When all servers are busy while a - client connects, the master creates a new server process, - provided that the trivial-rewrite server process limit is + taneous connections. When all servers are busy while a + client connects, the master creates a new server process, + provided that the trivial-rewrite server process limit is not exceeded. Each trivial-rewrite server terminates after serving at least $max_use clients of after $max_idle seconds of idle time. STANDARDS - None. The command does not interact with the outside + None. The command does not interact with the outside world. SECURITY - The trivial-rewrite daemon is not security sensitive. By - default, this daemon does not talk to remote or local - users. It can run at a fixed low privilege in a chrooted + The trivial-rewrite daemon is not security sensitive. By + default, this daemon does not talk to remote or local + users. It can run at a fixed low privilege in a chrooted environment. DIAGNOSTICS @@ -70,15 +89,15 @@ TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8) CONFIGURATION PARAMETERS On busy mail systems a long time may pass before a main.cf - change affecting trivial_rewrite(8) is picked up. Use the + change affecting trivial_rewrite(8) is picked up. Use the command "postfix reload" to speed up a change. - The text below provides only a parameter summary. See + The text below provides only a parameter summary. See postconf(5) for more details including examples. COMPATIBILITY CONTROLS resolve_dequoted_address (yes) - Resolve a recipient address safely instead of cor- + Resolve a recipient address safely instead of cor- rectly, by looking inside quotes. resolve_null_domain (no) @@ -89,29 +108,46 @@ TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8) ADDRESS REWRITING CONTROLS myorigin ($myhostname) The domain name that locally-posted mail appears to - come from, and that locally posted mail is deliv- + come from, and that locally posted mail is deliv- ered to. allow_percent_hack (yes) - Enable the rewriting of the form "user%domain" to + Enable the rewriting of the form "user%domain" to "user@domain". append_at_myorigin (yes) - Append the string "@$myorigin" to mail addresses - without domain information. + With locally submitted mail, append the string + "@$myorigin" to mail addresses without domain + information. append_dot_mydomain (yes) - Append the string ".$mydomain" to addresses that - have no ".domain" information. + With locally submitted mail, append the string + ".$mydomain" to addresses that have no ".domain" + information. recipient_delimiter (empty) The separator between user names and address exten- sions (user+foo). swap_bangpath (yes) - Enable the rewriting of "site!user" into + Enable the rewriting of "site!user" into "user@site". + Available in Postfix 2.2 and later: + + invalid_header_rewrite_context_domain (domain.invalid) + Append this domain to incomplete message header + addresses from remote clients, when + $remote_header_rewrite_context_name is set to + "invalid". + + Implemented by the smtpd(8) server: + + remote_header_rewrite_context_name (local) + The address rewriting context that should be used + for incomplete mail header addresses from remote + clients. + ROUTING CONTROLS The following is applicable to Postfix version 2.0 and later. Earlier versions do not have support for: vir- diff --git a/postfix/man/Makefile.in b/postfix/man/Makefile.in index 64e998971..703e3db7d 100644 --- a/postfix/man/Makefile.in +++ b/postfix/man/Makefile.in @@ -16,7 +16,7 @@ CONFIG = man5/access.5 man5/aliases.5 man5/canonical.5 man5/relocated.5 \ man5/transport.5 man5/virtual.5 man5/pcre_table.5 man5/regexp_table.5 \ man5/cidr_table.5 man5/tcp_table.5 man5/header_checks.5 \ man5/body_checks.5 man5/ldap_table.5 man5/mysql_table.5 \ - man5/pgsql_table.5 man5/master.5 + man5/pgsql_table.5 man5/master.5 man5/nisplus_table.5 TOOLS = man1/smtp-sink.1 man1/smtp-source.1 man1/qmqp-sink.1 \ man1/qmqp-source.1 man1/qshape.1 @@ -250,6 +250,9 @@ man5/master.5: ../proto/master man5/mysql_table.5: ../proto/mysql_table ../mantools/srctoman - $? >$@ +man5/nisplus_table.5: ../proto/nisplus_table + ../mantools/srctoman - $? >$@ + man5/pcre_table.5: ../proto/pcre_table ../mantools/srctoman - $? >$@ diff --git a/postfix/man/man1/postfix.1 b/postfix/man/man1/postfix.1 index c4802261b..4fa90c5ad 100644 --- a/postfix/man/man1/postfix.1 +++ b/postfix/man/man1/postfix.1 @@ -187,6 +187,7 @@ Table lookup mechanisms: cidr_table(5), Associate CIDR pattern with value ldap_table(5), Postfix LDAP client mysql_table(5), Postfix MYSQL client +nisplus_table(5), Postfix NIS+ client pcre_table(5), Associate PCRE pattern with value pgsql_table(5), Postfix PostgreSQL client regexp_table(5), Associate POSIX regexp pattern with value diff --git a/postfix/man/man5/cidr_table.5 b/postfix/man/man5/cidr_table.5 index e4e54beb1..ae6ef06cc 100644 --- a/postfix/man/man5/cidr_table.5 +++ b/postfix/man/man5/cidr_table.5 @@ -14,9 +14,9 @@ format of Postfix CIDR tables .SH DESCRIPTION .ad .fi -The Postfix mail system uses optional access control tables. +The Postfix mail system uses optional lookup tables. These tables are usually in \fBdbm\fR or \fBdb\fR format. -Alternatively, access control tables can be specified in CIDR +Alternatively, lookup tables can be specified in CIDR (Classless Inter-Domain Routing) form. To find out what types of lookup tables your Postfix system diff --git a/postfix/man/man5/nisplus_table.5 b/postfix/man/man5/nisplus_table.5 new file mode 100644 index 000000000..963fc9249 --- /dev/null +++ b/postfix/man/man5/nisplus_table.5 @@ -0,0 +1,102 @@ +.TH NISPLUS_TABLE 5 +.ad +.fi +.SH NAME +nisplus_table +\- +Postfix NIS+ client +.SH "SYNOPSIS" +.na +.nf +\fBpostmap -q "\fIstring\fB" "nisplus:[\fIname\fB=%s];\fIname.name.\fB"\fR + +\fBpostmap -q - "nisplus:[\fIname\fB=%s];\fIname.name.\fB"\fR <\fIinputfile\fR +.SH DESCRIPTION +.ad +.fi +The Postfix mail system uses optional lookup tables. +These tables are usually in \fBdbm\fR or \fBdb\fR format. +Alternatively, lookup tables can be specified as NIS+ +databases. + +To find out what types of lookup tables your Postfix system +supports use the "\fBpostconf -m\fR" command. + +To test Postfix NIS+ lookup tables, use the \fBpostmap\fR +command as described in the SYNOPSIS above. +.SH "QUERY SYNTAX" +.na +.nf +.ad +.fi +Most of the NIS+ query is specified via the NIS+ map name. The +general format of a Postfix NIS+ map name is as follows: + +.ti +4 +\fBnisplus:[\fIname\fB=%s];\fIname.name.name\fB.:\fIcolumn\fR + +Postfix NIS+ map names differ from what one normally +would use with commands such as \fBniscat\fR: +.IP \(bu +With each NIS+ table lookup, "\fB%s\fR" is replaced by a +version of the lookup string. There can be only one +"\fB%s\fR" instance in a Postfix NIS+ map name. +.IP \(bu +Postfix NIS+ map names use "\fB;\fR" instead of "\fB,\fR", +because the latter character is special in the Postfix +main.cf file. Postfix replaces "\fB;\fR" characters in +the map name by "\fB,\fR" before making NIS+ queries. +.IP \(bu +The ":\fIcolumn\fR" part in the NIS+ map name is not part +of the actual NIS+ query. Instead, it specifies the number +of the table column that provides the lookup result. When +no ":\fIcolumn\fR" is specified the first column (1) is used. +.SH "EXAMPLE" +.na +.nf +A NIS+ aliases map might be queried as follows: + +.ti +4 +alias_maps = dbm:/etc/mail/aliases, +.ti +2 + nisplus:[alias=%s];mail_aliases.org_dir.$mydomain.:1 +.ad +.fi + +This queries the local aliases file before the NIS+ file. +.SH "SEE ALSO" +.na +.nf +postmap(1), Postfix lookup table manager +.SH "README FILES" +.na +.nf +.ad +.fi +Use "\fBpostconf readme_directory\fR" or +"\fBpostconf html_directory\fR" to locate this information. +.na +.nf +DATABASE_README, Postfix lookup table overview +.SH "LICENSE" +.na +.nf +.ad +.fi +The Secure Mailer license must be distributed with this software. +.SH "AUTHOR(S)" +.na +.nf +Geoff Gibbs +UK-HGMP-RC +Hinxton +Cambridge +CB10 1SB, UK + +Based on the NIS client code: + +Adopted and adapted by: +Wietse Venema +IBM T.J. Watson Research +P.O. Box 704 +Yorktown Heights, NY 10598, USA diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index e54d11306..5537e4ad4 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -358,14 +358,16 @@ part of the stable Postfix 2.1 release. Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks). The default time unit is s (seconds). .SH append_at_myorigin (default: yes) -Append the string "@$myorigin" to mail addresses without domain -information. +With locally submitted mail, append the string "@$myorigin" to mail +addresses without domain information. With remotely submitted mail, +append the string "@$invalid_domain" instead. .PP This feature is enabled by default and must not be turned off. Postfix does not support domain-less addresses. .SH append_dot_mydomain (default: yes) -Append the string ".$mydomain" to addresses that have no ".domain" -information. +With locally submitted mail, append the string ".$mydomain" to +addresses that have no ".domain" information. With remotely submitted +mail, append the string ".$invalid_domain" instead. .PP This feature is enabled by default. If disabled, users will not be able to send mail to "user@partialdomainname" but will have to @@ -1306,6 +1308,11 @@ and via the pipe(8) and virtual(8) delivery agents. .PP Warning: with concurrency of 1, one bad message can be enough to block all mail to a site. +.SH invalid_header_rewrite_context_domain (default: domain.invalid) +Append this domain to incomplete message header addresses from +remote clients, when $remote_header_rewrite_context_name is set to +"invalid". This is one way to avoid appending your own domain to +addresses in spam from poorly written software. .SH invalid_hostname_reject_code (default: 501) The numerical Postfix SMTP server response code when the client HELO or EHLO command parameter is rejected by the reject_invalid_hostname @@ -1557,6 +1564,25 @@ the entry in the master.cf file. Setting this parameter to a value > 1 changes the meaning of local_destination_concurrency_limit from concurrency per recipient into concurrency per domain. +
    \fBlocal_header_rewrite_context_clients +(default: $inet_interfaces +$mynetworks)\fR
    +.PP +Append the domain names in $myorigin and $mydomain to incomplete +message header addresses from these clients. +.PP +Specify a list of network addresses or network/netmask patterns, +separated by comma or whitespace. The list is matched left to right, +and the search stops on the first match. Specify !address or +!network/netmask to exclude an address or network block from the +list. A network mask specifies the number of bits in the network +part of a host address. Continue long lines by starting the next +line with whitespace. +.PP +You can also specify "/file/name" or "type:table" patterns. +A "/file/name" pattern is replaced by its contents; a "type:table" +lookup table is matched when a client name or address matches a +lookup key (the lookup result is ignored). .SH local_recipient_maps (default: proxy:unix:passwd.byname $alias_maps) Lookup tables with all names or addresses of local recipients: a recipient address is local when its domain matches $mydestination, @@ -2361,7 +2387,7 @@ The location of Postfix README files that describe how to build, configure or operate a specific Postfix subsystem or feature. .SH receive_override_options (default: empty) Enable or disable recipient validation, built-in content -filtering, or address rewriting. Typically, these are specified in +filtering, or address mapping. Typically, these are specified in master.cf as command-line arguments for the smtpd(8), qmqpd(8) or pickup(8) daemons. .PP @@ -2623,6 +2649,29 @@ relocated_maps = hash:/etc/postfix/relocated .fi .ad .ft R +.SH remote_header_rewrite_context_name (default: local) +The address rewriting context that should be used for incomplete +mail header addresses from remote clients. +.IP \(bu +\fBlocal\fR Append the domains specified with $myorigin +or $mydomain to incomplete message header addresses from remote +clients. +.IP \(bu +\fBinvalid\fR Append the domain specified with +$invalid_header_rewrite_context_domain to incomplete message header +addresses from remote clients. This is one way to avoid appending +your own domain to addresses in spam from poorly written software. +This is a safe choice for gateways that have no control over +address rewriting by down-stream systems. +.IP \(bu +\fBnone\fR Don't modify message headers from remote +clients at all. This is another way to avoid appending your own +domain to addresses in spam from poorly written software. This +is the preferred choice for purists. +.PP +Note: Postfix always appends the domains specified with $myorigin +or $mydomain to incomplete envelope addresses, because those +addresses are effectively equivalent to local addresses. .SH require_home_directory (default: no) Whether or not a local(8) recipient's home directory must exist before mail delivery is attempted. By default this test is disabled. diff --git a/postfix/man/man8/cleanup.8 b/postfix/man/man8/cleanup.8 index ba4ead2b2..ef5690e7b 100644 --- a/postfix/man/man8/cleanup.8 +++ b/postfix/man/man8/cleanup.8 @@ -84,10 +84,6 @@ Message header that the Postfix cleanup(8) server inserts when a message contains no To: or Cc: message header. .PP Available in Postfix version 2.1 and later: -.IP "\fBenable_errors_to (no)\fR" -Report mail delivery errors to the address specified with the -non-standard Errors-To: message header, instead of the envelope -sender address. .SH "BUILT-IN CONTENT FILTERING CONTROLS" .na .nf diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index b44297142..617c75dc3 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -102,6 +102,28 @@ sender addresses, even when no explicit reject_unlisted_sender access restriction is specified. .IP "\fBsmtpd_sasl_exceptions_networks (empty)\fR" What SMTP clients Postfix will not offer AUTH support to. +.SH "ADDRESS REWRITING CONTROLS" +.na +.nf +.ad +.fi +.IP "\fBreceive_override_options (empty)\fR" +Enable or disable recipient validation, built-in content +filtering, or address mapping. +.PP +Available in Postfix version 2.2 and later: +.IP "\fBlocal_header_rewrite_context_clients ($inet_interfaces $mynetworks)\fR" +Append the domain names in $myorigin and $mydomain to incomplete +message header addresses from these clients. +.IP "\fBremote_header_rewrite_context_name (local)\fR" +The address rewriting context that should be used for incomplete +mail header addresses from remote clients. +.PP +Implemented by the trivial-rewrite(8) server: +.IP "\fBinvalid_header_rewrite_context_domain (domain.invalid)\fR" +Append this domain to incomplete message header addresses from +remote clients, when $remote_header_rewrite_context_name is set to +"invalid". .SH "AFTER QUEUE EXTERNAL CONTENT INSPECTION CONTROLS" .na .nf @@ -142,7 +164,7 @@ and external content filters. Available in Postfix version 2.1 and later: .IP "\fBreceive_override_options (empty)\fR" Enable or disable recipient validation, built-in content -filtering, or address rewriting. +filtering, or address mapping. .SH "EXTERNAL CONTENT INSPECTION CONTROLS" .na .nf diff --git a/postfix/man/man8/trivial-rewrite.8 b/postfix/man/man8/trivial-rewrite.8 index f433a48b1..b73109e5a 100644 --- a/postfix/man/man8/trivial-rewrite.8 +++ b/postfix/man/man8/trivial-rewrite.8 @@ -14,15 +14,29 @@ Postfix address rewriting and resolving daemon .fi The \fBtrivial-rewrite\fR daemon processes three types of client service requests: -.IP \fBrewrite\fR -Rewrite an address to standard form. The \fBtrivial-rewrite\fR -daemon by default appends local domain information to unqualified -addresses, swaps bang paths to domain form, and strips source -routing information. This process is under control of several -configuration parameters (see below). -.IP \fBresolve\fR +.IP "\fBrewrite \fIcontext address\fR" +Rewrite an address to standard form, according to the +address rewriting context: +.RS +.IP \fBlocal\fR +.IP \fBnone\fR +Append the domain names specified with \fB$myorigin\fR or +\fB$mydomain\fR to incomplete addresses; do \fBswap_bangpath\fR +and \fBallow_percent_hack\fR processing as described below, and +strip source routed addresses (\fI@site,@site:user@domain\fR) +to \fIuser@domain\fR form. +.IP \fBinvalid\fR +Append the domain name specified with +\fB$invalid_header_rewrite_context_domain\fR to incomplete +addresses. Otherwise the result is identical to that of +the \fBlocal\fR address rewriting context. This prevents +Postfix from appending the local domain to spam from poorly +written remote clients. +.RE +.IP "\fBresolve \fIaddress\fR" Resolve an address to a (\fItransport\fR, \fInexthop\fR, -\fIrecipient\fR) triple. The meaning of the results is as follows: +\fIrecipient\fR, \fIflags\fR) quadruple. The meaning of +the results is as follows: .RS .IP \fItransport\fR The delivery agent to use. This is the first field of an entry @@ -31,8 +45,11 @@ in the \fBmaster.cf\fR file. The host to send to and optional delivery method information. .IP \fIrecipient\fR The envelope recipient address that is passed on to \fInexthop\fR. +.IP \fIflags\fR +The address class, whether the address requires relaying, +whether the address has problems, and whether the request failed. .RE -.IP \fBverify\fR +.IP "\fBverify \fIaddress\fR" Resolve an address for address verification purposes. .SH "SERVER PROCESS MANAGEMENT" .na @@ -99,15 +116,26 @@ from, and that locally posted mail is delivered to. .IP "\fBallow_percent_hack (yes)\fR" Enable the rewriting of the form "user%domain" to "user@domain". .IP "\fBappend_at_myorigin (yes)\fR" -Append the string "@$myorigin" to mail addresses without domain -information. +With locally submitted mail, append the string "@$myorigin" to mail +addresses without domain information. .IP "\fBappend_dot_mydomain (yes)\fR" -Append the string ".$mydomain" to addresses that have no ".domain" -information. +With locally submitted mail, append the string ".$mydomain" to +addresses that have no ".domain" information. .IP "\fBrecipient_delimiter (empty)\fR" The separator between user names and address extensions (user+foo). .IP "\fBswap_bangpath (yes)\fR" Enable the rewriting of "site!user" into "user@site". +.PP +Available in Postfix 2.2 and later: +.IP "\fBinvalid_header_rewrite_context_domain (domain.invalid)\fR" +Append this domain to incomplete message header addresses from +remote clients, when $remote_header_rewrite_context_name is set to +"invalid". +.PP +Implemented by the smtpd(8) server: +.IP "\fBremote_header_rewrite_context_name (local)\fR" +The address rewriting context that should be used for incomplete +mail header addresses from remote clients. .SH "ROUTING CONTROLS" .na .nf diff --git a/postfix/mantools/makemanidx b/postfix/mantools/makemanidx index 39afc08fb..2e2725f90 100755 --- a/postfix/mantools/makemanidx +++ b/postfix/mantools/makemanidx @@ -52,9 +52,9 @@ overview

    Each Postfix manual page is numbered after a section of the UNIX manual: examples are mailq(1) or access(5). Unfortunately, -the organization of manual pages depends on the UNIX version being -used. Postfix documentation assumes the following convention: -

    +there is no single universal method to organize manual pages; each +UNIX flavor appears to be different. Postfix documentation assumes +the following convention:

    diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink index b9abb42cc..e09b82ada 100755 --- a/postfix/mantools/postlink +++ b/postfix/mantools/postlink @@ -183,6 +183,7 @@ while (<>) { s;\binet_interfaces\b;$&;g; s;\binitial_destination_concurrency\b;$&;g; s;\binvalid_hostname_reject_code\b;$&;g; + s;\binvalid_header_rewrite_con[-]*\n* *[]*text_domain\b;$&;g; s;\bipc_idle\b;$&;g; s;\bipc_timeout\b;$&;g; s;\bipc_ttl\b;$&;g; @@ -210,6 +211,7 @@ while (<>) { s;\blocal_recip[-]*\n* *[]*ient_maps\b;$&;g; s;\blocal_transport\b;$&;g; s;\bluser_relay\b;$&;g; + s;\blocal_header_rewrite_con[-]*\n* *[]*text_clients\b;$&;g; s;\bmail_name\b;$&;g; s;\bmail_owner\b;$&;g; s;\bmail_release_date\b;$&;g; @@ -238,11 +240,11 @@ while (<>) { s;\bminimal_backoff_time\b;$&;g; s;\bmulti_recip[-]*\n* *[]*ient_bounce_reject_code\b;$&;g; s;\bmydes[-]*\n*[ ]*tina[-]*\n*[ ]*tion\b;$&;g; - s;\bmydomain\b;$&;g; + s;\bmydo[-]*\n* *[]*main\b;$&;g; s;\bmyhostname\b;$&;g; - s;\bmynetworks\b;$&;g; + s;\bmynet[-]*\n* *[]*works\b;$&;g; s;\bmynetworks_style\b;$&;g; - s;\bmyorigin\b;$&;g; + s;\bmyo[-]*\n*[ ]*rigin\b;$&;g; s;\bnested_header_checks\b;$&;g; s;\bnewaliases_path\b;$&;g; s;\bnon_fqdn_reject_code\b;$&;g; @@ -274,6 +276,7 @@ while (<>) { s;\brbl_reply_maps\b;$&;g; s;\breadme_directory\b;$&;g; s;\breceive_override_options\b;$&;g; + s;\bremote_header_rewrite_con[-]*\n* *[]*text_name\b;$&;g; s;\bno_unknown_recip[-]*\n* *[]*ient_checks\b;$&;g; s;\bno_address_mappings\b;$&;g; s;\bno_header_body_checks\b;$&;g; @@ -494,6 +497,7 @@ while (<>) { s/[]*ldap[<\/bBiI>]*_[<\/iIbB>]*table[<\/bB>]*\(5\)/$&<\/a>/g; s/[]*mas[-<\/bB>]*\n* *[]*ter[<\/bB>]*\(5\)/$&<\/a>/g; s/[]*mysql[<\/bBiI>]*_[<\/iIbB>]*table[<\/bB>]*\(5\)/$&<\/a>/g; + s/[]*nisplus[<\/bBiI>]*_[<\/iIbB>]*table[<\/bB>]*\(5\)/$&<\/a>/g; s/[]*pcre[<\/bBiI>]*_[<\/iIbB>]*table[<\/bB>]*\(5\)/$&<\/a>/g; s/[]*pgsql[<\/bBiI>]*_[<\/iIbB>]*table[<\/bB>]*\(5\)/$&<\/a>/g; s/[]*postconf[<\/bB>]*\(5\)/$&<\/a>/g; @@ -628,6 +632,7 @@ while (<>) { s/\b(proxy):/$1<\/a>:/g; s/\b(pgsql):/$1<\/a>:/g; s/\b(mysql):/$1<\/a>:/g; + s/\b(nisplus):/$1<\/a>:/g; s/\b(ldap):/$1<\/a>:/g; s/\b(regexp):/$1<\/a>:/g; s/\b(tcp):/$1<\/a>:/g; diff --git a/postfix/proto/BASIC_CONFIGURATION_README.html b/postfix/proto/BASIC_CONFIGURATION_README.html index 24576b87f..46e422fa8 100644 --- a/postfix/proto/BASIC_CONFIGURATION_README.html +++ b/postfix/proto/BASIC_CONFIGURATION_README.html @@ -315,7 +315,8 @@ of listing the patterns in the main.cf file.

    What destinations to relay mail to

    By default, Postfix will forward mail from strangers (clients outside -authorized networks) to authorized destinations only. Authorized +authorized networks) to authorized remote destinations only. +Authorized remote destinations are defined with the relay_domains configuration parameter. The default is to authorize all domains (and subdomains) of the domains listed with the mydestination parameter.

    @@ -355,7 +356,9 @@ via a relay host.

    The form enclosed with [] eliminates DNS MX lookups. -Don't worry if you don't know what that means.

    +Don't worry if you don't know what that means. Just be sure to +specify the [] around the mailhub hostname that your ISP +gave to you, otherwise mail may be mis-delivered.

    The STANDARD_CONFIGURATION_README file has more hints and tips for firewalled and/or dial-up networks.

    diff --git a/postfix/proto/DATABASE_README.html b/postfix/proto/DATABASE_README.html index 85f03e621..5fbd1d8ce 100644 --- a/postfix/proto/DATABASE_README.html +++ b/postfix/proto/DATABASE_README.html @@ -297,6 +297,19 @@ are given in the ldap_table(5).
    Perform MySQL database lookups. Configuration details are given in mysql_table(5).
    +
    netinfo (read-only)
    + +
    Perform Netinfo database lookups.
    + +
    nis (read-only)
    + +
    Perform NIS database lookups.
    + +
    nisplus (read-only)
    + +
    Perform NIS+ database lookups. Configuration details are given +in nisplus_table(5).
    +
    pcre (read-only)
    A lookup table based on Perl Compatible Regular Expressions. diff --git a/postfix/proto/Makefile.in b/postfix/proto/Makefile.in index 8bb58cac9..743dc83b0 100644 --- a/postfix/proto/Makefile.in +++ b/postfix/proto/Makefile.in @@ -98,33 +98,12 @@ clobber: ../conf/canonical: canonical $(SRCTOMAN) - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ -../conf/cidr_table: cidr_table - $(SRCTOMAN) - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ - ../conf/header_checks: header_checks $(SRCTOMAN) - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ -../conf/ldap_table: ldap_table - $(SRCTOMAN) - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ - -../conf/mysql_table: mysql_table - $(SRCTOMAN) - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ - -../conf/pcre_table: pcre_table - $(SRCTOMAN) - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ - -../conf/pgsql_table: pgsql_table - $(SRCTOMAN) - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ - -../conf/regexp_table: regexp_table - $(SRCTOMAN) - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ - ../conf/relocated: relocated $(SRCTOMAN) - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ -../conf/tcp_table: tcp_table - $(SRCTOMAN) - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ - ../conf/transport: transport $(SRCTOMAN) - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ diff --git a/postfix/proto/cidr_table b/postfix/proto/cidr_table index 2c5058498..5a8df4c54 100644 --- a/postfix/proto/cidr_table +++ b/postfix/proto/cidr_table @@ -8,9 +8,9 @@ # # \fBpostmap -q - cidr:/etc/postfix/\fIfilename\fR <\fIinputfile\fR # DESCRIPTION -# The Postfix mail system uses optional access control tables. +# The Postfix mail system uses optional lookup tables. # These tables are usually in \fBdbm\fR or \fBdb\fR format. -# Alternatively, access control tables can be specified in CIDR +# Alternatively, lookup tables can be specified in CIDR # (Classless Inter-Domain Routing) form. # # To find out what types of lookup tables your Postfix system diff --git a/postfix/proto/nisplus_table b/postfix/proto/nisplus_table new file mode 100644 index 000000000..9ae21966f --- /dev/null +++ b/postfix/proto/nisplus_table @@ -0,0 +1,85 @@ +#++ +# NAME +# nisplus_table 5 +# SUMMARY +# Postfix NIS+ client +# SYNOPSIS +# \fBpostmap -q "\fIstring\fB" "nisplus:[\fIname\fB=%s];\fIname.name.\fB"\fR +# +# \fBpostmap -q - "nisplus:[\fIname\fB=%s];\fIname.name.\fB"\fR <\fIinputfile\fR +# DESCRIPTION +# The Postfix mail system uses optional lookup tables. +# These tables are usually in \fBdbm\fR or \fBdb\fR format. +# Alternatively, lookup tables can be specified as NIS+ +# databases. +# +# To find out what types of lookup tables your Postfix system +# supports use the "\fBpostconf -m\fR" command. +# +# To test Postfix NIS+ lookup tables, use the \fBpostmap\fR +# command as described in the SYNOPSIS above. +# QUERY SYNTAX +# .ad +# .fi +# Most of the NIS+ query is specified via the NIS+ map name. The +# general format of a Postfix NIS+ map name is as follows: +# +# .ti +4 +# \fBnisplus:[\fIname\fB=%s];\fIname.name.name\fB.:\fIcolumn\fR +# +# Postfix NIS+ map names differ from what one normally +# would use with commands such as \fBniscat\fR: +# .IP \(bu +# With each NIS+ table lookup, "\fB%s\fR" is replaced by a +# version of the lookup string. There can be only one +# "\fB%s\fR" instance in a Postfix NIS+ map name. +# .IP \(bu +# Postfix NIS+ map names use "\fB;\fR" instead of "\fB,\fR", +# because the latter character is special in the Postfix +# main.cf file. Postfix replaces "\fB;\fR" characters in +# the map name by "\fB,\fR" before making NIS+ queries. +# .IP \(bu +# The ":\fIcolumn\fR" part in the NIS+ map name is not part +# of the actual NIS+ query. Instead, it specifies the number +# of the table column that provides the lookup result. When +# no ":\fIcolumn\fR" is specified the first column (1) is used. +# EXAMPLE +# A NIS+ aliases map might be queried as follows: +# +# .ti +4 +# alias_maps = dbm:/etc/mail/aliases, +# .ti +2 +# nisplus:[alias=%s];mail_aliases.org_dir.$mydomain.:1 +# .ad +# .fi +# +# This queries the local aliases file before the NIS+ file. +# SEE ALSO +# postmap(1), Postfix lookup table manager +# README FILES +# .ad +# .fi +# Use "\fBpostconf readme_directory\fR" or +# "\fBpostconf html_directory\fR" to locate this information. +# .na +# .nf +# DATABASE_README, Postfix lookup table overview +# LICENSE +# .ad +# .fi +# The Secure Mailer license must be distributed with this software. +# AUTHOR(S) +# Geoff Gibbs +# UK-HGMP-RC +# Hinxton +# Cambridge +# CB10 1SB, UK +# +# Based on the NIS client code: +# +# Adopted and adapted by: +# Wietse Venema +# IBM T.J. Watson Research +# P.O. Box 704 +# Yorktown Heights, NY 10598, USA +#-- diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index 2c0388fad..f0d306f12 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -2794,7 +2794,7 @@ This feature is available in Postfix 2.0 and later. %PARAM receive_override_options

    Enable or disable recipient validation, built-in content -filtering, or address rewriting. Typically, these are specified in +filtering, or address mapping. Typically, these are specified in master.cf as command-line arguments for the smtpd(8), qmqpd(8) or pickup(8) daemons.

    @@ -5546,8 +5546,9 @@ and postdrop(1). %PARAM append_at_myorigin yes

    -Append the string "@$myorigin" to mail addresses without domain -information. +With locally submitted mail, append the string "@$myorigin" to mail +addresses without domain information. With remotely submitted mail, +append the string "@$invalid_domain" instead.

    @@ -5558,8 +5559,9 @@ Postfix does not support domain-less addresses. %PARAM append_dot_mydomain yes

    -Append the string ".$mydomain" to addresses that have no ".domain" -information. +With locally submitted mail, append the string ".$mydomain" to +addresses that have no ".domain" information. With remotely submitted +mail, append the string ".$invalid_domain" instead.

    @@ -7205,3 +7207,59 @@ is already bounded by $max_idle.

    How frequently the scache(8) server logs usage statistics with session cache hit and miss rates for logical destinations and for physical endpoints.

    + +%PARAM invalid_header_rewrite_context_domain domain.invalid + +

    Append this domain to incomplete message header addresses from +remote clients, when $remote_header_rewrite_context_name is set to +"invalid". This is one way to avoid appending your own domain to +addresses in spam from poorly written software.

    + +%PARAM local_header_rewrite_context_clients $inet_interfaces +$mynetworks + +

    Append the domain names in $myorigin and $mydomain to incomplete +message header addresses from these clients.

    + +

    Specify a list of network addresses or network/netmask patterns, +separated by comma or whitespace. The list is matched left to right, +and the search stops on the first match. Specify !address or +!network/netmask to exclude an address or network block from the +list. A network mask specifies the number of bits in the network +part of a host address. Continue long lines by starting the next +line with whitespace.

    + +

    You can also specify "/file/name" or "type:table" patterns. +A "/file/name" pattern is replaced by its contents; a "type:table" +lookup table is matched when a client name or address matches a +lookup key (the lookup result is ignored).

    + +%PARAM remote_header_rewrite_context_name local + +

    The address rewriting context that should be used for incomplete +mail header addresses from remote clients.

    + +
      + +
    • local Append the domains specified with $myorigin +or $mydomain to incomplete message header addresses from remote +clients.

      + +
    • invalid Append the domain specified with +$invalid_header_rewrite_context_domain to incomplete message header +addresses from remote clients. This is one way to avoid appending +your own domain to addresses in spam from poorly written software. +This is a safe choice for gateways that have no control over +address rewriting by down-stream systems. +

      + +
    • none Don't modify message headers from remote +clients at all. This is another way to avoid appending your own +domain to addresses in spam from poorly written software. This +is the preferred choice for purists.

      + +
    + +

    Note: Postfix always appends the domains specified with $myorigin +or $mydomain to incomplete envelope addresses, because those +addresses are effectively equivalent to local addresses.

    diff --git a/postfix/src/cleanup/Makefile.in b/postfix/src/cleanup/Makefile.in index b1a884c58..ba2aea086 100644 --- a/postfix/src/cleanup/Makefile.in +++ b/postfix/src/cleanup/Makefile.in @@ -186,12 +186,16 @@ cleanup_envelope.o: ../../include/mymalloc.h cleanup_envelope.o: ../../include/stringops.h cleanup_envelope.o: ../../include/nvtable.h cleanup_envelope.o: ../../include/htable.h +cleanup_envelope.o: ../../include/name_code.h cleanup_envelope.o: ../../include/record.h cleanup_envelope.o: ../../include/rec_type.h cleanup_envelope.o: ../../include/cleanup_user.h cleanup_envelope.o: ../../include/qmgr_user.h cleanup_envelope.o: ../../include/mail_params.h cleanup_envelope.o: ../../include/verp_sender.h +cleanup_envelope.o: ../../include/mail_proto.h +cleanup_envelope.o: ../../include/iostuff.h +cleanup_envelope.o: ../../include/attr.h cleanup_envelope.o: cleanup.h cleanup_envelope.o: ../../include/argv.h cleanup_envelope.o: ../../include/maps.h @@ -447,9 +451,10 @@ cleanup_rewrite.o: ../../include/vstring.h cleanup_rewrite.o: ../../include/vbuf.h cleanup_rewrite.o: ../../include/tok822.h cleanup_rewrite.o: ../../include/resolve_clnt.h -cleanup_rewrite.o: ../../include/rewrite_clnt.h cleanup_rewrite.o: ../../include/quote_822_local.h cleanup_rewrite.o: ../../include/quote_flags.h +cleanup_rewrite.o: ../../include/rewrite_clnt.h +cleanup_rewrite.o: ../../include/mail_params.h cleanup_rewrite.o: cleanup.h cleanup_rewrite.o: ../../include/vstream.h cleanup_rewrite.o: ../../include/argv.h diff --git a/postfix/src/cleanup/cleanup.c b/postfix/src/cleanup/cleanup.c index ec57f6c5a..ebb34a07b 100644 --- a/postfix/src/cleanup/cleanup.c +++ b/postfix/src/cleanup/cleanup.c @@ -68,10 +68,6 @@ /* message contains no To: or Cc: message header. /* .PP /* Available in Postfix version 2.1 and later: -/* .IP "\fBenable_errors_to (no)\fR" -/* Report mail delivery errors to the address specified with the -/* non-standard Errors-To: message header, instead of the envelope -/* sender address. /* BUILT-IN CONTENT FILTERING CONTROLS /* .ad /* .fi diff --git a/postfix/src/cleanup/cleanup.h b/postfix/src/cleanup/cleanup.h index 65ff8bc46..8ec055ec2 100644 --- a/postfix/src/cleanup/cleanup.h +++ b/postfix/src/cleanup/cleanup.h @@ -41,8 +41,6 @@ typedef struct CLEANUP_STATE { time_t time; /* posting time */ char *fullname; /* envelope sender full name */ char *sender; /* envelope sender address */ - char *from; /* From: address */ - char *resent_from; /* Resent-From: address */ char *recip; /* envelope recipient address */ char *orig_rcpt; /* original recipient address */ char *return_receipt; /* return-receipt address */ @@ -63,6 +61,7 @@ typedef struct CLEANUP_STATE { NVTABLE *attr; /* queue file attribute list */ MIME_STATE *mime_state; /* MIME state engine */ int mime_errs; /* MIME error flags */ + char *rewrite_context_name; /* address rewrite context */ char *filter; /* from header/body patterns */ char *redirect; /* from header/body patterns */ } CLEANUP_STATE; @@ -175,9 +174,9 @@ extern void cleanup_extracted(CLEANUP_STATE *, int, const char *, int); /* * cleanup_rewrite.c */ -extern void cleanup_rewrite_external(VSTRING *, const char *); -extern void cleanup_rewrite_internal(VSTRING *, const char *); -extern void cleanup_rewrite_tree(TOK822 *); +extern void cleanup_rewrite_external(const char *, VSTRING *, const char *); +extern void cleanup_rewrite_internal(const char *, VSTRING *, const char *); +extern void cleanup_rewrite_tree(const char *, TOK822 *); /* * cleanup_map11.c diff --git a/postfix/src/cleanup/cleanup_addr.c b/postfix/src/cleanup/cleanup_addr.c index fc00523c7..dab7dbf4b 100644 --- a/postfix/src/cleanup/cleanup_addr.c +++ b/postfix/src/cleanup/cleanup_addr.c @@ -83,6 +83,7 @@ #define STR vstring_str #define IGNORE_EXTENSION (char **) 0 +#define STREQ(x,y) (strcmp((x), (y)) == 0) /* cleanup_addr_sender - process envelope sender record */ @@ -91,7 +92,7 @@ void cleanup_addr_sender(CLEANUP_STATE *state, const char *buf) VSTRING *clean_addr = vstring_alloc(100); const char *bcc; - cleanup_rewrite_internal(clean_addr, buf); + cleanup_rewrite_internal(REWRITE_LOCAL, clean_addr, buf); if (strncasecmp(STR(clean_addr), MAIL_ADDR_MAIL_DAEMON "@", sizeof(MAIL_ADDR_MAIL_DAEMON)) == 0) { canon_addr_internal(state->temp1, MAIL_ADDR_MAIL_DAEMON); @@ -130,7 +131,8 @@ void cleanup_addr_recipient(CLEANUP_STATE *state, const char *buf) VSTRING *clean_addr = vstring_alloc(100); const char *bcc; - cleanup_rewrite_internal(clean_addr, *buf ? buf : var_empty_addr); + cleanup_rewrite_internal(REWRITE_LOCAL, + clean_addr, *buf ? buf : var_empty_addr); if (state->flags & CLEANUP_FLAG_MAP_OK) { if (cleanup_rcpt_canon_maps && (cleanup_rcpt_canon_flags & CLEANUP_CANON_FLAG_ENV_RCPT)) @@ -162,7 +164,7 @@ void cleanup_addr_bcc(CLEANUP_STATE *state, const char *bcc) { VSTRING *clean_addr = vstring_alloc(100); - cleanup_rewrite_internal(clean_addr, bcc); + cleanup_rewrite_internal(REWRITE_LOCAL, clean_addr, bcc); if (state->flags & CLEANUP_FLAG_MAP_OK) { if (cleanup_rcpt_canon_maps && (cleanup_rcpt_canon_flags & CLEANUP_CANON_FLAG_ENV_RCPT)) diff --git a/postfix/src/cleanup/cleanup_envelope.c b/postfix/src/cleanup/cleanup_envelope.c index 68587e180..56d36c8eb 100644 --- a/postfix/src/cleanup/cleanup_envelope.c +++ b/postfix/src/cleanup/cleanup_envelope.c @@ -57,6 +57,7 @@ #include #include #include +#include /* Global library. */ @@ -66,6 +67,7 @@ #include #include #include +#include /* Application-specific. */ @@ -109,6 +111,12 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type, char *attr_value; const char *error_text; int extra_opts; + NAME_CODE rewrite_context_names[] = { + REWRITE_LOCAL, 1, + REWRITE_INVALID, 1, + REWRITE_NONE, 1, + 0, 0, + }; if (msg_verbose) msg_info("initial envelope %c %.*s", type, len, buf); @@ -278,6 +286,18 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type, myfree(sbuf); return; } + if (strcmp(attr_name, MAIL_ATTR_RWR_CTXT_NAME) == 0) { + if (name_code(rewrite_context_names, NAME_CODE_FLAG_STRICT_CASE, + attr_value) == 0) { + msg_warn("%s: message rejected: bad rewriting context: %.100s", + state->queue_id, attr_value); + state->errs |= CLEANUP_STAT_BAD; + return; + } else { + myfree(state->rewrite_context_name); + state->rewrite_context_name = mystrdup(attr_value); + } + } nvtable_update(state->attr, attr_name, attr_value); myfree(sbuf); cleanup_out(state, type, buf, len); diff --git a/postfix/src/cleanup/cleanup_init.c b/postfix/src/cleanup/cleanup_init.c index ef51ae299..c3b8459cb 100644 --- a/postfix/src/cleanup/cleanup_init.c +++ b/postfix/src/cleanup/cleanup_init.c @@ -121,7 +121,6 @@ int var_virt_expan_limit; /* maximum virtual alias expansion */ int var_body_check_len; /* when to stop body scan */ char *var_send_bcc_maps; /* sender auto-bcc maps */ char *var_rcpt_bcc_maps; /* recipient auto-bcc maps */ -bool var_enable_errors_to; /* extract Errors-To: address. */ CONFIG_INT_TABLE cleanup_int_table[] = { VAR_HOPCOUNT_LIMIT, DEF_HOPCOUNT_LIMIT, &var_hopcount_limit, 1, 0, @@ -135,7 +134,6 @@ CONFIG_INT_TABLE cleanup_int_table[] = { CONFIG_BOOL_TABLE cleanup_bool_table[] = { VAR_ENABLE_ORCPT, DEF_ENABLE_ORCPT, &var_enable_orcpt, - VAR_ENABLE_ERRORS_TO, DEF_ENABLE_ERRORS_TO, &var_enable_errors_to, 0, }; diff --git a/postfix/src/cleanup/cleanup_message.c b/postfix/src/cleanup/cleanup_message.c index 8a5965a06..ddbc793a9 100644 --- a/postfix/src/cleanup/cleanup_message.c +++ b/postfix/src/cleanup/cleanup_message.c @@ -166,16 +166,16 @@ static void cleanup_rewrite_sender(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts, msg_info("rewrite_sender: %s", hdr_opts->name); /* - * Parse the header line, rewrite each address found, save copies of - * sender addresses, and regenerate the header line. Finally, pipe the - * result through the header line folding routine. + * Parse the header line, rewrite each address found, and regenerate the + * header line. Finally, pipe the result through the header line folding + * routine. */ tree = tok822_parse_limit(vstring_str(header_buf) + strlen(hdr_opts->name) + 1, var_token_limit); addr_list = tok822_grep(tree, TOK822_ADDR); for (tpp = addr_list; *tpp; tpp++) { - cleanup_rewrite_tree(*tpp); + cleanup_rewrite_tree(state->rewrite_context_name, *tpp); if (state->flags & CLEANUP_FLAG_MAP_OK) { if (cleanup_send_canon_maps && (cleanup_send_canon_flags & CLEANUP_CANON_FLAG_HDR_FROM)) @@ -189,20 +189,6 @@ static void cleanup_rewrite_sender(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts, && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_HDR_FROM)) cleanup_masquerade_tree(*tpp, cleanup_masq_domains); } - if (hdr_opts->type == HDR_FROM && state->from == 0) - state->from = cleanup_extract_internal(header_buf, *tpp); - if (hdr_opts->type == HDR_RESENT_FROM && state->resent_from == 0) - state->resent_from = - cleanup_extract_internal(header_buf, *tpp); -#if 0 - if (hdr_opts->type == HDR_RETURN_RECEIPT_TO && !state->return_receipt) - state->return_receipt = - cleanup_extract_internal(header_buf, *tpp); -#endif - if (var_enable_errors_to) - if (hdr_opts->type == HDR_ERRORS_TO && !state->errors_to) - state->errors_to = - cleanup_extract_internal(header_buf, *tpp); } vstring_sprintf(header_buf, "%s: ", hdr_opts->name); tok822_externalize(header_buf, tree, TOK822_STR_HEAD); @@ -225,16 +211,16 @@ static void cleanup_rewrite_recip(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts, msg_info("rewrite_recip: %s", hdr_opts->name); /* - * Parse the header line, rewrite each address found, save copies of - * recipient addresses, and regenerate the header line. Finally, pipe the - * result through the header line folding routine. + * Parse the header line, rewrite each address found, and regenerate the + * header line. Finally, pipe the result through the header line folding + * routine. */ tree = tok822_parse_limit(vstring_str(header_buf) + strlen(hdr_opts->name) + 1, var_token_limit); addr_list = tok822_grep(tree, TOK822_ADDR); for (tpp = addr_list; *tpp; tpp++) { - cleanup_rewrite_tree(*tpp); + cleanup_rewrite_tree(state->rewrite_context_name, *tpp); if (state->flags & CLEANUP_FLAG_MAP_OK) { if (cleanup_rcpt_canon_maps && (cleanup_rcpt_canon_flags & CLEANUP_CANON_FLAG_HDR_RCPT)) @@ -511,9 +497,11 @@ static void cleanup_header_callback(void *context, int header_class, if (CLEANUP_OUT_OK(state)) { if (hdr_opts->flags & HDR_OPT_RR) state->resent = "Resent-"; - if (hdr_opts->flags & HDR_OPT_SENDER) { + if ((hdr_opts->flags & HDR_OPT_SENDER) + && strcmp(state->rewrite_context_name, REWRITE_NONE) != 0) { cleanup_rewrite_sender(state, hdr_opts, header_buf); - } else if (hdr_opts->flags & HDR_OPT_RECIP) { + } else if ((hdr_opts->flags & HDR_OPT_RECIP) + && strcmp(state->rewrite_context_name, REWRITE_NONE) != 0) { cleanup_rewrite_recip(state, hdr_opts, header_buf); } else if ((hdr_opts->flags & HDR_OPT_DROP) == 0) { cleanup_out_header(state, header_buf); diff --git a/postfix/src/cleanup/cleanup_rewrite.c b/postfix/src/cleanup/cleanup_rewrite.c index 1ae6871d8..6bc57f0e1 100644 --- a/postfix/src/cleanup/cleanup_rewrite.c +++ b/postfix/src/cleanup/cleanup_rewrite.c @@ -6,15 +6,18 @@ /* SYNOPSIS /* #include /* -/* void cleanup_rewrite_external(result, addr) +/* void cleanup_rewrite_external(context_name, result, addr) +/* const char *context; /* VSTRING *result; /* const char *addr; /* -/* void cleanup_rewrite_internal(result, addr) +/* void cleanup_rewrite_internal(context_name, result, addr) +/* const char *context; /* VSTRING *result; /* const char *addr; /* -/* void cleanup_rewrite_tree(tree) +/* void cleanup_rewrite_tree(context_name, tree) +/* const char *context; /* TOK822 *tree; /* DESCRIPTION /* This module rewrites addresses to canonical form, adding missing @@ -33,6 +36,15 @@ /* cleanup_rewrite_tree() is a wrapper around the /* cleanup_rewrite_external() routine that transforms from /* internal parse tree form to external form and back. +/* +/* Arguments: +/* .IP context_name +/* The name of an address rewriting context that supplies +/* the equivalents of myorigin and mydomain. +/* .IP result +/* Result buffer. +/* .IP addr +/* Input buffer. /* DIAGNOSTICS /* LICENSE /* .ad @@ -57,8 +69,8 @@ /* Global library. */ #include -#include #include +#include /* Application-specific. */ @@ -68,20 +80,21 @@ /* cleanup_rewrite_external - rewrite address external form */ -void cleanup_rewrite_external(VSTRING *result, const char *addr) +void cleanup_rewrite_external(const char *context_name, VSTRING *result, + const char *addr) { - rewrite_clnt(REWRITE_CANON, addr, result); + rewrite_clnt(context_name, addr, result); } /* cleanup_rewrite_tree - rewrite address node */ -void cleanup_rewrite_tree(TOK822 *tree) +void cleanup_rewrite_tree(const char *context_name, TOK822 *tree) { VSTRING *dst = vstring_alloc(100); VSTRING *src = vstring_alloc(100); tok822_externalize(src, tree->head, TOK822_STR_DEFL); - cleanup_rewrite_external(dst, STR(src)); + cleanup_rewrite_external(context_name, dst, STR(src)); tok822_free_tree(tree->head); tree->head = tok822_scan(STR(dst), &tree->tail); vstring_free(dst); @@ -90,13 +103,14 @@ void cleanup_rewrite_tree(TOK822 *tree) /* cleanup_rewrite_internal - rewrite address internal form */ -void cleanup_rewrite_internal(VSTRING *result, const char *addr) +void cleanup_rewrite_internal(const char *context_name, + VSTRING *result, const char *addr) { VSTRING *dst = vstring_alloc(100); VSTRING *src = vstring_alloc(100); quote_822_local(src, addr); - cleanup_rewrite_external(dst, STR(src)); + cleanup_rewrite_external(context_name, dst, STR(src)); unquote_822_local(result, STR(dst)); vstring_free(dst); vstring_free(src); diff --git a/postfix/src/cleanup/cleanup_state.c b/postfix/src/cleanup/cleanup_state.c index a22a32d6f..161bccbe9 100644 --- a/postfix/src/cleanup/cleanup_state.c +++ b/postfix/src/cleanup/cleanup_state.c @@ -64,8 +64,6 @@ CLEANUP_STATE *cleanup_state_alloc(void) state->time = 0; state->fullname = 0; state->sender = 0; - state->from = 0; - state->resent_from = 0; state->recip = 0; state->orig_rcpt = 0; state->return_receipt = 0; @@ -86,6 +84,7 @@ CLEANUP_STATE *cleanup_state_alloc(void) state->attr = nvtable_create(10); state->mime_state = 0; state->mime_errs = 0; + state->rewrite_context_name = mystrdup(REWRITE_LOCAL); state->filter = 0; state->redirect = 0; return (state); @@ -101,10 +100,6 @@ void cleanup_state_free(CLEANUP_STATE *state) myfree(state->fullname); if (state->sender) myfree(state->sender); - if (state->from) - myfree(state->from); - if (state->resent_from) - myfree(state->resent_from); if (state->recip) myfree(state->recip); if (state->orig_rcpt) @@ -127,5 +122,7 @@ void cleanup_state_free(CLEANUP_STATE *state) myfree(state->filter); if (state->redirect) myfree(state->redirect); + if (state->rewrite_context_name) + myfree(state->rewrite_context_name); myfree((char *) state); } diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in index 1dd4f6c0a..a281c7f2d 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -455,6 +455,7 @@ canon_addr.o: ../../include/vstring.h canon_addr.o: ../../include/vbuf.h canon_addr.o: ../../include/mymalloc.h canon_addr.o: rewrite_clnt.h +canon_addr.o: mail_params.h canon_addr.o: canon_addr.h cfg_parser.o: cfg_parser.c cfg_parser.o: ../../include/sys_defs.h @@ -1381,6 +1382,7 @@ tok822_rewrite.o: ../../include/vstring.h tok822_rewrite.o: ../../include/vbuf.h tok822_rewrite.o: ../../include/msg.h tok822_rewrite.o: rewrite_clnt.h +tok822_rewrite.o: mail_params.h tok822_rewrite.o: tok822.h tok822_rewrite.o: resolve_clnt.h tok822_tree.o: tok822_tree.c diff --git a/postfix/src/global/deliver_pass.c b/postfix/src/global/deliver_pass.c index 7a87b9d55..c93aef143 100644 --- a/postfix/src/global/deliver_pass.c +++ b/postfix/src/global/deliver_pass.c @@ -114,6 +114,7 @@ static int deliver_pass_send_request(VSTREAM *stream, DELIVER_REQUEST *request, ATTR_TYPE_STR, MAIL_ATTR_SASL_METHOD, request->sasl_method, ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, request->sasl_username, ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, request->sasl_sender, + ATTR_TYPE_STR, MAIL_ATTR_RWR_CTXT_NAME, request->rewrite_context, ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, offs, ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orcpt, ATTR_TYPE_STR, MAIL_ATTR_RECIP, addr, diff --git a/postfix/src/global/deliver_request.c b/postfix/src/global/deliver_request.c index 7ec796899..39c835848 100644 --- a/postfix/src/global/deliver_request.c +++ b/postfix/src/global/deliver_request.c @@ -29,6 +29,7 @@ /* char *sasl_method; /* char *sasl_username; /* char *sasl_sender; +/* char *rewrite_context; /* .in -5 /* } DELIVER_REQUEST; /* @@ -189,6 +190,7 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) static VSTRING *sasl_method; static VSTRING *sasl_username; static VSTRING *sasl_sender; + static VSTRING *rewrite_context; long offset; /* @@ -212,6 +214,7 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) sasl_method = vstring_alloc(10); sasl_username = vstring_alloc(10); sasl_sender = vstring_alloc(10); + rewrite_context = vstring_alloc(10); } /* @@ -237,7 +240,8 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) ATTR_TYPE_STR, MAIL_ATTR_SASL_METHOD, sasl_method, ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, sasl_username, ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, sasl_sender, - ATTR_TYPE_END) != 18) { + ATTR_TYPE_STR, MAIL_ATTR_RWR_CTXT_NAME, rewrite_context, + ATTR_TYPE_END) != 19) { msg_warn("%s: error receiving common attributes", myname); return (-1); } @@ -259,6 +263,7 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) request->sasl_method = mystrdup(vstring_str(sasl_method)); request->sasl_username = mystrdup(vstring_str(sasl_username)); request->sasl_sender = mystrdup(vstring_str(sasl_sender)); + request->rewrite_context = mystrdup(vstring_str(rewrite_context)); /* * Extract the recipient offset and address list. Skip over any diff --git a/postfix/src/global/deliver_request.h b/postfix/src/global/deliver_request.h index badeba965..33f37afac 100644 --- a/postfix/src/global/deliver_request.h +++ b/postfix/src/global/deliver_request.h @@ -47,6 +47,7 @@ typedef struct DELIVER_REQUEST { char *sasl_method; /* SASL method */ char *sasl_username; /* SASL user name */ char *sasl_sender; /* SASL sender */ + char *rewrite_context; /* header rewrite context */ } DELIVER_REQUEST; /* diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 30811aa64..1c59cc3be 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -551,10 +551,6 @@ extern char *var_deliver_hdr; #define DEF_ENABLE_ORCPT 1 extern bool var_enable_orcpt; -#define VAR_ENABLE_ERRORS_TO "enable_errors_to" -#define DEF_ENABLE_ERRORS_TO 0 -extern bool var_enable_errors_to; - #define VAR_EXP_OWN_ALIAS "expand_owner_alias" #define DEF_EXP_OWN_ALIAS 0 extern bool var_exp_own_alias; @@ -2092,6 +2088,26 @@ extern char *var_anvil_service; #endif + /* + * What domain names to assume when no valid domain context exists. + */ +#define VAR_INV_RWR_DOMAIN "invalid_header_rewrite_context_domain" +#define DEF_INV_RWR_DOMAIN "domain.invalid" +extern char *var_inv_rwr_domain; + +#define VAR_REM_RWR_NAME "remote_header_rewrite_context_name" +#define DEF_REM_RWR_NAME REWRITE_LOCAL +extern char *var_remote_rwr_name; + +#define REWRITE_LOCAL "local" +#define REWRITE_INVALID "invalid" +#define REWRITE_NONE "none" + +#define VAR_LOC_RWR_CLIENTS "local_header_rewrite_context_clients" +#define DEF_LOC_RWR_CLIENTS "$" VAR_INET_INTERFACES \ + " $" VAR_MYNETWORKS +extern char *var_local_rwr_clients; + /* LICENSE /* .ad /* .fi diff --git a/postfix/src/global/mail_proto.h b/postfix/src/global/mail_proto.h index baa5aa54f..222e51e08 100644 --- a/postfix/src/global/mail_proto.h +++ b/postfix/src/global/mail_proto.h @@ -122,6 +122,7 @@ extern char *mail_pathname(const char *, const char *); #define MAIL_ATTR_SASL_USERNAME "sasl_username" #define MAIL_ATTR_SASL_SENDER "sasl_sender" #define MAIL_ATTR_DUMMY "dummy" +#define MAIL_ATTR_RWR_CTXT_NAME "rewrite_context_name" #define MAIL_ATTR_TTL "ttl" #define MAIL_ATTR_LABEL "label" @@ -179,6 +180,9 @@ extern char *mail_pathname(const char *, const char *); #define XFORWARD_PROTO "PROTO" /* client protocol */ #define XFORWARD_HELO "HELO" /* client helo */ #define XFORWARD_IDENT "IDENT" /* message identifier */ +#define XFORWARD_DOMAIN "DOMAIN" /* origin type */ +#define XFORWARD_DOM_LOCAL "LOCAL" /* local origin */ +#define XFORWARD_DOM_REMOTE "REMOTE" /* remote origin */ #define XFORWARD_UNAVAILABLE "[UNAVAILABLE]" /* attribute unavailable */ diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index f5946af92..98f0e7092 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change the patchlevel and the release date. Snapshots change the * release date only. */ -#define MAIL_RELEASE_DATE "20041013" +#define MAIL_RELEASE_DATE "20041019" #define MAIL_VERSION_NUMBER "2.2" #define VAR_MAIL_VERSION "mail_version" diff --git a/postfix/src/global/match_parent_style.c b/postfix/src/global/match_parent_style.c index a914f616f..d36643771 100644 --- a/postfix/src/global/match_parent_style.c +++ b/postfix/src/global/match_parent_style.c @@ -15,7 +15,8 @@ /* /* match_parent_style() looks up "name" in the /* parent_domain_matches_subdomain configuration parameter -/* and returns either MATCH_FLAG_PARENT or MATCH_PARENT_NONE. +/* and returns either MATCH_FLAG_PARENT (parent domain matches +/* subdomains) or MATCH_FLAG_NONE. /* DIAGNOSTICS /* Fatal error: out of memory, name listed under both parent wild card /* matching policies. diff --git a/postfix/src/global/rewrite_clnt.c b/postfix/src/global/rewrite_clnt.c index ac28d2546..db4545ea4 100644 --- a/postfix/src/global/rewrite_clnt.c +++ b/postfix/src/global/rewrite_clnt.c @@ -82,6 +82,12 @@ VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result) { VSTREAM *stream; + /* + * Sanity check. + */ + if (strcmp(rule, REWRITE_NONE) == 0) + msg_panic("rewrite_clnt: bad rewrite context: \"%s\"", rule); + /* * One-entry cache. */ diff --git a/postfix/src/global/rewrite_clnt.h b/postfix/src/global/rewrite_clnt.h index 8e2230180..0910b812e 100644 --- a/postfix/src/global/rewrite_clnt.h +++ b/postfix/src/global/rewrite_clnt.h @@ -15,12 +15,13 @@ * Utility library. */ #include +#include /* * External interface. */ #define REWRITE_ADDR "rewrite" -#define REWRITE_CANON "canonicalize" +#define REWRITE_CANON REWRITE_LOCAL /* backwards compatibility */ extern VSTRING *rewrite_clnt(const char *, const char *, VSTRING *); extern VSTRING *rewrite_clnt_internal(const char *, const char *, VSTRING *); diff --git a/postfix/src/global/rewrite_clnt.in b/postfix/src/global/rewrite_clnt.in index 4f79ebc27..a66fc2064 100644 --- a/postfix/src/global/rewrite_clnt.in +++ b/postfix/src/global/rewrite_clnt.in @@ -1,13 +1,26 @@ -x ! -x a! -x !b -x a!b -x % -x a% -x %b -x a%b -x @ -x a@ -x a@. -x a@b -x a@b. +canonical ! +canonical a! +canonical !b +canonical a!b +canonical % +canonical a% +canonical %b +canonical a%b +canonical @ +canonical a@ +canonical a@. +canonical a@b +canonical a@b. +invalid ! +invalid a! +invalid !b +invalid a!b +invalid % +invalid a% +invalid %b +invalid a%b +invalid @ +invalid a@ +invalid a@. +invalid a@b +invalid a@b. diff --git a/postfix/src/global/rewrite_clnt.ref b/postfix/src/global/rewrite_clnt.ref index b1df12986..328d0e1a1 100644 --- a/postfix/src/global/rewrite_clnt.ref +++ b/postfix/src/global/rewrite_clnt.ref @@ -1,52 +1,104 @@ -rule x +rule canonical address ! result ""@ -rule x +rule canonical address a! result ""@a.MYDOMAIN -rule x +rule canonical address !b result b@ -rule x +rule canonical address a!b result b@a.MYDOMAIN -rule x +rule canonical address % result ""@ -rule x +rule canonical address a% result a@ -rule x +rule canonical address %b result ""@b.MYDOMAIN -rule x +rule canonical address a%b result a@b.MYDOMAIN -rule x +rule canonical address @ result "" -rule x +rule canonical address a@ result a@ -rule x +rule canonical address a@. result a@. -rule x +rule canonical address a@b result a@b.MYDOMAIN -rule x +rule canonical +address a@b. +result a@b + +rule invalid +address ! +result ""@ + +rule invalid +address a! +result ""@a.domain.invalid + +rule invalid +address !b +result b@ + +rule invalid +address a!b +result b@a.domain.invalid + +rule invalid +address % +result ""@ + +rule invalid +address a% +result a@ + +rule invalid +address %b +result ""@b.domain.invalid + +rule invalid +address a%b +result a@b.domain.invalid + +rule invalid +address @ +result "" + +rule invalid +address a@ +result a@ + +rule invalid +address a@. +result a@. + +rule invalid +address a@b +result a@b.domain.invalid + +rule invalid address a@b. result a@b diff --git a/postfix/src/lmtp/lmtp.h b/postfix/src/lmtp/lmtp.h index 40f687c49..2c30226c4 100644 --- a/postfix/src/lmtp/lmtp.h +++ b/postfix/src/lmtp/lmtp.h @@ -65,6 +65,7 @@ typedef struct LMTP_STATE { #define LMTP_FEATURE_XFORWARD_ADDR (1<<7) #define LMTP_FEATURE_XFORWARD_PROTO (1<<8) #define LMTP_FEATURE_XFORWARD_HELO (1<<9) +#define LMTP_FEATURE_XFORWARD_DOMAIN (1<<10) /* * lmtp.c diff --git a/postfix/src/lmtp/lmtp_proto.c b/postfix/src/lmtp/lmtp_proto.c index 8251d6edc..b45543ed8 100644 --- a/postfix/src/lmtp/lmtp_proto.c +++ b/postfix/src/lmtp/lmtp_proto.c @@ -209,6 +209,7 @@ int lmtp_lhlo(LMTP_STATE *state) XFORWARD_ADDR, LMTP_FEATURE_XFORWARD_ADDR, XFORWARD_PROTO, LMTP_FEATURE_XFORWARD_PROTO, XFORWARD_HELO, LMTP_FEATURE_XFORWARD_HELO, + XFORWARD_DOMAIN, LMTP_FEATURE_XFORWARD_DOMAIN, 0, 0, }; @@ -418,6 +419,12 @@ static int lmtp_loop(LMTP_STATE *state, NOCLOBBER int send_state, vstring_sprintf_append(next_command, " %s=%s", XFORWARD_HELO, DEL_REQ_ATTR_AVAIL(request->client_helo) ? request->client_helo : XFORWARD_UNAVAILABLE); + if (state->features & LMTP_FEATURE_XFORWARD_DOMAIN) + vstring_sprintf_append(next_command, " %s=%s", XFORWARD_DOMAIN, + DEL_REQ_ATTR_AVAIL(request->rewrite_context) == 0 ? + XFORWARD_UNAVAILABLE : + strcmp(request->rewrite_context, REWRITE_LOCAL) ? + XFORWARD_DOM_LOCAL : XFORWARD_DOM_REMOTE); next_state = LMTP_STATE_MAIL; break; diff --git a/postfix/src/local/Makefile.in b/postfix/src/local/Makefile.in index 60b4c78dc..6987e83d3 100644 --- a/postfix/src/local/Makefile.in +++ b/postfix/src/local/Makefile.in @@ -438,8 +438,8 @@ resolve.o: ../../include/iostuff.h resolve.o: ../../include/attr.h resolve.o: ../../include/resolve_clnt.h resolve.o: ../../include/rewrite_clnt.h -resolve.o: ../../include/tok822.h resolve.o: ../../include/mail_params.h +resolve.o: ../../include/tok822.h resolve.o: ../../include/defer.h resolve.o: ../../include/bounce.h resolve.o: ../../include/deliver_request.h diff --git a/postfix/src/oqmgr/Makefile.in b/postfix/src/oqmgr/Makefile.in index 37a7e44bc..4451a2d44 100644 --- a/postfix/src/oqmgr/Makefile.in +++ b/postfix/src/oqmgr/Makefile.in @@ -188,6 +188,7 @@ qmgr_message.o: ../../include/mail_proto.h qmgr_message.o: ../../include/iostuff.h qmgr_message.o: ../../include/attr.h qmgr_message.o: ../../include/qmgr_user.h +qmgr_message.o: ../../include/split_addr.h qmgr_message.o: ../../include/rewrite_clnt.h qmgr_message.o: ../../include/resolve_clnt.h qmgr_message.o: qmgr.h diff --git a/postfix/src/oqmgr/qmgr.h b/postfix/src/oqmgr/qmgr.h index b11418366..0cac1664d 100644 --- a/postfix/src/oqmgr/qmgr.h +++ b/postfix/src/oqmgr/qmgr.h @@ -246,6 +246,7 @@ struct QMGR_MESSAGE { char *sasl_method; /* SASL method */ char *sasl_username; /* SASL user name */ char *sasl_sender; /* SASL sender */ + char *rewrite_context; /* address qualification */ QMGR_RCPT_LIST rcpt_list; /* complete addresses */ }; diff --git a/postfix/src/oqmgr/qmgr_deliver.c b/postfix/src/oqmgr/qmgr_deliver.c index f9556efd5..0c55ab300 100644 --- a/postfix/src/oqmgr/qmgr_deliver.c +++ b/postfix/src/oqmgr/qmgr_deliver.c @@ -162,8 +162,9 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream) ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, message->client_proto, ATTR_TYPE_STR, MAIL_ATTR_HELO_NAME, message->client_helo, ATTR_TYPE_STR, MAIL_ATTR_SASL_METHOD, message->sasl_method, - ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, message->sasl_username, + ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, message->sasl_username, ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, message->sasl_sender, + ATTR_TYPE_STR, MAIL_ATTR_RWR_CTXT_NAME, message->rewrite_context, ATTR_TYPE_END); if (sender_buf != 0) vstring_free(sender_buf); diff --git a/postfix/src/oqmgr/qmgr_message.c b/postfix/src/oqmgr/qmgr_message.c index fbe0606c8..b015d9ee6 100644 --- a/postfix/src/oqmgr/qmgr_message.c +++ b/postfix/src/oqmgr/qmgr_message.c @@ -122,6 +122,7 @@ #include #include #include +#include /* Client stubs. */ @@ -175,6 +176,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name, message->sasl_method = 0; message->sasl_username = 0; message->sasl_sender = 0; + message->rewrite_context = 0; qmgr_rcpt_list_init(&message->rcpt_list); return (message); } @@ -549,6 +551,13 @@ static int qmgr_message_read(QMGR_MESSAGE *message) msg_warn("%s: ignoring multiple %s attribute: %s", message->queue_id, MAIL_ATTR_SASL_SENDER, value); } + if (strcmp(name, MAIL_ATTR_RWR_CTXT_NAME) == 0) { + if (message->rewrite_context == 0) + message->rewrite_context = mystrdup(value); + else + msg_warn("%s: ignoring multiple %s attribute: %s", + message->queue_id, MAIL_ATTR_RWR_CTXT_NAME, value); + } /* Optional tracing flags. */ else if (strcmp(name, MAIL_ATTR_TRACE_FLAGS) == 0) { message->tflags = DEL_REQ_TRACE_FLAGS(atoi(value)); @@ -628,6 +637,8 @@ static int qmgr_message_read(QMGR_MESSAGE *message) message->sasl_username = mystrdup(""); if (message->sasl_sender == 0) message->sasl_sender = mystrdup(""); + if (message->rewrite_context == 0) + message->rewrite_context = mystrdup(""); /* * Clean up. diff --git a/postfix/src/postfix/postfix.c b/postfix/src/postfix/postfix.c index 24ed673a3..c5ad8e643 100644 --- a/postfix/src/postfix/postfix.c +++ b/postfix/src/postfix/postfix.c @@ -173,6 +173,7 @@ /* cidr_table(5), Associate CIDR pattern with value /* ldap_table(5), Postfix LDAP client /* mysql_table(5), Postfix MYSQL client +/* nisplus_table(5), Postfix NIS+ client /* pcre_table(5), Associate PCRE pattern with value /* pgsql_table(5), Postfix PostgreSQL client /* regexp_table(5), Associate POSIX regexp pattern with value diff --git a/postfix/src/qmgr/Makefile.in b/postfix/src/qmgr/Makefile.in index 368bd255c..e069952ae 100644 --- a/postfix/src/qmgr/Makefile.in +++ b/postfix/src/qmgr/Makefile.in @@ -201,6 +201,7 @@ qmgr_message.o: ../../include/mail_proto.h qmgr_message.o: ../../include/iostuff.h qmgr_message.o: ../../include/attr.h qmgr_message.o: ../../include/qmgr_user.h +qmgr_message.o: ../../include/split_addr.h qmgr_message.o: ../../include/rewrite_clnt.h qmgr_message.o: ../../include/resolve_clnt.h qmgr_message.o: qmgr.h diff --git a/postfix/src/qmgr/qmgr.h b/postfix/src/qmgr/qmgr.h index 612625bcf..976520636 100644 --- a/postfix/src/qmgr/qmgr.h +++ b/postfix/src/qmgr/qmgr.h @@ -286,6 +286,7 @@ struct QMGR_MESSAGE { char *sasl_method; /* SASL method */ char *sasl_username; /* SASL user name */ char *sasl_sender; /* SASL sender */ + char *rewrite_context; /* address qualification */ QMGR_RCPT_LIST rcpt_list; /* complete addresses */ int rcpt_count; /* used recipient slots */ int rcpt_limit; /* maximum read in-core */ diff --git a/postfix/src/qmgr/qmgr_deliver.c b/postfix/src/qmgr/qmgr_deliver.c index 3064e540a..9616735fc 100644 --- a/postfix/src/qmgr/qmgr_deliver.c +++ b/postfix/src/qmgr/qmgr_deliver.c @@ -167,8 +167,9 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream) ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, message->client_proto, ATTR_TYPE_STR, MAIL_ATTR_HELO_NAME, message->client_helo, ATTR_TYPE_STR, MAIL_ATTR_SASL_METHOD, message->sasl_method, - ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, message->sasl_username, + ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, message->sasl_username, ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, message->sasl_sender, + ATTR_TYPE_STR, MAIL_ATTR_RWR_CTXT_NAME, message->rewrite_context, ATTR_TYPE_END); if (sender_buf != 0) vstring_free(sender_buf); diff --git a/postfix/src/qmgr/qmgr_message.c b/postfix/src/qmgr/qmgr_message.c index 132a738a2..52ddfcdb0 100644 --- a/postfix/src/qmgr/qmgr_message.c +++ b/postfix/src/qmgr/qmgr_message.c @@ -131,6 +131,7 @@ #include #include #include +#include /* Client stubs. */ @@ -185,6 +186,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name, message->sasl_method = 0; message->sasl_username = 0; message->sasl_sender = 0; + message->rewrite_context = 0; qmgr_rcpt_list_init(&message->rcpt_list); message->rcpt_count = 0; message->rcpt_limit = var_qmgr_msg_rcpt_limit; @@ -584,6 +586,13 @@ static int qmgr_message_read(QMGR_MESSAGE *message) msg_warn("%s: ignoring multiple %s attribute: %s", message->queue_id, MAIL_ATTR_SASL_SENDER, value); } + if (strcmp(name, MAIL_ATTR_RWR_CTXT_NAME) == 0) { + if (message->rewrite_context == 0) + message->rewrite_context = mystrdup(value); + else + msg_warn("%s: ignoring multiple %s attribute: %s", + message->queue_id, MAIL_ATTR_RWR_CTXT_NAME, value); + } /* Optional tracing flags. */ else if (strcmp(name, MAIL_ATTR_TRACE_FLAGS) == 0) { message->tflags = DEL_REQ_TRACE_FLAGS(atoi(value)); @@ -663,6 +672,8 @@ static int qmgr_message_read(QMGR_MESSAGE *message) message->sasl_username = mystrdup(""); if (message->sasl_sender == 0) message->sasl_sender = mystrdup(""); + if (message->rewrite_context == 0) + message->rewrite_context = mystrdup(""); /* * Clean up. diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index bb061a966..25d631c88 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -101,7 +101,7 @@ typedef struct SMTP_STATE { #define SMTP_FEATURE_XFORWARD_ADDR (1<<8) #define SMTP_FEATURE_XFORWARD_PROTO (1<<9) #define SMTP_FEATURE_XFORWARD_HELO (1<<10) - +#define SMTP_FEATURE_XFORWARD_DOMAIN (1<<11) #define SMTP_FEATURE_BEST_MX (1<<12) /* for next-hop or fall-back */ #define SMTP_FEATURE_RSET_REJECTED (1<<13) /* RSET probe rejected */ #define SMTP_FEATURE_FROM_CACHE (1<<14) /* cached session */ diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index a56c9aa85..4e13a1432 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -223,6 +223,7 @@ int smtp_helo(SMTP_STATE *state, int misc_flags) XFORWARD_ADDR, SMTP_FEATURE_XFORWARD_ADDR, XFORWARD_PROTO, SMTP_FEATURE_XFORWARD_PROTO, XFORWARD_HELO, SMTP_FEATURE_XFORWARD_HELO, + XFORWARD_DOMAIN, SMTP_FEATURE_XFORWARD_DOMAIN, 0, 0, }; SOCKOPT_SIZE optlen; @@ -639,6 +640,12 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state, vstring_sprintf_append(next_command, " %s=%s", XFORWARD_HELO, DEL_REQ_ATTR_AVAIL(request->client_helo) ? request->client_helo : XFORWARD_UNAVAILABLE); + if (session->features & SMTP_FEATURE_XFORWARD_DOMAIN) + vstring_sprintf_append(next_command, " %s=%s", XFORWARD_DOMAIN, + DEL_REQ_ATTR_AVAIL(request->rewrite_context) == 0 ? + XFORWARD_UNAVAILABLE : + strcmp(request->rewrite_context, REWRITE_LOCAL) ? + XFORWARD_DOM_LOCAL : XFORWARD_DOM_REMOTE); next_state = SMTP_STATE_MAIL; break; diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index 254f39e21..d29e4c49f 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -210,7 +210,7 @@ smtpd_check.o: ../../include/match_ops.h smtpd_check.o: ../../include/namadr_list.h smtpd_check.o: ../../include/domain_list.h smtpd_check.o: ../../include/mail_params.h -smtpd_check.o: ../../include/canon_addr.h +smtpd_check.o: ../../include/rewrite_clnt.h smtpd_check.o: ../../include/resolve_clnt.h smtpd_check.o: ../../include/mail_error.h smtpd_check.o: ../../include/name_mask.h diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 8ade47c83..041e65512 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -86,6 +86,26 @@ /* access restriction is specified. /* .IP "\fBsmtpd_sasl_exceptions_networks (empty)\fR" /* What SMTP clients Postfix will not offer AUTH support to. +/* ADDRESS REWRITING CONTROLS +/* .ad +/* .fi +/* .IP "\fBreceive_override_options (empty)\fR" +/* Enable or disable recipient validation, built-in content +/* filtering, or address mapping. +/* .PP +/* Available in Postfix version 2.2 and later: +/* .IP "\fBlocal_header_rewrite_context_clients ($inet_interfaces $mynetworks)\fR" +/* Append the domain names in $myorigin and $mydomain to incomplete +/* message header addresses from these clients. +/* .IP "\fBremote_header_rewrite_context_name (local)\fR" +/* The address rewriting context that should be used for incomplete +/* mail header addresses from remote clients. +/* .PP +/* Implemented by the trivial-rewrite(8) server: +/* .IP "\fBinvalid_header_rewrite_context_domain (domain.invalid)\fR" +/* Append this domain to incomplete message header addresses from +/* remote clients, when $remote_header_rewrite_context_name is set to +/* "invalid". /* AFTER QUEUE EXTERNAL CONTENT INSPECTION CONTROLS /* .ad /* .fi @@ -120,7 +140,7 @@ /* Available in Postfix version 2.1 and later: /* .IP "\fBreceive_override_options (empty)\fR" /* Enable or disable recipient validation, built-in content -/* filtering, or address rewriting. +/* filtering, or address mapping. /* EXTERNAL CONTENT INSPECTION CONTROLS /* .ad /* .fi @@ -775,6 +795,9 @@ char *var_smtpd_hoggers; #endif +char *var_remote_rwr_name; +char *var_local_rwr_clients; + /* * Silly little macros. */ @@ -794,13 +817,11 @@ static NAMADR_LIST *verp_clients; * its own access control. */ static NAMADR_LIST *xclient_hosts; -static int xclient_allowed; /* * XFORWARD command. Access control is cached. */ static NAMADR_LIST *xforward_hosts; -static int xforward_allowed; /* * Client connection and rate limiting. @@ -966,14 +987,15 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) if (namadr_list_match(verp_clients, state->name, state->addr)) smtpd_chat_reply(state, "250-%s", VERP_CMD); /* XCLIENT must not override its own access control. */ - if (xclient_allowed) + if (state->xclient_allowed) smtpd_chat_reply(state, "250-" XCLIENT_CMD " " XCLIENT_NAME " " XCLIENT_ADDR " " XCLIENT_PROTO " " XCLIENT_HELO); - if (xforward_allowed) + if (state->xforward_allowed) smtpd_chat_reply(state, "250-" XFORWARD_CMD " " XFORWARD_NAME " " XFORWARD_ADDR - " " XFORWARD_PROTO " " XFORWARD_HELO); + " " XFORWARD_PROTO " " XFORWARD_HELO + " " XFORWARD_DOMAIN); smtpd_chat_reply(state, "250 8BITMIME"); return (0); } @@ -1051,6 +1073,8 @@ static void mail_open_stream(SMTPD_STATE *state) rec_fprintf(state->cleanup, REC_TYPE_TIME, "%ld", (long) state->time); if (*var_filter_xport) rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport); + rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", + MAIL_ATTR_RWR_CTXT_NAME, state->rewrite_context_name); } #ifdef USE_SASL_AUTH if (var_smtpd_sasl_enable) { @@ -1253,7 +1277,7 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) */ #ifdef SNAPSHOT if (SMTPD_STAND_ALONE(state) == 0 - && !xclient_allowed + && !state->xclient_allowed && anvil_clnt && var_smtpd_cmail_limit > 0 && !namadr_list_match(hogger_list, state->name, state->addr) @@ -1463,7 +1487,7 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) */ #ifdef SNAPSHOT if (SMTPD_STAND_ALONE(state) == 0 - && !xclient_allowed + && !state->xclient_allowed && anvil_clnt && var_smtpd_crcpt_limit > 0 && !namadr_list_match(hogger_list, state->name, state->addr) @@ -1514,6 +1538,7 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) * we have a valid recipient address. */ if (state->proxy == 0 && state->cleanup == 0) { + smtpd_check_rewrite(state); if (state->proxy_mail) { if (smtpd_proxy_open(state, var_smtpd_proxy_filt, var_smtpd_proxy_tmout, var_smtpd_proxy_ehlo, @@ -2080,7 +2105,7 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) XCLIENT_CMD); return (-1); } - if (!xclient_allowed) { + if (!state->xclient_allowed) { state->error_mask |= MAIL_ERROR_POLICY; smtpd_chat_reply(state, "554 Error: insufficient authorization"); return (-1); @@ -2217,9 +2242,20 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) XFORWARD_ADDR, SMTPD_STATE_XFORWARD_ADDR, XFORWARD_PROTO, SMTPD_STATE_XFORWARD_PROTO, XFORWARD_HELO, SMTPD_STATE_XFORWARD_HELO, + XFORWARD_DOMAIN, SMTPD_STATE_XFORWARD_DOMAIN, 0, 0, }; + static char *context_name[] = { + REWRITE_LOCAL, /* Postfix internal form */ + 0, /* filled in on the fly */ + }; + static NAME_CODE xforward_to_context[] = { + XFORWARD_DOM_LOCAL, 0, /* XFORWARD representation */ + XFORWARD_DOM_REMOTE, 1, /* XFORWARD representation */ + 0, -1, + }; int flag; + int context_code; /* * Sanity checks. @@ -2235,7 +2271,7 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) XFORWARD_CMD); return (-1); } - if (!xforward_allowed) { + if (!state->xforward_allowed) { state->error_mask |= MAIL_ERROR_POLICY; smtpd_chat_reply(state, "554 Error: insufficient authorization"); return (-1); @@ -2332,6 +2368,28 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) UPDATE_STR(state->xforward.protocol, attr_value); break; + /* + * DOMAIN=local or remote. + */ + case SMTPD_STATE_XFORWARD_DOMAIN: + context_name[1] = var_remote_rwr_name; + if ((context_code = name_code(xforward_to_context, + NAME_CODE_FLAG_NONE, + attr_value)) < 0) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Bad %s syntax: %s", + XFORWARD_DOMAIN, attr_value); + return (-1); + } + if (state->rewrite_context_name + && strcmp(state->rewrite_context_name, + context_name[context_code])) { + myfree(state->rewrite_context_name); + state->rewrite_context_name = + mystrdup(context_name[context_code]); + } + break; + /* * Unknown attribute name. Complain. */ @@ -2490,7 +2548,7 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service) */ #ifdef SNAPSHOT if (SMTPD_STAND_ALONE(state) == 0 - && !xclient_allowed + && !state->xclient_allowed && anvil_clnt && !namadr_list_match(hogger_list, state->name, state->addr) && anvil_clnt_connect(anvil_clnt, service, state->addr, @@ -2591,7 +2649,7 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service) */ #ifdef SNAPSHOT if (SMTPD_STAND_ALONE(state) == 0 - && !xclient_allowed + && !state->xclient_allowed && anvil_clnt && !namadr_list_match(hogger_list, state->name, state->addr)) anvil_clnt_disconnect(anvil_clnt, service, state->addr); @@ -2650,15 +2708,21 @@ static void smtpd_service(VSTREAM *stream, char *service, char **argv) /* * XCLIENT must not override its own access control. */ - xclient_allowed = + state.xclient_allowed = namadr_list_match(xclient_hosts, state.name, state.addr); /* * Overriding XFORWARD access control makes no sense, either. */ - xforward_allowed = + state.xforward_allowed = namadr_list_match(xforward_hosts, state.name, state.addr); + /* + * Choose a default address rewriting context. This should be made more + * configurable. + */ + smtpd_check_rewrite(&state); + /* * See if we need to turn on verbose logging for this client. */ @@ -2733,13 +2797,19 @@ static void pre_jail_init(char *unused_name, char **unused_argv) static void post_jail_init(char *unused_name, char **unused_argv) { + NAME_CODE rewrite_context_names[] = { + REWRITE_LOCAL, 1, + REWRITE_INVALID, 1, + REWRITE_NONE, 1, + 0, 0, + }; /* * Initialize the receive transparency options: do we want unknown * recipient checks, address mapping, header_body_checks?. */ smtpd_input_transp_mask = - input_transp_mask(VAR_INPUT_TRANSP, var_input_transp); + input_transp_mask(VAR_INPUT_TRANSP, var_input_transp); /* * Sanity checks. The queue_minfree value should be at least as large as @@ -2761,6 +2831,14 @@ static void post_jail_init(char *unused_name, char **unused_argv) || var_smtpd_cmail_limit || var_smtpd_crcpt_limit) anvil_clnt = anvil_clnt_create(); #endif + + /* + * Sanity check. + */ + if (name_code(rewrite_context_names, NAME_CODE_FLAG_STRICT_CASE, + var_remote_rwr_name) == 0) + msg_fatal("parameter %s: invalid value: %s", + VAR_REM_RWR_NAME, var_remote_rwr_name); } /* main - the main program */ @@ -2863,6 +2941,8 @@ int main(int argc, char **argv) #ifdef SNAPSHOT VAR_SMTPD_HOGGERS, DEF_SMTPD_HOGGERS, &var_smtpd_hoggers, 0, 0, #endif + VAR_REM_RWR_NAME, DEF_REM_RWR_NAME, &var_remote_rwr_name, 1, 0, + VAR_LOC_RWR_CLIENTS, DEF_LOC_RWR_CLIENTS, &var_local_rwr_clients, 1, 0, 0, }; static CONFIG_RAW_TABLE raw_table[] = { diff --git a/postfix/src/smtpd/smtpd.h b/postfix/src/smtpd/smtpd.h index ffe0c9c70..54ae936d4 100644 --- a/postfix/src/smtpd/smtpd.h +++ b/postfix/src/smtpd/smtpd.h @@ -87,6 +87,9 @@ typedef struct SMTPD_STATE { off_t msg_size; /* MAIL FROM message size */ int junk_cmds; /* counter */ int rcpt_overshoot; /* counter */ + char *rewrite_context_name; /* address rewriting context */ + int xclient_allowed; /* permission to use XCLIENT */ + int xforward_allowed; /* permission to use XFORWARD */ /* * SASL specific. @@ -145,6 +148,7 @@ typedef struct SMTPD_STATE { #define SMTPD_STATE_XFORWARD_PROTO (1<<3) /* protocol received */ #define SMTPD_STATE_XFORWARD_HELO (1<<4) /* client helo received */ #define SMTPD_STATE_XFORWARD_IDENT (1<<5) /* message identifier */ +#define SMTPD_STATE_XFORWARD_DOMAIN (1<<6) /* message identifier */ #define SMTPD_STATE_XFORWARD_CLIENT_MASK \ (SMTPD_STATE_XFORWARD_NAME | SMTPD_STATE_XFORWARD_ADDR \ diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index 3bc853490..bcd65f166 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -12,6 +12,9 @@ /* int smtpd_check_addr(address) /* const char *address; /* +/* char *smtpd_check_rewrite(state) +/* SMTPD_STATE *state; +/* /* char *smtpd_check_client(state) /* SMTPD_STATE *state; /* @@ -45,6 +48,10 @@ /* smtpd_check_addr() sanity checks an email address and returns /* non-zero in case of badness. /* +/* smtpd_check_rewrite() shuod be called before opening a queue +/* file or proxy connection, in order to establish the proper +/* header address rewriting context. +/* /* Each of the following routines scrutinizes the argument passed to /* an SMTP command such as HELO, MAIL FROM, RCPT TO, or scrutinizes /* the initial client connection request. The administrator can @@ -186,7 +193,7 @@ #include #include #include -#include +#include #include #include #include @@ -269,6 +276,7 @@ static MAPS *smtpd_sender_login_maps; static DOMAIN_LIST *relay_domains; static NAMADR_LIST *mynetworks; static NAMADR_LIST *perm_mx_networks; +static NAMADR_LIST *local_rewrite_clients; /* * How to do parent domain wildcard matching, if any. @@ -415,7 +423,7 @@ static void *resolve_pagein(const char *addr, void *unused_context) /* * Resolve the address. */ - canon_addr_internal(query, addr); + rewrite_clnt_internal(REWRITE_LOCAL, addr, query); resolve_clnt_query(STR(query), reply); lowercase(STR(reply->recipient)); @@ -563,6 +571,8 @@ void smtpd_check_init(void) perm_mx_networks = namadr_list_init(match_parent_style(VAR_PERM_MX_NETWORKS), var_perm_mx_networks); + local_rewrite_clients = + namadr_list_init(MATCH_FLAG_NONE, var_local_rwr_clients); /* * Pre-parse and pre-open the recipient maps. @@ -1646,8 +1656,8 @@ static int not_in_client_helo(SMTPD_STATE *state, const char *table, * Thus, if delay_reject=no, client and helo actions such as FILTER or * HOLD also should not affect subsequent mail deliveries. Hmm... * - * XXX If the MAIL FROM command is rejected then we have to reset access - * map side effects such as FILTER. + * XXX If the MAIL FROM command is rejected then we have to reset access map + * side effects such as FILTER. */ if (state->sender == 0) { msg_warn("access table %s: with %s=%s, " @@ -2240,8 +2250,8 @@ static int check_mail_access(SMTPD_STATE *state, const char *table, reject_dict_retry(state, addr); /* - * Garbage in, garbage out. Every address from canon_addr_internal() and - * from resolve_clnt_query() must be fully qualified. + * Garbage in, garbage out. Every address from rewrite_clnt_internal() + * and from resolve_clnt_query() must be fully qualified. */ if ((domain = strrchr(CONST_STR(reply->recipient), '@')) == 0) { msg_warn("%s: no @domain in address: %s", myname, @@ -3356,6 +3366,33 @@ int smtpd_check_addr(const char *addr) return (0); } +/* smtpd_check_rewrite - choose address qualification context */ + +void smtpd_check_rewrite(SMTPD_STATE *state) +{ + + /* + * This should be made more configurable. + */ +#define SASL_AUTHENTICATED 1 +#define NOT_SASL_AUTHENTICATED 0 + + /* + * XXX We want to be able to use !pattern to make exceptions, but then we + * should not confuse matters by mixing names with addresses. + */ + if (SMTPD_STAND_ALONE(state) + || namadr_list_match(local_rewrite_clients, " ", state->addr) +#ifdef USE_SASL_AUTH + || permit_sasl_auth(state, SASL_AUTHENTICATED, + NOT_SASL_AUTHENTICATED) +#endif + ) + state->rewrite_context_name = mystrdup(REWRITE_LOCAL); + else + state->rewrite_context_name = mystrdup(var_remote_rwr_name); +} + /* smtpd_check_client - validate client name or address */ char *smtpd_check_client(SMTPD_STATE *state) @@ -3532,7 +3569,9 @@ char *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient) if (*recipient) { if (canon_verify_sender == 0) { canon_verify_sender = vstring_alloc(10); - canon_addr_internal(canon_verify_sender, var_verify_sender); + rewrite_clnt_internal(REWRITE_LOCAL, + var_verify_sender, + canon_verify_sender); } if (strcasecmp(STR(canon_verify_sender), recipient) == 0) return (0); @@ -3875,7 +3914,7 @@ char *smtpd_check_size(SMTPD_STATE *state, off_t size) char *smtpd_check_data(SMTPD_STATE *state) { int status; - char *NOCLOBBER saved_recipient; + char *NOCLOBBER saved_recipient; /* * Minor kluge so that we can delegate work to the generic routine. We @@ -3979,6 +4018,8 @@ char *var_def_rbl_reply; char *var_relay_rcpt_maps; char *var_verify_sender; char *var_smtpd_sasl_opts; +char *var_remote_rwr_name; +char *var_local_rwr_clients; typedef struct { char *name; @@ -4019,6 +4060,8 @@ static STRING_TABLE string_table[] = { VAR_VERIFY_SENDER, DEF_VERIFY_SENDER, &var_verify_sender, VAR_MAIL_NAME, DEF_MAIL_NAME, &var_mail_name, VAR_SMTPD_SASL_OPTS, DEF_SMTPD_SASL_OPTS, &var_smtpd_sasl_opts, + VAR_REM_RWR_NAME, DEF_REM_RWR_NAME, &var_remote_rwr_name, + VAR_LOC_RWR_CLIENTS, DEF_LOC_RWR_CLIENTS, &var_local_rwr_clients, 0, }; @@ -4243,12 +4286,13 @@ int verify_clnt_query(const char *addr, int *addr_status, VSTRING *why) return (VRFY_STAT_OK); } -/* canon_addr_internal - stub */ +/* rewrite_clnt_internal - stub */ -VSTRING *canon_addr_internal(VSTRING *result, const char *addr) +VSTRING *rewrite_clnt_internal(const char *context, const char *addr, + VSTRING *result) { if (addr == STR(result)) - msg_panic("canon_addr_internal: result clobbers input"); + msg_panic("rewrite_clnt_internal: result clobbers input"); if (*addr && strchr(addr, '@') == 0) msg_fatal("%s: address rewriting is disabled", addr); vstring_strcpy(result, addr); diff --git a/postfix/src/smtpd/smtpd_check.h b/postfix/src/smtpd/smtpd_check.h index 101673f16..8d706bb9a 100644 --- a/postfix/src/smtpd/smtpd_check.h +++ b/postfix/src/smtpd/smtpd_check.h @@ -14,6 +14,7 @@ */ extern void smtpd_check_init(void); extern int smtpd_check_addr(const char *); +extern void smtpd_check_rewrite(SMTPD_STATE *); extern char *smtpd_check_client(SMTPD_STATE *); extern char *smtpd_check_helo(SMTPD_STATE *, char *); extern char *smtpd_check_mail(SMTPD_STATE *, char *); diff --git a/postfix/src/smtpd/smtpd_proxy.c b/postfix/src/smtpd/smtpd_proxy.c index cc06db98e..282743b92 100644 --- a/postfix/src/smtpd/smtpd_proxy.c +++ b/postfix/src/smtpd/smtpd_proxy.c @@ -171,6 +171,7 @@ #define SMTPD_PROXY_XFORWARD_PROTO (1<<2) /* protocol */ #define SMTPD_PROXY_XFORWARD_HELO (1<<3) /* client helo */ #define SMTPD_PROXY_XFORWARD_IDENT (1<<4) /* message identifier */ +#define SMTPD_PROXY_XFORWARD_DOMAIN (1<<5) /* origin type */ /* * SLMs. @@ -178,6 +179,7 @@ #define STR(x) vstring_str(x) #define LEN(x) VSTRING_LEN(x) #define SMTPD_PROXY_CONNECT ((char *) 0) +#define STREQ(x, y) (strcmp((x), (y)) == 0) /* smtpd_xforward_flush - flush forwarding information */ @@ -243,6 +245,7 @@ int smtpd_proxy_open(SMTPD_STATE *state, const char *service, XFORWARD_ADDR, SMTPD_PROXY_XFORWARD_ADDR, XFORWARD_PROTO, SMTPD_PROXY_XFORWARD_PROTO, XFORWARD_HELO, SMTPD_PROXY_XFORWARD_HELO, + XFORWARD_DOMAIN, SMTPD_PROXY_XFORWARD_DOMAIN, 0, 0, }; @@ -318,22 +321,26 @@ int smtpd_proxy_open(SMTPD_STATE *state, const char *service, if (state->proxy_xforward_features) { buf = vstring_alloc(100); bad = 0; - if ((state->proxy_xforward_features & SMTPD_PROXY_XFORWARD_NAME) - && !(bad = smtpd_xforward(state, buf, XFORWARD_NAME, + if ((!(state->proxy_xforward_features & SMTPD_PROXY_XFORWARD_NAME) + || !(bad = smtpd_xforward(state, buf, XFORWARD_NAME, IS_AVAIL_CLIENT_NAME(FORWARD_NAME(state)), - FORWARD_NAME(state))) - && (state->proxy_xforward_features & SMTPD_PROXY_XFORWARD_ADDR) - && !(bad = smtpd_xforward(state, buf, XFORWARD_ADDR, + FORWARD_NAME(state)))) + && (!(state->proxy_xforward_features & SMTPD_PROXY_XFORWARD_ADDR) + || !(bad = smtpd_xforward(state, buf, XFORWARD_ADDR, IS_AVAIL_CLIENT_ADDR(FORWARD_ADDR(state)), - FORWARD_ADDR(state))) - && (state->proxy_xforward_features & SMTPD_PROXY_XFORWARD_HELO) - && !(bad = smtpd_xforward(state, buf, XFORWARD_HELO, + FORWARD_ADDR(state)))) + && (!(state->proxy_xforward_features & SMTPD_PROXY_XFORWARD_HELO) + || !(bad = smtpd_xforward(state, buf, XFORWARD_HELO, IS_AVAIL_CLIENT_HELO(FORWARD_HELO(state)), - FORWARD_HELO(state))) - && (state->proxy_xforward_features & SMTPD_PROXY_XFORWARD_PROTO) - && !(bad = smtpd_xforward(state, buf, XFORWARD_PROTO, + FORWARD_HELO(state)))) + && (!(state->proxy_xforward_features & SMTPD_PROXY_XFORWARD_PROTO) + || !(bad = smtpd_xforward(state, buf, XFORWARD_PROTO, IS_AVAIL_CLIENT_PROTO(FORWARD_PROTO(state)), - FORWARD_PROTO(state)))) + FORWARD_PROTO(state)))) + && (!(state->proxy_xforward_features & SMTPD_PROXY_XFORWARD_DOMAIN) + || !(bad = smtpd_xforward(state, buf, XFORWARD_DOMAIN, 1, + STREQ(state->rewrite_context_name, REWRITE_LOCAL) ? + XFORWARD_DOM_LOCAL : XFORWARD_DOM_REMOTE)))) bad = smtpd_xforward_flush(state, buf); vstring_free(buf); if (bad) { diff --git a/postfix/src/smtpd/smtpd_state.c b/postfix/src/smtpd/smtpd_state.c index 5989df75e..f8d8e1e20 100644 --- a/postfix/src/smtpd/smtpd_state.c +++ b/postfix/src/smtpd/smtpd_state.c @@ -114,6 +114,9 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream, state->saved_flags = 0; state->instance = vstring_alloc(10); state->seqno = 0; + state->rewrite_context_name = 0; + state->xclient_allowed = 0; + state->xforward_allowed = 0; #ifdef USE_SASL_AUTH if (SMTPD_STAND_ALONE(state)) @@ -170,6 +173,8 @@ void smtpd_state_reset(SMTPD_STATE *state) vstring_free(state->proxy_buffer); if (state->instance) vstring_free(state->instance); + if (state->rewrite_context_name) + myfree(state->rewrite_context_name); #ifdef USE_SASL_AUTH if (var_smtpd_sasl_enable) diff --git a/postfix/src/trivial-rewrite/Makefile.in b/postfix/src/trivial-rewrite/Makefile.in index 0b734b348..ecfa05cf7 100644 --- a/postfix/src/trivial-rewrite/Makefile.in +++ b/postfix/src/trivial-rewrite/Makefile.in @@ -146,7 +146,6 @@ trivial-rewrite.o: ../../include/attr.h trivial-rewrite.o: ../../include/resolve_local.h trivial-rewrite.o: ../../include/mail_conf.h trivial-rewrite.o: ../../include/resolve_clnt.h -trivial-rewrite.o: ../../include/rewrite_clnt.h trivial-rewrite.o: ../../include/tok822.h trivial-rewrite.o: ../../include/mail_addr.h trivial-rewrite.o: ../../include/mail_server.h diff --git a/postfix/src/trivial-rewrite/resolve.c b/postfix/src/trivial-rewrite/resolve.c index 56ac4f5f6..924b51e6a 100644 --- a/postfix/src/trivial-rewrite/resolve.c +++ b/postfix/src/trivial-rewrite/resolve.c @@ -279,7 +279,7 @@ static void resolve_addr(RES_CONTEXT *rp, char *addr, if (tok822_rfind_type(tree->tail, '@') || (var_swap_bangpath && tok822_rfind_type(tree->tail, '!')) || (var_percent_hack && tok822_rfind_type(tree->tail, '%'))) { - rewrite_tree(REWRITE_CANON, tree); + rewrite_tree(&local_context, tree); continue; } @@ -306,7 +306,7 @@ static void resolve_addr(RES_CONTEXT *rp, char *addr, } tok822_free(tree->head); tree->head = tok822_scan(STR(addr_buf), &tree->tail); - rewrite_tree(REWRITE_CANON, tree); + rewrite_tree(&local_context, tree); continue; } diff --git a/postfix/src/trivial-rewrite/rewrite.c b/postfix/src/trivial-rewrite/rewrite.c index 8bd6e8409..a0eca67bf 100644 --- a/postfix/src/trivial-rewrite/rewrite.c +++ b/postfix/src/trivial-rewrite/rewrite.c @@ -11,14 +11,17 @@ /* void rewrite_proto(stream) /* VSTREAM *stream; /* -/* void rewrite_addr(rule, addr, result) -/* char *rule; +/* void rewrite_addr(context, addr, result) +/* RWR_CONTEXT *context; /* char *addr; /* VSTRING *result; /* -/* void rewrite_tree(rule, tree) -/* char *rule; +/* void rewrite_tree(context, tree) +/* RWR_CONTEXT *context; /* TOK822 *tree; +/* +/* RWR_CONTEXT local_context; +/* RWR_CONTEXT inval_context; /* DESCRIPTION /* This module implements the trivial address rewriting engine. /* @@ -35,6 +38,9 @@ /* /* rewrite_tree() rewrites a parse tree with a single address to /* another tree. A tree is a dummy node on top of a token list. +/* +/* local_context and inval_context provide domain names for +/* completing incomplete address forms. /* STANDARDS /* DIAGNOSTICS /* Problems and transactions are logged to the syslog daemon. @@ -77,13 +83,23 @@ #include "trivial-rewrite.h" +RWR_CONTEXT local_context = { + VAR_MYORIGIN, &var_myorigin, + VAR_MYDOMAIN, &var_mydomain, +}; + +RWR_CONTEXT inval_context = { + VAR_INV_RWR_DOMAIN, &var_inv_rwr_domain, + VAR_INV_RWR_DOMAIN, &var_inv_rwr_domain, +}; + static VSTRING *ruleset; static VSTRING *address; static VSTRING *result; /* rewrite_tree - rewrite address according to rule set */ -void rewrite_tree(char *unused_ruleset, TOK822 *tree) +void rewrite_tree(RWR_CONTEXT *context, TOK822 *tree) { TOK822 *colon; TOK822 *domain; @@ -159,7 +175,8 @@ void rewrite_tree(char *unused_ruleset, TOK822 *tree) */ 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)); + tok822_sub_append(tree, tok822_scan(REW_PARAM_VALUE(context->origin), + (TOK822 **) 0)); } } @@ -174,7 +191,8 @@ void rewrite_tree(char *unused_ruleset, TOK822 *tree) && tok822_find_type(domain, TOK822_DOMLIT) == 0 && tok822_find_type(domain, '.') == 0) { tok822_sub_append(tree, tok822_alloc('.', (char *) 0)); - tok822_sub_append(tree, tok822_scan(var_mydomain, (TOK822 **) 0)); + tok822_sub_append(tree, tok822_scan(REW_PARAM_VALUE(context->domain), + (TOK822 **) 0)); } /* @@ -191,7 +209,7 @@ void rewrite_tree(char *unused_ruleset, TOK822 *tree) /* rewrite_addr - rewrite address according to rule set */ -void rewrite_addr(char *ruleset, char *addr, VSTRING *result) +void rewrite_addr(RWR_CONTEXT *context, char *addr, VSTRING *result) { TOK822 *tree; @@ -199,7 +217,7 @@ void rewrite_addr(char *ruleset, char *addr, VSTRING *result) * Sanity check. An address is supposed to be in externalized form. */ if (*addr == 0) { - msg_warn("rewrite_addr: null address, ruleset \"%s\"", ruleset); + msg_warn("rewrite_addr: null address"); vstring_strcpy(result, addr); return; } @@ -209,7 +227,7 @@ void rewrite_addr(char *ruleset, char *addr, VSTRING *result) * rewrite it, and convert back. */ tree = tok822_scan_addr(addr); - rewrite_tree(ruleset, tree); + rewrite_tree(context, tree); tok822_externalize(result, tree, TOK822_STR_DEFL); tok822_free_tree(tree); } @@ -218,13 +236,32 @@ void rewrite_addr(char *ruleset, char *addr, VSTRING *result) int rewrite_proto(VSTREAM *stream) { + RWR_CONTEXT *context; + if (attr_scan(stream, ATTR_FLAG_STRICT, ATTR_TYPE_STR, MAIL_ATTR_RULE, ruleset, ATTR_TYPE_STR, MAIL_ATTR_ADDR, address, ATTR_TYPE_END) != 2) return (-1); - rewrite_addr(vstring_str(ruleset), vstring_str(address), result); + /* + * Note: an unqualified username is for all practical purposes equivalent + * to a fully qualified local address, if only because a reply to an + * unqualified address will be sent to a local recipient. Having to + * support both forms is error prone, therefore an unqualified address is + * rewritten in the local domain context when no address rewriting + * context is given. + */ + if (strcmp(vstring_str(ruleset), REWRITE_LOCAL) == 0 + || strcmp(vstring_str(ruleset), REWRITE_NONE) == 0) + context = &local_context; + else if (strcmp(vstring_str(ruleset), REWRITE_INVALID) == 0) + context = &inval_context; + else { + msg_warn("unknown context: %s", vstring_str(ruleset)); + return (-1); + } + rewrite_addr(context, vstring_str(address), result); if (msg_verbose) msg_info("`%s' `%s' -> `%s'", vstring_str(ruleset), diff --git a/postfix/src/trivial-rewrite/trivial-rewrite.c b/postfix/src/trivial-rewrite/trivial-rewrite.c index 5d0728702..cdc1ebb7f 100644 --- a/postfix/src/trivial-rewrite/trivial-rewrite.c +++ b/postfix/src/trivial-rewrite/trivial-rewrite.c @@ -8,15 +8,29 @@ /* DESCRIPTION /* The \fBtrivial-rewrite\fR daemon processes three types of client /* service requests: -/* .IP \fBrewrite\fR -/* Rewrite an address to standard form. The \fBtrivial-rewrite\fR -/* daemon by default appends local domain information to unqualified -/* addresses, swaps bang paths to domain form, and strips source -/* routing information. This process is under control of several -/* configuration parameters (see below). -/* .IP \fBresolve\fR +/* .IP "\fBrewrite \fIcontext address\fR" +/* Rewrite an address to standard form, according to the +/* address rewriting context: +/* .RS +/* .IP \fBlocal\fR +/* .IP \fBnone\fR +/* Append the domain names specified with \fB$myorigin\fR or +/* \fB$mydomain\fR to incomplete addresses; do \fBswap_bangpath\fR +/* and \fBallow_percent_hack\fR processing as described below, and +/* strip source routed addresses (\fI@site,@site:user@domain\fR) +/* to \fIuser@domain\fR form. +/* .IP \fBinvalid\fR +/* Append the domain name specified with +/* \fB$invalid_header_rewrite_context_domain\fR to incomplete +/* addresses. Otherwise the result is identical to that of +/* the \fBlocal\fR address rewriting context. This prevents +/* Postfix from appending the local domain to spam from poorly +/* written remote clients. +/* .RE +/* .IP "\fBresolve \fIaddress\fR" /* Resolve an address to a (\fItransport\fR, \fInexthop\fR, -/* \fIrecipient\fR) triple. The meaning of the results is as follows: +/* \fIrecipient\fR, \fIflags\fR) quadruple. The meaning of +/* the results is as follows: /* .RS /* .IP \fItransport\fR /* The delivery agent to use. This is the first field of an entry @@ -25,8 +39,11 @@ /* The host to send to and optional delivery method information. /* .IP \fIrecipient\fR /* The envelope recipient address that is passed on to \fInexthop\fR. +/* .IP \fIflags\fR +/* The address class, whether the address requires relaying, +/* whether the address has problems, and whether the request failed. /* .RE -/* .IP \fBverify\fR +/* .IP "\fBverify \fIaddress\fR" /* Resolve an address for address verification purposes. /* SERVER PROCESS MANAGEMENT /* .ad @@ -79,15 +96,26 @@ /* .IP "\fBallow_percent_hack (yes)\fR" /* Enable the rewriting of the form "user%domain" to "user@domain". /* .IP "\fBappend_at_myorigin (yes)\fR" -/* Append the string "@$myorigin" to mail addresses without domain -/* information. +/* With locally submitted mail, append the string "@$myorigin" to mail +/* addresses without domain information. /* .IP "\fBappend_dot_mydomain (yes)\fR" -/* Append the string ".$mydomain" to addresses that have no ".domain" -/* information. +/* With locally submitted mail, append the string ".$mydomain" to +/* addresses that have no ".domain" information. /* .IP "\fBrecipient_delimiter (empty)\fR" /* The separator between user names and address extensions (user+foo). /* .IP "\fBswap_bangpath (yes)\fR" /* Enable the rewriting of "site!user" into "user@site". +/* .PP +/* Available in Postfix 2.2 and later: +/* .IP "\fBinvalid_header_rewrite_context_domain (domain.invalid)\fR" +/* Append this domain to incomplete message header addresses from +/* remote clients, when $remote_header_rewrite_context_name is set to +/* "invalid". +/* .PP +/* Implemented by the smtpd(8) server: +/* .IP "\fBremote_header_rewrite_context_name (local)\fR" +/* The address rewriting context that should be used for incomplete +/* mail header addresses from remote clients. /* ROUTING CONTROLS /* .ad /* .fi @@ -273,6 +301,7 @@ char *var_def_transport; char *var_empty_addr; int var_show_unk_rcpt_table; int var_resolve_nulldom; +char *var_inv_rwr_domain; /* * Shadow personality for address verification. @@ -400,6 +429,7 @@ int main(int argc, char **argv) VAR_VRFY_RELAY_XPORT, DEF_VRFY_RELAY_XPORT, &var_vrfy_relay_xport, 1, 0, VAR_VRFY_DEF_XPORT, DEF_VRFY_DEF_XPORT, &var_vrfy_def_xport, 1, 0, VAR_VRFY_RELAYHOST, DEF_VRFY_RELAYHOST, &var_vrfy_relayhost, 0, 0, + VAR_INV_RWR_DOMAIN, DEF_INV_RWR_DOMAIN, &var_inv_rwr_domain, 1, 0, 0, }; static CONFIG_BOOL_TABLE bool_table[] = { diff --git a/postfix/src/trivial-rewrite/trivial-rewrite.h b/postfix/src/trivial-rewrite/trivial-rewrite.h index c3816ab40..ce59970a9 100644 --- a/postfix/src/trivial-rewrite/trivial-rewrite.h +++ b/postfix/src/trivial-rewrite/trivial-rewrite.h @@ -22,10 +22,21 @@ /* * rewrite.c */ +typedef struct { + const char *origin_name; /* name of variable */ + char **origin; /* default origin */ + const char *domain_name; /* name of variable */ + char **domain; /* default domain */ +} RWR_CONTEXT; + +#define REW_PARAM_VALUE(x) (*(x)) /* make it easy to do it right */ + extern void rewrite_init(void); extern int rewrite_proto(VSTREAM *); -extern void rewrite_addr(char *, char *, VSTRING *); -extern void rewrite_tree(char *, TOK822 *); +extern void rewrite_addr(RWR_CONTEXT *, char *, VSTRING *); +extern void rewrite_tree(RWR_CONTEXT *, TOK822 *); +extern RWR_CONTEXT local_context; +extern RWR_CONTEXT inval_context; /* * resolve.c @@ -61,4 +72,3 @@ extern int resolve_proto(RES_CONTEXT *, VSTREAM *); /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /*--*/ - diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index 91ed1ba72..21170ea26 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -693,10 +693,11 @@ dict_nisplus.o: dict_nisplus.c dict_nisplus.o: sys_defs.h dict_nisplus.o: msg.h dict_nisplus.o: mymalloc.h -dict_nisplus.o: htable.h +dict_nisplus.o: vstring.h +dict_nisplus.o: vbuf.h +dict_nisplus.o: stringops.h dict_nisplus.o: dict.h dict_nisplus.o: vstream.h -dict_nisplus.o: vbuf.h dict_nisplus.o: argv.h dict_nisplus.o: dict_nisplus.h dict_open.o: dict_open.c diff --git a/postfix/src/util/attr_clnt.c b/postfix/src/util/attr_clnt.c index eabf01537..6dd230713 100644 --- a/postfix/src/util/attr_clnt.c +++ b/postfix/src/util/attr_clnt.c @@ -225,7 +225,7 @@ int attr_clnt_request(ATTR_CLNT *client, int send_flags,...) SKIP_ARG(ap, long); break; case ATTR_TYPE_HASH: - SKIP_ARG(ap, HTABLE *); + (void) va_arg(ap, HTABLE *); break; default: msg_panic("%s: unexpected attribute type %d", diff --git a/postfix/src/util/dict_nisplus.c b/postfix/src/util/dict_nisplus.c index e6f3467d8..7ac002149 100644 --- a/postfix/src/util/dict_nisplus.c +++ b/postfix/src/util/dict_nisplus.c @@ -6,8 +6,8 @@ /* SYNOPSIS /* #include /* -/* DICT *dict_nisplus_open(map, dummy, dict_flags) -/* char *map; +/* DICT *dict_nisplus_open(map, open_flags, dict_flags) +/* const char *map; /* int dummy; /* int dict_flags; /* DESCRIPTION @@ -16,11 +16,21 @@ /* The \fIdummy\fR argument is not used. /* SEE ALSO /* dict(3) generic dictionary manager +/* DIAGNOSTICS +/* Fatal errors: /* LICENSE /* .ad /* .fi /* The Secure Mailer license must be distributed with this software. /* AUTHOR(S) +/* Geoff Gibbs +/* UK-HGMP-RC +/* Hinxton +/* Cambridge +/* CB10 1SB, UK +/* +/* based on the code for dict_nis.c et al by :- +/* /* Wietse Venema /* IBM T.J. Watson Research /* P.O. Box 704 @@ -29,41 +39,239 @@ /* System library. */ -#include "sys_defs.h" +#include #include +#include +#include +#include +#ifdef HAS_NISPLUS +#include /* for nis_list */ +#endif /* Utility library. */ -#include "msg.h" -#include "mymalloc.h" -#include "htable.h" -#include "dict.h" -#include "dict_nisplus.h" +#include +#include +#include +#include +#include +#include + +#ifdef HAS_NISPLUS /* Application-specific. */ typedef struct { DICT dict; /* generic members */ + char *template; /* parsed query template */ + int column; /* NIS+ field number (start at 1) */ } DICT_NISPLUS; + /* + * Begin quote from nis+(1): + * + * The following text represents a context-free grammar that defines the + * set of legal NIS+ names. The terminals in this grammar are the + * characters `.' (dot), `[' (open bracket), `]' (close bracket), `,' + * (comma), `=' (equals) and whitespace. Angle brackets (`<' and `>'), + * which delineate non- terminals, are not part of the grammar. The + * character `|' (vertical bar) is used to separate alternate productions + * and should be read as ``this production OR this production''. + * + * name ::= . | | + * + * simple name ::= . | . + * + * indexed name ::= , + * + * search criterion ::= [ ] + * + * attribute list ::= | , + * + * attribute ::= = + * + * string ::= ISO Latin 1 character set except the character + * '/' (slash). The initial character may not be a terminal character or + * the characters '@' (at), '+' (plus), or (`-') hyphen. + * + * Terminals that appear in strings must be quoted with `"' (double quote). + * The `"' character may be quoted by quoting it with itself `""'. + * + * End quote fron nis+(1). + * + * This NIS client always quotes the entire query string (the value part of + * [attribute=value],file.domain.) so the issue with initial characters + * should not be applicable. One wonders what restrictions are applicable + * when a string is quoted, but the manual doesn't specify what can appear + * between quotes, and we don't want to get burned. + */ + + /* + * SLMs. + */ +#define STR(x) vstring_str(x) + +/* dict_nisplus_lookup - find table entry */ + +static const char *dict_nisplus_lookup(DICT *dict, const char *key) +{ + const char *myname = "dict_nisplus_lookup"; + DICT_NISPLUS *dict_nisplus = (DICT_NISPLUS *) dict; + static VSTRING *quoted_key; + static VSTRING *query; + static VSTRING *reply; + nis_result *nis_alias; + int count; + const char *cp; + int ch; + + /* + * Initialize. + */ + dict_errno = 0; + if (quoted_key == 0) { + query = vstring_alloc(100); + reply = vstring_alloc(100); + quoted_key = vstring_alloc(100); + } + + /* + * Check that the lookup key does not contain characters disallowed by + * nis+(1). + * + * XXX Many client implementations don't seem to care about disallowed + * characters. + */ + VSTRING_RESET(quoted_key); + VSTRING_ADDCH(quoted_key, '"'); + for (cp = key; (ch = *(unsigned const char *) cp) != 0; cp++) { + if ((ISASCII(ch) && !ISPRINT(ch)) || (ch > 126 && ch < 160)) { + msg_warn("map %s:%s: lookup key with non-printing character 0x%x:" + " ignoring this request", + dict->type, dict->name, ch); + return (0); + } else if (ch == '"') { + VSTRING_ADDCH(quoted_key, '"'); + } + VSTRING_ADDCH(quoted_key, ch); + } + VSTRING_ADDCH(quoted_key, '"'); + VSTRING_TERMINATE(quoted_key); + + /* + * Plug the key into the query template, which typically looks something + * like the following: [alias=%s],mail_aliases.org_dir.my.nisplus.domain. + * + * XXX The nis+ documentation defines a length limit for simple names like + * a.b.c., but defines no length limit for (the components of) indexed + * names such as [x=y],a.b.c. Our query length is limited because Postfix + * addresses (in envelopes or in headers) have a finite length. + */ + vstring_sprintf(query, dict_nisplus->template, STR(quoted_key)); + nis_alias = nis_list(STR(query), FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); + + /* + * When lookup succeeds, the result may be unusable because it is + * ambiguous. + */ + if (nis_alias->status == NIS_SUCCESS) { + if ((count = NIS_RES_NUMOBJ(nis_alias)) != 1) { + msg_warn("ambiguous match (%d results) for %s in NIS+ map %s:" + " ignoring this request", + count, key, dict_nisplus->dict.name); + nis_freeresult(nis_alias); + return (0); + } else { + vstring_strcpy(reply, + NIS_RES_OBJECT(nis_alias)->zo_data.objdata_u + .en_data.en_cols.en_cols_val[dict_nisplus->column] + .ec_value.ec_value_val); + if (msg_verbose) + msg_info("%s: %s, column %d -> %s", myname, STR(query), + dict_nisplus->column, STR(reply)); + nis_freeresult(nis_alias); + return (STR(reply)); + } + } + + /* + * When the NIS+ lookup fails for reasons other than "key not found", + * keep logging warnings, and hope that someone will eventually notice + * the problem and fix it. + */ + else { + if (nis_alias->status != NIS_NOTFOUND + && nis_alias->status != NIS_PARTIAL) { + msg_warn("lookup %s, NIS+ map %s: %s", + key, dict_nisplus->dict.name, + nis_sperrno(nis_alias->status)); + dict_errno = DICT_ERR_RETRY; + } + nis_freeresult(nis_alias); + return (0); + } +} + /* dict_nisplus_close - close NISPLUS map */ static void dict_nisplus_close(DICT *dict) { DICT_NISPLUS *dict_nisplus = (DICT_NISPLUS *) dict; - myfree((char *) dict_nisplus); + myfree(dict_nisplus->template); + dict_free(dict); } /* dict_nisplus_open - open NISPLUS map */ -DICT *dict_nisplus_open(const char *map, int unused_flags, int dict_flags) +DICT *dict_nisplus_open(const char *map, int open_flags, int dict_flags) { + const char *myname = "dict_nisplus_open"; DICT_NISPLUS *dict_nisplus; + char *col_field; + + /* + * Sanity check. + */ + if (open_flags != O_RDONLY) + msg_fatal("%s:%s map requires O_RDONLY access mode", + DICT_TYPE_NISPLUS, map); - dict_nisplus = (DICT_NISPLUS *) dict_alloc(DICT_TYPE_NISPLUS, map, - sizeof(*dict_nisplus)); + /* + * Initialize. This is a read-only map with fixed strings, not with + * regular expressions. + */ + dict_nisplus = (DICT_NISPLUS *) + dict_alloc(DICT_TYPE_NISPLUS, map, sizeof(*dict_nisplus)); + dict_nisplus->dict.lookup = dict_nisplus_lookup; dict_nisplus->dict.close = dict_nisplus_close; dict_nisplus->dict.flags = dict_flags | DICT_FLAG_FIXED; - return (DICT_DEBUG(&dict_nisplus->dict)); + + /* + * Convert the query template into an indexed name and column number. The + * query template looks like: + * + * [attribute=%s;attribute=value...];simple.name.:column + * + * One instance of %s gets to be replaced by a version of the lookup key; + * other attributes must specify fixed values. The reason for using ';' + * is that the comma character is special in main.cf. When no column + * number is given at the end of the map name, we use a default column. + */ + dict_nisplus->template = mystrdup(map); + translit(dict_nisplus->template, ";", ","); + if ((col_field = strstr(dict_nisplus->template, ".:")) != 0) { + col_field[1] = 0; + col_field += 2; + if (!alldig(col_field) || (dict_nisplus->column = atoi(col_field)) < 1) + msg_fatal("bad column field in NIS+ map name: %s", map); + } else { + dict_nisplus->column = 1; + } + if (msg_verbose) + msg_info("%s: opened NIS+ table %s for column %d", + myname, dict_nisplus->template, dict_nisplus->column); + return (DICT_DEBUG (&dict_nisplus->dict)); } + +#endif diff --git a/postfix/src/util/name_mask.c b/postfix/src/util/name_mask.c index 0ed7a7558..14e206a57 100644 --- a/postfix/src/util/name_mask.c +++ b/postfix/src/util/name_mask.c @@ -60,7 +60,7 @@ /* name_mask - compute mask corresponding to list of names */ -int name_mask(const char *context, NAME_MASK * table, const char *names) +int name_mask(const char *context, NAME_MASK *table, const char *names) { char *myname = "name_mask"; char *saved_names = mystrdup(names); @@ -92,7 +92,7 @@ int name_mask(const char *context, NAME_MASK * table, const char *names) /* str_name_mask - mask to string */ -const char *str_name_mask(const char *context, NAME_MASK * table, int mask) +const char *str_name_mask(const char *context, NAME_MASK *table, int mask) { char *myname = "name_mask"; NAME_MASK *np;