-TRESPONSE
-TREST_TABLE
-TRES_CONTEXT
+-TRWR_CONTEXT
-TSCACHE
-TSCACHE_CLNT
-TSCACHE_MULTI
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?
W\bWh\bha\bat\bt d\bde\bes\bst\bti\bin\bna\bat\bti\bio\bon\bns\bs t\bto\bo r\bre\bel\bla\bay\by m\bma\bai\bil\bl t\bto\bo
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):
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.
m\bmy\bys\bsq\bql\bl (read-only)
Perform MySQL database lookups. Configuration details are given in
mysql_table(5).
+ n\bne\bet\bti\bin\bnf\bfo\bo (read-only)
+ Perform Netinfo database lookups.
+ n\bni\bis\bs (read-only)
+ Perform NIS database lookups.
+ n\bni\bis\bsp\bpl\blu\bus\bs (read-only)
+ Perform NIS+ database lookups. Configuration details are given in
+ nisplus_table(5).
p\bpc\bcr\bre\be (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
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
=======================================================
$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
$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
<h2> <a name="relay_to"> What destinations to relay mail to </a> </h2>
<p> 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 <a href="postconf.5.html#relay_domains">relay_domains</a> configuration
parameter. The default is to authorize all domains (and subdomains)
of the domains listed with the <a href="postconf.5.html#mydestination">mydestination</a> parameter. </p>
</blockquote>
<p> The form enclosed with <tt>[]</tt> eliminates DNS MX lookups.
-Don't worry if you don't know what that means. </p>
+Don't worry if you don't know what that means. Just be sure to
+specify the <tt>[]</tt> around the mailhub hostname that your ISP
+gave to you, otherwise mail may be mis-delivered. </p>
<p> The <a href="STANDARD_CONFIGURATION_README.html">STANDARD_CONFIGURATION_README</a> file has more hints and tips
for firewalled and/or dial-up networks. </p>
<dd> Perform MySQL database lookups. Configuration details are given
in <a href="mysql_table.5.html">mysql_table(5)</a>. </dd>
+<dt> <b>netinfo</b> (read-only) </dt>
+
+<dd> Perform Netinfo database lookups. </dd>
+
+<dt> <b>nis</b> (read-only) </dt>
+
+<dd> Perform NIS database lookups. </dd>
+
+<dt> <b>nisplus</b> (read-only) </dt>
+
+<dd> Perform NIS+ database lookups. Configuration details are given
+in <a href="nisplus_table.5.html">nisplus_table(5)</a>. </dd>
+
<dt> <b>pcre</b> (read-only) </dt>
<dd> A lookup table based on Perl Compatible Regular Expressions.
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)\"`"
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 >$@
<b>postmap -q - <a href="cidr_table.5.html">cidr</a>:/etc/postfix/</b><i>filename</i> <<i>inputfile</i>
<b>DESCRIPTION</b>
- The Postfix mail system uses optional access control
- tables. These tables are usually in <b>dbm</b> or <b>db</b> 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 <b>dbm</b> or <b>db</b> 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 <b>postconf -m</b> command.
Available in Postfix version 2.1 and later:
- <b>enable_errors_to (no)</b>
- Report mail delivery errors to the address speci-
- fied with the non-standard Errors-To: message
- header, instead of the envelope sender address.
-
<b>BUILT-IN CONTENT FILTERING CONTROLS</b>
Postfix built-in content filtering is meant to stop a
flood of worms or viruses. It is not a general content
--- /dev/null
+<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html> <head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+<title> Postfix manual - nisplus_table(5) </title>
+</head> <body> <pre>
+NISPLUS_TABLE(5) NISPLUS_TABLE(5)
+
+<b>NAME</b>
+ nisplus_table - Postfix NIS+ client
+
+<b>SYNOPSIS</b>
+ <b>postmap -q "</b><i>string</i><b>" "<a href="nisplus_table.5.html">nisplus</a>:[</b><i>name</i><b>=%s];</b><i>name.name.</i><b>"</b>
+
+ <b>postmap -q - "<a href="nisplus_table.5.html">nisplus</a>:[</b><i>name</i><b>=%s];</b><i>name.name.</i><b>"</b> <<i>inputfile</i>
+
+<b>DESCRIPTION</b>
+ The Postfix mail system uses optional lookup tables.
+ These tables are usually in <b>dbm</b> or <b>db</b> 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 "<b>postconf -m</b>" command.
+
+ To test Postfix NIS+ lookup tables, use the <b>postmap</b> com-
+ mand as described in the SYNOPSIS above.
+
+<b>QUERY SYNTAX</b>
+ 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:
+
+ <b><a href="nisplus_table.5.html">nisplus</a>:[</b><i>name</i><b>=%s];</b><i>name.name.name</i><b>.:</b><i>column</i>
+
+ Postfix NIS+ map names differ from what one normally would
+ use with commands such as <b>niscat</b>:
+
+ <b>o</b> With each NIS+ table lookup, "<b>%s</b>" is replaced by a
+ version of the lookup string. There can be only
+ one "<b>%s</b>" instance in a Postfix NIS+ map name.
+
+ <b>o</b> Postfix NIS+ map names use "<b>;</b>" instead of "<b>,</b>",
+ because the latter character is special in the
+ Postfix main.cf file. Postfix replaces "<b>;</b>" charac-
+ ters in the map name by "<b>,</b>" before making NIS+
+ queries.
+
+ <b>o</b> The ":<i>column</i>" 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 ":<i>column</i>" is specified the first
+ column (1) is used.
+
+<b>EXAMPLE</b>
+ A NIS+ aliases map might be queried as follows:
+
+ <a href="postconf.5.html#alias_maps">alias_maps</a> = dbm:/etc/mail/aliases,
+ <a href="nisplus_table.5.html">nisplus</a>:[alias=%s];mail_aliases.org_dir.$<a href="postconf.5.html#mydomain">mydomain</a>.:1
+
+ This queries the local aliases file before the NIS+ file.
+
+<b>SEE ALSO</b>
+ <a href="postmap.1.html">postmap(1)</a>, Postfix lookup table manager
+
+<b>README FILES</b>
+ <a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
+
+<b>LICENSE</b>
+ The Secure Mailer license must be distributed with this
+ software.
+
+<b>AUTHOR(S)</b>
+ 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)
+</pre> </body> </html>
(default: yes)</b></DT><DD>
<p>
-Append the string "@$<a href="postconf.5.html#myorigin">myorigin</a>" to mail addresses without domain
-information.
+With locally submitted mail, append the string "@$<a href="postconf.5.html#myorigin">myorigin</a>" to mail
+addresses without domain information. With remotely submitted mail,
+append the string "@$invalid_domain" instead.
</p>
<p>
(default: yes)</b></DT><DD>
<p>
-Append the string ".$<a href="postconf.5.html#mydomain">mydomain</a>" to addresses that have no ".domain"
-information.
+With locally submitted mail, append the string ".$<a href="postconf.5.html#mydomain">mydomain</a>" to
+addresses that have no ".domain" information. With remotely submitted
+mail, append the string ".$invalid_domain" instead.
</p>
<p>
</p>
+</DD>
+
+<DT><b><a name="invalid_header_rewrite_context_domain">invalid_header_rewrite_context_domain</a>
+(default: domain.invalid)</b></DT><DD>
+
+<p> Append this domain to incomplete message header addresses from
+remote clients, when $<a href="postconf.5.html#remote_header_rewrite_context_name">remote_header_rewrite_context_name</a> is set to
+"invalid". This is one way to avoid appending your own domain to
+addresses in spam from poorly written software. </p>
+
+
</DD>
<DT><b><a name="invalid_hostname_reject_code">invalid_hostname_reject_code</a>
into concurrency per domain. </p>
+</DD>
+
+<DT><b><a name="local_header_rewrite_context_clients">local_header_rewrite_context_clients</a>
+(default: $<a href="postconf.5.html#inet_interfaces">inet_interfaces</a>
+$<a href="postconf.5.html#mynetworks">mynetworks</a>)</b></DT><DD>
+
+<p> Append the domain names in $<a href="postconf.5.html#myorigin">myorigin</a> and $<a href="postconf.5.html#mydomain">mydomain</a> to incomplete
+message header addresses from these clients. </p>
+
+<p> 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. </p>
+
+<p> You can also specify "/file/name" or "<a href="DATABASE_README.html">type:table</a>" patterns.
+A "/file/name" pattern is replaced by its contents; a "<a href="DATABASE_README.html">type:table</a>"
+lookup table is matched when a client name or address matches a
+lookup key (the lookup result is ignored). </p>
+
+
</DD>
<DT><b><a name="local_recipient_maps">local_recipient_maps</a>
(default: empty)</b></DT><DD>
<p> 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 <a href="smtpd.8.html">smtpd(8)</a>, <a href="qmqpd.8.html">qmqpd(8)</a> or
<a href="pickup.8.html">pickup(8)</a> daemons. </p>
</pre>
+</DD>
+
+<DT><b><a name="remote_header_rewrite_context_name">remote_header_rewrite_context_name</a>
+(default: local)</b></DT><DD>
+
+<p> The address rewriting context that should be used for incomplete
+mail header addresses from remote clients. </p>
+
+<ul>
+
+<li> <p> <b>local</b> Append the domains specified with $<a href="postconf.5.html#myorigin">myorigin</a>
+or $<a href="postconf.5.html#mydomain">mydomain</a> to incomplete message header addresses from remote
+clients. </p>
+
+<li> <p> <b>invalid</b> Append the domain specified with
+$<a href="postconf.5.html#invalid_header_rewrite_context_domain">invalid_header_rewrite_context_domain</a> 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.
+</p>
+
+<li> <p> <b>none</b> 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. </p>
+
+</ul>
+
+<p> Note: Postfix always appends the domains specified with $<a href="postconf.5.html#myorigin">myorigin</a>
+or $<a href="postconf.5.html#mydomain">mydomain</a> to incomplete envelope addresses, because those
+addresses are effectively equivalent to local addresses. </p>
+
+
</DD>
<DT><b><a name="require_home_directory">require_home_directory</a>
<p> Each Postfix manual page is numbered after a section of the
UNIX manual: examples are <a href="mailq.1.html">mailq(1)</a> or <a href="access.5.html">access(5)</a>. Unfortunately,
-the organization of manual pages depends on the UNIX version being
-used. Postfix documentation assumes the following convention:
-</p>
+there is no single universal method to organize manual pages; each
+UNIX flavor appears to be different. Postfix documentation assumes
+the following convention: </p>
<blockquote>
<li> <a href="mysql_table.5.html">mysql_table(5)</a>, Postfix MYSQL client
+<li> <a href="nisplus_table.5.html">nisplus_table(5)</a>, Postfix NIS+ client
+
<li> <a href="pcre_table.5.html">pcre_table(5)</a>, Associate PCRE pattern with value
<li> <a href="pgsql_table.5.html">pgsql_table(5)</a>, Postfix PostgreSQL client
<a href="cidr_table.5.html">cidr_table(5)</a>, Associate CIDR pattern with value
<a href="ldap_table.5.html">ldap_table(5)</a>, Postfix LDAP client
<a href="mysql_table.5.html">mysql_table(5)</a>, Postfix MYSQL client
+ <a href="nisplus_table.5.html">nisplus_table(5)</a>, Postfix NIS+ client
<a href="pcre_table.5.html">pcre_table(5)</a>, Associate PCRE pattern with value
<a href="pgsql_table.5.html">pgsql_table(5)</a>, Postfix PostgreSQL client
<a href="regexp_table.5.html">regexp_table(5)</a>, Associate POSIX regexp pattern with value
What SMTP clients Postfix will not offer AUTH sup-
port to.
+<b>ADDRESS REWRITING CONTROLS</b>
+ <b><a href="postconf.5.html#receive_override_options">receive_override_options</a> (empty)</b>
+ Enable or disable recipient validation, built-in
+ content filtering, or address mapping.
+
+ Available in Postfix version 2.2 and later:
+
+ <b><a href="postconf.5.html#local_header_rewrite_context_clients">local_header_rewrite_context_clients</a> ($<a href="postconf.5.html#inet_interfaces">inet_interfaces</a></b>
+ <b>$<a href="postconf.5.html#mynetworks">mynetworks</a>)</b>
+ Append the domain names in $<a href="postconf.5.html#myorigin">myorigin</a> and $<a href="postconf.5.html#mydomain">mydomain</a>
+ to incomplete message header addresses from these
+ clients.
+
+ <b><a href="postconf.5.html#remote_header_rewrite_context_name">remote_header_rewrite_context_name</a> (local)</b>
+ The address rewriting context that should be used
+ for incomplete mail header addresses from remote
+ clients.
+
+ Implemented by the <a href="trivial-rewrite.8.html">trivial-rewrite(8)</a> server:
+
+ <b><a href="postconf.5.html#invalid_header_rewrite_context_domain">invalid_header_rewrite_context_domain</a> (domain.invalid)</b>
+ Append this domain to incomplete message header
+ addresses from remote clients, when
+ $<a href="postconf.5.html#remote_header_rewrite_context_name">remote_header_rewrite_context_name</a> is set to
+ "invalid".
+
<b>AFTER QUEUE EXTERNAL CONTENT INSPECTION CONTROLS</b>
As of version 1.0, Postfix can be configured to send new
mail to an external content filter AFTER the mail is
<b><a href="postconf.5.html#receive_override_options">receive_override_options</a> (empty)</b>
Enable or disable recipient validation, built-in
- content filtering, or address rewriting.
+ content filtering, or address mapping.
<b>EXTERNAL CONTENT INSPECTION CONTROLS</b>
The following parameters are applicable for both before-
The <b>trivial-rewrite</b> daemon processes three types of client
service requests:
- <b>rewrite</b>
- Rewrite an address to standard form. The <b>trivial-</b>
- <b>rewrite</b> 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).
-
- <b>resolve</b>
+ <b>rewrite</b> <i>context address</i>
+ Rewrite an address to standard form, according to
+ the address rewriting context:
+
+ <b>local</b>
+
+ <b>none</b> Append the domain names specified with <b>$<a href="postconf.5.html#myorigin">myo</a>-</b>
+ <b><a href="postconf.5.html#myorigin">rigin</a></b> or <b>$<a href="postconf.5.html#mydomain">mydomain</a></b> to incomplete addresses;
+ do <b><a href="postconf.5.html#swap_bangpath">swap_bangpath</a></b> and <b><a href="postconf.5.html#allow_percent_hack">allow_percent_hack</a></b> pro-
+ cessing as described below, and strip source
+ routed addresses (<i>@site,@site:user@domain</i>)
+ to <i>user@domain</i> form.
+
+ <b>invalid</b>
+ Append the domain name specified with
+ <b>$<a href="postconf.5.html#invalid_header_rewrite_context_domain">invalid_header_rewrite_context_domain</a></b> to
+ incomplete addresses. Otherwise the result
+ is identical to that of the <b>local</b> address
+ rewriting context. This prevents Postfix
+ from appending the <a href="ADDRESS_CLASS_README.html#local_domain_class">local domain</a> to spam from
+ poorly written remote clients.
+
+ <b>resolve</b> <i>address</i>
Resolve an address to a (<i>transport</i>, <i>nexthop</i>, <i>recip-</i>
- <i>ient</i>) triple. The meaning of the results is as fol-
- lows:
+ <i>ient</i>, <i>flags</i>) quadruple. The meaning of the results
+ is as follows:
<i>transport</i>
The delivery agent to use. This is the first
field of an entry in the <b>master.cf</b> file.
<i>nexthop</i>
- The host to send to and optional delivery
+ The host to send to and optional delivery
method information.
<i>recipient</i>
- The envelope recipient address that is
+ The envelope recipient address that is
passed on to <i>nexthop</i>.
- <b>verify</b> Resolve an address for address verification pur-
+ <i>flags</i> The address class, whether the address
+ requires relaying, whether the address has
+ problems, and whether the request failed.
+
+ <b>verify</b> <i>address</i>
+ Resolve an address for address verification pur-
poses.
<b>SERVER PROCESS MANAGEMENT</b>
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 <b>$<a href="postconf.5.html#max_use">max_use</a></b> clients of after <b>$<a href="postconf.5.html#max_idle">max_idle</a></b>
seconds of idle time.
<b>STANDARDS</b>
- None. The command does not interact with the outside
+ None. The command does not interact with the outside
world.
<b>SECURITY</b>
- The <b>trivial-rewrite</b> 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 <b>trivial-rewrite</b> 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.
<b>DIAGNOSTICS</b>
<b>CONFIGURATION PARAMETERS</b>
On busy mail systems a long time may pass before a <b>main.cf</b>
- change affecting trivial_rewrite(8) is picked up. Use the
+ change affecting trivial_rewrite(8) is picked up. Use the
command "<b>postfix reload</b>" to speed up a change.
- The text below provides only a parameter summary. See
+ The text below provides only a parameter summary. See
<a href="postconf.5.html">postconf(5)</a> for more details including examples.
<b>COMPATIBILITY CONTROLS</b>
<b><a href="postconf.5.html#resolve_dequoted_address">resolve_dequoted_address</a> (yes)</b>
- Resolve a recipient address safely instead of cor-
+ Resolve a recipient address safely instead of cor-
rectly, by looking inside quotes.
<b><a href="postconf.5.html#resolve_null_domain">resolve_null_domain</a> (no)</b>
<b>ADDRESS REWRITING CONTROLS</b>
<b><a href="postconf.5.html#myorigin">myorigin</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
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.
<b><a href="postconf.5.html#allow_percent_hack">allow_percent_hack</a> (yes)</b>
- Enable the rewriting of the form "user%domain" to
+ Enable the rewriting of the form "user%domain" to
"user@domain".
<b><a href="postconf.5.html#append_at_myorigin">append_at_myorigin</a> (yes)</b>
- Append the string "@$<a href="postconf.5.html#myorigin">myorigin</a>" to mail addresses
- without domain information.
+ With locally submitted mail, append the string
+ "@$<a href="postconf.5.html#myorigin">myorigin</a>" to mail addresses without domain
+ information.
<b><a href="postconf.5.html#append_dot_mydomain">append_dot_mydomain</a> (yes)</b>
- Append the string ".$<a href="postconf.5.html#mydomain">mydomain</a>" to addresses that
- have no ".domain" information.
+ With locally submitted mail, append the string
+ ".$<a href="postconf.5.html#mydomain">mydomain</a>" to addresses that have no ".domain"
+ information.
<b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
The separator between user names and address exten-
sions (user+foo).
<b><a href="postconf.5.html#swap_bangpath">swap_bangpath</a> (yes)</b>
- Enable the rewriting of "site!user" into
+ Enable the rewriting of "site!user" into
"user@site".
+ Available in Postfix 2.2 and later:
+
+ <b><a href="postconf.5.html#invalid_header_rewrite_context_domain">invalid_header_rewrite_context_domain</a> (domain.invalid)</b>
+ Append this domain to incomplete message header
+ addresses from remote clients, when
+ $<a href="postconf.5.html#remote_header_rewrite_context_name">remote_header_rewrite_context_name</a> is set to
+ "invalid".
+
+ Implemented by the <a href="smtpd.8.html">smtpd(8)</a> server:
+
+ <b><a href="postconf.5.html#remote_header_rewrite_context_name">remote_header_rewrite_context_name</a> (local)</b>
+ The address rewriting context that should be used
+ for incomplete mail header addresses from remote
+ clients.
+
<b>ROUTING CONTROLS</b>
The following is applicable to Postfix version 2.0 and
later. Earlier versions do not have support for: <a href="postconf.5.html#virtual_transport">vir</a>-
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
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 - $? >$@
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
.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
--- /dev/null
+.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
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
.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
Setting this parameter to a value > 1 changes the meaning of
local_destination_concurrency_limit from concurrency per recipient
into concurrency per domain.
+<DT>\fBlocal_header_rewrite_context_clients
+(default: $inet_interfaces
+$mynetworks)\fR</DT><DD>
+.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,
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
.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.
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
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
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
.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
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
.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
<p> 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:
-</p>
+there is no single universal method to organize manual pages; each
+UNIX flavor appears to be different. Postfix documentation assumes
+the following convention: </p>
<blockquote>
s;\binet_interfaces\b;<a href="postconf.5.html#inet_interfaces">$&</a>;g;
s;\binitial_destination_concurrency\b;<a href="postconf.5.html#initial_destination_concurrency">$&</a>;g;
s;\binvalid_hostname_reject_code\b;<a href="postconf.5.html#invalid_hostname_reject_code">$&</a>;g;
+ s;\binvalid_header_rewrite_con[-</bB>]*\n* *[<bB>]*text_domain\b;<a href="postconf.5.html#invalid_header_rewrite_context_domain">$&</a>;g;
s;\bipc_idle\b;<a href="postconf.5.html#ipc_idle">$&</a>;g;
s;\bipc_timeout\b;<a href="postconf.5.html#ipc_timeout">$&</a>;g;
s;\bipc_ttl\b;<a href="postconf.5.html#ipc_ttl">$&</a>;g;
s;\blocal_recip[-</bB>]*\n* *[<bB>]*ient_maps\b;<a href="postconf.5.html#local_recipient_maps">$&</a>;g;
s;\blocal_transport\b;<a href="postconf.5.html#local_transport">$&</a>;g;
s;\bluser_relay\b;<a href="postconf.5.html#luser_relay">$&</a>;g;
+ s;\blocal_header_rewrite_con[-</bB>]*\n* *[<bB>]*text_clients\b;<a href="postconf.5.html#local_header_rewrite_context_clients">$&</a>;g;
s;\bmail_name\b;<a href="postconf.5.html#mail_name">$&</a>;g;
s;\bmail_owner\b;<a href="postconf.5.html#mail_owner">$&</a>;g;
s;\bmail_release_date\b;<a href="postconf.5.html#mail_release_date">$&</a>;g;
s;\bminimal_backoff_time\b;<a href="postconf.5.html#minimal_backoff_time">$&</a>;g;
s;\bmulti_recip[-</bB>]*\n* *[<bB>]*ient_bounce_reject_code\b;<a href="postconf.5.html#multi_recipient_bounce_reject_code">$&</a>;g;
s;\bmydes[-</bB>]*\n*[ <bB>]*tina[-</bB>]*\n*[ <bB>]*tion\b;<a href="postconf.5.html#mydestination">$&</a>;g;
- s;\bmydomain\b;<a href="postconf.5.html#mydomain">$&</a>;g;
+ s;\bmydo[-</bB>]*\n* *[<bB>]*main\b;<a href="postconf.5.html#mydomain">$&</a>;g;
s;\bmyhostname\b;<a href="postconf.5.html#myhostname">$&</a>;g;
- s;\bmynetworks\b;<a href="postconf.5.html#mynetworks">$&</a>;g;
+ s;\bmynet[-</bB>]*\n* *[<bB>]*works\b;<a href="postconf.5.html#mynetworks">$&</a>;g;
s;\bmynetworks_style\b;<a href="postconf.5.html#mynetworks_style">$&</a>;g;
- s;\bmyorigin\b;<a href="postconf.5.html#myorigin">$&</a>;g;
+ s;\bmyo[-</bB>]*\n*[ <bB>]*rigin\b;<a href="postconf.5.html#myorigin">$&</a>;g;
s;\bnested_header_checks\b;<a href="postconf.5.html#nested_header_checks">$&</a>;g;
s;\bnewaliases_path\b;<a href="postconf.5.html#newaliases_path">$&</a>;g;
s;\bnon_fqdn_reject_code\b;<a href="postconf.5.html#non_fqdn_reject_code">$&</a>;g;
s;\brbl_reply_maps\b;<a href="postconf.5.html#rbl_reply_maps">$&</a>;g;
s;\breadme_directory\b;<a href="postconf.5.html#readme_directory">$&</a>;g;
s;\breceive_override_options\b;<a href="postconf.5.html#receive_override_options">$&</a>;g;
+ s;\bremote_header_rewrite_con[-</bB>]*\n* *[<bB>]*text_name\b;<a href="postconf.5.html#remote_header_rewrite_context_name">$&</a>;g;
s;\bno_unknown_recip[-</bB>]*\n* *[<bB>]*ient_checks\b;<a href="postconf.5.html#no_unknown_recipient_checks">$&</a>;g;
s;\bno_address_mappings\b;<a href="postconf.5.html#no_address_mappings">$&</a>;g;
s;\bno_header_body_checks\b;<a href="postconf.5.html#no_header_body_checks">$&</a>;g;
s/[<bB>]*ldap[<\/bBiI>]*_[<\/iIbB>]*table[<\/bB>]*\(5\)/<a href="ldap_table.5.html">$&<\/a>/g;
s/[<bB>]*mas[-<\/bB>]*\n* *[<bB>]*ter[<\/bB>]*\(5\)/<a href="master.5.html">$&<\/a>/g;
s/[<bB>]*mysql[<\/bBiI>]*_[<\/iIbB>]*table[<\/bB>]*\(5\)/<a href="mysql_table.5.html">$&<\/a>/g;
+ s/[<bB>]*nisplus[<\/bBiI>]*_[<\/iIbB>]*table[<\/bB>]*\(5\)/<a href="nisplus_table.5.html">$&<\/a>/g;
s/[<bB>]*pcre[<\/bBiI>]*_[<\/iIbB>]*table[<\/bB>]*\(5\)/<a href="pcre_table.5.html">$&<\/a>/g;
s/[<bB>]*pgsql[<\/bBiI>]*_[<\/iIbB>]*table[<\/bB>]*\(5\)/<a href="pgsql_table.5.html">$&<\/a>/g;
s/[<bB>]*postconf[<\/bB>]*\(5\)/<a href="postconf.5.html">$&<\/a>/g;
s/\b(proxy):/<a href="proxymap.8.html">$1<\/a>:/g;
s/\b(pgsql):/<a href="pgsql_table.5.html">$1<\/a>:/g;
s/\b(mysql):/<a href="mysql_table.5.html">$1<\/a>:/g;
+ s/\b(nisplus):/<a href="nisplus_table.5.html">$1<\/a>:/g;
s/\b(ldap):/<a href="ldap_table.5.html">$1<\/a>:/g;
s/\b(regexp):/<a href="regexp_table.5.html">$1<\/a>:/g;
s/\b(tcp):/<a href="tcp_table.5.html">$1<\/a>:/g;
<h2> <a name="relay_to"> What destinations to relay mail to </a> </h2>
<p> 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. </p>
</blockquote>
<p> The form enclosed with <tt>[]</tt> eliminates DNS MX lookups.
-Don't worry if you don't know what that means. </p>
+Don't worry if you don't know what that means. Just be sure to
+specify the <tt>[]</tt> around the mailhub hostname that your ISP
+gave to you, otherwise mail may be mis-delivered. </p>
<p> The STANDARD_CONFIGURATION_README file has more hints and tips
for firewalled and/or dial-up networks. </p>
<dd> Perform MySQL database lookups. Configuration details are given
in mysql_table(5). </dd>
+<dt> <b>netinfo</b> (read-only) </dt>
+
+<dd> Perform Netinfo database lookups. </dd>
+
+<dt> <b>nis</b> (read-only) </dt>
+
+<dd> Perform NIS database lookups. </dd>
+
+<dt> <b>nisplus</b> (read-only) </dt>
+
+<dd> Perform NIS+ database lookups. Configuration details are given
+in nisplus_table(5). </dd>
+
<dt> <b>pcre</b> (read-only) </dt>
<dd> A lookup table based on Perl Compatible Regular Expressions.
../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/^/# /' >$@
#
# \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
--- /dev/null
+#++
+# 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
+#--
%PARAM receive_override_options
<p> 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. </p>
%PARAM append_at_myorigin yes
<p>
-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.
</p>
<p>
%PARAM append_dot_mydomain yes
<p>
-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.
</p>
<p>
<p> How frequently the scache(8) server logs usage statistics with
session cache hit and miss rates for logical destinations and for
physical endpoints. </p>
+
+%PARAM invalid_header_rewrite_context_domain domain.invalid
+
+<p> 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. </p>
+
+%PARAM local_header_rewrite_context_clients $inet_interfaces
+$mynetworks
+
+<p> Append the domain names in $myorigin and $mydomain to incomplete
+message header addresses from these clients. </p>
+
+<p> 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. </p>
+
+<p> 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). </p>
+
+%PARAM remote_header_rewrite_context_name local
+
+<p> The address rewriting context that should be used for incomplete
+mail header addresses from remote clients. </p>
+
+<ul>
+
+<li> <p> <b>local</b> Append the domains specified with $myorigin
+or $mydomain to incomplete message header addresses from remote
+clients. </p>
+
+<li> <p> <b>invalid</b> 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.
+</p>
+
+<li> <p> <b>none</b> 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. </p>
+
+</ul>
+
+<p> Note: Postfix always appends the domains specified with $myorigin
+or $mydomain to incomplete envelope addresses, because those
+addresses are effectively equivalent to local addresses. </p>
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
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
/* 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
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 */
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;
/*
* 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
#define STR vstring_str
#define IGNORE_EXTENSION (char **) 0
+#define STREQ(x,y) (strcmp((x), (y)) == 0)
/* cleanup_addr_sender - process envelope sender record */
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);
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))
{
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))
#include <mymalloc.h>
#include <stringops.h>
#include <nvtable.h>
+#include <name_code.h>
/* Global library. */
#include <qmgr_user.h>
#include <mail_params.h>
#include <verp_sender.h>
+#include <mail_proto.h>
/* Application-specific. */
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);
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);
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,
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,
};
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))
&& (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);
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))
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);
/* SYNOPSIS
/* #include <cleanup.h>
/*
-/* 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
/* 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
/* Global library. */
#include <tok822.h>
-#include <rewrite_clnt.h>
#include <quote_822_local.h>
+#include <rewrite_clnt.h>
/* Application-specific. */
/* 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);
/* 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);
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;
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);
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)
myfree(state->filter);
if (state->redirect)
myfree(state->redirect);
+ if (state->rewrite_context_name)
+ myfree(state->rewrite_context_name);
myfree((char *) state);
}
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
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
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,
/* char *sasl_method;
/* char *sasl_username;
/* char *sasl_sender;
+/* char *rewrite_context;
/* .in -5
/* } DELIVER_REQUEST;
/*
static VSTRING *sasl_method;
static VSTRING *sasl_username;
static VSTRING *sasl_sender;
+ static VSTRING *rewrite_context;
long offset;
/*
sasl_method = vstring_alloc(10);
sasl_username = vstring_alloc(10);
sasl_sender = vstring_alloc(10);
+ rewrite_context = vstring_alloc(10);
}
/*
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);
}
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
char *sasl_method; /* SASL method */
char *sasl_username; /* SASL user name */
char *sasl_sender; /* SASL sender */
+ char *rewrite_context; /* header rewrite context */
} DELIVER_REQUEST;
/*
#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;
#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
#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"
#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 */
* 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"
/*
/* 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.
{
VSTREAM *stream;
+ /*
+ * Sanity check.
+ */
+ if (strcmp(rule, REWRITE_NONE) == 0)
+ msg_panic("rewrite_clnt: bad rewrite context: \"%s\"", rule);
+
/*
* One-entry cache.
*/
* Utility library.
*/
#include <vstring.h>
+#include <mail_params.h>
/*
* 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 *);
-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.
-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
#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
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,
};
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;
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
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
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 */
};
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);
#include <verp_sender.h>
#include <mail_proto.h>
#include <qmgr_user.h>
+#include <split_addr.h>
/* Client stubs. */
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);
}
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));
message->sasl_username = mystrdup("");
if (message->sasl_sender == 0)
message->sasl_sender = mystrdup("");
+ if (message->rewrite_context == 0)
+ message->rewrite_context = mystrdup("");
/*
* Clean up.
/* 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
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
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 */
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);
#include <verp_sender.h>
#include <mail_proto.h>
#include <qmgr_user.h>
+#include <split_addr.h>
/* Client stubs. */
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;
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));
message->sasl_username = mystrdup("");
if (message->sasl_sender == 0)
message->sasl_sender = mystrdup("");
+ if (message->rewrite_context == 0)
+ message->rewrite_context = mystrdup("");
/*
* Clean up.
#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 */
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;
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;
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
/* 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
/* 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
#endif
+char *var_remote_rwr_name;
+char *var_local_rwr_clients;
+
/*
* Silly little macros.
*/
* 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.
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);
}
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) {
*/
#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)
*/
#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)
* 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,
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);
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.
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);
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.
*/
*/
#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,
*/
#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);
/*
* 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.
*/
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
|| 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 */
#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[] = {
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.
#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 \
/* int smtpd_check_addr(address)
/* const char *address;
/*
+/* char *smtpd_check_rewrite(state)
+/* SMTPD_STATE *state;
+/*
/* char *smtpd_check_client(state)
/* SMTPD_STATE *state;
/*
/* 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
#include <namadr_list.h>
#include <domain_list.h>
#include <mail_params.h>
-#include <canon_addr.h>
+#include <rewrite_clnt.h>
#include <resolve_clnt.h>
#include <mail_error.h>
#include <resolve_local.h>
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.
/*
* 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));
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.
* 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, "
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,
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)
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);
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
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;
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,
};
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);
*/
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 *);
#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.
#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 */
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,
};
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) {
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))
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)
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
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;
}
}
tok822_free(tree->head);
tree->head = tok822_scan(STR(addr_buf), &tree->tail);
- rewrite_tree(REWRITE_CANON, tree);
+ rewrite_tree(&local_context, tree);
continue;
}
/* 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.
/*
/*
/* 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.
#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;
*/
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));
}
}
&& 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));
}
/*
/* 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;
* 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;
}
* 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);
}
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),
/* 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
/* 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
/* .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
char *var_empty_addr;
int var_show_unk_rcpt_table;
int var_resolve_nulldom;
+char *var_inv_rwr_domain;
/*
* Shadow personality for address verification.
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[] = {
/*
* 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
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
-
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
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",
/* SYNOPSIS
/* #include <dict_nisplus.h>
/*
-/* 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
/* 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
/* System library. */
-#include "sys_defs.h"
+#include <sys_defs.h>
#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#ifdef HAS_NISPLUS
+#include <rpcsvc/nis.h> /* for nis_list */
+#endif
/* Utility library. */
-#include "msg.h"
-#include "mymalloc.h"
-#include "htable.h"
-#include "dict.h"
-#include "dict_nisplus.h"
+#include <msg.h>
+#include <mymalloc.h>
+#include <vstring.h>
+#include <stringops.h>
+#include <dict.h>
+#include <dict_nisplus.h>
+
+#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>
+ *
+ * simple name ::= <string>. | <string>.<simple name>
+ *
+ * indexed name ::= <search criterion>,<simple name>
+ *
+ * search criterion ::= [ <attribute list> ]
+ *
+ * attribute list ::= <attribute> | <attribute>,<attribute list>
+ *
+ * attribute ::= <string> = <string>
+ *
+ * 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
/* 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);
/* 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;