From: Wietse Venema Date: Tue, 12 Aug 2003 05:00:00 +0000 (-0500) Subject: postfix-2.0.16-20030914 X-Git-Tag: v2.1-RC1-20040331~42 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=61fb4506a821adb24e6b2eed60c7e976bf9e8b1b;p=thirdparty%2Fpostfix.git postfix-2.0.16-20030914 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index ae2d125b8..e75da3493 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -8437,14 +8437,121 @@ Apologies for any names omitted. when it is given a non-existent command-line macro name. File: pipe/pipe.c. +20030810 + + Bugfix: dict_ldap had a few harmless memory leaks. By + Liviu Daia. File: util/dict_ldap.c. + + Feature: support for LDAP URLs in the LDAP parameter + "server_host", if Postfix is linked against OpenLDAP. This + allows Postfix to connect to LDAP SSL sources. By Liviu + Daia. File: util/dict_ldap.c. + + 20030811 Cleanup: produce a warning when host:port specifies a badly formatted numerical port. Files: util/find_inet.c, smtp/smtp_connect.c, lmtp/lmtp_connect.c. +20030822 + + Feature: the export_environment and import_environment + parameters now accept name=value information that will be + entered into the new environment. File: util/clean_env.c. + +20030823 + + Feature: smtpd_sasl_exceptions_networks parameter to prevent + Postfix from offering AUTH to clients that match the listed + networks. Based on code by Ben Rosengart, Panix. Files: + conf/sample-auth.cf, smtpd/smtpd.c. + +20030905 + + Workaround: Solaris 8 select() claims that a non-blocking + socket is readable and then read() fails with EAGAIN. Files: + util/timed_read.c and as precautionary measure, + util/timed_write.c. + + Bugfix: dict_register() should not be called from dict_open() + in dict_mysql and dict_pgsql. Liviu Daia. Files: + util/dict_mysql.c, util/dict_pgsql.c. + + Feature: LDAP parameters can now be specified in external + files. This makes it possible to securely store bind + passwords for plain auth outside of main.cf (which is world + readable). By Liviu Daia, based on a suggestion by Victor + Duchovni and Lamont Jones. File: util/dict_ldap.c. + + Feature: STARTTLS option for LDAP, if Postfix is linked + against OpenLDAP. By Liviu Daia, amended by Victor Duchovni. + File: util/dict_ldap.c. + + Cleanup: connections to LDAP sources are now postponed + until they are actually needed. By Liviu Daia. File: + util/dict_ldap.c. + +20030908 + + The 20030905 workaround triggers too many warnings. TCP + sockets are back to blocking, and keepalives are turned on + to kill off dead sockets, as suggested by Leandro Santi. + Files: master/{single,multi}_server.c, smtpd/smtpd.c, + util/sys_defs.h. + +20030909 + + Bugfix: the LMTP session caching code had problems with + SASL authentication after the first connection, and pipelining + was working poorly. Fix by Victor Duchovni, Morgan Stanley. + Files: lmtp/lmtp.c, lmtp/lmtp_proto.c. + +20030913 + + Safety: set-gid commands don't trust TZ. File: msg_syslog.c. + +20030914 + + Address extension propagation wasn't documented enough when + it was added to Postfix. Based on patches by Roman Neuhauser. + + Added clarifying notes to main.cf, master.cf and access by + Dean Gibson. + + In header/body_checks, DUNNO is now the preferred action + instead of the now deprecated OK. + + In header/body_checks, allow text after IGNORE and DUNNO, + suggested by Victor Duchovni, Morgan Stanley. File: + src/cleanup/cleanup_message.c. + + Feature: reject_rhsbl_helo. File: smtpd/smtpd_check.c. + + Cleanup: the LMTP and SMTP clients now send "MAIL FROM: + AUTH=<>" when SASL authenticated. Suggested by by Victor + Duchovni, Morgan Stanley. Files: smtp/smtp_proto.c, + lmtp/lmtp_proto.c. + Open problems: + Med: do not list myorigin in virtual_alias_maps. + + High: when virtual aliasing is turned off after content + filtering, local submissions may escape virtual aliasing. + + Med: qmgr should not exit while an asynchronous bounce + request is in progress; this can result in multiple + non-delivery notifications. + + Low: postcat should be null byte transparent. + + Low: qmgr_move should not reset time stamps on queue files + without shared lock (i.e. not open by a delivery agent). + + Low: postsuper re-run after renaming files, but only a + limited number of times. + Doc: mention the proxy_interfaces parameter everywhere the inet_interfaces and mydestination parameters are mentioned. diff --git a/postfix/README_FILES/LDAP_README b/postfix/README_FILES/LDAP_README index abf8fd5d9..e41eb6672 100644 --- a/postfix/README_FILES/LDAP_README +++ b/postfix/README_FILES/LDAP_README @@ -69,39 +69,41 @@ CONFIGURING LDAP LOOKUPS In order to use LDAP lookups, define at least one LDAP source as a table lookup in main.cf, for example: - alias_maps = hash:/etc/aliases, ldap:ldapsource + alias_maps = hash:/etc/aliases, ldap:/etc/ldap-aliases.cf -Each LDAP source can have the following parameters, which should be -prefixed in main.cf with the name you've given the source in its -definition and an underscore. To continue the example, the first -parameter below, "server_host", would be defined in main.cf as -"ldapsource_server_host". Defaults are given in parentheses: +The file /etc/postfix/ldap-aliases.cf can specify the following +parameters. Defaults are given in parentheses: server_host (localhost) The name of the host running the LDAP server, e.g. - ldapsource_server_host = ldap.your.com + server_host = ldap.your.com It should be possible with all the libraries mentioned above to specify multiple servers separated by spaces, with the libraries trying them in order should the first one fail. It should also be possible to give each server in the list a different port, by naming them like "ldap.your.com:1444". + With OpenLDAP, LDAP URLs can be used to request connection + over UNIX domain sockets (ldapi://%2Fsome%2Fpath) or LDAP SSL + (ldaps://ldap.your.com:636, provided OpenLDAP was compiled with + support for SSL). + server_port (389) The port the LDAP server listens on, e.g. - ldapsource_server_port = 778 + server_port = 778 search_base (No default; you must configure this.) The base at which to conduct the search, e.g. - ldapsource_search_base = dc=your, dc=com + search_base = dc=your, dc=com timeout (10 seconds) The number of seconds a search can take before timing out, e.g. - ldapsource_timeout = 5 + timeout = 5 query_filter (mailacceptinggeneralid=%s) The RFC2254 filter used to search the directory, where %s is a substitute for the address Postfix is trying to resolve, e.g. - ldapsource_query_filter = (&(mail=%s)(paid_up=true)) + query_filter = (&(mail=%s)(paid_up=true)) result_filter (%s) Filter applied to result attributes. Supports the same expansions @@ -114,17 +116,17 @@ parameter below, "server_host", would be defined in main.cf as performed. This means that the LDAP map won't get searched for 'user', nor will it get searched for any domain not listed. This can significantly reduce the query load on the LDAP server. - ldapsource_domain = postfix.org, hash:/etc/postfix/searchdomains + domain = postfix.org, hash:/etc/postfix/searchdomains result_attribute (maildrop) The attribute(s) Postfix will read from any directory entries returned by the lookup, to be resolved to an email address. - ldapsource_result_attribute = mailbox,maildrop + result_attribute = mailbox,maildrop special_result_attribute (No default) The attribute(s) of directory entries that can contain DNs or URLs. If found, a recursive subsequent search is done using their values. - ldapsource_special_result_attribute = member + special_result_attribute = member scope (sub) The LDAP search scope: sub, base, or one. These translate into @@ -134,7 +136,7 @@ parameter below, "server_host", would be defined in main.cf as Whether or not to bind to the LDAP server. Newer LDAP implementations don't require clients to bind, which saves time. Example: - ldapsource_bind = no + bind = no If you do need to bind, you might consider configuring Postfix to connect to the local machine on a port that's an SSL tunnel @@ -146,13 +148,17 @@ parameter below, "server_host", would be defined in main.cf as bind_dn ("") If you do have to bind, do it with this distinguished name. Example: - ldapsource_bind_dn = uid=postfix, dc=your, dc=com + bind_dn = uid=postfix, dc=your, dc=com bind_pw ("") - The password for the distinguished name above. If you have to - use this, you probably want to make main.cf readable only by - the Postfix user. Example: - ldapsource_bind_pw = postfixpw + The password for the distinguished name above. If you have to + use this, you probably want to make the map configuration file + readable only by the Postfix user. When using the obselete + ldap:ldapsource syntax, with map parameters in main.cf, it is + not possible to securely store the bind password. This is + because main.cf needs to be world readable to allow local + accounts to submit mail via the sendmail command. Example: + bind_pw = postfixpw cache (IGNORED with a warning) cache_expiry (IGNORED with a warning) @@ -213,6 +219,76 @@ parameter below, "server_host", would be defined in main.cf as Don't use quotes in these variables; at least, not until the Postfix configuration routines understand how to deal with quoted strings. +For backward compatibility, these parameters can also be defined +in main.cf, prefixed with the name you've given the source in its +definition, and an underscore. For example, if the map is specified as +"ldap:ldapsource", the first parameter above, "server_host", would be +defined in main.cf as "ldapsource_server_host". + +LDAP SSL and STARTTLS +--------------------- + +If you're using the OpenLDAP libraries compiled with SSL support, +Postfix can connect to LDAP SSL servers and can issue the STARTTLS +command. The first form can be requested by using a LDAP URL in +server_host: + + server_host = ldaps://ldap.your.com:636 + +STARTTLS can be turned on with the start_tls command: + + start_tls = yes + +Both forms require LDAP protocol version 3, which has to be set +explicitly: + + version = 3 + +If any of the Postfix programs querying the map is configured in +master.cf to run chrooted, all the certificates and keys involved have +to be copied to the chroot jail. Of course, the private keys should +only be readable by the user "postfix". + +The following commands are relevant to LDAP SSL and STARTTLS: + + start_tls (no) + Whether or not to issue STARTTLS upon connection to + the server. Don't set this with LDAP SSL. + + tls_ca_cert_dir (No default; set either this or tls_ca_cert_file) + Directory containing, in separate individual files, + the X509 Certificate Authority certificates which + are to be recognized by the client in SSL/TLS con- + nections. + + tls_ca_cert_file (No default; set either this or tls_ca_cert_dir) + File containing the X509 Certificate Authority cer- + tificates which are to be recognized by the client + in SSL/TLS connections. This setting takes prece- + dence over tls_ca_cert_dir. + + tls_cert (No default; you must set this) + File containing client's X509 certificate to be + used by the client in SSL/TLS connections. + + tls_key (No default; you must set this) + File containing the private key corresponding to + the above tls_cert. + + tls_require_cert (no) + Whether or not to request server's X509 certificate + and check its validity when establishing SSL/TLS + connections. + + tls_random_file (No default) + Path of a file to obtain random bits from when + /dev/[u]random is not available, to be used by the + client in SSL/TLS connections. + + tls_cipher_suite (No default) + Cipher suite to use in SSL/TLS negotiations. + + EXAMPLES ======== @@ -220,11 +296,14 @@ ALIASES ------- Here's a basic example for using LDAP to look up aliases. Assume that in -main.cf, you have these configuration parameters defined: +main.cf, you have: + +alias_maps = hash:/etc/aliases, ldap:/etc/ldap-aliases.cf + +and in ldap:/etc/ldap-aliases.cf you have: -alias_maps = hash:/etc/aliases, ldap:ldapsource -ldapsource_server_host = ldap.my.com -ldapsource_search_base = dc=my, dc=com +server_host = ldap.my.com +search_base = dc=my, dc=com Upon receiving mail for a local address "ldapuser" that isn't found in the /etc/aliases database, Postfix will search the LDAP server listening @@ -321,7 +400,7 @@ NOTES AND THINGS TO THINK ABOUT Postfix can't know how to set the ownership for program or file delivery. Your query_filter should probably look something like this: - virtual_query_filter = (&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*")(maildrop="*:*")(maildrop="*/*")))) + query_filter = (&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*")(maildrop="*:*")(maildrop="*/*")))) - And for that matter, even for aliases, you may not want users able to specify their maildrops as programs, includes, etc. This might be @@ -330,7 +409,7 @@ NOTES AND THINGS TO THINK ABOUT the fun stuff only for directory entries owned by an administrative account: - local_query_filter = (&(mailacceptinggeneralid=%s)(|(!(maildrop="*|*")(maildrop="*:*")(maildrop="*/*"))(owner=cn=root, dc=your, dc=com))) + query_filter = (&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*")(maildrop="*:*")(maildrop="*/*"))(owner=cn=root, dc=your, dc=com))) So that if the object had a program as its maildrop and weren't owned by "cn=root" it wouldn't be returned as a valid local user. This will @@ -356,7 +435,7 @@ contents, please include the applicable bits of some directory entries. CREDITS ======= -Manuel Guesdon: Spotted a bug with the ldapsource_timeout attribute. +Manuel Guesdon: Spotted a bug with the timeout attribute. John Hensley: Multiple LDAP sources with more configurable attributes. Carsten Hoeger: Search scope handling. LaMont Jones: Domain restriction, URL and DN searches, multiple result @@ -369,5 +448,11 @@ Samuel Tardieu: Noticed that searches could include wildcards, prompting the work on RFC 2254 escaping in queries. Spotted a bug in binding. Sami Haahtinen: Referral chasing and v3 support. +Victor Duchovni: ldap_bind() timeout. With fixes from LaMont Jones: + OpenLDAP cache deprecation. Limits on recursion, expansion + and query results size. +Liviu Daia: Support for SSL/STARTTLS. Support for storing map definitions in + external files (ldap:/path/ldap.cf) need to securely store + passwords for plain auth. And of course Wietse. diff --git a/postfix/README_FILES/SMTPD_PROXY_README b/postfix/README_FILES/SMTPD_PROXY_README index 613ad27e9..3379a588b 100644 --- a/postfix/README_FILES/SMTPD_PROXY_README +++ b/postfix/README_FILES/SMTPD_PROXY_README @@ -1,9 +1,9 @@ -Purpose of the SMTPD pass-through proxy feature -=============================================== +Purpose of the SMTP-based before-queue proxy filter feature +=========================================================== Normally, Postfix receives mail, stores it in the mail queue and then delivers it. The Postfix SMTP server can be configured to -forward all incoming mail to an SMTP proxy server (for example, a +forward all incoming mail through a proxy filter (for example, a real-time SPAM filter) that inspects all mail BEFORE it is stored in the Postfix mail queue. @@ -11,10 +11,11 @@ in the Postfix mail queue. FILTER_README document, where all mail is inspected AFTER it is stored in the Postfix mail queue] -This feature is meant to be used as follows: - / smtp - Internet -> smtpd -> proxy -> smtpd -> cleanup -> queue -> local - Postfix Postfix \ virtual etc. +The SMTP-based before-queue proxy filter is meant to be used as follows: + + before / smtp + Internet -> smtpd -> queue -> smtpd -> cleanup -> queue -> local + Postfix filter Postfix \ virtual etc. For reference, this is the normal path through Postfix: @@ -23,20 +24,21 @@ For reference, this is the normal path through Postfix: Postfix \ virtual etc. For comparison, this is the FILTER_README approach with an SMTP-based -content filter: +after-queue content filter: / smtp Internet -> smtpd -> cleanup -> queue -> local Postfix ^ v \ virtual etc. smtpd smtp Postfix Postfix - \ / - filter <- + \ after / + queue <- + filter -The SMTP proxy server receives unfiltered mail from Postfix and -does one of the following: +The SMTP-based before-queue proxy filter receives unfiltered mail +from Postfix and does one of the following: -1 - Re-inject the mail back into Postfix, perhaps after changing - content. +1 - Re-inject the mail back into Postfix via SMTP, perhaps after + changing content. 2 - Reject the mail (by sending a suitable status code back to Postfix). Postfix passes the status back to the remote SMTP @@ -47,8 +49,8 @@ does one of the following: Limitations =========== -When used with a real-time SPAM filter, this approach allows Postfix -to reject mail before the SMTP mail transfer completes, so that +The SMTP-based before-queue proxy filter allows Postfix to reject +mail before the incoming SMTP mail transfer completes, so that Postfix does not have to send rejected mail back to the sender. Mail that is not accepted remains the responsibility of the client. @@ -57,7 +59,7 @@ to the existing content filter (see FILTER_README) which processes mail AFTER it is queued, because that gives you full control over how many filtering processes can be run in parallel. -The problem with real-time content filtering is that the remote +The problem with before-queue content filtering is that the remote SMTP client expects an SMTP reply within a deadline. As the system load increases, fewer and fewer CPU cycles remain available to answer within the deadline, and eventually you either have to stop @@ -69,15 +71,23 @@ triggers a Postfix header_checks FILTER action, or send the mail into Postfix via an alternative Postfix SMTP server that always turns on content filtering. -How the Postfix talks to the SMTP proxy -======================================= +How Postfix talks to the before-queue proxy filter +================================================== + +When passing mail to the SMTP-based before-queue filter, Postfix +generates its own EHLO, DATA and QUIT commands, and forwards +unmodified copies of the MAIL FROM and RCPT TO commands that the +Postfix SMTP server has approved. All commands are sent without +using ESMTP command pipelining. The SMTP proxy server should accept +the same MAIL FROM and RCPT TO command syntax as the Postfix SMTP +server. -When Postfix talks to the SMTP proxy server it generates its own -EHLO, DATA and QUIT commands, and forwards unmodified copies of -the MAIL FROM and RCPT TO commands that the Postfix SMTP server -has approved. All commands are sent without using ESMTP command -pipelining. The SMTP proxy server must accept the same MAIL FROM -and RCPT TO command syntax as the Postfix SMTP server. +The before-queue proxy filter is expected literally pass on the +SMTP commands that it receives from Postfix to an after-filter +Postfix SMTP server that listens on a non-standard port. When the +filter rejects content, it should send a negative response back to +Postfix, and it should abort any connection with the after-filter +Postfix SMTP server without completing the SMTP dialog. Configuration parameters ======================== @@ -86,26 +96,28 @@ Parameters that control proxying: smtpd_proxy_filter (syntax: host:port) - The host and TCP port of the SMTP proxy server. When no host - or host: is specified, localhost is assumed. + The host and TCP port of the before-queue proxy filter. When + no host or host: is specified, localhost is assumed. smtpd_proxy_timeout (default: 100s) - Timeout for connecting to the SMTP proxy server and for sending - and receiving data. All proxy errors are logged to the maillog - file, but the client sees "451 Error: queue file write error". + Timeout for connecting to the before-queue proxy filter and + for sending and receiving commands and data. All proxy errors + are logged to the maillog file. For privacy reasons, all the + remote SMTP client sees is "451 Error: queue file write error". smtpd_proxy_ehlo (default: $myhostname) - The hostname to use when sending an EHLO command to the SMTP - proxy server. + The hostname to use when sending an EHLO command to the + before-queue proxy filter. Testing the SMTP pass-through proxy feature =========================================== The following example sets up a null proxy, that is, the Postfix SMTP server gives the mail directly to another Postfix SMTP server -process. +process without intervening content filter. This useful only for +testing, of course. /etc/postfix/master.cf smtp inet n - n - - smtpd diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 217c2de86..5824fc4ff 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -22,6 +22,53 @@ snapshot release). Patches change the patchlevel and the release date. Snapshots change only the release date, unless they include the same bugfixes as a patch release. +Incompatible changes with Postfix snapshot 2.0.13-20030914 +========================================================== + +In header/body_checks actions, the OK action is being phased out, +and the DUNNO action is being phased in. Both actions still work +and do the same thing, but hopefully DUNNO causes less confusion. + +Major changes with Postfix snapshot 2.0.13-20030914 +=================================================== + +LDAP parameters can now be defined in external files. Specify the +LDAP maps in main.cf as + + ldap:/path/to/ldap.cf + +and write the LDAP parameters in /path/to/ldap.cf, without the +"ldapsource_" prefix. This makes it possible to securely store +bind passwords for plain auth outside of main.cf (which must be +world readable). The old syntax still works, for backwards +compatibility. By Liviu Daia, based on a suggestion by Victor +Duchovni and Lamont Jones. + +Support for LDAP URLs in the LDAP parameter "server_host", if +Postfix is linked against OpenLDAP. LDAP hosts, ports, and connection +protocols to be used as LDAP sources can be specified as a +blank-separated list of LDAP URLs in "server_host". As with +OpenLDAP, specifying a port in a LDAP URL overrides "server_port". +Examples: + + server_host = ldap://ldap.itd.umich.edu + server_host = ldaps://ldap.itd.umich.edu:636 + server_host = ldapi://%2Fsome%2Fpath + +The LDAP SSL scheme ldaps:// is available if OpenLDAP was compiled +with SSL support. New parameters "tls_ca_cert_dir", "tls_ca_cert_file", +"tls_cert", "tls_key", "tls_require_cert", "tls_random_file", +"tls_cipher_suite" control the certificates, source of random +numbers, and cipher suites used for SSL connections. See LDAP_README +for further information. By Liviu Daia. + +Support for STARTTLS command in LDAP, if Postfix is linked against +OpenLDAP and OpenLDAP was compiled with SSL support. STARTTLS is +controlled by the "start_tls" parameter. The above parameters for +certificates, source of random numbers, and cipher suites also +apply. See LDAP_README for further information. By Liviu Daia, +amended by Victor Duchovni. + Major changes with Postfix snapshot 2.0.13-20030715 =================================================== diff --git a/postfix/conf/canonical b/postfix/conf/canonical index d24d5732d..4cea8b406 100644 --- a/postfix/conf/canonical +++ b/postfix/conf/canonical @@ -98,49 +98,52 @@ # When a mail address localpart contains the optional recip- # ient delimiter (e.g., user+foo@domain), the lookup order # becomes: user+foo@domain, user@domain, user+foo, user, and -# @domain. An unmatched address extension (+foo) is propa- +# @domain. +# +# The propagate_unmatched_extensions parameter controls +# whether an unmatched address extension (+foo) is propa- # gated to the result of table lookup. # # REGULAR EXPRESSION TABLES -# This section describes how the table lookups change when +# This section describes how the table lookups change when # the table is given in the form of regular expressions. For -# a description of regular expression lookup table syntax, +# a description of regular expression lookup table syntax, # see regexp_table(5) or pcre_table(5). # -# Each pattern is a regular expression that is applied to +# Each pattern is a regular expression that is applied to # the entire address being looked up. Thus, user@domain mail -# addresses are not broken up into their user and @domain +# addresses are not broken up into their user and @domain # constituent parts, nor is user+foo broken up into user and # foo. # -# Patterns are applied in the order as specified in the -# table, until a pattern is found that matches the search +# Patterns are applied in the order as specified in the +# table, until a pattern is found that matches the search # string. # -# Results are the same as with indexed file lookups, with -# the additional feature that parenthesized substrings from +# Results are the same as with indexed file lookups, with +# the additional feature that parenthesized substrings from # the pattern can be interpolated as $1, $2 and so on. # # TCP-BASED TABLES -# This section describes how the table lookups change when +# This section describes how the table lookups change when # lookups are directed to a TCP-based server. For a descrip- -# tion of the TCP client/server lookup protocol, see +# tion of the TCP client/server lookup protocol, see # tcp_table(5). # # Each lookup operation uses the entire address once. Thus, -# user@domain mail addresses are not broken up into their +# user@domain mail addresses are not broken up into their # user and @domain constituent parts, nor is user+foo broken # up into user and foo. # # Results are the same as with indexed file lookups. # # BUGS -# The table format does not understand quoting conventions. +# The table format does not understand quoting conventions. # # CONFIGURATION PARAMETERS -# The following main.cf parameters are especially relevant -# to this topic. See the Postfix main.cf file for syntax -# details and for default values. Use the postfix reload +# The following main.cf parameters are especially relevant +# to this topic. See the Postfix main.cf file for syntax +# details and for default values. Use the postfix reload # command after a configuration change. # # canonical_maps @@ -154,28 +157,35 @@ # Address mapping lookup table for envelope and # header sender addresses. # +# propagate_unmatched_extensions +# A list of address rewriting or forwarding mecha- +# nisms that propagate an address extension from the +# original address to the result. Specify zero or +# more of canonical, virtual, alias, forward, or +# include. +# # Other parameters of interest: # # inet_interfaces -# The network interface addresses that this system +# The network interface addresses that this system # receives mail on. You need to stop and start Post- # fix when this parameter changes. # # masquerade_classes -# List of address classes subject to masquerading: -# zero or more of envelope_sender, envelope_recipi- +# List of address classes subject to masquerading: +# zero or more of envelope_sender, envelope_recipi- # ent, header_sender, header_recipient. # # masquerade_domains -# List of domains that hide their subdomain struc- +# List of domains that hide their subdomain struc- # ture. # # masquerade_exceptions -# List of user names that are not subject to address +# List of user names that are not subject to address # masquerading. # # mydestination -# List of domains that this mail system considers +# List of domains that this mail system considers # local. # # myorigin @@ -194,7 +204,7 @@ # tcp_table(5) TCP client/server table lookup protocol # # LICENSE -# The Secure Mailer license must be distributed with this +# The Secure Mailer license must be distributed with this # software. # # AUTHOR(S) diff --git a/postfix/conf/main.cf b/postfix/conf/main.cf index fd7a99836..957b18138 100644 --- a/postfix/conf/main.cf +++ b/postfix/conf/main.cf @@ -1,7 +1,7 @@ # Global Postfix configuration file. This file lists only a subset # of all 300+ parameters. See the sample-xxx.cf files for a full list. # -# The general format is lines with parameter = value pairs. Lines +# The general format of each line is: parameter = value. Lines # that begin with whitespace continue the previous line. A value can # contain references to other $names or ${name}s. # @@ -147,6 +147,12 @@ mail_owner = postfix # a name matches a lookup key (the right-hand side is ignored). # Continue long lines by starting the next line with whitespace. # +# DO NOT LIST RELAY DESTINATIONS IN MYDESTINATION. +# DO NOT LIST RELAY DESTINATIONS IN MYDESTINATION. +# DO NOT LIST RELAY DESTINATIONS IN MYDESTINATION. +# DO NOT LIST RELAY DESTINATIONS IN MYDESTINATION. +# DO NOT LIST RELAY DESTINATIONS IN MYDESTINATION. +# # See also below, section "REJECTING MAIL FOR UNKNOWN LOCAL USERS". # #mydestination = $myhostname, localhost.$mydomain diff --git a/postfix/conf/master.cf b/postfix/conf/master.cf index 141866760..c3b46d85a 100644 --- a/postfix/conf/master.cf +++ b/postfix/conf/master.cf @@ -56,6 +56,12 @@ # in the main.cf configuration file). See individual command man pages # for specific command-line options, if any. # +# General main.cf options can be overridden for specific services. +# To override one or more main.cf options, specify them as arguments +# below, preceding each option by "-o". There must be no whitespace +# in the option itself (separate multiple values for an option by +# commas). +# # In order to use the "uucp" message tranport below, set up entries # in the transport table. # diff --git a/postfix/conf/sample-auth.cf b/postfix/conf/sample-auth.cf index 5ab638e11..7d3943241 100644 --- a/postfix/conf/sample-auth.cf +++ b/postfix/conf/sample-auth.cf @@ -78,6 +78,25 @@ smtpd_sasl_security_options = noanonymous #smtpd_sasl_local_domain = $mydomain smtpd_sasl_local_domain = $myhostname +# The smtpd_sasl_exceptions_networks parameter controls what SMTP +# clients Postfix will not offer AUTH support. +# +# Some clients (Netscape 4 at least) have a bug that causes them to +# require a login and password whenever AUTH is offered, whether it's +# necessary or not. To work around this, specify, for example, +# $mynetworks to prevent Postfix from offering AUTH to local clients. +# +# Specify an explicit list of network/netmask patterns, where the +# mask specifies the number of bits in the network part of a host +# address. +# +# You can also specify the absolute pathname of a pattern file instead +# of listing the patterns here. Specify type:table for table-based lookups +# (the value on the table right-hand side is not used). +# +#smtpd_sasl_exceptions_networks = $mynetworks +smtpd_sasl_exceptions_networks = + # SMTP CLIENT CONTROLS # The smtp_sasl_auth_enable parameter controls whether authentication diff --git a/postfix/conf/sample-filter.cf b/postfix/conf/sample-filter.cf index 6424d8732..0f667ca7e 100644 --- a/postfix/conf/sample-filter.cf +++ b/postfix/conf/sample-filter.cf @@ -18,25 +18,27 @@ # REJECT [optional text...] # Reject the entire message. The optional text is sent to the # originator and is logged to the maillog file. -# OK Skip all further header patterns for this header line. -# IGNORE Silently discard the header line. +# DUNNO [optional text...] +# Skip all further header patterns for this header line. +# IGNORE [optional text...] +# Silently discard the header line. # WARN [optional text...] # Log the message header and the optional text. This is useful # for testing. When the pattern is good, change the WARN into a # REJECT or into a DISCARD. # HOLD [optional text...] # Place the message on the hold queue. Mail on hold can be -# inspected with the postcat command, and can be destroyed or -# taken off hold (i.e. delivered) with the postsuper command. -# The matched header is logged with the optional text. +# inspected with the postcat command, and can be destroyed or +# taken off hold (i.e. delivered) with the postsuper command. +# The matched header is logged with the optional text. # DISCARD [optional text...] # Claim successful delivery and silently discard the message. -# The matched header is logged with the optional text. +# The matched header is logged with the optional text. # FILTER transport:nexthop -# after the message is queued, the message is sent through -# a content filter. This requires different cleanup servers -# before and after the filter, with header/body checks turned -# off in the second cleanup server. More info about content +# After the message is queued, send the message through +# a content filter. This requires different cleanup servers +# before and after the filter, with header/body checks turned +# off in the second cleanup server. More info about content # filtering is in the Postfix FILTER_README file. This feature # overrides the main.cf content_filter setting. # REDIRECT user@domain @@ -60,38 +62,7 @@ header_checks = regexp:/etc/postfix/header_checks # For examples of pattern syntax see the sample-regexp-header.cf and # sample-pcre-header files. # -# When a pattern matches, what happens next depends on the associated -# action that is specified in the right-hand side of the table: -# -# REJECT [optional text...] -# Reject the entire message. The optional text is sent to the -# originator and is logged to the maillog file. -# OK Skip all further header patterns for this header line. -# IGNORE Silently discard the body line -# WARN [optional text...] -# Log the body line and the optional text. This is useful -# for testing. When the pattern is good, change the WARN into a -# REJECT or into a DISCARD. -# HOLD [optional text...] -# Place the message on the hold queue. Mail on hold can be -# inspected with the postcat command, and can be destroyed or -# taken off hold (i.e. delivered) with the postsuper command. -# The matched body line is logged with the optional text. -# DISCARD [optional text...] -# Claim successful delivery and silently discard the message. -# The matched body line is logged with the optional text. -# FILTER transport:nexthop -# after the message is queued, the message is sent through -# a content filter. This requires different cleanup servers -# before and after the filter, with header/body checks turned -# off in the second cleanup server. More info about content -# filtering is in the Postfix FILTER_README file. This feature -# overrides the main.cf content_filter setting. -# REDIRECT user@domain -# Send the message to the specified address instead of the -# intended recipient(s). This feature overrides the FILTER action. -# -# By default, the same patterns are applied as for header_checks. +# Actions on the table right-hand side are the same as with header_checks. # mime_header_checks = $header_checks @@ -107,33 +78,7 @@ mime_header_checks = $header_checks # When a pattern matches, what happens next depends on the associated # action that is specified in the right-hand side of the table: # -# REJECT [optional text...] -# Reject the entire message. The optional text is sent to the -# originator and is logged to the maillog file. -# OK Skip all further header patterns for this header line. -# IGNORE Silently discard the body line -# WARN [optional text...] -# Log the body line and the optional text. This is useful -# for testing. When the pattern is good, change the WARN into a -# REJECT or into a DISCARD. -# HOLD [optional text...] -# Place the message on the hold queue. Mail on hold can be -# inspected with the postcat command, and can be destroyed or -# taken off hold (i.e. delivered) with the postsuper command. -# The matched body line is logged with the optional text. -# DISCARD [optional text...] -# Claim successful delivery and silently discard the message. -# The matched body line is logged with the optional text. -# FILTER transport:nexthop -# after the message is queued, the message is sent through -# a content filter. This requires different cleanup servers -# before and after the filter, with header/body checks turned -# off in the second cleanup server. More info about content -# filtering is in the Postfix FILTER_README file. This feature -# overrides the main.cf content_filter setting. -# REDIRECT user@domain -# Send the message to the specified address instead of the -# intended recipient(s). This feature overrides the FILTER action. +# Actions on the table right-hand side are the same as with header_checks. # # By default, the same patterns are applied as for header_checks. # @@ -150,21 +95,7 @@ nested_header_checks = $header_checks # For examples of pattern syntax see the sample-regexp-body.cf and # sample-pcre-body.cf files. # -# When a pattern matches, what happens next depends on the associated -# action that is specified in the right-hand side of the table: -# -# REJECT the entire message is rejected. -# REJECT text.... The text is sent to the originator. -# IGNORE the body line is silently discarded. -# WARN the body line is logged (not rejected) with a warning message. -# WARN text... as above, and the text is logged, too. -# FILTER transport:nexthop -# after the message is queued, the message is sent through -# a content filter. This requires different cleanup servers -# before and after the filter, with header/body checks turned -# off in the second cleanup server. More info about content -# filtering is in the Postfix FILTER_README file. This feature -# overrides the main.cf content_filter setting. +# Actions on the table right-hand side are the same as with header_checks. # body_checks = regexp:/etc/postfix/body_checks diff --git a/postfix/conf/sample-ldap.cf b/postfix/conf/sample-ldap.cf index 2f8e56458..e1eb3d008 100644 --- a/postfix/conf/sample-ldap.cf +++ b/postfix/conf/sample-ldap.cf @@ -5,24 +5,28 @@ # parameters that control LDAP lookups. Source code for LDAP # lookup is available separately from http://www.postfix.org/ -# The ldap_timeout parameter specifies the timeout for LDAP database +# The timeout parameter specifies the timeout for LDAP database # lookups. # -#ldap_timeout = 10 +#timeout = 10 -# The ldap_search_base parameter specifies the LDAP database to search. +# The search_base parameter specifies the LDAP database to search. # -#ldap_search_base = +#search_base = -# The ldap_server_host parameter specifies the LDAP server hostname. +# The server_host parameter specifies the LDAP server hostname. # -#ldap_server_host = localhost +#server_host = localhost -# The ldap_server_port parameter specifies the LDAP server port number. +# The server_port parameter specifies the LDAP server port number. # -#ldap_server_port = 389 +#server_port = 389 -# The ldap_query_filter parameter specifies the filter used for queries. +# The version parameter specifies the LDAP protocol version to use. +# +#version = 2 + +# The query_filter parameter specifies the filter used for queries. # The replacement for "%s" is the address input into the map; e.g. # for alias maps, the "user" part (the RFC 2822 local-part) of # "user@domain.com" for To: addresses destined for local delivery @@ -31,69 +35,69 @@ # "%u" provides just the user portion of the input, and "%d" provides # just the hostname. # -#ldap_query_filter = (mailacceptinggeneralid=%s) +#query_filter = (mailacceptinggeneralid=%s) -# The ldap_result_filter parameter specifies the filter to be applied -# to the result attribute(s). See ldap_query_filter for valid expansions. +# The result_filter parameter specifies the filter to be applied +# to the result attribute(s). See query_filter for valid expansions. # -#ldap_result_filter = %s +#result_filter = %s -# The ldap_result_attribute parameter specifies the attribute returned by +# The result_attribute parameter specifies the attribute returned by # the search. # -#ldap_result_attribute = maildrop +#result_attribute = maildrop -# The ldap_special_result_attribute lists the attribute(s) of an +# The special_result_attribute lists the attribute(s) of an # entry which contain links, either ldap url's or distinguished names. # The entries referenced by these links are (recursively) treated as if # they were contained in the referencing entity. # -#ldap_special_result_attribute = +#special_result_attribute = -# The ldap_scope parameter specifies the LDAP search scope: sub, base, or one. +# The scope parameter specifies the LDAP search scope: sub, base, or one. # -#ldap_scope = sub +#scope = sub -# The ldap_bind parameter specifies whether or not to bind to the server. +# The bind parameter specifies whether or not to bind to the server. # LDAP v3 implementations don't require it, which saves some overhead. # -#ldap_bind = yes +#bind = yes -# The ldap_bind_dn parameter specifies what distinguished name to use +# The bind_dn parameter specifies what distinguished name to use # when binding. # -#ldap_bind_dn = +#bind_dn = -# The ldap_bind_pw parameter specifies the password to use. +# The bind_pw parameter specifies the password to use. # -#ldap_bind_pw = +#bind_pw = -#ldap_cache (IGNORED with a warning) -#ldap_cache_expiry (IGNORED with a warning) -#ldap_cache_size (IGNORED with a warning) +#cache (IGNORED with a warning) +#cache_expiry (IGNORED with a warning) +#cache_size (IGNORED with a warning) # # The above parameters are NO LONGER SUPPORTED by Postfix. # Cache support has been dropped from OpenLDAP as of release 2.1.13. -# The ldap_recursion_limit parameter specifies a limit on the nesting +# The recursion_limit parameter specifies a limit on the nesting # depth of DN and URL special result attribute evaluation. The limit # must be a non-zero positive number. The default value is 1000. # -#ldap_recursion_limit = 1000 +#recursion_limit = 1000 -# The ldap_expansion_limit parameter specifies a limit on the total +# The expansion_limit parameter specifies a limit on the total # number of result elements returned (as a comma separated list) by a lookup # against the map. A setting of 0 disables the limit. Lookups fail with a # temporary error if the limit is exceeded. Setting the limit to 1 ensures # that lookups do not return multiple values. The default value is 0. # -#ldap_expansion_limit = 0 +#expansion_limit = 0 -# The ldap_size_limit parameter specifies a limit on the number of LDAP +# The size_limit parameter specifies a limit on the number of LDAP # entries returned by any single LDAP query performed as part of the # lookup. A setting of 0 disables the limit. Expansion of DN and URL # references involves nested LDAP queries, each of which is separately -# subjected to this limit. The default value is $ldap_expansion_limit. +# subjected to this limit. The default value is $expansion_limit. # # Note: even a single LDAP entry can generate multiple lookup results, via # multiple result attributes and/or multi-valued result attributes. @@ -101,18 +105,65 @@ # not the final multiplicity of the lookup result. It is analogous to the # "-z" option of "ldapsearch". # -#ldap_size_limit = $ldap_expansion_limit +#size_limit = 0 -# The ldap_deference parameter specifies how to handle LDAP aliases. See the +# The deference parameter specifies how to handle LDAP aliases. See the # ldap_open(3) man page. # -#ldap_dereference = 0 +#dereference = 0 -# The ldap_domain parameter limits the LDAP searches to just things in +# The domain parameter limits the LDAP searches to just things in # (exactly) the specified list of domains. # -#ldap_domain = +#domain = + +# The start_tls parameter specifies whether or not to issue +# STARTTLS upon connection to the server. STARTTLS requires LDAP +# protocol version 3. +# +#start_tls = no + +# The tls_ca_cert_dir parameter specifies a directory containing, +# in separate individual files, the X509 Certificate Authority +# certificates which are to be recognized by the client in SSL/TLS +# connections. +# +#tls_ca_cert_dir = + +# The tls_ca_cert_file parameter specifies a file containing the +# X509 Certificate Authority certificates which are to be recognized by +# the client in SSL/TLS connections. This setting takes precedence over +# tls_ca_cert_dir. +# +#tls_ca_cert_file = + +# The tls_cert parameter specifies the client's X509 certificate to +# be used in SSL/TLS connections. +# +#tls_cert = + +# The tls_key parameter specifies the private key corresponding to +# the above tls_cert. +# +#tls_key = + +# The tls_require_cert parameter specifies whether or not to +# request server's X509 certificate and check its validity when +# establishing SSL/TLS connections. +# +#tls_require_cert = no + +# The tls_random_file parameter specifies a file to obtain random +# bits from when /dev/[u]random is not available, to be used in SSL/TLS +# connections. +# +#tls_random_file = + +# The tls_cipher_suite parameter specifies the cipher suite to be +# use in SSL/TLS negotiations. +# +#tls_cipher_suite = -# The ldap_debuglevel parameter sets the debug level in the OpenLDAP +# The debuglevel parameter sets the debug level in the OpenLDAP # libraries. -#ldap_debuglevel = 0 +#debuglevel = 0 diff --git a/postfix/conf/sample-misc.cf b/postfix/conf/sample-misc.cf index ce7698da6..4d010158e 100644 --- a/postfix/conf/sample-misc.cf +++ b/postfix/conf/sample-misc.cf @@ -88,8 +88,10 @@ enable_original_recipient = yes # # - TZ is needed for sane time keeping on most SYSV-ish systems # -# Specify a list of names separated by whitespace or comma. +# Specify a list of names and/or name=value pairs, separated by +# whitespace or comma. # +#export_environment = TZ PATH=/bin:/usr/bin export_environment = TZ # The hash_queue_depth parameter specifies the number of subdirectory @@ -133,7 +135,8 @@ hopcount_limit = 50 # with an X-windows debugger. # - MAIL_CONFIG is needed to make "postfix -c" work. # -# Specify a list of names separated by whitespace or comma. +# Specify a list of names and/or name=value pairs, separated by +# whitespace or comma. # #import_environment = MAIL_CONFIG TZ XAUTHORITY DISPLAY HOME PURIFYOPTIONS import_environment = MAIL_CONFIG MAIL_DEBUG MAIL_LOGTAG TZ XAUTHORITY DISPLAY diff --git a/postfix/conf/sample-smtpd.cf b/postfix/conf/sample-smtpd.cf index bb45d9587..a3fdb46b0 100644 --- a/postfix/conf/sample-smtpd.cf +++ b/postfix/conf/sample-smtpd.cf @@ -360,6 +360,10 @@ smtpd_helo_required = no # see access(5) for possible lookup results. # check_policy_service transport:endpoint: delegate the decision to # an external policy server. See SMTPD_POLICY_README for details. +# reject_rhsbl_helo domain.tld: reject if the helo argument is listed +# in an A record under domain.tld. +# Append e.g., "=127.0.0.2" to the RBL domain name to select a specific +# address record when an RBL server provides multi-valued results. # reject: reject the request. Place this at the end of a restriction. # permit: permit the request. Place this at the end of a restriction. # warn_if_reject: next restriction logs a warning instead of rejecting. diff --git a/postfix/conf/virtual b/postfix/conf/virtual index 17493baa3..9baed6d5d 100644 --- a/postfix/conf/virtual +++ b/postfix/conf/virtual @@ -102,24 +102,27 @@ # When a mail address localpart contains the optional recip- # ient delimiter (e.g., user+foo@domain), the lookup order # becomes: user+foo@domain, user@domain, user+foo, user, and -# @domain. An unmatched address extension (+foo) is propa- +# @domain. +# +# The propagate_unmatched_extensions parameter controls +# whether an unmatched address extension (+foo) is propa- # gated to the result of table lookup. # # VIRTUAL ALIAS DOMAINS -# Besides virtual aliases, the virtual alias table can also +# Besides virtual aliases, the virtual alias table can also # be used to implement virtual alias domains. With a virtual -# alias domain, all recipient addresses are aliased to +# alias domain, all recipient addresses are aliased to # addresses in other domains. # # Virtual alias domains are not to be confused with the vir- # tual mailbox domains that are implemented with the Postfix # virtual(8) mail delivery agent. With virtual mailbox -# domains, each recipient address can have its own mailbox. +# domains, each recipient address can have its own mailbox. # -# With a virtual alias domain, the virtual domain has its -# own user name space. Local (i.e. non-virtual) usernames -# are not visible in a virtual alias domain. In particular, -# local aliases(5) and local mailing lists are not visible +# With a virtual alias domain, the virtual domain has its +# own user name space. Local (i.e. non-virtual) usernames +# are not visible in a virtual alias domain. In particular, +# local aliases(5) and local mailing lists are not visible # as localname@virtual-alias.domain. # # Support for a virtual alias domain looks like: @@ -127,7 +130,7 @@ # /etc/postfix/main.cf: # virtual_alias_maps = hash:/etc/postfix/virtual # -# Note: some systems use dbm databases instead of hash. +# Note: some systems use dbm databases instead of hash. # See the output from postconf -m for available database # types. # @@ -137,87 +140,94 @@ # user1@virtual-alias.domain address1 # user2@virtual-alias.domain address2, address3 # -# The virtual-alias.domain anything entry is required for a +# The virtual-alias.domain anything entry is required for a # virtual alias domain. Without this entry, mail is rejected -# with "relay access denied", or bounces with "mail loops +# with "relay access denied", or bounces with "mail loops # back to myself". # -# Do not specify virtual alias domain names in the main.cf +# Do not specify virtual alias domain names in the main.cf # mydestination or relay_domains configuration parameters. # -# With a virtual alias domain, the Postfix SMTP server -# accepts mail for known-user@virtual-alias.domain, and -# rejects mail for unknown-user@virtual-alias.domain as +# With a virtual alias domain, the Postfix SMTP server +# accepts mail for known-user@virtual-alias.domain, and +# rejects mail for unknown-user@virtual-alias.domain as # undeliverable. # -# Instead of specifying the virtual alias domain name via -# the virtual_alias_maps table, you may also specify it via +# Instead of specifying the virtual alias domain name via +# the virtual_alias_maps table, you may also specify it via # the main.cf virtual_alias_domains configuration parameter. -# This latter parameter uses the same syntax as the main.cf +# This latter parameter uses the same syntax as the main.cf # mydestination configuration parameter. # # REGULAR EXPRESSION TABLES -# This section describes how the table lookups change when +# This section describes how the table lookups change when # the table is given in the form of regular expressions. For -# a description of regular expression lookup table syntax, +# a description of regular expression lookup table syntax, # see regexp_table(5) or pcre_table(5). # -# Each pattern is a regular expression that is applied to +# Each pattern is a regular expression that is applied to # the entire address being looked up. Thus, user@domain mail -# addresses are not broken up into their user and @domain +# addresses are not broken up into their user and @domain # constituent parts, nor is user+foo broken up into user and # foo. # -# Patterns are applied in the order as specified in the -# table, until a pattern is found that matches the search +# Patterns are applied in the order as specified in the +# table, until a pattern is found that matches the search # string. # -# Results are the same as with indexed file lookups, with -# the additional feature that parenthesized substrings from +# Results are the same as with indexed file lookups, with +# the additional feature that parenthesized substrings from # the pattern can be interpolated as $1, $2 and so on. # # TCP-BASED TABLES -# This section describes how the table lookups change when +# This section describes how the table lookups change when # lookups are directed to a TCP-based server. For a descrip- -# tion of the TCP client/server lookup protocol, see +# tion of the TCP client/server lookup protocol, see # tcp_table(5). # # Each lookup operation uses the entire address once. Thus, -# user@domain mail addresses are not broken up into their +# user@domain mail addresses are not broken up into their # user and @domain constituent parts, nor is user+foo broken # up into user and foo. # # Results are the same as with indexed file lookups. # # BUGS -# The table format does not understand quoting conventions. +# The table format does not understand quoting conventions. # # CONFIGURATION PARAMETERS -# The following main.cf parameters are especially relevant -# to this topic. See the Postfix main.cf file for syntax -# details and for default values. Use the postfix reload +# The following main.cf parameters are especially relevant +# to this topic. See the Postfix main.cf file for syntax +# details and for default values. Use the postfix reload # command after a configuration change. # # virtual_alias_maps # List of virtual aliasing tables. # # virtual_alias_domains -# List of virtual alias domains. This uses the same +# List of virtual alias domains. This uses the same # syntax as the mydestination parameter. # +# propagate_unmatched_extensions +# A list of address rewriting or forwarding mecha- +# nisms that propagate an address extension from the +# original address to the result. Specify zero or +# more of canonical, virtual, alias, forward, or +# include. +# # Other parameters of interest: # # inet_interfaces -# The network interface addresses that this system +# The network interface addresses that this system # receives mail on. You need to stop and start Post- # fix when this parameter changes. # # mydestination -# List of domains that this mail system considers +# List of domains that this mail system considers # local. # # myorigin -# The domain that is appended to any address that +# The domain that is appended to any address that # does not have a domain. # # owner_request_special @@ -232,7 +242,7 @@ # tcp_table(5) TCP client/server table lookup protocol # # LICENSE -# The Secure Mailer license must be distributed with this +# The Secure Mailer license must be distributed with this # software. # # AUTHOR(S) diff --git a/postfix/examples/smtpd-policy/smtpd-policy.pl b/postfix/examples/smtpd-policy/smtpd-policy.pl index 1b9f9f22f..b42cfc3b0 100755 --- a/postfix/examples/smtpd-policy/smtpd-policy.pl +++ b/postfix/examples/smtpd-policy/smtpd-policy.pl @@ -65,6 +65,9 @@ use Sys::Syslog qw(:DEFAULT setlogsock); # or /var/tmp. DO NOT create the greylist database in a file system # that can run out of space. # +# In case of database corruption, this script saves the database as +# $database_name.time(), so that the mail system does not get stuck. +# $database_name="/var/mta/smtpd-policy.db"; $greylist_delay=3600; @@ -147,7 +150,8 @@ sub open_database { # # Read database. Use a shared lock to avoid reading the database -# while it is being changed. +# while it is being changed. XXX There should be a way to synchronize +# our cache from the on-file database before looking up the key. # sub read_database { my($key) = @_; @@ -155,6 +159,7 @@ sub read_database { flock DATABASE_HANDLE, LOCK_SH || fatal_exit "Can't get shared lock on %s: $!", $database_name; + # XXX Synchronize our cache from the on-disk copy before lookup. $value = $db_hash{$key}; syslog $syslog_priority, "lookup %s: %s", $key, $value if $verbose; flock DATABASE_HANDLE, LOCK_UN || @@ -164,7 +169,9 @@ sub read_database { # # Update database. Use an exclusive lock to avoid collisions with -# other updaters, and to avoid surprises in database readers. +# other updaters, and to avoid surprises in database readers. XXX +# There should be a way to synchronize our cache from the on-file +# database before updating the database. # sub update_database { my($key, $value) = @_; @@ -172,6 +179,7 @@ sub update_database { syslog $syslog_priority, "store %s: %s", $key, $value if $verbose; flock DATABASE_HANDLE, LOCK_EX || fatal_exit "Can't exclusively lock %s: $!", $database_name; + # XXX Synchronize our cache from the on-disk copy before update. $db_hash{$key} = $value; $database_obj->sync() && fatal_exit "Can't update %s: $!", $database_name; @@ -179,6 +187,21 @@ sub update_database { fatal_exit "Can't unlock %s: $!", $database_name; } +# +# Signal 11 means that we have some kind of database corruption (yes +# Berkeley DB should handle this better). Move the corrupted database +# out of the way, and start with a new database. +# +sub sigsegv_handler { + my $backup = $database_name . time(); + + rename $database_name, $backup || + fatal_exit "Can't save %s as %s: $!", $database_name, $backup; + fatal_exit "Caught signal 11; the corrupted database is saved as $backup"; +} + +$SIG{'SEGV'} = 'sigsegv_handler'; + # # This process runs as a daemon, so it can't log to a terminal. Use # syslog so that people can actually see our messages. diff --git a/postfix/html/canonical.5.html b/postfix/html/canonical.5.html index a09bf0683..b767e0fcf 100644 --- a/postfix/html/canonical.5.html +++ b/postfix/html/canonical.5.html @@ -1,4 +1,4 @@ -
+  
 CANONICAL(5)                                         CANONICAL(5)
 
 NAME
@@ -99,49 +99,52 @@ CANONICAL(5)                                         CANONICAL(5)
        When a mail address localpart contains the optional recip-
        ient delimiter (e.g., user+foo@domain), the  lookup  order
        becomes: user+foo@domain, user@domain, user+foo, user, and
-       @domain.  An unmatched address extension (+foo) is  propa-
+       @domain.
+
+       The  propagate_unmatched_extensions   parameter   controls
+       whether  an  unmatched  address extension (+foo) is propa-
        gated to the result of table lookup.
 
 REGULAR EXPRESSION TABLES
-       This  section  describes how the table lookups change when
+       This section describes how the table lookups  change  when
        the table is given in the form of regular expressions. For
-       a  description  of regular expression lookup table syntax,
+       a description of regular expression lookup  table  syntax,
        see regexp_table(5) or pcre_table(5).
 
-       Each pattern is a regular expression that  is  applied  to
+       Each  pattern  is  a regular expression that is applied to
        the entire address being looked up. Thus, user@domain mail
-       addresses are not broken up into their  user  and  @domain
+       addresses  are  not  broken up into their user and @domain
        constituent parts, nor is user+foo broken up into user and
        foo.
 
-       Patterns are applied in the  order  as  specified  in  the
-       table,  until  a  pattern is found that matches the search
+       Patterns  are  applied  in  the  order as specified in the
+       table, until a pattern is found that  matches  the  search
        string.
 
-       Results are the same as with indexed  file  lookups,  with
-       the  additional feature that parenthesized substrings from
+       Results  are  the  same as with indexed file lookups, with
+       the additional feature that parenthesized substrings  from
        the pattern can be interpolated as $1, $2 and so on.
 
 TCP-BASED TABLES
-       This section describes how the table lookups  change  when
+       This  section  describes how the table lookups change when
        lookups are directed to a TCP-based server. For a descrip-
-       tion  of  the  TCP  client/server  lookup  protocol,   see
+       tion   of  the  TCP  client/server  lookup  protocol,  see
        tcp_table(5).
 
        Each lookup operation uses the entire address once.  Thus,
-       user@domain mail addresses are not broken  up  into  their
+       user@domain  mail  addresses  are not broken up into their
        user and @domain constituent parts, nor is user+foo broken
        up into user and foo.
 
        Results are the same as with indexed file lookups.
 
 BUGS
-       The table format does not understand quoting  conventions.
+       The  table format does not understand quoting conventions.
 
 CONFIGURATION PARAMETERS
-       The  following  main.cf parameters are especially relevant
-       to this topic. See the Postfix  main.cf  file  for  syntax
-       details  and  for  default  values. Use the postfix reload
+       The following main.cf parameters are  especially  relevant
+       to  this  topic.  See  the Postfix main.cf file for syntax
+       details and for default values.  Use  the  postfix  reload
        command after a configuration change.
 
        canonical_maps
@@ -155,28 +158,35 @@ CANONICAL(5)                                         CANONICAL(5)
               Address  mapping  lookup  table  for  envelope  and
               header sender addresses.
 
+       propagate_unmatched_extensions
+              A  list  of  address rewriting or forwarding mecha-
+              nisms that propagate an address extension from  the
+              original  address  to  the result.  Specify zero or
+              more of  canonical,  virtual,  alias,  forward,  or
+              include.
+
        Other parameters of interest:
 
        inet_interfaces
-              The network interface addresses  that  this  system
+              The  network  interface  addresses that this system
               receives mail on.  You need to stop and start Post-
               fix when this parameter changes.
 
        masquerade_classes
-              List of address classes  subject  to  masquerading:
-              zero  or  more of envelope_sender, envelope_recipi-
+              List  of  address  classes subject to masquerading:
+              zero or more of  envelope_sender,  envelope_recipi-
               ent, header_sender, header_recipient.
 
        masquerade_domains
-              List of domains that hide  their  subdomain  struc-
+              List  of  domains  that hide their subdomain struc-
               ture.
 
        masquerade_exceptions
-              List  of user names that are not subject to address
+              List of user names that are not subject to  address
               masquerading.
 
        mydestination
-              List of domains that  this  mail  system  considers
+              List  of  domains  that  this mail system considers
               local.
 
        myorigin
@@ -195,7 +205,7 @@ CANONICAL(5)                                         CANONICAL(5)
        tcp_table(5) TCP client/server table lookup protocol
 
 LICENSE
-       The  Secure  Mailer  license must be distributed with this
+       The Secure Mailer license must be  distributed  with  this
        software.
 
 AUTHOR(S)
diff --git a/postfix/html/cleanup.8.html b/postfix/html/cleanup.8.html
index 10ec2edd7..c283ca901 100644
--- a/postfix/html/cleanup.8.html
+++ b/postfix/html/cleanup.8.html
@@ -1,4 +1,4 @@
-    
+  
 CLEANUP(8)                                             CLEANUP(8)
 
 NAME
@@ -200,6 +200,13 @@ CLEANUP(8)                                             CLEANUP(8)
               List of user names that are not subject to  address
               masquerading.
 
+       propagate_unmatched_extensions
+              A  list  of  address rewriting or forwarding mecha-
+              nisms that propagate an address extension from  the
+              original  address  to  the result.  Specify zero or
+              more of  canonical,  virtual,  alias,  forward,  or
+              include.
+
        virtual_alias_maps
               Address mapping lookup table for envelope recipient
               addresses.
diff --git a/postfix/html/faq.html b/postfix/html/faq.html
index 17e7a3133..1f593d55f 100644
--- a/postfix/html/faq.html
+++ b/postfix/html/faq.html
@@ -1441,7 +1441,20 @@ the address does resolve to a name.
 

You run the Postfix SMTP server inside a chroot jail for -extra security, but some configuration files are missing. In order +extra security, but some configuration files are missing or have +incorrect information. The command "postfix check" will report +what files may have incorrect information. For example: + +

+
+warning: /var/spool/postfix/etc/resolv.conf and /etc/resolv.conf differ
+warning: /var/spool/postfix/etc/localtime and /etc/localtime differ
+
+
+ +

+ +In order to run inside a chroot jail, the Postfix SMTP client and server need copies of system configuration files inside the Postfix queue directory. The exact list of files is very system dependent, but @@ -1776,7 +1789,8 @@ for the /etc/resolv.conf file. Check out your Postfix master.cf file. If the SMTP client runs chrooted, then it needs a bunch of files inside the Postfix queue directory. Examples are in the source distribution in the -examples subdirectory. +examples subdirectory. See also the other FAQ entry on +name service trouble. diff --git a/postfix/html/lmtp.8.html b/postfix/html/lmtp.8.html index 1f9342a08..1d368f761 100644 --- a/postfix/html/lmtp.8.html +++ b/postfix/html/lmtp.8.html @@ -1,4 +1,4 @@ -

+  
 LMTP(8)                                                   LMTP(8)
 
 NAME
@@ -37,7 +37,7 @@ LMTP(8)                                                   LMTP(8)
               ified local or remote host. If no  port  is  speci-
               fied,  connect  to the port defined as lmtp in ser-
               vices(4).   If  no  such  service  is  found,   the
-              lmtp_tcp_port   configuration   parameter  (default
+              lmtp_tcp_port   configuration   parameter  (default
               value of 24) will be used.
 
               The  LMTP  client  does  not   perform   MX   (mail
@@ -67,58 +67,58 @@ LMTP(8)                                                   LMTP(8)
        rupted message files are marked so that the queue  manager
        can move them to the corrupt queue for further inspection.
 
-       Depending on the setting of the notify_classes  parameter,
+       Depending on the setting of the notify_classes  parameter,
        the  postmaster is notified of bounces, protocol problems,
        and of other trouble.
 
 BUGS
-CONFIGURATION PARAMETERS
+CONFIGURATION PARAMETERS
        The following main.cf parameters are  especially  relevant
        to  this  program. See the Postfix main.cf file for syntax
-       details and for default values.  Use  the  postfix  reload
+       details and for default values.  Use  the  postfix  reload
        command after a configuration change.
 
 Miscellaneous
-       debug_peer_level
+       debug_peer_level
               Verbose  logging  level  increment  for  hosts that
-              match a pattern in the debug_peer_list parameter.
+              match a pattern in the debug_peer_list parameter.
 
-       debug_peer_list
+       debug_peer_list
               List of domain or network patterns. When  a  remote
               host  matches  a pattern, increase the verbose log-
               ging  level  by  the  amount   specified   in   the
-              debug_peer_level parameter.
+              debug_peer_level parameter.
 
-       error_notice_recipient
+       error_notice_recipient
               Recipient    of   protocol/policy/resource/software
               error notices.
 
-       notify_classes
+       notify_classes
               When this parameter includes  the  protocol  class,
               send  mail  to  the  postmaster with transcripts of
               LMTP sessions with protocol errors.
 
-       lmtp_skip_quit_response
+       lmtp_skip_quit_response
               Do not wait for the server response  after  sending
               QUIT.
 
-       lmtp_tcp_port
+       lmtp_tcp_port
               The  TCP  port to be used when connecting to a LMTP
               server.  Used as backup if the lmtp service is  not
               found in services(4).
 
-Authentication controls
-       lmtp_sasl_auth_enable
+Authentication controls
+       lmtp_sasl_auth_enable
               Enable  per-session  authentication as per RFC 2554
               (SASL).  By default, Postfix is built without  SASL
               support.
 
-       lmtp_sasl_password_maps
+       lmtp_sasl_password_maps
               Lookup tables with per-host or domain name:password
               entries.  No entry for a host means no  attempt  to
               authenticate.
 
-       lmtp_sasl_security_options
+       lmtp_sasl_security_options
               Zero or more of the following.
 
               noplaintext
@@ -136,8 +136,8 @@ LMTP(8)                                                   LMTP(8)
               noanonymous
                      Disallow anonymous logins.
 
-Resource controls
-       lmtp_cache_connection
+Resource controls
+       lmtp_cache_connection
               Should  we cache the connection to the LMTP server?
               The effectiveness of  cached  connections  will  be
               determined  by  the  number of LMTP servers in use,
@@ -147,14 +147,14 @@ LMTP(8)                                                   LMTP(8)
 
               o      The LMTP client idle time limit is  reached.
                      This  limit  is  specified  with the Postfix
-                     max_idle configuration parameter.
+                     max_idle configuration parameter.
 
               o      A delivery  request  specifies  a  different
                      destination than the one currently cached.
 
               o      The  per-process  limit  on  the  number  of
                      delivery requests is reached.  This limit is
-                     specified  with the Postfix max_use configu-
+                     specified  with the Postfix max_use configu-
                      ration parameter.
 
               o      Upon the onset of another delivery  request,
@@ -162,20 +162,20 @@ LMTP(8)                                                   LMTP(8)
                      session does not respond to  the  RSET  com-
                      mand.
 
-       transport_destination_concurrency_limit
+       transport_destination_concurrency_limit
               Limit the number of parallel deliveries to the same
               destination  via  this  mail  delivery   transport.
               transport  is  the name of the service as specified
               in the master.cf file.  The default limit is  taken
-              from    the   default_destination_concurrency_limit
+              from    the   default_destination_concurrency_limit
               parameter.
 
-       transport_destination_recipient_limit
+       transport_destination_recipient_limit
               Limit the number of recipients per message delivery
               via  this mail delivery transport. transport is the
               name of the service as specified in  the  master.cf
               file.    The   default  limit  is  taken  from  the
-              default_destination_recipient_limit parameter.
+              default_destination_recipient_limit parameter.
 
               This parameter  becomes  significant  if  the  LMTP
               client  is  used  for  local  delivery.   Some LMTP
@@ -191,51 +191,51 @@ LMTP(8)                                                   LMTP(8)
               of  recipients.   Exercise  care  when setting this
               parameter.
 
-Timeout controls
+Timeout controls
        The default time unit is seconds; an  explicit  time  unit
        can  be  specified by appending a one-letter suffix to the
        value: s (seconds), m (minutes), h (hours), d (days) or  w
        (weeks).
 
-       lmtp_connect_timeout
+       lmtp_connect_timeout
               Timeout  for  opening  a  connection  to  the  LMTP
               server.  If no connection can be  made  within  the
               deadline, the message is deferred.
 
-       lmtp_lhlo_timeout
+       lmtp_lhlo_timeout
               Timeout  for  sending  the  LHLO  command,  and for
               receiving the server response.
 
-       lmtp_mail_timeout
-              Timeout for sending the MAIL FROM command, and  for
+       lmtp_mail_timeout
+              Timeout for sending the MAIL FROM command, and  for
               receiving the server response.
 
-       lmtp_rcpt_timeout
-              Timeout  for  sending  the RCPT TO command, and for
+       lmtp_rcpt_timeout
+              Timeout  for  sending  the RCPT TO command, and for
               receiving the server response.
 
-       lmtp_data_init_timeout
+       lmtp_data_init_timeout
               Timeout for  sending  the  DATA  command,  and  for
               receiving the server response.
 
-       lmtp_data_xfer_timeout
+       lmtp_data_xfer_timeout
               Timeout for sending the message content.
 
-       lmtp_data_done_timeout
+       lmtp_data_done_timeout
               Timeout  for  sending  the  "."  command,  and  for
               receiving the server response. When no response  is
               received,  a warning is logged that the mail may be
               delivered multiple times.
 
-       lmtp_rset_timeout
+       lmtp_rset_timeout
               Timeout for  sending  the  RSET  command,  and  for
               receiving the server response.
 
-       lmtp_quit_timeout
+       lmtp_quit_timeout
               Timeout  for  sending  the  QUIT  command,  and for
               receiving the server response.
 
-SEE ALSO
+SEE ALSO
        bounce(8) non-delivery status reports
        local(8) local mail delivery
        master(8) process manager
diff --git a/postfix/html/local.8.html b/postfix/html/local.8.html
index ab2f45f0e..67fab1c90 100644
--- a/postfix/html/local.8.html
+++ b/postfix/html/local.8.html
@@ -1,4 +1,4 @@
-    
+  
 LOCAL(8)                                                 LOCAL(8)
 
 NAME
@@ -31,20 +31,20 @@ LOCAL(8)                                                 LOCAL(8)
 
        The  system  administrator can specify a comma/space sepa-
        rated list of  ~/.forward  like  files  through  the  for-
-       ward_path  configuration  parameter.  Upon  delivery,  the
+       ward_path  configuration  parameter.  Upon  delivery,  the
        local delivery agent tries each pathname in the list until
-       a file is found.  The forward_path parameter is subject to
+       a file is found.  The forward_path parameter is subject to
        interpolation of $user (recipient username), $home (recip-
        ient home directory), $shell (recipient shell), $recipient
        (complete  recipient   address),   $extension   (recipient
        address  extension),  $domain  (recipient  domain),  local
-       (entire recipient address localpart) and $recipient_delim-
+       (entire recipient address localpart) and $recipient_delim-
        iter.  The  forms  ${name?value}  and ${name:value} expand
        conditionally to value when $name  is  (is  not)  defined.
        Characters  that  may have special meaning to the shell or
        file system are replaced  by  underscores.   The  list  of
-       acceptable characters is specified with the forward_expan-
-       sion_filter configuration parameter.
+       acceptable characters is specified with the forward_expan-
+       sion_filter configuration parameter.
 
        An alias or ~/.forward file may list  any  combination  of
        external   commands,  destination  file  names,  :include:
@@ -61,11 +61,11 @@ LOCAL(8)                                                 LOCAL(8)
        In order to prevent the mail system from using  up  unrea-
        sonable   amounts  of  memory,  input  records  read  from
        :include: or from ~/.forward  files  are  broken  up  into
-       chunks of length line_length_limit.
+       chunks of length line_length_limit.
 
        While  expanding aliases, ~/.forward files, and so on, the
        program attempts to avoid duplicate deliveries. The dupli-
-       cate_filter_limit  configuration parameter limits the num-
+       cate_filter_limit  configuration parameter limits the num-
        ber of remembered recipients.
 
 MAIL FORWARDING
@@ -74,51 +74,51 @@ LOCAL(8)                                                 LOCAL(8)
        rate on-file delivery status record.
 
        In order to stop mail forwarding loops early, the software
-       adds  an  optional  Delivered-To: header with the envelope
-       recipient address. If mail arrives for a recipient that is
-       already  listed  in a Delivered-To: header, the message is
-       bounced.
+       adds an optional Delivered-To: header with the final enve-
+       lope recipient address. If mail arrives  for  a  recipient
+       that is already listed in a Delivered-To: header, the mes-
+       sage is bounced.
 
 MAILBOX DELIVERY
        The default per-user mailbox is a file in  the  UNIX  mail
        spool  directory (/var/mail/user or /var/spool/mail/user);
-       the location can be specified with  the  mail_spool_direc-
+       the location can be specified with  the  mail_spool_direc-
        tory  configuration  parameter. Specify a name ending in /
        for qmail-compatible maildir delivery.
 
        Alternatively, the per-user mailbox can be a file  in  the
        user's  home  directory  with  a  name  specified  via the
-       home_mailbox configuration parameter. Specify  a  relative
+       home_mailbox configuration parameter. Specify  a  relative
        path name. Specify a name ending in / for qmail-compatible
        maildir delivery.
 
        Mailbox delivery can be delegated to an  external  command
-       specified  with  the mailbox_command configuration parame-
+       specified  with  the mailbox_command configuration parame-
        ter. The command  executes  with  the  privileges  of  the
        recipient  user  (exception:  in case of delivery as root,
        the   command   executes   with    the    privileges    of
-       default_privs).
+       default_privs).
 
        Mailbox  delivery  can be delegated to alternative message
        transports specified in the  master.cf  file.   The  mail-
-       box_transport  configuration parameter specifies a message
+       box_transport  configuration parameter specifies a message
        transport that is to be used  for  all  local  recipients,
        regardless  of  whether  they are found in the UNIX passwd
-       database.  The fallback_transport  parameter  specifies  a
+       database.  The fallback_transport  parameter  specifies  a
        message transport for recipients that are not found in the
        UNIX passwd database.
 
        In the case of UNIX-style mailbox delivery, the local dae-
-       mon prepends a "From sender time_stamp" envelope header to
+       mon prepends a "From sender time_stamp" envelope header to
        each message, prepends an X-Original-To: header  with  the
        recipient   address  as  given  to  Postfix,  prepends  an
-       optional Delivered-To: header with the envelope  recipient
-       address,  prepends a Return-Path: header with the envelope
-       sender address, prepends a > character to lines  beginning
-       with  "From  ", and appends an empty line.  The mailbox is
-       locked for exclusive access while delivery is in progress.
-       In  case  of  problems, an attempt is made to truncate the
-       mailbox to its original length.
+       optional Delivered-To:  header  with  the  final  envelope
+       recipient address, prepends a Return-Path: header with the
+       envelope sender address, prepends a > character  to  lines
+       beginning  with  "From  ", and appends an empty line.  The
+       mailbox is locked for exclusive access while  delivery  is
+       in  progress.  In  case of problems, an attempt is made to
+       truncate the mailbox to its original length.
 
        In the case of maildir delivery, the local daemon prepends
        an  optional  Delivered-To: header with the final envelope
@@ -127,7 +127,7 @@ LOCAL(8)                                                 LOCAL(8)
        Return-Path: header with the envelope sender address.
 
 EXTERNAL COMMAND DELIVERY
-       The   allow_mail_to_commands    configuration    parameter
+       The   allow_mail_to_commands    configuration    parameter
        restricts  delivery to external commands. The default set-
        ting (alias,  forward)  forbids  command  destinations  in
        :include: files.
@@ -140,15 +140,15 @@ LOCAL(8)                                                 LOCAL(8)
        A limited amount of command output  (standard  output  and
        standard  error) is captured for inclusion with non-deliv-
        ery status reports.  A command is forcibly  terminated  if
-       it  does  not  complete within command_time_limit seconds.
+       it  does  not  complete within command_time_limit seconds.
        Command exit status codes are expected to follow the  con-
        ventions defined in <sysexits.h>.
 
        A  limited amount of message context is exported via envi-
        ronment variables. Characters that may have special  mean-
        ing to the shell are replaced by underscores.  The list of
-       acceptable characters is specified with the command_expan-
-       sion_filter configuration parameter.
+       acceptable characters is specified with the command_expan-
+       sion_filter configuration parameter.
 
        SHELL  The recipient user's login shell.
 
@@ -174,60 +174,62 @@ LOCAL(8)                                                 LOCAL(8)
 
        The PATH environment variable is always reset to a system-
        dependent  default  path,  and environment variables whose
-       names are blessed by the export_environment  configuration
+       names are blessed by the export_environment  configuration
        parameter are exported unchanged.
 
        The current working directory is the mail queue directory.
 
-       The local daemon prepends a "From sender time_stamp" enve-
+       The local daemon prepends a "From sender time_stamp" enve-
        lope  header  to  each message, prepends an X-Original-To:
        header with the recipient address  as  given  to  Postfix,
-       prepends an optional Delivered-To: header with the recipi-
-       ent envelope address, prepends a Return-Path: header  with
-       the sender envelope address, and appends no empty line.
+       prepends  an  optional Delivered-To: header with the final
+       recipient envelope address, prepends a Return-Path: header
+       with  the  sender  envelope  address, and appends no empty
+       line.
 
 EXTERNAL FILE DELIVERY
-       The  delivery  format  depends on the destination filename
-       syntax.  The default is to use UNIX-style mailbox  format.
-       Specify  a  name  ending in / for qmail-compatible maildir
+       The delivery format depends on  the  destination  filename
+       syntax.   The default is to use UNIX-style mailbox format.
+       Specify a name ending in /  for  qmail-compatible  maildir
        delivery.
 
-       The allow_mail_to_files configuration parameter  restricts
-       delivery  to  external  files. The default setting (alias,
+       The  allow_mail_to_files configuration parameter restricts
+       delivery to external files. The  default  setting  (alias,
        forward) forbids file destinations in :include: files.
 
        In the case of UNIX-style mailbox delivery, the local dae-
-       mon prepends a "From sender time_stamp" envelope header to
-       each message, prepends an X-Original-To: header  with  the
-       recipient   address  as  given  to  Postfix,  prepends  an
-       optional Delivered-To: header with the recipient  envelope
-       address,  prepends  a  > character to lines beginning with
-       "From ", and appends an empty line.  The  envelope  sender
-       address is available in the Return-Path: header.  When the
-       destination is a regular file, it is locked for  exclusive
-       access while delivery is in progress. In case of problems,
-       an attempt is made to truncate a regular file to its orig-
-       inal length.
+       mon prepends a "From sender time_stamp" envelope header to
+       each  message,  prepends an X-Original-To: header with the
+       recipient  address  as  given  to  Postfix,  prepends   an
+       optional  Delivered-To:  header  with  the final recipient
+       envelope address, prepends a > character to  lines  begin-
+       ning  with  "From ", and appends an empty line.  The enve-
+       lope sender  address  is  available  in  the  Return-Path:
+       header.   When  the  destination  is a regular file, it is
+       locked for exclusive access while delivery is in progress.
+       In case of problems, an attempt is made to truncate a reg-
+       ular file to its original length.
 
        In the case of maildir delivery, the local daemon prepends
-       an optional Delivered-To: header with the envelope recipi-
-       ent  address,  and  prepends an X-Original-To: header with
-       the recipient address as given to Postfix.   The  envelope
-       sender address is available in the Return-Path: header.
+       an  optional  Delivered-To: header with the final envelope
+       recipient address, and prepends an  X-Original-To:  header
+       with the recipient address as given to Postfix.  The enve-
+       lope sender  address  is  available  in  the  Return-Path:
+       header.
 
 ADDRESS EXTENSION
-       The  optional  recipient_delimiter configuration parameter
+       The  optional  recipient_delimiter configuration parameter
        specifies how to separate address  extensions  from  local
        recipient names.
 
-       For  example,  with  "recipient_delimiter  =  +", mail for
+       For  example,  with  "recipient_delimiter  =  +", mail for
        name+foo is delivered to the  alias  name+foo  or  to  the
        alias  name,  to  the  destinations  listed in ~name/.for-
        ward+foo or in ~name/.forward, to the mailbox owned by the
        user name, or it is sent back as undeliverable.
 
        In all cases the local daemon prepends an optional `Deliv-
-       ered-To: name+foo' header line.
+       ered-To: header line with the final recipient address.
 
 DELIVERY RIGHTS
        Deliveries to external files  and  external  commands  are
@@ -236,7 +238,7 @@ LOCAL(8)                                                 LOCAL(8)
        the  local  daemon  uses the owner rights of the :include:
        file or alias database.  When those files are owned by the
        superuser, delivery is made with the rights specified with
-       the default_privs configuration parameter.
+       the default_privs configuration parameter.
 
 STANDARDS
        RFC 822 (ARPA Internet Text Messages)
@@ -246,7 +248,7 @@ LOCAL(8)                                                 LOCAL(8)
        rupted  message files are marked so that the queue manager
        can move them to the corrupt queue afterwards.
 
-       Depending on the setting of the notify_classes  parameter,
+       Depending on the setting of the notify_classes  parameter,
        the  postmaster  is notified of bounces and of other trou-
        ble.
 
@@ -268,176 +270,183 @@ LOCAL(8)                                                 LOCAL(8)
        command after a configuration change.
 
 Miscellaneous
-       alias_maps
+       alias_maps
               List of alias databases.
 
        biff   Enable  or disable notification of new mail via the
               comsat network service.
 
-       expand_owner_alias
+       expand_owner_alias
               When delivering to an alias that has an owner- com-
               panion  alias,  set  the envelope sender address to
               the right-hand side of  the  owner  alias,  instead
               using of the left-hand side address.
 
-       export_environment
+       export_environment
               List of names of environment parameters that can be
               exported to non-Postfix processes.
 
-       forward_path
+       forward_path
               Search list for .forward files.  The names are sub-
               ject to $name expansion.
 
-       local_command_shell
+       local_command_shell
               Shell  to  use  for external command execution (for
               example, /some/where/smrsh -c).  When  a  shell  is
               specified, it is invoked even when the command con-
               tains no shell built-in commands  or  meta  charac-
               ters.
 
-       owner_request_special
+       owner_request_special
               Give special treatment to owner-xxx and xxx-request
               addresses.
 
-       prepend_delivered_header
+       prepend_delivered_header
               Prepend  an  optional  Delivered-To:  header   upon
               external  forwarding,  delivery to command or file.
               Specify zero or more of:  command,  file,  forward.
               Turning  off  Delivered-To: when forwarding mail is
               not recommended.
 
-       recipient_delimiter
+       propagate_unmatched_extensions
+              A list of address rewriting  or  forwarding  mecha-
+              nisms  that propagate an address extension from the
+              original address to the result.   Specify  zero  or
+              more  of  canonical,  virtual,  alias,  forward, or
+              include.
+
+       recipient_delimiter
               Separator between username and address extension.
 
-       require_home_directory
+       require_home_directory
               Require that a recipient's home directory is acces-
               sible  by the recipient before attempting delivery.
               Defer delivery otherwise.
 
 Mailbox delivery
-       fallback_transport
+       fallback_transport
               Message transport for recipients that are not found
               in  the UNIX passwd database.  This parameter over-
-              rides luser_relay.
+              rides luser_relay.
 
-              Note: you must update the local_recipient_maps set-
+              Note: you must update the local_recipient_maps set-
               ting  in  the  main.cf  file, otherwise the Postfix
               SMTP server will reject mail for non-UNIX  accounts
               with "User unknown in local recipient table".
 
-       home_mailbox
+       home_mailbox
               Pathname  of  a  mailbox  relative to a user's home
               directory.  Specify a path ending in / for maildir-
               style delivery.
 
-       luser_relay
+       luser_relay
               Destination  (@domain  or address) for non-existent
               users.  The address is subjected  to  $name  expan-
               sion.
 
-              Note:  you  must  specify  "local_recipient_maps ="
+              Note:  you  must  specify  "local_recipient_maps ="
               (i.e. empty) in the  main.cf  file,  otherwise  the
               Postfix  SMTP  server will reject mail for non-UNIX
               accounts with  "User  unknown  in  local  recipient
               table".
 
-       mail_spool_directory
+       mail_spool_directory
               Directory  with  UNIX-style  mailboxes. The default
               pathname is system dependent.  Specify a path  end-
               ing in / for maildir-style delivery.
 
-       mailbox_command
+       mailbox_command
               External  command  to use for mailbox delivery. The
               command  executes  with  the  recipient  privileges
               (exception:  root).  The string is subject to $name
               expansions.
 
-       mailbox_command_maps
+       mailbox_command_maps
               Lookup tables with per-recipient external  commands
               to  use  for  mailbox delivery. Behavior is as with
-              mailbox_command.
+              mailbox_command.
 
-       mailbox_transport
+       mailbox_transport
               Message transport to use for  mailbox  delivery  to
               all local recipients, whether or not they are found
               in the UNIX passwd database.  This parameter  over-
               rides  all other configuration parameters that con-
-              trol mailbox delivery, including luser_relay.
+              trol mailbox delivery, including luser_relay.
 
               Note: if you use this feature to receive  mail  for
               non-UNIX   accounts   then   you  must  update  the
-              local_recipient_maps setting in the  main.cf  file,
+              local_recipient_maps setting in the  main.cf  file,
               otherwise  the Postfix SMTP server will reject mail
               for non-UNIX accounts with "User unknown  in  local
               recipient table".
 
 Locking controls
-       deliver_lock_attempts
+       deliver_lock_attempts
               Limit  the  number of attempts to acquire an exclu-
               sive lock on a mailbox or external file.
 
-       deliver_lock_delay
+       deliver_lock_delay
               Time in  seconds  between  successive  attempts  to
               acquire an exclusive lock.
 
-       stale_lock_time
+       stale_lock_time
               Limit the time after which a stale lock is removed.
 
-       mailbox_delivery_lock
+       mailbox_delivery_lock
               What file locking method(s) to use when  delivering
               to  a  UNIX-style  mailbox.  The default setting is
               system dependent.  For a  list  of  available  file
               locking methods, use the postconf -l command.
 
 Resource controls
-       command_time_limit
+       command_time_limit
               Limit  the  amount of time for delivery to external
               command.
 
-       duplicate_filter_limit
+       duplicate_filter_limit
               Limit the size of the duplicate filter for  results
               from alias etc. expansion.
 
-       line_length_limit
+       line_length_limit
               Limit  the  amount  of memory used for processing a
               partial input line.
 
-       local_destination_concurrency_limit
+       local_destination_concurrency_limit
               Limit the number of parallel deliveries to the same
               user.    The   default  limit  is  taken  from  the
-              default_destination_concurrency_limit parameter.
+              default_destination_concurrency_limit parameter.
 
-       local_destination_recipient_limit
+       local_destination_recipient_limit
               Limit the number of recipients per  message  deliv-
               ery.    The   default   limit  is  taken  from  the
-              default_destination_recipient_limit parameter.
+              default_destination_recipient_limit parameter.
 
-       mailbox_size_limit
+       mailbox_size_limit
               Limit the size of a mailbox  etc.  file  (any  file
               that  is written to upon delivery).  Set to zero to
               disable the limit.
 
 Security controls
-       allow_mail_to_commands
+       allow_mail_to_commands
               Restrict the usage of  mail  delivery  to  external
               command.   Specify zero or more of: alias, forward,
               include.
 
-       allow_mail_to_files
+       allow_mail_to_files
               Restrict the usage of  mail  delivery  to  external
               file.   Specify  zero  or  more of: alias, forward,
               include.
 
-       command_expansion_filter
+       command_expansion_filter
               What characters are  allowed  to  appear  in  $name
               expansions  of  mailbox_command. Illegal characters
               are replaced by underscores.
 
-       default_privs
+       default_privs
               Default rights for delivery  to  external  file  or
               command.
 
-       forward_expansion_filter
+       forward_expansion_filter
               What  characters  are  allowed  to  appear in $name
               expansions of forward_path. Illegal characters  are
               replaced by underscores.
diff --git a/postfix/html/postalias.1.html b/postfix/html/postalias.1.html
index 09a3169c1..56f2fd370 100644
--- a/postfix/html/postalias.1.html
+++ b/postfix/html/postalias.1.html
@@ -1,4 +1,4 @@
-    
+  
 POSTALIAS(1)                                         POSTALIAS(1)
 
 NAME
@@ -71,14 +71,14 @@ POSTALIAS(1)                                         POSTALIAS(1)
               ate a new  file  with  default  access  permissions
               (mode 0644).
 
-       -q key Search  the  specified  maps  for key and print the
-              first value found on the  standard  output  stream.
+       -q key Search  the  specified  maps  for key and write the
+              first value found to the  standard  output  stream.
               The exit status is zero when the requested informa-
               tion was found.
 
               If a key value of - is specified, the program reads
               key  values  from  the  standard  input  stream and
-              prints one line of key: value output for  each  key
+              writes one line of key: value output for  each  key
               that  was  found.  The  exit status is zero when at
               least one of the requested keys was found.
 
diff --git a/postfix/html/sendmail.1.html b/postfix/html/sendmail.1.html
index cbdf2d5c6..173d9bf31 100644
--- a/postfix/html/sendmail.1.html
+++ b/postfix/html/sendmail.1.html
@@ -1,17 +1,17 @@
-    
+  
 SENDMAIL(1)                                           SENDMAIL(1)
 
 NAME
        sendmail - Postfix to Sendmail compatibility interface
 
 SYNOPSIS
-       sendmail [option ...] [recipient ...]
+       sendmail [option ...] [recipient ...]
 
        mailq
-       sendmail -bp
+       sendmail -bp
 
        newaliases
-       sendmail -I
+       sendmail -I
 
 DESCRIPTION
        The  sendmail  program  implements the Postfix to Sendmail
@@ -40,9 +40,9 @@ SENDMAIL(1)                                           SENDMAIL(1)
               Initialize the alias database.  If no input file is
               specified (with the -oA  option,  see  below),  the
               program  processes  the  file(s) specified with the
-              alias_database  configuration  parameter.   If   no
+              alias_database  configuration  parameter.   If   no
               alias  database type is specified, the program uses
-              the type specified with  the  default_database_type
+              the type specified with  the  default_database_type
               configuration parameter.  This mode of operation is
               implemented by running the postalias(1) command.
 
@@ -64,14 +64,14 @@ SENDMAIL(1)                                           SENDMAIL(1)
               regardless of whether or not a message is  an  ini-
               tial submission.
 
-       -B body_type
+       -B body_type
               The message body MIME type: 7BIT or 8BITMIME.
 
-       -C config_file (ignored :-)
+       -C config_file (ignored :-)
               The path name of the sendmail.cf file. Postfix con-
               figuration files are kept in /etc/postfix.
 
-       -F full_name
+       -F full_name
               Set the sender full name. This is  used  only  with
               messages that have no From: message header.
 
@@ -83,20 +83,20 @@ SENDMAIL(1)                                           SENDMAIL(1)
               mand above.
 
        -L label (ignored)
-              The  logging  label. Use the syslog_name configura-
+              The  logging  label. Use the syslog_name configura-
               tion parameter instead.
 
        -N dsn (ignored)
               Delivery status  notification  control.  Currently,
               Postfix does not implement DSN.
 
-       -R return_limit (ignored)
+       -R return_limit (ignored)
               Limit   the   size   of   bounced   mail.  Use  the
-              bounce_size_limit configuration parameter  instead.
+              bounce_size_limit configuration parameter  instead.
 
-       -X log_file (ignored)
-              Log  mailer  traffic.  Use  the debug_peer_list and
-              debug_peer_level configuration parameters  instead.
+       -X log_file (ignored)
+              Log  mailer  traffic.  Use  the debug_peer_list and
+              debug_peer_level configuration parameters  instead.
 
        -U (ignored)
               Initial user submission.
@@ -109,16 +109,16 @@ SENDMAIL(1)                                           SENDMAIL(1)
               By  default,  the  personalized   envelope   sender
               address  is  owner-listname+user=domain@origin. The
               default + and = characters  are  configurable  with
-              the  default_verp_delimiters  configuration parame-
+              the  default_verp_delimiters  configuration parame-
               ter.
 
        -Vxy   As -V, but uses x and y as the VERP delimiter char-
               acters,  instead  of  the characters specified with
-              the default_verp_delimiters  configuration  parame-
+              the default_verp_delimiters  configuration  parame-
               ter.
 
        -bd    Go  into  daemon  mode.  This  mode of operation is
-              implemented by executing the postfix start command.
+              implemented by executing the postfix start command.
 
        -bi    Initialize  alias database. See the newaliases com-
               mand above.
@@ -133,7 +133,7 @@ SENDMAIL(1)                                           SENDMAIL(1)
               dard  output.  In stand-alone SMTP server mode, UCE
               restrictions and access controls  are  disabled  by
               default.  To  enable  them,  run the process as the
-              mail_owner user.
+              mail_owner user.
 
               This mode of operation is  implemented  by  running
               the smtpd(8) daemon.
@@ -148,8 +148,8 @@ SENDMAIL(1)                                           SENDMAIL(1)
               address where delivery problems are sent to, unless
               the message contains an Errors-To: message  header.
 
-       -h hop_count (ignored)
-              Hop  count limit. Use the hopcount_limit configura-
+       -h hop_count (ignored)
+              Hop  count limit. Use the hopcount_limit configura-
               tion parameter instead.
 
        -i     When reading a message from standard  input,  don't
@@ -162,7 +162,7 @@ SENDMAIL(1)                                           SENDMAIL(1)
        -n (ignored)
               Backwards compatibility.
 
-       -oAalias_database
+       -oAalias_database
               Non-default alias  database.  Specify  pathname  or
               type:pathname. See postalias(1) for details.
 
@@ -181,7 +181,7 @@ SENDMAIL(1)                                           SENDMAIL(1)
               The  sender  is  never  eliminated  from alias etc.
               expansions.
 
-       -o x value (ignored)
+       -o x value (ignored)
               Set option x to value. Use the equivalent  configu-
               ration parameter in main.cf instead.
 
@@ -195,7 +195,7 @@ SENDMAIL(1)                                           SENDMAIL(1)
 
        -qinterval (ignored)
               The   interval   between   queue   runs.   Use  the
-              queue_run_delay configuration parameter instead.
+              queue_run_delay configuration parameter instead.
 
        -qRsite
               Schedule immediate delivery of  all  mail  that  is
@@ -207,7 +207,7 @@ SENDMAIL(1)                                           SENDMAIL(1)
 
        -qSsite
               This  command  is  not  implemented. Use the slower
-              sendmail -q command instead.
+              sendmail -q command instead.
 
        -t     Extract recipients from message headers. These  are
               added  to  any  recipients specified on the command
@@ -229,101 +229,101 @@ SENDMAIL(1)                                           SENDMAIL(1)
        error stream.
 
 ENVIRONMENT
-       MAIL_CONFIG
+       MAIL_CONFIG
               Directory with Postfix configuration files.
 
-       MAIL_VERBOSE
+       MAIL_VERBOSE
               Enable verbose logging for debugging purposes.
 
-       MAIL_DEBUG
+       MAIL_DEBUG
               Enable debugging with an external command, as spec-
-              ified  with  the   debugger_command   configuration
+              ified  with  the   debugger_command   configuration
               parameter.
 
 FILES
        /var/spool/postfix, mail queue
        /etc/postfix, configuration files
 
-CONFIGURATION PARAMETERS
+CONFIGURATION PARAMETERS
        See  the  Postfix  main.cf file for syntax details and for
-       default values. Use the postfix  reload  command  after  a
+       default values. Use the postfix  reload  command  after  a
        configuration change.
 
-       alias_database
+       alias_database
               Default   alias  database(s)  for  newaliases.  The
               default value for  this  parameter  is  system-spe-
               cific.
 
-       bounce_size_limit
+       bounce_size_limit
               The amount of original message context that is sent
               along with a non-delivery notification.
 
-       default_database_type
+       default_database_type
               Default alias etc. database type. On many UNIX sys-
               tems the default type is either dbm or hash.
 
-       debugger_command
+       debugger_command
               Command that is executed after a Postfix daemon has
               initialized.
 
-       debug_peer_level
+       debug_peer_level
               Increment in verbose logging level  when  a  remote
-              host  matches  a  pattern  in  the  debug_peer_list
+              host  matches  a  pattern  in  the  debug_peer_list
               parameter.
 
-       debug_peer_list
+       debug_peer_list
               List of domain or network patterns. When  a  remote
               host  matches  a pattern, increase the verbose log-
               ging  level  by  the  amount   specified   in   the
-              debug_peer_level parameter.
+              debug_peer_level parameter.
 
-       default_verp_delimiters
+       default_verp_delimiters
               The  VERP  delimiter  characters that are used when
               the -V command line  option  is  specified  without
               delimiter characters.
 
-       fast_flush_domains
+       fast_flush_domains
               List of domains that will receive "fast flush" ser-
               vice (default: all  domains  that  this  system  is
               willing  to relay mail to). This list specifies the
               domains that  Postfix  accepts  in  the  SMTP  ETRN
-              request and in the sendmail -qR command.
+              request and in the sendmail -qR command.
 
-       fork_attempts
+       fork_attempts
               Number  of attempts to fork() a process before giv-
               ing up.
 
-       fork_delay
+       fork_delay
               Delay  in   seconds   between   successive   fork()
               attempts.
 
-       hopcount_limit
+       hopcount_limit
               Limit the number of Received: message headers.
 
-       mail_owner
+       mail_owner
               The  owner  of  the  mail queue and of most Postfix
               processes.
 
-       command_directory
+       command_directory
               Directory with Postfix support commands.
 
-       daemon_directory
+       daemon_directory
               Directory with Postfix daemon programs.
 
-       queue_directory
+       queue_directory
               Top-level directory of the Postfix queue.  This  is
               also the root directory of Postfix daemons that run
               chrooted.
 
-       queue_run_delay
+       queue_run_delay
               The time between successive scans of  the  deferred
               queue.
 
-       verp_delimiter_filter
+       verp_delimiter_filter
               The  characters that Postfix accepts as VERP delim-
               iter characters.
 
-SEE ALSO
+SEE ALSO
        pickup(8) mail pickup daemon
        postsuper(1) queue maintenance
        postalias(1) maintain alias database
diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html
index 864b182a4..b9e87a03e 100644
--- a/postfix/html/smtpd.8.html
+++ b/postfix/html/smtpd.8.html
@@ -1,4 +1,4 @@
-    
+  
 SMTPD(8)                                                 SMTPD(8)
 
 NAME
@@ -62,53 +62,61 @@ SMTPD(8)                                                 SMTPD(8)
               with comments that Sendmail allows.
 
        broken_sasl_auth_clients
-              Support older Microsoft clients that  mis-implement
-              the AUTH protocol, and that expect an EHLO response
-              of "250 AUTH=list" instead of "250 AUTH list".
+              Support Microsoft clients that implement  an  older
+              version  of  the  AUTH protocol, and that expect an
+              EHLO response of "250 AUTH=list"  instead  of  "250
+              AUTH list".
+
+       smtpd_sasl_exceptions_networks
+              Don't offer AUTH in the response to EHLO when talk-
+              ing to clients in the specified networks.  This  is
+              a  workaround  for clients that that demand a login
+              and password from the user whenever AUTH is offered
+              by an SMTP server.
 
        smtpd_noop_commands
               List of commands that are treated as NOOP (no oper-
-              ation)   commands,  without  any  parameter  syntax
-              checking and without any state change.   This  list
+              ation)  commands,  without  any  parameter   syntax
+              checking  and  without any state change.  This list
               overrides built-in command definitions.
 
 Content inspection controls
-       Optionally,  Postfix can be configured to send new mail to
+       Optionally, Postfix can be configured to send new mail  to
        external content filter software AFTER the mail is queued.
 
        content_filter
-              The  name of a mail delivery transport that filters
+              The name of a mail delivery transport that  filters
               mail and that either bounces mail or re-injects the
-              result  back into Postfix.  This parameter uses the
-              same syntax as the right-hand  side  of  a  Postfix
+              result back into Postfix.  This parameter uses  the
+              same  syntax  as  the  right-hand side of a Postfix
               transport table.
 
        receive_override_options
-              The  following  options  override main.cf settings.
-              The options are  either  implemented  by  the  SMTP
-              server  or  are passed on to the downstream cleanup
+              The following options  override  main.cf  settings.
+              The  options  are  either  implemented  by the SMTP
+              server or are passed on to the  downstream  cleanup
               server.
 
               no_unknown_recipient_checks
-                     Do not try  to  reject  unknown  recipients.
-                     This  is  typically  specified with the SMTP
+                     Do  not  try  to  reject unknown recipients.
+                     This is typically specified  with  the  SMTP
                      server after an external content filter.
 
               no_address_mappings
-                     Disable canonical address  mapping,  virtual
-                     alias  map  expansion, address masquerading,
-                     and automatic BCC recipients. This is  typi-
-                     cally  specified with the SMTP server before
+                     Disable  canonical  address mapping, virtual
+                     alias map expansion,  address  masquerading,
+                     and  automatic BCC recipients. This is typi-
+                     cally specified with the SMTP server  before
                      an external content filter.
 
               no_header_body_checks
-                     Disable header/body_checks.  This  is  typi-
-                     cally  specified  with the SMTP server after
+                     Disable  header/body_checks.  This  is typi-
+                     cally specified with the SMTP  server  after
                      an external content filter.
 
 Pass-through proxy
-       Optionally, the Postfix SMTP server can be  configured  to
-       forward  all  mail  to a proxy server, for example a real-
+       Optionally,  the  Postfix SMTP server can be configured to
+       forward all mail to a proxy server, for  example  a  real-
        time content filter, BEFORE mail is queued.
 
        smtpd_proxy_filter
@@ -125,8 +133,8 @@ SMTPD(8)                                                 SMTPD(8)
 
 Authentication controls
        smtpd_sasl_auth_enable
-              Enable  per-session  authentication as per RFC 2554
-              (SASL).  This functionality is available only  when
+              Enable per-session authentication as per  RFC  2554
+              (SASL).   This functionality is available only when
               explicitly  selected  at  program  build  time  and
               explicitly enabled at runtime.
 
@@ -152,8 +160,8 @@ SMTPD(8)                                                 SMTPD(8)
                      Disallow anonymous logins.
 
        smtpd_sender_login_maps
-              Maps that specify the SASL login name that  owns  a
-              MAIL    FROM    sender   address.   Used   by   the
+              Maps  that  specify the SASL login name that owns a
+              MAIL   FROM   sender   address.   Used    by    the
               reject_sender_login_mismatch  sender  anti-spoofing
               restriction.
 
@@ -163,23 +171,23 @@ SMTPD(8)                                                 SMTPD(8)
               that are authorized to use the XVERP extension.
 
        debug_peer_level
-              Increment in verbose logging level  when  a  remote
+              Increment  in  verbose  logging level when a remote
               host  matches  a  pattern  in  the  debug_peer_list
               parameter.
 
        debug_peer_list
-              List of domain or network patterns. When  a  remote
-              host  matches  a pattern, increase the verbose log-
-              ging  level  by  the  amount   specified   in   the
+              List  of  domain or network patterns. When a remote
+              host matches a pattern, increase the  verbose  log-
+              ging   level   by   the  amount  specified  in  the
               debug_peer_level parameter.
 
        default_verp_delimiters
               The default VERP delimiter characters that are used
-              when  the  XVERP  command  is   specified   without
+              when   the   XVERP  command  is  specified  without
               explicit delimiters.
 
        error_notice_recipient
-              Recipient    of   protocol/policy/resource/software
+              Recipient   of    protocol/policy/resource/software
               error notices.
 
        hopcount_limit
@@ -188,18 +196,18 @@ SMTPD(8)                                                 SMTPD(8)
        notify_classes
               List of error classes. Of special interest are:
 
-              policy When a client violates any  policy,  mail  a
+              policy When  a  client  violates any policy, mail a
                      transcript of the entire SMTP session to the
                      postmaster.
 
               protocol
-                     When a client violates the SMTP protocol  or
+                     When  a client violates the SMTP protocol or
                      issues  an  unimplemented  command,  mail  a
                      transcript of the entire SMTP session to the
                      postmaster.
 
        smtpd_banner
-              Text  that  follows the 220 status code in the SMTP
+              Text that follows the 220 status code in  the  SMTP
               greeting banner.
 
        smtpd_expansion_filter
@@ -207,57 +215,57 @@ SMTPD(8)                                                 SMTPD(8)
               expansion of rbl template responses and other text.
 
        smtpd_recipient_limit
-              Restrict the number of  recipients  that  the  SMTP
+              Restrict  the  number  of  recipients that the SMTP
               server accepts per message delivery.
 
        smtpd_timeout
-              Limit  the  time  to  send a server response and to
+              Limit the time to send a  server  response  and  to
               receive a client request.
 
        soft_bounce
-              Change hard (5xx) reject responses into soft  (4xx)
-              reject  responses.   This can be useful for testing
+              Change  hard (5xx) reject responses into soft (4xx)
+              reject responses.  This can be useful  for  testing
               purposes.
 
        verp_delimiter_filter
-              The characters that Postfix accepts as VERP  delim-
+              The  characters that Postfix accepts as VERP delim-
               iter characters.
 
 Known versus unknown recipients
        show_user_unknown_table_name
-              Whether  or  not  to  reveal  the table name in the
-              "User unknown" responses. The  extra  detail  makes
-              trouble  shooting  easier but also reveals informa-
+              Whether or not to reveal  the  table  name  in  the
+              "User  unknown"  responses.  The extra detail makes
+              trouble shooting easier but also  reveals  informa-
               tion that is nobody elses business.
 
        unknown_local_recipient_reject_code
               The response code when a client specifies a recipi-
-              ent   whose   domain   matches   $mydestination  or
+              ent  whose   domain   matches   $mydestination   or
               $inet_interfaces,  while  $local_recipient_maps  is
-              non-empty  and  does not list the recipient address
+              non-empty and does not list the  recipient  address
               or address local-part.
 
        unknown_relay_recipient_reject_code
               The response code when a client specifies a recipi-
               ent  whose  domain  matches  $relay_domains,  while
-              $relay_recipient_maps is  non-empty  and  does  not
+              $relay_recipient_maps  is  non-empty  and  does not
               list the recipient address.
 
        unknown_virtual_alias_reject_code
               The response code when a client specifies a recipi-
-              ent whose  domain  matches  $virtual_alias_domains,
-              while   the   recipient  is  not  listed  in  $vir-
+              ent  whose  domain  matches $virtual_alias_domains,
+              while  the  recipient  is  not  listed   in   $vir-
               tual_alias_maps.
 
        unknown_virtual_mailbox_reject_code
               The response code when a client specifies a recipi-
-              ent  whose domain matches $virtual_mailbox_domains,
+              ent whose domain matches  $virtual_mailbox_domains,
               while the recipient is not listed in $virtual_mail-
               box_maps.
 
 Resource controls
        line_length_limit
-              Limit  the  amount  of memory in bytes used for the
+              Limit the amount of memory in bytes  used  for  the
               handling of partial input lines.
 
        message_size_limit
@@ -265,8 +273,8 @@ SMTPD(8)                                                 SMTPD(8)
               ing on-disk storage for envelope information.
 
        queue_minfree
-              Minimal  amount of free space in bytes in the queue
-              file system for the SMTP server to accept any  mail
+              Minimal amount of free space in bytes in the  queue
+              file  system for the SMTP server to accept any mail
               at all.
 
        smtpd_history_flush_threshold
@@ -281,17 +289,17 @@ SMTPD(8)                                                 SMTPD(8)
 
        smtpd_soft_error_limit
               When an SMTP client has made this number of errors,
-              wait  error_count  seconds before responding to any
+              wait error_count seconds before responding  to  any
               client request.
 
        smtpd_hard_error_limit
-              Disconnect after a client has made this  number  of
+              Disconnect  after  a client has made this number of
               errors.
 
        smtpd_junk_command_limit
               Limit the number of times a client can issue a junk
-              command such as NOOP, VRFY, ETRN  or  RSET  in  one
-              SMTP  session  before  it  is penalized with tarpit
+              command  such  as  NOOP,  VRFY, ETRN or RSET in one
+              SMTP session before it  is  penalized  with  tarpit
               delays.
 
 Delegated policy
@@ -300,17 +308,17 @@ SMTPD(8)                                                 SMTPD(8)
               receiving from a delegated SMTPD policy server.
 
        smtpd_policy_service_max_idle
-              Time  after  which  an  unused SMTPD policy service
+              Time after which an  unused  SMTPD  policy  service
               connection is closed.
 
        smtpd_policy_service_timeout
-              Time after which an  active  SMTPD  policy  service
+              Time  after  which  an  active SMTPD policy service
               connection is closed.
 
 UCE control restrictions
        parent_domain_matches_subdomains
-              List  of  Postfix features that use domain.tld pat-
-              terns  to  match  sub.domain.tld  (as  opposed   to
+              List of Postfix features that use  domain.tld  pat-
+              terns   to  match  sub.domain.tld  (as  opposed  to
               requiring .domain.tld patterns).
 
        smtpd_client_restrictions
@@ -318,19 +326,19 @@ SMTPD(8)                                                 SMTPD(8)
               tem.
 
        smtpd_helo_required
-              Require that clients introduce  themselves  at  the
+              Require  that  clients  introduce themselves at the
               beginning of an SMTP session.
 
        smtpd_helo_restrictions
-              Restrict  what client hostnames are allowed in HELO
+              Restrict what client hostnames are allowed in  HELO
               and EHLO commands.
 
        smtpd_sender_restrictions
-              Restrict what sender addresses are allowed in  MAIL
+              Restrict  what sender addresses are allowed in MAIL
               FROM commands.
 
        smtpd_recipient_restrictions
-              Restrict  what  recipient  addresses are allowed in
+              Restrict what recipient addresses  are  allowed  in
               RCPT TO commands.
 
        smtpd_etrn_restrictions
@@ -338,96 +346,96 @@ SMTPD(8)                                                 SMTPD(8)
               mands, and what clients may issue ETRN commands.
 
        smtpd_data_restrictions
-              Restrictions  on  the  DATA command. Currently, the
-              only  restriction  that   makes   sense   here   is
+              Restrictions on the DATA  command.  Currently,  the
+              only   restriction   that   makes   sense  here  is
               reject_unauth_pipelining.
 
        allow_untrusted_routing
-              Allow  untrusted  clients to specify addresses with
-              sender-specified routing.  Enabling this  opens  up
-              nasty  relay  loopholes involving trusted backup MX
+              Allow untrusted clients to specify  addresses  with
+              sender-specified  routing.   Enabling this opens up
+              nasty relay loopholes involving trusted  backup  MX
               hosts.
 
        smtpd_restriction_classes
-              Declares the name of zero or more  parameters  that
-              contain  a  list  of UCE restrictions. The names of
-              these parameters can then be used  instead  of  the
+              Declares  the  name of zero or more parameters that
+              contain a list of UCE restrictions.  The  names  of
+              these  parameters  can  then be used instead of the
               restriction lists that they represent.
 
        smtpd_null_access_lookup_key
-              The  lookup  key  to be used in SMTPD access tables
-              instead of the null sender address. A  null  sender
+              The lookup key to be used in  SMTPD  access  tables
+              instead  of  the null sender address. A null sender
               address cannot be looked up.
 
        maps_rbl_domains (deprecated)
-              List  of  DNS domains that publish the addresses of
+              List of DNS domains that publish the  addresses  of
               blacklisted hosts. This is used with the deprecated
               reject_maps_rbl restriction.
 
        permit_mx_backup_networks
-              Only  domains  whose  primary  MX  hosts  match the
-              listed  networks  are   eligible   for   the   per-
+              Only domains  whose  primary  MX  hosts  match  the
+              listed   networks   are   eligible   for  the  per-
               mit_mx_backup feature.
 
        relay_domains
-              Restrict  what  domains this mail system will relay
-              mail to. The domains are  routed  to  the  delivery
+              Restrict what domains this mail system  will  relay
+              mail  to.  The  domains  are routed to the delivery
               agent specified with the relay_transport setting.
 
 Sender/recipient address verification
        Address verification is implemented by sending probe email
-       messages that are not actually delivered, and  is  enabled
-       via    the   reject_unverified_{sender,recipient}   access
-       restriction.  The status of verification probes  is  main-
+       messages  that  are not actually delivered, and is enabled
+       via   the   reject_unverified_{sender,recipient}    access
+       restriction.   The  status of verification probes is main-
        tained by the address verification service.
 
        address_verify_poll_count
-              How  many  times  to query the address verification
-              service for completion of an  address  verification
-              request.   Specify  1 to implement a simple form of
-              greylisting, that is, always defer the request  for
+              How many times to query  the  address  verification
+              service  for  completion of an address verification
+              request.  Specify 1 to implement a simple  form  of
+              greylisting,  that is, always defer the request for
               a new sender or recipient address.
 
        address_verify_poll_delay
-              Time  to  wait after querying the address verifica-
+              Time to wait after querying the  address  verifica-
               tion service for completion of an address verifica-
               tion request.
 
 UCE control responses
        access_map_reject_code
-              Response  code  when  a  client  violates an access
+              Response code when  a  client  violates  an  access
               database restriction.
 
        default_rbl_reply
               Default template reply when a request is RBL black-
-              listed.   This template is used by the reject_rbl_*
-              and   reject_rhsbl_*   restrictions.   See    also:
+              listed.  This template is used by the  reject_rbl_*
+              and    reject_rhsbl_*   restrictions.   See   also:
               rbl_reply_maps and smtpd_expansion_filter.
 
        defer_code
-              Response  code when a client request is rejected by
+              Response code when a client request is rejected  by
               the defer restriction.
 
        invalid_hostname_reject_code
-              Response  code   when   a   client   violates   the
+              Response   code   when   a   client   violates  the
               reject_invalid_hostname restriction.
 
        maps_rbl_reject_code
               Response code when a request is RBL blacklisted.
 
        multi_recipient_bounce_reject_code
-              Response  code  when  a  multi-recipient  bounce is
+              Response code  when  a  multi-recipient  bounce  is
               blocked.
 
        rbl_reply_maps
-              Table with template responses for  RBL  blacklisted
-              requests,  indexed  by  RBL domain name. These tem-
+              Table  with  template responses for RBL blacklisted
+              requests, indexed by RBL domain  name.  These  tem-
               plates   are   used   by   the   reject_rbl_*   and
-              reject_rhsbl_*      restrictions.     See     also:
+              reject_rhsbl_*     restrictions.     See      also:
               default_rbl_reply and smtpd_expansion_filter.
 
        reject_code
-              Response code when  the  client  matches  a  reject
+              Response  code  when  the  client  matches a reject
               restriction.
 
        relay_domains_reject_code
@@ -435,7 +443,7 @@ SMTPD(8)                                                 SMTPD(8)
               mail relay policy.
 
        unknown_address_reject_code
-              Response  code   when   a   client   violates   the
+              Response   code   when   a   client   violates  the
               reject_unknown_address restriction.
 
        unknown_client_reject_code
@@ -444,15 +452,15 @@ SMTPD(8)                                                 SMTPD(8)
               tion.
 
        unknown_hostname_reject_code
-              Response   code   when   a   client   violates  the
+              Response  code   when   a   client   violates   the
               reject_unknown_hostname restriction.
 
        unverified_sender_reject_code
-              Response code when a sender address is known to  be
+              Response  code when a sender address is known to be
               undeliverable.
 
        unverified_recipient_reject_code
-              Response  code when a recipient address is known to
+              Response code when a recipient address is known  to
               be undeliverable.
 
 SEE ALSO
@@ -463,7 +471,7 @@ SMTPD(8)                                                 SMTPD(8)
        verify(8) address verification service
 
 LICENSE
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 AUTHOR(S)
diff --git a/postfix/html/uce.html b/postfix/html/uce.html
index dfc4f9d89..f75848d09 100644
--- a/postfix/html/uce.html
+++ b/postfix/html/uce.html
@@ -134,9 +134,14 @@ matches a table, the action depends on the lookup result:
 Reject the message, log the header and the optional text,
 and send the optional text to the originator.
 
-
OK
Skip all further header patterns for this header line. +
DUNNO
-
IGNORE
Delete the header line from the message. +
DUNNO text...
Skip all further header patterns for this header line. +This has the same effect as OK, which is deprecated. + +
IGNORE
+ +
IGNORE text...
Delete the header line from the message.
WARN
@@ -247,9 +252,14 @@ and send the optional text to the originator. Log (but do not reject) the body line with a warning, and log the optional text. -
OK
Skip all further body patterns for this body line. +
DUNNO
+ +
DUNNO text...
Skip all further body patterns for this body line. +This has the same effect as OK, which is deprecated. -
IGNORE
Delete the body line from the message. +
IGNORE
+ +
IGNORE text...
Delete the body line from the message.
HOLD
@@ -358,8 +368,8 @@ reject_rbl_client relays.mail-abuse.org (paid service)
smtpd_client_restrictions = hash:/etc/postfix/access, reject_rbl_client relays.ordb.org (free service) -
smtpd_client_restrictions = hash:/etc/postfix/access, -reject_rhsbl_client dsn.rfc-ignorant.org (free service) +
smtpd_sender_restrictions = hash:/etc/postfix/access, +reject_rhsbl_sender dsn.rfc-ignorant.org (free service)
smtpd_client_restrictions = permit_mynetworks, reject_unknown_client @@ -589,6 +599,27 @@ or parent domains.

+ + +

reject_rhsbl_helo domain.tld=127.0.0.2 + +
reject_rhsbl_helo domain.tld
Reject the +request when the HELO (or EHLO) hostname is listed with an A record +under domain.tld. See above for additional RBL related +configuration parameters. + +Append the address to the RBL server's domain name to select a +specific address from a multi-valued result. + +The maps_rbl_reject_code parameter specifies the response +code for rejected requests (default: 554), the default_rbl_reply parameter +specifies the default server reply, and the +rbl_reply_maps parameter specifies tables with server replies +indexed by RBL domain. + +

+

permit
defer @@ -974,19 +1005,19 @@ lookup tables: - - + - - - -
Recipient domain matches Recipient lookup table +
Recipient domain matches Recipient lookup table
$mydestination or -$inet_interfaces -$local_recipient_maps +
$mydestination or +$inet_interfaces$local_recipient_maps
$virtual_alias_domains $virtual_alias_maps +
$virtual_alias_domains $virtual_alias_maps
$virtual_mailbox_domains $virtual_mailbox_maps +
$virtual_mailbox_domains $virtual_mailbox_maps
$relay_domains $relay_recipient_maps +
$relay_domains $relay_recipient_maps
+ diff --git a/postfix/html/virtual.5.html b/postfix/html/virtual.5.html index 6181cae1d..fdeb53c3e 100644 --- a/postfix/html/virtual.5.html +++ b/postfix/html/virtual.5.html @@ -1,4 +1,4 @@ -
+  
 VIRTUAL(5)                                             VIRTUAL(5)
 
 NAME
@@ -103,24 +103,27 @@ VIRTUAL(5)                                             VIRTUAL(5)
        When a mail address localpart contains the optional recip-
        ient delimiter (e.g., user+foo@domain), the  lookup  order
        becomes: user+foo@domain, user@domain, user+foo, user, and
-       @domain.  An unmatched address extension (+foo) is  propa-
+       @domain.
+
+       The  propagate_unmatched_extensions   parameter   controls
+       whether  an  unmatched  address extension (+foo) is propa-
        gated to the result of table lookup.
 
 VIRTUAL ALIAS DOMAINS
-       Besides  virtual aliases, the virtual alias table can also
+       Besides virtual aliases, the virtual alias table can  also
        be used to implement virtual alias domains. With a virtual
-       alias  domain,  all  recipient  addresses  are  aliased to
+       alias domain,  all  recipient  addresses  are  aliased  to
        addresses in other domains.
 
        Virtual alias domains are not to be confused with the vir-
        tual mailbox domains that are implemented with the Postfix
        virtual(8)  mail  delivery  agent.  With  virtual  mailbox
-       domains,  each recipient address can have its own mailbox.
+       domains, each recipient address can have its own  mailbox.
 
-       With a virtual alias domain, the virtual  domain  has  its
-       own  user  name  space. Local (i.e. non-virtual) usernames
-       are not visible in a virtual alias domain. In  particular,
-       local  aliases(5)  and local mailing lists are not visible
+       With  a  virtual  alias domain, the virtual domain has its
+       own user name space. Local  (i.e.  non-virtual)  usernames
+       are  not visible in a virtual alias domain. In particular,
+       local aliases(5) and local mailing lists are  not  visible
        as localname@virtual-alias.domain.
 
        Support for a virtual alias domain looks like:
@@ -128,7 +131,7 @@ VIRTUAL(5)                                             VIRTUAL(5)
        /etc/postfix/main.cf:
            virtual_alias_maps = hash:/etc/postfix/virtual
 
-           Note: some systems use dbm databases instead of  hash.
+           Note:  some systems use dbm databases instead of hash.
            See the output from postconf -m for available database
            types.
 
@@ -138,87 +141,94 @@ VIRTUAL(5)                                             VIRTUAL(5)
            user1@virtual-alias.domain   address1
            user2@virtual-alias.domain   address2, address3
 
-       The virtual-alias.domain anything entry is required for  a
+       The  virtual-alias.domain anything entry is required for a
        virtual alias domain. Without this entry, mail is rejected
-       with "relay access denied", or bounces  with  "mail  loops
+       with  "relay  access  denied", or bounces with "mail loops
        back to myself".
 
-       Do  not  specify virtual alias domain names in the main.cf
+       Do not specify virtual alias domain names in  the  main.cf
        mydestination or relay_domains configuration parameters.
 
-       With a virtual  alias  domain,  the  Postfix  SMTP  server
-       accepts   mail  for  known-user@virtual-alias.domain,  and
-       rejects  mail  for  unknown-user@virtual-alias.domain   as
+       With  a  virtual  alias  domain,  the  Postfix SMTP server
+       accepts  mail  for  known-user@virtual-alias.domain,   and
+       rejects   mail  for  unknown-user@virtual-alias.domain  as
        undeliverable.
 
-       Instead  of  specifying  the virtual alias domain name via
-       the virtual_alias_maps table, you may also specify it  via
+       Instead of specifying the virtual alias  domain  name  via
+       the  virtual_alias_maps table, you may also specify it via
        the main.cf virtual_alias_domains configuration parameter.
-       This latter parameter uses the same syntax as the  main.cf
+       This  latter parameter uses the same syntax as the main.cf
        mydestination configuration parameter.
 
 REGULAR EXPRESSION TABLES
-       This  section  describes how the table lookups change when
+       This section describes how the table lookups  change  when
        the table is given in the form of regular expressions. For
-       a  description  of regular expression lookup table syntax,
+       a description of regular expression lookup  table  syntax,
        see regexp_table(5) or pcre_table(5).
 
-       Each pattern is a regular expression that  is  applied  to
+       Each  pattern  is  a regular expression that is applied to
        the entire address being looked up. Thus, user@domain mail
-       addresses are not broken up into their  user  and  @domain
+       addresses  are  not  broken up into their user and @domain
        constituent parts, nor is user+foo broken up into user and
        foo.
 
-       Patterns are applied in the  order  as  specified  in  the
-       table,  until  a  pattern is found that matches the search
+       Patterns  are  applied  in  the  order as specified in the
+       table, until a pattern is found that  matches  the  search
        string.
 
-       Results are the same as with indexed  file  lookups,  with
-       the  additional feature that parenthesized substrings from
+       Results  are  the  same as with indexed file lookups, with
+       the additional feature that parenthesized substrings  from
        the pattern can be interpolated as $1, $2 and so on.
 
 TCP-BASED TABLES
-       This section describes how the table lookups  change  when
+       This  section  describes how the table lookups change when
        lookups are directed to a TCP-based server. For a descrip-
-       tion  of  the  TCP  client/server  lookup  protocol,   see
+       tion   of  the  TCP  client/server  lookup  protocol,  see
        tcp_table(5).
 
        Each lookup operation uses the entire address once.  Thus,
-       user@domain mail addresses are not broken  up  into  their
+       user@domain  mail  addresses  are not broken up into their
        user and @domain constituent parts, nor is user+foo broken
        up into user and foo.
 
        Results are the same as with indexed file lookups.
 
 BUGS
-       The table format does not understand quoting  conventions.
+       The  table format does not understand quoting conventions.
 
 CONFIGURATION PARAMETERS
-       The  following  main.cf parameters are especially relevant
-       to this topic. See the Postfix  main.cf  file  for  syntax
-       details  and  for  default  values. Use the postfix reload
+       The following main.cf parameters are  especially  relevant
+       to  this  topic.  See  the Postfix main.cf file for syntax
+       details and for default values.  Use  the  postfix  reload
        command after a configuration change.
 
        virtual_alias_maps
               List of virtual aliasing tables.
 
        virtual_alias_domains
-              List of virtual alias domains. This uses  the  same
+              List  of  virtual alias domains. This uses the same
               syntax as the mydestination parameter.
 
+       propagate_unmatched_extensions
+              A list of address rewriting  or  forwarding  mecha-
+              nisms  that propagate an address extension from the
+              original address to the result.   Specify  zero  or
+              more  of  canonical,  virtual,  alias,  forward, or
+              include.
+
        Other parameters of interest:
 
        inet_interfaces
-              The  network  interface  addresses that this system
+              The network interface addresses  that  this  system
               receives mail on.  You need to stop and start Post-
               fix when this parameter changes.
 
        mydestination
-              List  of  domains  that  this mail system considers
+              List of domains that  this  mail  system  considers
               local.
 
        myorigin
-              The domain that is appended  to  any  address  that
+              The  domain  that  is  appended to any address that
               does not have a domain.
 
        owner_request_special
@@ -233,7 +243,7 @@ VIRTUAL(5)                                             VIRTUAL(5)
        tcp_table(5) TCP client/server table lookup protocol
 
 LICENSE
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 AUTHOR(S)
diff --git a/postfix/man/man1/postalias.1 b/postfix/man/man1/postalias.1
index e03d69862..7317bd316 100644
--- a/postfix/man/man1/postalias.1
+++ b/postfix/man/man1/postalias.1
@@ -66,12 +66,12 @@ Do not inherit the file access permissions from the input file
 when creating a new file.  Instead, create a new file with default
 access permissions (mode 0644).
 .IP "\fB-q \fIkey\fR"
-Search the specified maps for \fIkey\fR and print the first value
-found on the standard output stream. The exit status is zero
+Search the specified maps for \fIkey\fR and write the first value
+found to the standard output stream. The exit status is zero
 when the requested information was found.
 
 If a key value of \fB-\fR is specified, the program reads key
-values from the standard input stream and prints one line of
+values from the standard input stream and writes one line of
 \fIkey: value\fR output for each key that was found. The exit
 status is zero when at least one of the requested keys was found.
 .IP \fB-r\fR
diff --git a/postfix/man/man1/smtp-sink.1 b/postfix/man/man1/smtp-sink.1
index 05e522ef0..637ddc97e 100644
--- a/postfix/man/man1/smtp-sink.1
+++ b/postfix/man/man1/smtp-sink.1
@@ -25,11 +25,15 @@ IPV4 is the default.
 This program is the complement of the \fIsmtp-source\fR program.
 
 Arguments:
+.IP \fB-a\fR
+Do not announce SASL authentication support.
 .IP \fB-c\fR
 Display a running counter that is updated whenever an SMTP
 QUIT command is executed.
 .IP \fB-e\fR
 Disable ESMTP support.
+.IP "\fB-f  \fIcommand,command,...\fR"
+Reject the specified commands with a hard (5xx) error code.
 .IP \fB-h\fI hostname\fR
 Use \fIhostname\fR in the SMTP greeting, in the HELO response,
 and in the EHLO response. The default hostname is "smtp-sink".
@@ -42,6 +46,8 @@ Disable ESMTP command pipelining.
 .IP \fB-P\fR
 Change the server greeting so that it appears to come through
 a CISCO PIX system. Implies \fB-e\fR.
+.IP "\fB-r  \fIcommand,command,...\fR"
+Reject the specified commands with a soft (4xx) error code.
 .IP "\fB-s \fIcommand,command,...\fR"
 Log the named commands to syslogd.
 Examples of commands that can be logged are HELO, EHLO, LHLO, MAIL,
diff --git a/postfix/man/man5/canonical.5 b/postfix/man/man5/canonical.5
index 09778b32f..99a1da1ae 100644
--- a/postfix/man/man5/canonical.5
+++ b/postfix/man/man5/canonical.5
@@ -97,8 +97,11 @@ In all the above forms, when \fIaddress\fR has the form
 When a mail address localpart contains the optional recipient delimiter
 (e.g., \fIuser+foo\fR@\fIdomain\fR), the lookup order becomes:
 \fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, \fIuser+foo\fR,
-\fIuser\fR, and @\fIdomain\fR.  An unmatched address extension
-(\fI+foo\fR) is propagated to the result of table lookup.
+\fIuser\fR, and @\fIdomain\fR.
+
+The \fBpropagate_unmatched_extensions\fR parameter controls whether
+an unmatched address extension (\fI+foo\fR) is propagated to the
+result of table lookup.
 .SH REGULAR EXPRESSION TABLES
 .na
 .nf
@@ -156,6 +159,11 @@ addresses.
 .IP \fBsender_canonical_maps\fR
 Address mapping lookup table for envelope and header sender
 addresses.
+.IP \fBpropagate_unmatched_extensions\fR
+A list of address rewriting or forwarding mechanisms that propagate
+an address extension from the original address to the result.
+Specify zero or more of \fBcanonical\fR, \fBvirtual\fR, \fBalias\fR,
+\fBforward\fR, or \fBinclude\fR.
 .PP
 Other parameters of interest:
 .IP \fBinet_interfaces\fR
diff --git a/postfix/man/man5/virtual.5 b/postfix/man/man5/virtual.5
index 59fccdd09..c95c5dc0b 100644
--- a/postfix/man/man5/virtual.5
+++ b/postfix/man/man5/virtual.5
@@ -97,8 +97,11 @@ This works for the first address in the expansion only.
 When a mail address localpart contains the optional recipient delimiter
 (e.g., \fIuser+foo\fR@\fIdomain\fR), the lookup order becomes:
 \fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, \fIuser+foo\fR,
-\fIuser\fR, and @\fIdomain\fR.  An unmatched address extension
-(\fI+foo\fR) is propagated to the result of table lookup.
+\fIuser\fR, and @\fIdomain\fR.
+
+The \fBpropagate_unmatched_extensions\fR parameter controls whether
+an unmatched address extension (\fI+foo\fR) is propagated to the
+result of table lookup.
 .SH VIRTUAL ALIAS DOMAINS
 .na
 .nf
@@ -212,6 +215,11 @@ List of virtual aliasing tables.
 .IP \fBvirtual_alias_domains\fR
 List of virtual alias domains. This uses the same syntax
 as the \fBmydestination\fR parameter.
+.IP \fBpropagate_unmatched_extensions\fR
+A list of address rewriting or forwarding mechanisms that propagate
+an address extension from the original address to the result.
+Specify zero or more of \fBcanonical\fR, \fBvirtual\fR, \fBalias\fR,
+\fBforward\fR, or \fBinclude\fR.
 .PP
 Other parameters of interest:
 .IP \fBinet_interfaces\fR
diff --git a/postfix/man/man8/cleanup.8 b/postfix/man/man8/cleanup.8
index 8542c99dd..63c7c2d17 100644
--- a/postfix/man/man8/cleanup.8
+++ b/postfix/man/man8/cleanup.8
@@ -169,6 +169,11 @@ more of \fBenvelope_sender\fR, \fBenvelope_recipient\fR,
 List of domains that hide their subdomain structure.
 .IP \fBmasquerade_exceptions\fR
 List of user names that are not subject to address masquerading.
+.IP \fBpropagate_unmatched_extensions\fR
+A list of address rewriting or forwarding mechanisms that propagate
+an address extension from the original address to the result.
+Specify zero or more of \fBcanonical\fR, \fBvirtual\fR, \fBalias\fR,
+\fBforward\fR, or \fBinclude\fR.
 .IP \fBvirtual_alias_maps\fR
 Address mapping lookup table for envelope recipient addresses.
 .SH "Resource controls"
diff --git a/postfix/man/man8/local.8 b/postfix/man/man8/local.8
index c92ad6a94..ca23b1671 100644
--- a/postfix/man/man8/local.8
+++ b/postfix/man/man8/local.8
@@ -85,7 +85,7 @@ delivery status record.
 
 In order to stop mail forwarding loops early, the software adds an
 optional
-\fBDelivered-To:\fR header with the envelope recipient address. If
+\fBDelivered-To:\fR header with the final envelope recipient address. If
 mail arrives for a recipient that is already listed in a
 \fBDelivered-To:\fR header, the message is bounced.
 .SH MAILBOX DELIVERY
@@ -124,7 +124,7 @@ envelope header to each message, prepends an
 \fBX-Original-To:\fR header with the recipient address as given to
 Postfix, prepends an
 optional \fBDelivered-To:\fR header
-with the envelope recipient address, prepends a \fBReturn-Path:\fR
+with the final envelope recipient address, prepends a \fBReturn-Path:\fR
 header with the envelope sender address, prepends a \fB>\fR character
 to lines beginning with "\fBFrom \fR", and appends an empty line.
 The mailbox is locked for exclusive access while delivery is in
@@ -196,7 +196,7 @@ envelope header to each message, prepends an
 \fBX-Original-To:\fR header with the recipient address as given to
 Postfix, prepends an
 optional \fBDelivered-To:\fR
-header with the recipient envelope address, prepends a
+header with the final recipient envelope address, prepends a
 \fBReturn-Path:\fR header with the sender envelope address,
 and appends no empty line.
 .SH EXTERNAL FILE DELIVERY
@@ -218,7 +218,7 @@ envelope header to each message, prepends an
 \fBX-Original-To:\fR header with the recipient address as given to
 Postfix, prepends an
 optional \fBDelivered-To:\fR
-header with the recipient envelope address, prepends a \fB>\fR
+header with the final recipient envelope address, prepends a \fB>\fR
 character to lines beginning with "\fBFrom \fR", and appends an
 empty line.
 The envelope sender address is available in the \fBReturn-Path:\fR
@@ -229,8 +229,8 @@ is made to truncate a regular file to its original length.
 
 In the case of \fBmaildir\fR delivery, the local daemon prepends
 an optional
-\fBDelivered-To:\fR header with the envelope recipient address, and
-prepends an
+\fBDelivered-To:\fR header with the final envelope recipient address,
+and prepends an
 \fBX-Original-To:\fR header with the recipient address as given to
 Postfix.
 The envelope sender address is available in the \fBReturn-Path:\fR
@@ -252,7 +252,8 @@ to the mailbox owned by the user \fIname\fR, or it is sent back as
 undeliverable.
 
 In all cases the \fBlocal\fR daemon prepends an optional
-`\fBDelivered-To:\fR \fIname\fR+\fIfoo\fR' header line.
+`\fBDelivered-To:\fR header line with the final recipient
+address.
 .SH DELIVERY RIGHTS
 .na
 .nf
@@ -329,6 +330,11 @@ Prepend an optional \fBDelivered-To:\fR header upon external
 forwarding, delivery to command or file. Specify zero or more of:
 \fBcommand, file, forward\fR. Turning off \fBDelivered-To:\fR when
 forwarding mail is not recommended.
+.IP \fBpropagate_unmatched_extensions\fR
+A list of address rewriting or forwarding mechanisms that propagate
+an address extension from the original address to the result.
+Specify zero or more of \fBcanonical\fR, \fBvirtual\fR, \fBalias\fR,
+\fBforward\fR, or \fBinclude\fR.
 .IP \fBrecipient_delimiter\fR
 Separator between username and address extension.
 .IP \fBrequire_home_directory\fR
diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8
index 1e004fad2..71ba43107 100644
--- a/postfix/man/man8/smtpd.8
+++ b/postfix/man/man8/smtpd.8
@@ -73,9 +73,14 @@ a configuration change.
 Disallow non-RFC 821 style addresses in SMTP commands. For example,
 the RFC822-style address forms with comments that Sendmail allows.
 .IP \fBbroken_sasl_auth_clients\fR
-Support older Microsoft clients that mis-implement the AUTH
+Support Microsoft clients that implement an older version of the AUTH
 protocol, and that expect an EHLO response of "250 AUTH=list"
 instead of "250 AUTH list".
+.IP \fBsmtpd_sasl_exceptions_networks\fR
+Don't offer AUTH in the response to EHLO when talking to clients
+in the specified networks.  This is a workaround for clients that
+that demand a login and password from the user whenever AUTH is
+offered by an SMTP server.
 .IP \fBsmtpd_noop_commands\fR
 List of commands that are treated as NOOP (no operation) commands,
 without any parameter syntax checking and without any state change.
diff --git a/postfix/mantools/man2html b/postfix/mantools/man2html
index be7c1c822..23f673cbc 100755
--- a/postfix/mantools/man2html
+++ b/postfix/mantools/man2html
@@ -2,7 +2,7 @@
 
 # Crude script to convert formatted manual pages to HTML
 
-echo '    
'
+echo '  
'
 
 sed '
 	s/\([<>&]\)\1/\1/g
diff --git a/postfix/proto/access b/postfix/proto/access
index 68c3c0b76..700d4f339 100644
--- a/postfix/proto/access
+++ b/postfix/proto/access
@@ -56,7 +56,8 @@
 # .sp
 #	The pattern \fIdomain.tld\fR also matches subdomains, but only
 #	when the string \fBsmtpd_access_maps\fR is listed in the Postfix
-#	\fBparent_domain_matches_subdomains\fR configuration setting.
+#	\fBparent_domain_matches_subdomains\fR configuration setting
+#	(note that this is the default for some versions of Postfix).
 #	Otherwise, specify \fI.domain.tld\fR (note the initial dot) in
 #	order to match subdomains.
 # .IP \fIuser\fR@
diff --git a/postfix/proto/canonical b/postfix/proto/canonical
index 7245d920d..3cc6ae707 100644
--- a/postfix/proto/canonical
+++ b/postfix/proto/canonical
@@ -87,8 +87,11 @@
 #	When a mail address localpart contains the optional recipient delimiter
 #	(e.g., \fIuser+foo\fR@\fIdomain\fR), the lookup order becomes:
 #	\fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, \fIuser+foo\fR,
-#	\fIuser\fR, and @\fIdomain\fR.  An unmatched address extension
-#	(\fI+foo\fR) is propagated to the result of table lookup.
+#	\fIuser\fR, and @\fIdomain\fR.
+#
+#	The \fBpropagate_unmatched_extensions\fR parameter controls whether
+#	an unmatched address extension (\fI+foo\fR) is propagated to the 
+#	result of table lookup.
 # REGULAR EXPRESSION TABLES
 # .ad
 # .fi
@@ -138,6 +141,11 @@
 # .IP \fBsender_canonical_maps\fR
 #	Address mapping lookup table for envelope and header sender
 #	addresses.
+# .IP \fBpropagate_unmatched_extensions\fR 
+#	A list of address rewriting or forwarding mechanisms that propagate
+#	an address extension from the original address to the result.
+#	Specify zero or more of \fBcanonical\fR, \fBvirtual\fR, \fBalias\fR,  
+#	\fBforward\fR, or \fBinclude\fR.
 # .PP
 #	Other parameters of interest:
 # .IP \fBinet_interfaces\fR
diff --git a/postfix/proto/virtual b/postfix/proto/virtual
index 2df396de3..284b18796 100644
--- a/postfix/proto/virtual
+++ b/postfix/proto/virtual
@@ -87,8 +87,11 @@
 #	When a mail address localpart contains the optional recipient delimiter
 #	(e.g., \fIuser+foo\fR@\fIdomain\fR), the lookup order becomes:
 #	\fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, \fIuser+foo\fR,
-#	\fIuser\fR, and @\fIdomain\fR.  An unmatched address extension
-#	(\fI+foo\fR) is propagated to the result of table lookup.
+#	\fIuser\fR, and @\fIdomain\fR.
+#
+#	The \fBpropagate_unmatched_extensions\fR parameter controls whether
+#	an unmatched address extension (\fI+foo\fR) is propagated to the
+#	result of table lookup.
 # VIRTUAL ALIAS DOMAINS
 # .ad
 # .fi
@@ -192,6 +195,11 @@
 # .IP \fBvirtual_alias_domains\fR
 #	List of virtual alias domains. This uses the same syntax
 #	as the \fBmydestination\fR parameter.
+# .IP \fBpropagate_unmatched_extensions\fR
+#	A list of address rewriting or forwarding mechanisms that propagate   
+#	an address extension from the original address to the result.     
+#	Specify zero or more of \fBcanonical\fR, \fBvirtual\fR, \fBalias\fR,
+#	\fBforward\fR, or \fBinclude\fR.
 # .PP
 #	Other parameters of interest:
 # .IP \fBinet_interfaces\fR
diff --git a/postfix/src/cleanup/cleanup.c b/postfix/src/cleanup/cleanup.c
index 50db85b85..5eb690e76 100644
--- a/postfix/src/cleanup/cleanup.c
+++ b/postfix/src/cleanup/cleanup.c
@@ -148,13 +148,18 @@
 /*	Address mapping lookup table for envelope and header sender
 /*	addresses.
 /* .IP \fBmasquerade_classes\fR
-/*      List of address classes subject to masquerading: zero or
-/*      more of \fBenvelope_sender\fR, \fBenvelope_recipient\fR,
+/*	List of address classes subject to masquerading: zero or
+/*	more of \fBenvelope_sender\fR, \fBenvelope_recipient\fR,
 /*	\fBheader_sender\fR, \fBheader_recipient\fR.
 /* .IP \fBmasquerade_domains\fR
 /*	List of domains that hide their subdomain structure.
 /* .IP \fBmasquerade_exceptions\fR
 /*	List of user names that are not subject to address masquerading.
+/* .IP \fBpropagate_unmatched_extensions\fR
+/*	A list of address rewriting or forwarding mechanisms that propagate   
+/*	an address extension from the original address to the result.
+/*	Specify zero or more of \fBcanonical\fR, \fBvirtual\fR, \fBalias\fR,  
+/*	\fBforward\fR, or \fBinclude\fR.
 /* .IP \fBvirtual_alias_maps\fR
 /*	Address mapping lookup table for envelope recipient addresses.
 /* .SH "Resource controls"
diff --git a/postfix/src/cleanup/cleanup_message.c b/postfix/src/cleanup/cleanup_message.c
index 328d62890..48f1178c4 100644
--- a/postfix/src/cleanup/cleanup_message.c
+++ b/postfix/src/cleanup/cleanup_message.c
@@ -342,14 +342,15 @@ static int cleanup_act(CLEANUP_STATE *state, char *context, const char *buf,
 	}
 	return (CLEANUP_ACT_KEEP);
     }
-    if (*optional_text)
-	msg_warn("unexpected text after command in %s map: %s",
-		 map_class, value);
+    /* Allow and ignore optional text after the action. */
 
     if (STREQUAL(value, "IGNORE", command_len))
 	return (CLEANUP_ACT_DROP);
 
-    if (STREQUAL(value, "OK", command_len))
+    if (STREQUAL(value, "DUNNO", command_len))	/* preferred */
+	return (CLEANUP_ACT_KEEP);
+
+    if (STREQUAL(value, "OK", command_len))	/* compat */
 	return (CLEANUP_ACT_KEEP);
 
     msg_warn("unknown command in %s map: %s", map_class, value);
diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h
index 7d8961c6f..0d16455bf 100644
--- a/postfix/src/global/mail_params.h
+++ b/postfix/src/global/mail_params.h
@@ -939,6 +939,10 @@ extern int var_lmtpd_err_sleep;
 #define DEF_LMTPD_JUNK_CMD	1000
 extern int var_lmtpd_junk_cmd_limit;
 
+#define VAR_SMTPD_SASL_EXCEPTIONS_NETWORKS	"smtpd_sasl_exceptions_networks"
+#define DEF_SMTPD_SASL_EXCEPTIONS_NETWORKS	""
+extern char *var_smtpd_sasl_exceptions_networks;
+
  /*
   * SASL authentication support, LMTP server side.
   */
@@ -1315,6 +1319,7 @@ extern int var_access_map_code;
 #define REJECT_RBL		"reject_rbl"	/* LaMont compatibility */
 #define REJECT_RBL_CLIENT	"reject_rbl_client"
 #define REJECT_RHSBL_CLIENT	"reject_rhsbl_client"
+#define REJECT_RHSBL_HELO	"reject_rhsbl_helo"
 #define REJECT_RHSBL_SENDER	"reject_rhsbl_sender"
 #define REJECT_RHSBL_RECIPIENT	"reject_rhsbl_recipient"
 
diff --git a/postfix/src/global/mime_state.c b/postfix/src/global/mime_state.c
index 5a3345fe3..eb7bfc4ba 100644
--- a/postfix/src/global/mime_state.c
+++ b/postfix/src/global/mime_state.c
@@ -56,7 +56,7 @@
 /*	A message header contains 8-bit data. This is always illegal.
 /* .IP MIME_ERR_8BIT_IN_7BIT_BODY
 /*	A MIME header specifies (or defaults to) 7-bit content, but the
-/*	correspnding message body or body parts contain 8-bit content.
+/*	corresponding message body or body parts contain 8-bit content.
 /* .IP MIME_ERR_ENCODING_DOMAIN
 /*	An entity of type "message" or "multipart" specifies the wrong
 /*	content transfer encoding domain, or specifies a transformation
diff --git a/postfix/src/global/pipe_command.c b/postfix/src/global/pipe_command.c
index 322747b8a..7cbd9795c 100644
--- a/postfix/src/global/pipe_command.c
+++ b/postfix/src/global/pipe_command.c
@@ -413,7 +413,8 @@ int     pipe_command(VSTREAM *src, VSTRING *why,...)
 	 */
     case 0:
 	set_ugid(args.uid, args.gid);
-	setsid();
+	if (setsid() < 0)
+	    msg_warn("setsid failed: %m");
 
 	/*
 	 * Pipe plumbing.
diff --git a/postfix/src/global/post_mail.c b/postfix/src/global/post_mail.c
index 3550d299b..bff950cf3 100644
--- a/postfix/src/global/post_mail.c
+++ b/postfix/src/global/post_mail.c
@@ -294,6 +294,7 @@ static void post_mail_open_event(int event, char *context)
 	    event_disable_readwrite(vstream_fileno(state->stream));
 	    vstream_fclose(state->stream);
 	} else {
+    case EVENT_XCPT:
 	    msg_warn("connect to service: %s: %m", var_cleanup_service);
 	}
 	myfree(state->sender);
diff --git a/postfix/src/lmtp/Makefile.in b/postfix/src/lmtp/Makefile.in
index 41303b3bc..4b86772e8 100644
--- a/postfix/src/lmtp/Makefile.in
+++ b/postfix/src/lmtp/Makefile.in
@@ -130,6 +130,7 @@ lmtp_connect.o: ../../include/iostuff.h
 lmtp_connect.o: ../../include/timed_connect.h
 lmtp_connect.o: ../../include/stringops.h
 lmtp_connect.o: ../../include/host_port.h
+lmtp_connect.o: ../../include/sane_connect.h
 lmtp_connect.o: ../../include/mail_params.h
 lmtp_connect.o: ../../include/mail_proto.h
 lmtp_connect.o: ../../include/attr.h
diff --git a/postfix/src/lmtp/lmtp.c b/postfix/src/lmtp/lmtp.c
index e1f36e45a..8eb40b7e0 100644
--- a/postfix/src/lmtp/lmtp.c
+++ b/postfix/src/lmtp/lmtp.c
@@ -337,6 +337,10 @@ static int deliver_message(DELIVER_REQUEST *request, char **unused_argv)
 	    lmtp_quit(state);
 	    lmtp_chat_reset(state);
 	    state->session = lmtp_session_free(state->session);
+#ifdef USE_SASL_AUTH
+	    if (var_lmtp_sasl_enable)
+		lmtp_sasl_cleanup(state);
+#endif
 	}
 
 	/*
@@ -346,6 +350,10 @@ static int deliver_message(DELIVER_REQUEST *request, char **unused_argv)
 	else if (lmtp_rset(state) != 0) {
 	    lmtp_chat_reset(state);
 	    state->session = lmtp_session_free(state->session);
+#ifdef USE_SASL_AUTH
+	    if (var_lmtp_sasl_enable)
+		lmtp_sasl_cleanup(state);
+#endif
 	}
 
 	/*
@@ -380,6 +388,10 @@ static int deliver_message(DELIVER_REQUEST *request, char **unused_argv)
 	 */
 	else if (lmtp_lhlo(state) != 0) {
 	    state->session = lmtp_session_free(state->session);
+#ifdef USE_SASL_AUTH
+	    if (var_lmtp_sasl_enable)
+		lmtp_sasl_cleanup(state);
+#endif
 	}
 
 	/*
diff --git a/postfix/src/lmtp/lmtp.h b/postfix/src/lmtp/lmtp.h
index 419cb38d5..2f9643970 100644
--- a/postfix/src/lmtp/lmtp.h
+++ b/postfix/src/lmtp/lmtp.h
@@ -53,7 +53,6 @@ typedef struct LMTP_STATE {
     sasl_callback_t *sasl_callbacks;	/* stateful callbacks */
 #endif
     int     sndbufsize;			/* total window size */
-    int     sndbuffree;			/* remaining window */
     int     reuse;			/* connection being reused */
 } LMTP_STATE;
 
diff --git a/postfix/src/lmtp/lmtp_connect.c b/postfix/src/lmtp/lmtp_connect.c
index 63321e496..36c19246c 100644
--- a/postfix/src/lmtp/lmtp_connect.c
+++ b/postfix/src/lmtp/lmtp_connect.c
@@ -93,6 +93,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Global library. */
 
@@ -221,7 +222,7 @@ static LMTP_SESSION *lmtp_connect_sock(int sock, struct sockaddr * sa, int len,
 	non_blocking(sock, BLOCKING);
 	errno = saved_errno;
     } else {
-	conn_stat = connect(sock, sa, len);
+	conn_stat = sane_connect(sock, sa, len);
     }
     if (conn_stat < 0) {
 	vstring_sprintf(why, "connect to %s[%s]: %m",
diff --git a/postfix/src/lmtp/lmtp_proto.c b/postfix/src/lmtp/lmtp_proto.c
index 808811bae..ccf905e60 100644
--- a/postfix/src/lmtp/lmtp_proto.c
+++ b/postfix/src/lmtp/lmtp_proto.c
@@ -246,11 +246,6 @@ int     lmtp_lhlo(LMTP_STATE *state)
     if (msg_verbose)
 	msg_info("server features: 0x%x", state->features);
 
-#ifdef USE_SASL_AUTH
-    if (var_lmtp_sasl_enable && (state->features & LMTP_FEATURE_AUTH))
-	return (lmtp_sasl_helo_login(state));
-#endif
-
     /*
      * We use LMTP command pipelining if the server said it supported it.
      * Since we use blocking I/O, RFC 2197 says that we should inspect the
@@ -276,6 +271,11 @@ int     lmtp_lhlo(LMTP_STATE *state)
     } else
 	state->sndbufsize = 0;
 
+#ifdef USE_SASL_AUTH
+    if (var_lmtp_sasl_enable && (state->features & LMTP_FEATURE_AUTH))
+	return (lmtp_sasl_helo_login(state));
+#endif
+
     return (0);
 }
 
@@ -383,6 +383,16 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
 		    msg_warn("%s: unknown content encoding: %s",
 			     request->queue_id, request->encoding);
 	    }
+
+	    /*
+	     * We authenticate the client, not the sender.
+	     */
+#ifdef USE_SASL_AUTH
+	    if (var_lmtp_sasl_enable
+		&& (state->features & LMTP_FEATURE_AUTH)
+		&& state->sasl_passwd)
+		vstring_strcat(next_command, " AUTH=<>");
+#endif
 	    next_state = LMTP_STATE_RCPT;
 	    break;
 
@@ -536,8 +546,8 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
 				&& sent(DEL_REQ_TRACE_FLAGS(request->flags),
 					request->queue_id, rcpt->orig_addr,
 					rcpt->address, session->namaddr,
-					request->arrival_time, "%s", 
-					translit(resp->str, "\n", " ")) == 0) {
+					request->arrival_time, "%s",
+				     translit(resp->str, "\n", " ")) == 0) {
 				if (request->flags & DEL_REQ_FLAG_SUCCESS)
 				    deliver_completed(state->src, rcpt->offset);
 				rcpt->offset = 0;	/* in case deferred */
@@ -720,8 +730,8 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
 	/*
 	 * Copy the next command to the buffer and update the sender state.
 	 */
-	if (state->sndbuffree > 0)
-	    state->sndbuffree -= VSTRING_LEN(next_command) + 2;
+	if (sndbuffree > 0)
+	    sndbuffree -= VSTRING_LEN(next_command) + 2;
 	lmtp_chat_cmd(state, "%s", vstring_str(next_command));
 	send_state = next_state;
 	send_rcpt = next_rcpt;
diff --git a/postfix/src/lmtp/lmtp_sasl_glue.c b/postfix/src/lmtp/lmtp_sasl_glue.c
index 9b0e673c0..05bcc7d92 100644
--- a/postfix/src/lmtp/lmtp_sasl_glue.c
+++ b/postfix/src/lmtp/lmtp_sasl_glue.c
@@ -38,7 +38,7 @@
 /*	policy of the SASL authentication.
 /*
 /*	lmtp_sasl_passwd_lookup() looks up the username/password
-/*	for the current SMTP server. The result is zero in case
+/*	for the current LMTP server. The result is zero in case
 /*	of failure.
 /*
 /*	lmtp_sasl_authenticate() implements the SASL authentication
@@ -49,7 +49,7 @@
 /*	suceeds.
 /*
 /*	lmtp_sasl_cleanup() cleans up. It must be called at the
-/*	end of every SMTP session that uses SASL authentication.
+/*	end of every LMTP session that uses SASL authentication.
 /*	This routine is a noop for non-SASL sessions.
 /*
 /*	Arguments:
diff --git a/postfix/src/lmtp/lmtp_state.c b/postfix/src/lmtp/lmtp_state.c
index 9f25f8149..f3cadc0b3 100644
--- a/postfix/src/lmtp/lmtp_state.c
+++ b/postfix/src/lmtp/lmtp_state.c
@@ -80,7 +80,6 @@ LMTP_STATE *lmtp_state_alloc(void)
     lmtp_sasl_connect(state);
 #endif
     state->sndbufsize = 0;
-    state->sndbuffree = 0;
     state->reuse = 0;
     return (state);
 }
diff --git a/postfix/src/local/local.c b/postfix/src/local/local.c
index 0a387d506..d0f7cec23 100644
--- a/postfix/src/local/local.c
+++ b/postfix/src/local/local.c
@@ -75,7 +75,7 @@
 /*
 /*	In order to stop mail forwarding loops early, the software adds an
 /*	optional
-/*	\fBDelivered-To:\fR header with the envelope recipient address. If
+/*	\fBDelivered-To:\fR header with the final envelope recipient address. If
 /*	mail arrives for a recipient that is already listed in a
 /*	\fBDelivered-To:\fR header, the message is bounced.
 /* MAILBOX DELIVERY
@@ -112,7 +112,7 @@
 /*	\fBX-Original-To:\fR header with the recipient address as given to
 /*	Postfix, prepends an
 /*	optional \fBDelivered-To:\fR header
-/*	with the envelope recipient address, prepends a \fBReturn-Path:\fR
+/*	with the final envelope recipient address, prepends a \fBReturn-Path:\fR
 /*	header with the envelope sender address, prepends a \fB>\fR character
 /*	to lines beginning with "\fBFrom \fR", and appends an empty line.
 /*	The mailbox is locked for exclusive access while delivery is in
@@ -182,7 +182,7 @@
 /*	\fBX-Original-To:\fR header with the recipient address as given to
 /*	Postfix, prepends an
 /*	optional \fBDelivered-To:\fR
-/*	header with the recipient envelope address, prepends a
+/*	header with the final recipient envelope address, prepends a
 /*	\fBReturn-Path:\fR header with the sender envelope address,
 /*	and appends no empty line.
 /* EXTERNAL FILE DELIVERY
@@ -202,7 +202,7 @@
 /*	\fBX-Original-To:\fR header with the recipient address as given to
 /*	Postfix, prepends an
 /*	optional \fBDelivered-To:\fR
-/*	header with the recipient envelope address, prepends a \fB>\fR
+/*	header with the final recipient envelope address, prepends a \fB>\fR
 /*	character to lines beginning with "\fBFrom \fR", and appends an
 /*	empty line.
 /*	The envelope sender address is available in the \fBReturn-Path:\fR
@@ -213,8 +213,8 @@
 /*
 /*	In the case of \fBmaildir\fR delivery, the local daemon prepends
 /*	an optional
-/*	\fBDelivered-To:\fR header with the envelope recipient address, and
-/*	prepends an
+/*	\fBDelivered-To:\fR header with the final envelope recipient address,
+/*	and prepends an
 /*	\fBX-Original-To:\fR header with the recipient address as given to
 /*	Postfix.
 /*	The envelope sender address is available in the \fBReturn-Path:\fR
@@ -234,7 +234,8 @@
 /*	undeliverable.
 /*
 /*	In all cases the \fBlocal\fR daemon prepends an optional
-/*	`\fBDelivered-To:\fR \fIname\fR+\fIfoo\fR' header line.
+/*	`\fBDelivered-To:\fR header line with the final recipient
+/*	address.
 /* DELIVERY RIGHTS
 /* .ad
 /* .fi
@@ -301,6 +302,11 @@
 /*	forwarding, delivery to command or file. Specify zero or more of:
 /*	\fBcommand, file, forward\fR. Turning off \fBDelivered-To:\fR when
 /*	forwarding mail is not recommended.
+/* .IP \fBpropagate_unmatched_extensions\fR
+/*	A list of address rewriting or forwarding mechanisms that propagate
+/*	an address extension from the original address to the result.
+/*	Specify zero or more of \fBcanonical\fR, \fBvirtual\fR, \fBalias\fR,
+/*	\fBforward\fR, or \fBinclude\fR.
 /* .IP \fBrecipient_delimiter\fR
 /*	Separator between username and address extension.
 /* .IP \fBrequire_home_directory\fR
diff --git a/postfix/src/postalias/postalias.c b/postfix/src/postalias/postalias.c
index f7f95666a..2df71cc5c 100644
--- a/postfix/src/postalias/postalias.c
+++ b/postfix/src/postalias/postalias.c
@@ -60,12 +60,12 @@
 /*	when creating a new file.  Instead, create a new file with default
 /*	access permissions (mode 0644).
 /* .IP "\fB-q \fIkey\fR"
-/*	Search the specified maps for \fIkey\fR and print the first value
-/*	found on the standard output stream. The exit status is zero
+/*	Search the specified maps for \fIkey\fR and write the first value
+/*	found to the standard output stream. The exit status is zero
 /*	when the requested information was found.
 /*
 /*	If a key value of \fB-\fR is specified, the program reads key
-/*	values from the standard input stream and prints one line of
+/*	values from the standard input stream and writes one line of
 /*	\fIkey: value\fR output for each key that was found. The exit
 /*	status is zero when at least one of the requested keys was found.
 /* .IP \fB-r\fR
diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in
index 205767d76..d51009814 100644
--- a/postfix/src/smtp/Makefile.in
+++ b/postfix/src/smtp/Makefile.in
@@ -137,6 +137,7 @@ smtp_connect.o: ../../include/iostuff.h
 smtp_connect.o: ../../include/timed_connect.h
 smtp_connect.o: ../../include/stringops.h
 smtp_connect.o: ../../include/host_port.h
+smtp_connect.o: ../../include/sane_connect.h
 smtp_connect.o: ../../include/mail_params.h
 smtp_connect.o: ../../include/own_inet_addr.h
 smtp_connect.o: ../../include/dns.h
diff --git a/postfix/src/smtp/smtp_connect.c b/postfix/src/smtp/smtp_connect.c
index bdfb00ca3..95bb9179c 100644
--- a/postfix/src/smtp/smtp_connect.c
+++ b/postfix/src/smtp/smtp_connect.c
@@ -112,6 +112,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Global library. */
 
@@ -208,7 +209,7 @@ static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
 	non_blocking(sock, BLOCKING);
 	errno = saved_errno;
     } else {
-	conn_stat = connect(sock, (struct sockaddr *) & sin, sizeof(sin));
+	conn_stat = sane_connect(sock, (struct sockaddr *) & sin, sizeof(sin));
     }
     if (conn_stat < 0) {
 	vstring_sprintf(why, "connect to %s[%s]: %m",
diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c
index 6cbdb5d3f..943720b7c 100644
--- a/postfix/src/smtp/smtp_proto.c
+++ b/postfix/src/smtp/smtp_proto.c
@@ -504,6 +504,16 @@ int     smtp_xfer(SMTP_STATE *state)
 		    msg_warn("%s: unknown content encoding: %s",
 			     request->queue_id, request->encoding);
 	    }
+
+	    /*
+	     * We authenticate the client, not the sender.
+	     */
+#ifdef USE_SASL_AUTH
+	    if (var_smtp_sasl_enable
+		&& (state->features & SMTP_FEATURE_AUTH)
+		&& state->sasl_passwd)
+		vstring_strcat(next_command, " AUTH=<>");
+#endif
 	    next_state = SMTP_STATE_RCPT;
 	    break;
 
diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c
index d77b8fd4e..ad0640f3b 100644
--- a/postfix/src/smtpd/smtpd.c
+++ b/postfix/src/smtpd/smtpd.c
@@ -59,9 +59,14 @@
 /*	Disallow non-RFC 821 style addresses in SMTP commands. For example,
 /*	the RFC822-style address forms with comments that Sendmail allows.
 /* .IP \fBbroken_sasl_auth_clients\fR
-/*	Support older Microsoft clients that mis-implement the AUTH
+/*	Support Microsoft clients that implement an older version of the AUTH
 /*	protocol, and that expect an EHLO response of "250 AUTH=list"
 /*	instead of "250 AUTH list".
+/* .IP \fBsmtpd_sasl_exceptions_networks\fR
+/*	Don't offer AUTH in the response to EHLO when talking to clients
+/*	in the specified networks.  This is a workaround for clients that
+/*	that demand a login and password from the user whenever AUTH is
+/*	offered by an SMTP server.
 /* .IP \fBsmtpd_noop_commands\fR
 /*	List of commands that are treated as NOOP (no operation) commands,
 /*	without any parameter syntax checking and without any state change.
@@ -492,6 +497,7 @@ int     var_smtpd_junk_cmd_limit;
 bool    var_smtpd_sasl_enable;
 char   *var_smtpd_sasl_opts;
 char   *var_smtpd_sasl_realm;
+char   *var_smtpd_sasl_exceptions_networks;
 char   *var_filter_xport;
 bool    var_broken_auth_clients;
 char   *var_perm_mx_networks;
@@ -549,6 +555,35 @@ static void mail_reset(SMTPD_STATE *);
 static void rcpt_reset(SMTPD_STATE *);
 static void chat_reset(SMTPD_STATE *, int);
 
+ /*
+  * SASL exceptions.
+  */
+static NAMADR_LIST *sasl_exceptions_networks;
+
+/* sasl_client_exception - can we offer AUTH for this client */
+
+static int sasl_client_exception(SMTPD_STATE *state)
+{
+    int     match;
+
+    /*
+     * This is to work around a Netscape mail client bug where it tries to
+     * use AUTH if available, even if user has not configured it. Returns
+     * TRUE if AUTH should be offered in the EHLO.
+     */
+    if (sasl_exceptions_networks == 0)
+	return (0);
+
+    match = namadr_list_match(sasl_exceptions_networks,
+			      state->name, state->addr);
+
+    if (msg_verbose)
+	msg_info("sasl_exceptions: %s[%s], match=%d",
+		 state->name, state->addr, match);
+
+    return (match);
+}
+
 /* collapse_args - put arguments together again */
 
 static void collapse_args(int argc, SMTPD_TOKEN *argv)
@@ -635,7 +670,7 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
 	smtpd_chat_reply(state, "250-VRFY");
     smtpd_chat_reply(state, "250-ETRN");
 #ifdef USE_SASL_AUTH
-    if (var_smtpd_sasl_enable) {
+    if (var_smtpd_sasl_enable && !sasl_client_exception(state)) {
 	smtpd_chat_reply(state, "250-AUTH %s", state->sasl_mechanism_list);
 	if (var_broken_auth_clients)
 	    smtpd_chat_reply(state, "250-AUTH=%s", state->sasl_mechanism_list);
@@ -1764,13 +1799,6 @@ static void smtpd_service(VSTREAM *stream, char *unused_service, char **argv)
     smtpd_state_init(&state, stream);
     msg_info("connect from %s[%s]", state.name, state.addr);
 
-    /*
-     * XXX non_blocking() aborts upon error.
-     */
-#ifdef BROKEN_READ_SELECT_ON_BLOCKING_SOCKET
-    non_blocking(vstream_fileno(stream), NON_BLOCKING);
-#endif
-
     /*
      * See if we need to turn on verbose logging for this client.
      */
@@ -1820,6 +1848,11 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
     if (var_smtpd_sasl_enable)
 #ifdef USE_SASL_AUTH
 	smtpd_sasl_initialize();
+
+    if (*var_smtpd_sasl_exceptions_networks)
+	sasl_exceptions_networks =
+	    namadr_list_init(MATCH_FLAG_NONE,
+			     var_smtpd_sasl_exceptions_networks);
 #else
 	msg_warn("%s is true, but SASL support is not compiled in",
 		 VAR_SMTPD_SASL_ENABLE);
@@ -1912,6 +1945,7 @@ int     main(int argc, char **argv)
 	VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0,
 	VAR_SMTPD_SASL_OPTS, DEF_SMTPD_SASL_OPTS, &var_smtpd_sasl_opts, 0, 0,
 	VAR_SMTPD_SASL_REALM, DEF_SMTPD_SASL_REALM, &var_smtpd_sasl_realm, 0, 0,
+	VAR_SMTPD_SASL_EXCEPTIONS_NETWORKS, DEF_SMTPD_SASL_EXCEPTIONS_NETWORKS, &var_smtpd_sasl_exceptions_networks, 0, 0,
 	VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0,
 	VAR_PERM_MX_NETWORKS, DEF_PERM_MX_NETWORKS, &var_perm_mx_networks, 0, 0,
 	VAR_SMTPD_SND_AUTH_MAPS, DEF_SMTPD_SND_AUTH_MAPS, &var_smtpd_snd_auth_maps, 0, 0,
diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c
index bd9f8b2a6..387ffa65d 100644
--- a/postfix/src/smtpd/smtpd_check.c
+++ b/postfix/src/smtpd/smtpd_check.c
@@ -103,9 +103,10 @@
 /*	configuration parameter specifies the reject status code used in
 /*	the default template (default: 554).
 /* .IP reject_rhsbl_client rbl.domain.tld
+/* .IP reject_rhsbl_helo rbl.domain.tld
 /* .IP reject_rhsbl_sender rbl.domain.tld
 /* .IP reject_rhsbl_recipient rbl.domain.tld
-/*	Look up the client/sender/recipient domain name in the specified
+/*	Look up the client/helo/sender/recipient domain name in the specified
 /*	real-time blackhole DNS zone.  The \fIrbl_reply_maps\fR configuration
 /*	parameter is used to generate the template for the reject message.
 /*	If it is not specified, or the rbl domain cannot be found, then a
@@ -2987,6 +2988,16 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
 		    status = reject_invalid_hostaddr(state, state->helo_name,
 					 state->helo_name, SMTPD_NAME_HELO);
 	    }
+	} else if (strcasecmp(name, REJECT_RHSBL_HELO) == 0) {
+	    if (cpp[1] == 0)
+		msg_warn("restriction %s requires domain name argument",
+			 name);
+	    else {
+		cpp += 1;
+		if (state->helo_name)
+		    status = reject_rbl_domain(state, *cpp, state->helo_name,
+					       SMTPD_NAME_HELO);
+	    }
 	}
 
 	/*
diff --git a/postfix/src/smtpstone/Makefile.in b/postfix/src/smtpstone/Makefile.in
index 186538bb6..c541cdbaa 100644
--- a/postfix/src/smtpstone/Makefile.in
+++ b/postfix/src/smtpstone/Makefile.in
@@ -103,6 +103,7 @@ qmqp-source.o: ../../include/mymalloc.h
 qmqp-source.o: ../../include/events.h
 qmqp-source.o: ../../include/find_inet.h
 qmqp-source.o: ../../include/netstring.h
+qmqp-source.o: ../../include/sane_connect.h
 qmqp-source.o: ../../include/mail_date.h
 qmqp-source.o: ../../include/qmqp_proto.h
 smtp-sink.o: smtp-sink.c
@@ -119,6 +120,7 @@ smtp-sink.o: ../../include/events.h
 smtp-sink.o: ../../include/mymalloc.h
 smtp-sink.o: ../../include/msg_vstream.h
 smtp-sink.o: ../../include/stringops.h
+smtp-sink.o: ../../include/sane_accept.h
 smtp-sink.o: ../../include/smtp_stream.h
 smtp-source.o: smtp-source.c
 smtp-source.o: ../../include/sys_defs.h
@@ -135,5 +137,6 @@ smtp-source.o: ../../include/iostuff.h
 smtp-source.o: ../../include/mymalloc.h
 smtp-source.o: ../../include/events.h
 smtp-source.o: ../../include/find_inet.h
+smtp-source.o: ../../include/sane_connect.h
 smtp-source.o: ../../include/smtp_stream.h
 smtp-source.o: ../../include/mail_date.h
diff --git a/postfix/src/smtpstone/qmqp-source.c b/postfix/src/smtpstone/qmqp-source.c
index b2beb0202..16ef364a4 100644
--- a/postfix/src/smtpstone/qmqp-source.c
+++ b/postfix/src/smtpstone/qmqp-source.c
@@ -83,6 +83,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Global library. */
 
@@ -312,7 +313,7 @@ static void start_connect(SESSION *session)
     session->stream = vstream_fdopen(fd, O_RDWR);
     event_enable_write(fd, connect_done, (char *) session);
     netstring_setup(session->stream, var_timeout);
-    if (connect(fd, sa, sa_length) < 0 && errno != EINPROGRESS)
+    if (sane_connect(fd, sa, sa_length) < 0 && errno != EINPROGRESS)
 	fail_connect(session);
 }
 
diff --git a/postfix/src/smtpstone/smtp-sink.c b/postfix/src/smtpstone/smtp-sink.c
index 2f3f7af04..6d305e23b 100644
--- a/postfix/src/smtpstone/smtp-sink.c
+++ b/postfix/src/smtpstone/smtp-sink.c
@@ -19,11 +19,15 @@
 /*	This program is the complement of the \fIsmtp-source\fR program.
 /*
 /*	Arguments:
+/* .IP \fB-a\fR
+/*	Do not announce SASL authentication support.
 /* .IP \fB-c\fR
 /*	Display a running counter that is updated whenever an SMTP
 /*	QUIT command is executed.
 /* .IP \fB-e\fR
 /*	Disable ESMTP support.
+/* .IP "\fB-f  \fIcommand,command,...\fR"
+/*	Reject the specified commands with a hard (5xx) error code.
 /* .IP \fB-h\fI hostname\fR
 /*	Use \fIhostname\fR in the SMTP greeting, in the HELO response,
 /*	and in the EHLO response. The default hostname is "smtp-sink".
@@ -36,6 +40,8 @@
 /* .IP \fB-P\fR
 /*	Change the server greeting so that it appears to come through
 /*	a CISCO PIX system. Implies \fB-e\fR.
+/* .IP "\fB-r  \fIcommand,command,...\fR"
+/*	Reject the specified commands with a soft (4xx) error code.
 /* .IP "\fB-s \fIcommand,command,...\fR"
 /*	Log the named commands to syslogd.
 /*	Examples of commands that can be logged are HELO, EHLO, LHLO, MAIL,
@@ -98,6 +104,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Global library. */
 
@@ -135,6 +142,7 @@ static int fixed_delay;
 static int disable_esmtp;
 static int enable_lmtp;
 static int pretend_pix;
+static int disable_saslauth;
 
 /* ehlo_response - respond to EHLO command */
 
@@ -145,6 +153,8 @@ static void ehlo_response(SINK_STATE *state)
 	smtp_printf(state->stream, "250-PIPELINING");
     if (!disable_8bitmime)
 	smtp_printf(state->stream, "250-8BITMIME");
+    if (!disable_saslauth)
+	smtp_printf(state->stream, "250-AUTH PLAIN LOGIN");
     smtp_printf(state->stream, "250 ");
     smtp_flush(state->stream);
 }
@@ -205,8 +215,8 @@ static void data_event(int unused_event, char *context)
 static void dot_response(SINK_STATE *state)
 {
     if (enable_lmtp) {
-	while (state->rcpts-- > 0)		/* XXX this could block */
-	    ok_response(state);			/* XXX this flushes too often */
+	while (state->rcpts-- > 0)	/* XXX this could block */
+	    ok_response(state);		/* XXX this flushes too often */
     } else {
 	ok_response(state);
     }
@@ -297,11 +307,14 @@ typedef struct SINK_COMMAND {
 
 #define FLAG_ENABLE	(1<<0)		/* command is enabled */
 #define FLAG_SYSLOG	(1<<1)		/* log the command */
+#define FLAG_HARD_ERR	(1<<2)		/* report hard error */
+#define FLAG_SOFT_ERR	(1<<3)		/* report soft error */
 
 static SINK_COMMAND command_table[] = {
     "helo", helo_response, 0,
     "ehlo", ehlo_response, 0,
     "lhlo", ehlo_response, 0,
+    "auth", ok_response, FLAG_ENABLE,
     "mail", mail_response, FLAG_ENABLE,
     "rcpt", rcpt_response, FLAG_ENABLE,
     "data", data_response, FLAG_ENABLE,
@@ -436,6 +449,16 @@ static int command_read(SINK_STATE *state)
 	smtp_flush(state->stream);
 	return (0);
     }
+    if (cmdp->flags & FLAG_HARD_ERR) {
+	smtp_printf(state->stream, "500 Error: command failed");
+	smtp_flush(state->stream);
+	return (0);
+    }
+    if (cmdp->flags & FLAG_SOFT_ERR) {
+	smtp_printf(state->stream, "450 Error: command failed");
+	smtp_flush(state->stream);
+	return (0);
+    }
     /* We use raw syslog. Sanitize data content and length. */
     if (cmdp->flags & FLAG_SYSLOG)
 	syslog(LOG_INFO, "%s %.100s", command, printable(ptr, '?'));
@@ -503,7 +526,7 @@ static void connect_event(int unused_event, char *context)
     SINK_STATE *state;
     int     fd;
 
-    if ((fd = accept(sock, &sa, &len)) >= 0) {
+    if ((fd = sane_accept(sock, &sa, &len)) >= 0) {
 	if (msg_verbose)
 	    msg_info("connect (%s)",
 #ifdef AF_LOCAL
@@ -555,14 +578,20 @@ int     main(int argc, char **argv)
     /*
      * Parse JCL.
      */
-    while ((ch = GETOPT(argc, argv, "ceh:Ln:pPs:vw:8")) > 0) {
+    while ((ch = GETOPT(argc, argv, "acef:h:Ln:pPr:s:vw:8")) > 0) {
 	switch (ch) {
+	case 'a':
+	    disable_saslauth = 1;
+	    break;
 	case 'c':
 	    count++;
 	    break;
 	case 'e':
 	    disable_esmtp = 1;
 	    break;
+	case 'f':
+	    set_cmds_flags(optarg, FLAG_HARD_ERR);
+	    break;
 	case 'h':
 	    var_myhostname = optarg;
 	    break;
@@ -579,6 +608,9 @@ int     main(int argc, char **argv)
 	    pretend_pix = 1;
 	    disable_esmtp = 1;
 	    break;
+	case 'r':
+	    set_cmds_flags(optarg, FLAG_SOFT_ERR);
+	    break;
 	case 's':
 	    openlog(basename(argv[0]), LOG_PID, LOG_MAIL);
 	    set_cmds_flags(optarg, FLAG_SYSLOG);
diff --git a/postfix/src/smtpstone/smtp-source.c b/postfix/src/smtpstone/smtp-source.c
index c575c5a34..fdb2f8690 100644
--- a/postfix/src/smtpstone/smtp-source.c
+++ b/postfix/src/smtpstone/smtp-source.c
@@ -103,6 +103,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Global library. */
 
@@ -418,7 +419,7 @@ static void start_connect(SESSION *session)
     session->stream = vstream_fdopen(fd, O_RDWR);
     event_enable_write(fd, connect_done, (char *) session);
     smtp_timeout_setup(session->stream, var_timeout);
-    if (connect(fd, sa, sa_length) < 0 && errno != EINPROGRESS)
+    if (sane_connect(fd, sa, sa_length) < 0 && errno != EINPROGRESS)
 	fail_connect(session);
 }
 
diff --git a/postfix/src/trivial-rewrite/resolve.c b/postfix/src/trivial-rewrite/resolve.c
index 8e6f88b0a..a8fa58d71 100644
--- a/postfix/src/trivial-rewrite/resolve.c
+++ b/postfix/src/trivial-rewrite/resolve.c
@@ -46,6 +46,10 @@
 #include 
 #include 
 
+#ifdef STRCASECMP_IN_STRINGS_H
+#include 
+#endif
+
 /* Utility library. */
 
 #include 
@@ -405,6 +409,9 @@ static void resolve_addr(RES_CONTEXT *rp, char *addr,
 		    msg_warn("do not list domain %s in BOTH %s and %s",
 			     rcpt_domain, VAR_VIRT_ALIAS_DOMS,
 			     VAR_RELAY_DOMAINS);
+		if (strcasecmp(rcpt_domain, var_myorigin) == 0)
+		    msg_warn("do not list $%s in %s",
+			     VAR_MYORIGIN, VAR_VIRT_ALIAS_DOMS);
 	    }
 	    vstring_strcpy(channel, MAIL_SERVICE_ERROR);
 	    vstring_sprintf(nexthop, "User unknown%s",
diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in
index 3bffdf56f..5dc045801 100644
--- a/postfix/src/util/Makefile.in
+++ b/postfix/src/util/Makefile.in
@@ -27,7 +27,7 @@ SRCS	= alldig.c argv.c argv_split.c attr_print0.c attr_print64.c \
 	username.c valid_hostname.c vbuf.c vbuf_print.c vstream.c \
 	vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \
 	write_buf.c write_wait.c auto_clnt.c attr_clnt.c attr_scan_plain.c \
-	attr_print_plain.c
+	attr_print_plain.c sane_connect.c
 OBJS	= alldig.o argv.o argv_split.o attr_print0.o attr_print64.o \
 	attr_scan0.o attr_scan64.o base64_code.o basename.o binhash.o \
 	chroot_uid.o clean_env.o close_on_exec.o concatenate.o ctable.o \
@@ -56,7 +56,7 @@ OBJS	= alldig.o argv.o argv_split.o attr_print0.o attr_print64.o \
 	username.o valid_hostname.o vbuf.o vbuf_print.o vstream.o \
 	vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \
 	write_buf.o write_wait.o auto_clnt.o attr_clnt.o attr_scan_plain.o \
-	attr_print_plain.o $(STRCASE)
+	attr_print_plain.o sane_connect.o $(STRCASE)
 HDRS	= argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \
 	connect.h ctable.h dict.h dict_db.h dict_dbm.h dict_env.h \
 	dict_cidr.h dict_ht.h dict_ldap.h dict_mysql.h dict_ni.h dict_nis.h \
@@ -75,7 +75,7 @@ HDRS	= argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \
 	split_at.h stat_as.h stringops.h sys_defs.h timed_connect.h \
 	timed_wait.h trigger.h username.h valid_hostname.h vbuf.h \
 	vbuf_print.h vstream.h vstring.h vstring_vstream.h watchdog.h \
-	auto_clnt.h attr_clnt.h
+	auto_clnt.h attr_clnt.h sane_connect.h
 TESTSRC	= fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
 	stream_test.c dup2_pass_on_exec.c
 WARN	= -W -Wformat -Wimplicit -Wmissing-prototypes \
@@ -891,6 +891,7 @@ inet_connect.o: msg.h
 inet_connect.o: find_inet.h
 inet_connect.o: inet_util.h
 inet_connect.o: iostuff.h
+inet_connect.o: sane_connect.h
 inet_connect.o: connect.h
 inet_connect.o: timed_connect.h
 inet_listen.o: inet_listen.c
@@ -1002,6 +1003,7 @@ msg_syslog.o: stringops.h
 msg_syslog.o: msg.h
 msg_syslog.o: msg_output.h
 msg_syslog.o: msg_syslog.h
+msg_syslog.o: safe.h
 msg_vstream.o: msg_vstream.c
 msg_vstream.o: sys_defs.h
 msg_vstream.o: vstream.h
@@ -1122,6 +1124,10 @@ sane_accept.o: sane_accept.c
 sane_accept.o: sys_defs.h
 sane_accept.o: msg.h
 sane_accept.o: sane_accept.h
+sane_connect.o: sane_connect.c
+sane_connect.o: sys_defs.h
+sane_connect.o: msg.h
+sane_connect.o: sane_connect.h
 sane_link.o: sane_link.c
 sane_link.o: sys_defs.h
 sane_link.o: msg.h
@@ -1229,9 +1235,11 @@ timed_connect.o: timed_connect.c
 timed_connect.o: sys_defs.h
 timed_connect.o: msg.h
 timed_connect.o: iostuff.h
+timed_connect.o: sane_connect.h
 timed_connect.o: timed_connect.h
 timed_read.o: timed_read.c
 timed_read.o: sys_defs.h
+timed_read.o: msg.h
 timed_read.o: iostuff.h
 timed_wait.o: timed_wait.c
 timed_wait.o: sys_defs.h
@@ -1240,6 +1248,7 @@ timed_wait.o: posix_signals.h
 timed_wait.o: timed_wait.h
 timed_write.o: timed_write.c
 timed_write.o: sys_defs.h
+timed_write.o: msg.h
 timed_write.o: iostuff.h
 translit.o: translit.c
 translit.o: sys_defs.h
@@ -1260,6 +1269,7 @@ unix_connect.o: unix_connect.c
 unix_connect.o: sys_defs.h
 unix_connect.o: msg.h
 unix_connect.o: iostuff.h
+unix_connect.o: sane_connect.h
 unix_connect.o: connect.h
 unix_connect.o: timed_connect.h
 unix_listen.o: unix_listen.c
diff --git a/postfix/src/util/clean_env.c b/postfix/src/util/clean_env.c
index edd8675c9..14023dfe2 100644
--- a/postfix/src/util/clean_env.c
+++ b/postfix/src/util/clean_env.c
@@ -12,7 +12,8 @@
 /*	clean_env() reduces the process environment to the bare minimum.
 /*	The function takes a null-terminated list of arguments.
 /*	Each argument specifies the name of an environment variable
-/*	that should be preserved.
+/*	that should be preserved, or specifies a name=value that should
+/*	be entered into the new environment.
 /* DIAGNOSTICS
 /*	Fatal error: out of memory.
 /* SEE ALSO
@@ -33,6 +34,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Utility library. */
 
@@ -49,15 +51,20 @@ void    clean_env(char **preserve_list)
     ARGV   *save_list;
     char   *value;
     char  **cpp;
+    char   *eq;
 
     /*
-     * Preserve selected environment variables.
+     * Preserve or specify selected environment variables.
      */
+#define STRING_AND_LENGTH(x, y) (x), (y)
+
     save_list = argv_alloc(10);
     for (cpp = preserve_list; *cpp; cpp++)
-	if ((value = safe_getenv(*cpp)) != 0)
+	if ((eq = strchr(*cpp, '=')) != 0)
+	    argv_addn(save_list, STRING_AND_LENGTH(*cpp, eq - *cpp),
+		      STRING_AND_LENGTH(eq + 1, strlen(eq + 1)), (char *) 0);
+	else if ((value = safe_getenv(*cpp)) != 0)
 	    argv_add(save_list, *cpp, value, (char *) 0);
-    argv_terminate(save_list);
 
     /*
      * Truncate the process environment, if available. On some systems
@@ -71,7 +78,7 @@ void    clean_env(char **preserve_list)
      */
     for (cpp = save_list->argv; *cpp; cpp += 2)
 	if (setenv(cpp[0], cpp[1], 1))
-	    msg_fatal("setenv: %m");
+	    msg_fatal("setenv(%s, %s): %m", cpp[0], cpp[1]);
 
     /*
      * Cleanup.
diff --git a/postfix/src/util/dict_ldap.c b/postfix/src/util/dict_ldap.c
index c4867ba65..1523c3397 100644
--- a/postfix/src/util/dict_ldap.c
+++ b/postfix/src/util/dict_ldap.c
@@ -16,71 +16,108 @@
 /*
 /*	Arguments:
 /* .IP ldapsource
-/*	The prefix which will be used to obtain configuration parameters
-/*	for this search. If it's 'ldapone', the configuration variables below
-/*	would look like 'ldapone_server_host', 'ldapone_search_base', and so
-/*	on in main.cf.
+/*      Either the path to the LDAP configuration file (if it starts
+/*      with '/' or '.'), or the prefix which will be used to obtain
+/*      configuration parameters for this search.
+/*
+/*      In the first case, the configuration variables below are
+/*      specified in the file as \fBname\fR=\fBvalue\fR pairs.
+/*
+/*      In the second case, the configuration variables are prefixed
+/*      with the value of \fIldapsource\fR and an underscore,
+/*      and they are specified in main.cf.  For example, if this
+/*      value is \fBldapone\fR, the variables would look like
+/*      \fBldapone_server_host\fR, \fBldapone_search_base\fR, and so on.
 /* .IP dummy
 /*	Not used; this argument exists only for compatibility with
 /*	the dict_open(3) interface.
 /* .PP
 /*	Configuration parameters:
-/* .IP \fIldapsource_\fRserver_host
-/*	The host at which all LDAP queries are directed.
-/* .IP \fIldapsource_\fRserver_port
+/* .IP server_host
+/*	Blank-separated list of hosts at which all LDAP queries are directed.
+/*	The host names can also be LDAP URLs if the LDAP client library used
+/*	is OpenLDAP.
+/* .IP server_port
 /*	The port the LDAP server listens on.
-/* .IP \fIldapsource_\fRsearch_base
+/* .IP search_base
 /*	The LDAP search base, for example: \fIO=organization name, C=country\fR.
-/* .IP \fIldapsource_\fRdomain
+/* .IP domain
 /*	If specified, only lookups ending in this value will be queried.
 /*      This can significantly reduce the query load on the LDAP server.
-/* .IP \fIldapsource_\fRtimeout
+/* .IP timeout
 /*	Deadline for LDAP open() and LDAP search() .
-/* .IP \fIldapsource_\fRquery_filter
+/* .IP query_filter
 /*	The filter used to search for directory entries, for example
 /*	\fI(mailacceptinggeneralid=%s)\fR.
-/* .IP \fIldapsource_\fRresult_filter
+/* .IP result_filter
 /*	The filter used to expand results from queries.  Default is
 /*	\fI%s\fR.
-/* .IP \fIldapsource_\fRresult_attribute
+/* .IP result_attribute
 /*	The attribute(s) returned by the search, in which to find
 /*	RFC822 addresses, for example \fImaildrop\fR.
-/* .IP \fIldapsource_\fRspecial_result_attribute
+/* .IP special_result_attribute
 /*	The attribute(s) of directory entries that can contain DNs or URLs.
 /*      If found, a recursive subsequent search is done using their values.
-/* .IP \fIldapsource_\fRscope
+/* .IP scope
 /*	LDAP search scope: sub, base, or one.
-/* .IP \fIldapsource_\fRbind
+/* .IP bind
 /*	Whether or not to bind to the server -- LDAP v3 implementations don't
 /*	require it, which saves some overhead.
-/* .IP \fIldapsource_\fRbind_dn
+/* .IP bind_dn
 /*	If you must bind to the server, do it with this distinguished name ...
-/* .IP \fIldapsource_\fRbind_pw
+/* .IP bind_pw
 /*	\&... and this password.
-/* .IP \fIldapsource_\fRcache (no longer supported)
+/* .IP cache (no longer supported)
 /*	Whether or not to turn on client-side caching.
-/* .IP \fIldapsource_\fRcache_expiry (no longer supported)
+/* .IP cache_expiry (no longer supported)
 /*	If you do cache results, expire them after this many seconds.
-/* .IP \fIldapsource_\fRcache_size (no longer supported)
+/* .IP cache_size (no longer supported)
 /*	The cache size in bytes. Does nothing if the cache is off, of course.
-/* .IP \fIldapsource_\fRrecursion_limit
+/* .IP recursion_limit
 /*	Maximum recursion depth when expanding DN or URL references.
 /*	Queries which exceed the recursion limit fail with
 /*	dict_errno = DICT_ERR_RETRY.
-/* .IP \fIldapsource_\fRexpansion_limit
+/* .IP expansion_limit
 /*	Limit (if any) on the total number of lookup result values. Lookups which
 /*	exceed the limit fail with dict_errno=DICT_ERR_RETRY. Note that
 /*	each value of a multivalued result attribute counts as one result.
-/* .IP \fIldapsource_\fRsize_limit
+/* .IP size_limit
 /*	Limit on the number of entries returned by individual LDAP queries.
 /*	Queries which exceed the limit fail with dict_errno=DICT_ERR_RETRY.
 /*	This is an *entry* count, for any single query performed during the
 /*	possibly recursive lookup.
-/* .IP \fIldapsource_\fRchase_referrals
+/* .IP chase_referrals
 /*	Controls whether LDAP referrals are obeyed.
-/* .IP \fIldapsource_\fRdereference
+/* .IP dereference
 /*	How to handle LDAP aliases. See ldap.h or ldap_open(3) man page.
-/* .IP \fIldapsource_\fRdebuglevel
+/* .IP version
+/*	Specifies the LDAP protocol version to use.  Default is version
+/*	\fI2\fR.
+/* .IP start_tls
+/*	Whether or not to issue STARTTLS upon connection to the server.
+/*	At this time, STARTTLS and LDAP SSL are only available if the
+/*	LDAP client library used is OpenLDAP.  Default is \fIno\fR.
+/* .IP tls_ca_cert_file
+/* 	File containing certificates for all of the X509 Certificate
+/* 	Authorities the client will recognize.  Takes precedence over
+/* 	tls_ca_cert_dir.
+/* .IP tls_ca_cert_dir
+/*	Directory containing X509 Certificate Authority certificates
+/*	in separate individual files.
+/* .IP tls_cert
+/*	File containing client's X509 certificate.
+/* .IP tls_key
+/*	File containing the private key corresponding to
+/*	tls_cert.
+/* .IP tls_require_cert
+/*	Whether or not to request server's X509 certificate and check its
+/*	validity.
+/* .IP tls_random_file
+/*	Path of a file to obtain random bits from when /dev/[u]random is
+/*	not available. Generally set to the name of the EGD/PRNGD socket.
+/* .IP tls_cipher_suite
+/*	Cipher suite to use in SSL/TLS negotiations.
+/* .IP debuglevel
 /*	Debug level.  See 'loglevel' option in slapd.conf(5) man page.
 /*      Currently only in openldap libraries (and derivatives).
 /* SEE ALSO
@@ -142,6 +179,7 @@
 #include "vstring.h"
 #include "dict.h"
 #include "dict_ldap.h"
+#include "stringops.h"
 
 /* AAARGH!! */
 
@@ -174,10 +212,27 @@ typedef struct {
     int     chase_referrals;
     int     debuglevel;
     int     version;
+#ifdef LDAP_API_FEATURE_X_OPENLDAP
+    int     ldap_ssl;
+    int     start_tls;
+    int     tls_require_cert;
+    char   *tls_ca_cert_file;
+    char   *tls_ca_cert_dir;
+    char   *tls_cert;
+    char   *tls_key;
+    char   *tls_random_file;
+    char   *tls_cipher_suite;
+#endif
     LDAP   *ld;
 } DICT_LDAP;
 
-#ifndef LDAP_OPT_NETWORK_TIMEOUT
+typedef struct {
+    char   *(*get_str) (const char *, const char *, const char *, int, int);
+    int     (*get_int) (const char *, const char *, int, int, int);
+    int     (*get_bool) (const char *, const char *, int);
+}       CFG_PARSER;
+
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) || !defined(LDAP_OPT_NETWORK_TIMEOUT)
 /*
  * LDAP connection timeout support.
  */
@@ -198,6 +253,104 @@ static void dict_ldap_logprint(LDAP_CONST char *data)
 }
 
 
+static char *dict_ldap_get_dict_str(const char *opt_dict_name,
+			               const char *name, const char *defval,
+				            int min, int max)
+{
+    const char *strval;
+    int     len;
+
+    if ((strval = (char *) dict_lookup(opt_dict_name, name)) == 0)
+	strval = defval;
+
+    len = strlen(strval);
+    if (min && len < min)
+	msg_fatal("%s: bad string length %d < %d: %s = %s",
+		  opt_dict_name, len, min, name, strval);
+    if (max && len > max)
+	msg_fatal("%s: bad string length %d > %d: %s = %s",
+		  opt_dict_name, len, max, name, strval);
+    return (mystrdup(strval));
+}
+
+static char *dict_ldap_get_mail_str(const char *opt_dict_name,
+			               const char *name, const char *defval,
+				            int min, int max)
+{
+    static VSTRING *buf = 0;
+
+    if (buf == 0)
+	buf = vstring_alloc(15);
+    vstring_sprintf(buf, "%s_%s", opt_dict_name, name);
+    return ((char *) get_mail_conf_str(vstring_str(buf),
+				       defval, min, max));
+}
+
+static int dict_ldap_get_dict_int(const char *opt_dict_name,
+		             const char *name, int defval, int min, int max)
+{
+    const char *strval;
+    int     intval;
+    char    junk;
+
+    if ((strval = (char *) dict_lookup(opt_dict_name, name)) != 0) {
+	if (sscanf(strval, "%d%c", &intval, &junk) != 1)
+	    msg_fatal("%s: bad numerical configuration: %s = %s",
+		      opt_dict_name, name, strval);
+    } else
+	intval = defval;
+    if (min && intval < min)
+	msg_fatal("%s: invalid %s parameter value %d < %d",
+		  opt_dict_name, name, intval, min);
+    if (max && intval > max)
+	msg_fatal("%s: invalid %s parameter value %d > %d",
+		  opt_dict_name, name, intval, max);
+    return (intval);
+}
+
+static int dict_ldap_get_mail_int(const char *opt_dict_name,
+		             const char *name, int defval, int min, int max)
+{
+    static VSTRING *buf = 0;
+
+    if (buf == 0)
+	buf = vstring_alloc(15);
+    vstring_sprintf(buf, "%s_%s", opt_dict_name, name);
+    return (get_mail_conf_int(vstring_str(buf), defval, min, max));
+}
+
+static int dict_ldap_get_dict_bool(const char *opt_dict_name,
+				           const char *name, int defval)
+{
+    const char *strval;
+    int     intval;
+
+    if ((strval = (char *) dict_lookup(opt_dict_name, name)) != 0) {
+	if (strcasecmp(strval, CONFIG_BOOL_YES) == 0) {
+	    intval = 1;
+	} else if (strcasecmp(strval, CONFIG_BOOL_NO) == 0) {
+	    intval = 0;
+	} else {
+	    msg_fatal("%s: bad boolean configuration: %s = %s",
+		      opt_dict_name, name, strval);
+	}
+    } else
+	intval = defval;
+    return (intval);
+}
+
+static int dict_ldap_get_mail_bool(const char *opt_dict_name,
+				           const char *name, int defval)
+{
+    static VSTRING *buf = 0;
+
+    if (buf == 0)
+	buf = vstring_alloc(15);
+    vstring_sprintf(buf, "%s_%s", opt_dict_name, name);
+    return (get_mail_conf_bool(vstring_str(buf), defval));
+}
+
+
 static int dict_ldap_get_errno(LDAP * ld)
 {
     int     rc;
@@ -240,6 +393,67 @@ static int dict_ldap_bind_st(DICT_LDAP *dict_ldap)
     return (ldap_result2error(dict_ldap->ld, res, 1));
 }
 
+#ifdef LDAP_API_FEATURE_X_OPENLDAP
+static void dict_ldap_set_tls_options(DICT_LDAP *dict_ldap)
+{
+    char   *myname = "dict_ldap_set_tls_options";
+    int     rc;
+
+    if (dict_ldap->start_tls || dict_ldap->ldap_ssl) {
+	if (*dict_ldap->tls_random_file) {
+	    if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
+			       dict_ldap->tls_random_file)) != LDAP_SUCCESS)
+		msg_warn("%s: Unable to set tls_random_file to %s: %d: %s",
+			 myname, dict_ldap->tls_random_file,
+			 rc, ldap_err2string(rc));
+	}
+	if (*dict_ldap->tls_ca_cert_file) {
+	    if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
+			      dict_ldap->tls_ca_cert_file)) != LDAP_SUCCESS)
+		msg_warn("%s: Unable to set tls_ca_cert_file to %s: %d: %s",
+			 myname, dict_ldap->tls_ca_cert_file,
+			 rc, ldap_err2string(rc));
+	}
+	if (*dict_ldap->tls_ca_cert_dir) {
+	    if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTDIR,
+			       dict_ldap->tls_ca_cert_dir)) != LDAP_SUCCESS)
+		msg_warn("%s: Unable to set tls_ca_cert_dir to %s: %d: %s",
+			 myname, dict_ldap->tls_ca_cert_dir,
+			 rc, ldap_err2string(rc));
+	}
+	if (*dict_ldap->tls_cert) {
+	    if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CERTFILE,
+				      dict_ldap->tls_cert)) != LDAP_SUCCESS)
+		msg_warn("%s: Unable to set tls_cert to %s: %d: %s",
+			 myname, dict_ldap->tls_cert,
+			 rc, ldap_err2string(rc));
+	}
+	if (*dict_ldap->tls_key) {
+	    if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_KEYFILE,
+				      dict_ldap->tls_key)) != LDAP_SUCCESS)
+		msg_warn("%s: Unable to set tls_key to %s: %d: %s",
+			 myname, dict_ldap->tls_key,
+			 rc, ldap_err2string(rc));
+	}
+	if (*dict_ldap->tls_cipher_suite) {
+	    if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
+			      dict_ldap->tls_cipher_suite)) != LDAP_SUCCESS)
+		msg_warn("%s: Unable to set tls_cipher_suite to %s: %d: %s",
+			 myname, dict_ldap->tls_cipher_suite,
+			 rc, ldap_err2string(rc));
+	}
+	if (dict_ldap->tls_require_cert) {
+	    if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
+			   &(dict_ldap->tls_require_cert))) != LDAP_SUCCESS)
+		msg_warn("%s: Unable to set tls_require_cert to %d: %d: %s",
+			 myname, dict_ldap->tls_require_cert,
+			 rc, ldap_err2string(rc));
+	}
+    }
+}
+
+#endif
+
 /* Establish a connection to the LDAP server. */
 static int dict_ldap_connect(DICT_LDAP *dict_ldap)
 {
@@ -249,7 +463,9 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
 #ifdef LDAP_OPT_NETWORK_TIMEOUT
     struct timeval mytimeval;
 
-#else
+#endif
+
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) || !defined(LDAP_OPT_NETWORK_TIMEOUT)
     void    (*saved_alarm) (int);
 
 #endif
@@ -261,8 +477,13 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
 		 dict_ldap->server_host);
 
 #ifdef LDAP_OPT_NETWORK_TIMEOUT
+#ifdef LDAP_API_FEATURE_X_OPENLDAP
+    dict_ldap_set_tls_options(dict_ldap);
+    ldap_initialize(&(dict_ldap->ld), dict_ldap->server_host);
+#else
     dict_ldap->ld = ldap_init(dict_ldap->server_host,
 			      (int) dict_ldap->server_port);
+#endif
     if (dict_ldap->ld == NULL) {
 	msg_warn("%s: Unable to init LDAP server %s",
 		 myname, dict_ldap->server_host);
@@ -318,7 +539,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
 			    &dict_ldap->version) != LDAP_OPT_SUCCESS)
 	    msg_warn("%s: Unable to get LDAP protocol version", myname);
 	else
-	    msg_warn("%s: Actual Protocol version used is %d.",
+	    msg_info("%s: Actual Protocol version used is %d.",
 		     myname, dict_ldap->version);
     }
 #endif
@@ -368,6 +589,36 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
     }
 #endif
 
+#ifdef LDAP_API_FEATURE_X_OPENLDAP
+    if (dict_ldap->start_tls) {
+	if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR) {
+	    msg_warn("%s: Error setting signal handler for STARTTLS timeout: %m",
+		     myname);
+	    dict_errno = DICT_ERR_RETRY;
+	    return (-1);
+	}
+	alarm(dict_ldap->timeout);
+	if (setjmp(env) == 0)
+	    rc = ldap_start_tls_s(dict_ldap->ld, NULL, NULL);
+	else
+	    rc = LDAP_TIMEOUT;
+	alarm(0);
+
+	if (signal(SIGALRM, saved_alarm) == SIG_ERR) {
+	    msg_warn("%s: Error resetting signal handler after STARTTLS: %m",
+		     myname);
+	    dict_errno = DICT_ERR_RETRY;
+	    return (-1);
+	}
+	if (rc != LDAP_SUCCESS) {
+	    msg_error("%s: Unable to set STARTTLS: %d: %s", myname,
+		      rc, ldap_err2string(rc));
+	    dict_errno = DICT_ERR_RETRY;
+	    return (-1);
+	}
+    }
+#endif
+
     /*
      * If this server requires a bind, do so. Thanks to Sam Tardieu for
      * noticing that the original bind call was broken.
@@ -893,6 +1144,14 @@ static void dict_ldap_close(DICT *dict)
     argv_free(dict_ldap->result_attributes);
     myfree(dict_ldap->bind_dn);
     myfree(dict_ldap->bind_pw);
+#ifdef LDAP_API_FEATURE_X_OPENLDAP
+    myfree(dict_ldap->tls_ca_cert_file);
+    myfree(dict_ldap->tls_ca_cert_dir);
+    myfree(dict_ldap->tls_cert);
+    myfree(dict_ldap->tls_key);
+    myfree(dict_ldap->tls_random_file);
+    myfree(dict_ldap->tls_cipher_suite);
+#endif
     dict_free(dict);
 }
 
@@ -902,7 +1161,15 @@ DICT   *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
 {
     char   *myname = "dict_ldap_open";
     DICT_LDAP *dict_ldap;
-    VSTRING *config_param;
+
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(LDAP_OPT_NETWORK_TIMEOUT)
+    VSTRING *url_list;
+    char   *s,
+           *h;
+
+#endif
+    char   *server_host;
+    CFG_PARSER parser;
     char   *domainlist;
     char   *scope;
     char   *attr;
@@ -917,71 +1184,134 @@ DICT   *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
     dict_ldap->dict.close = dict_ldap_close;
     dict_ldap->dict.flags = dict_flags | DICT_FLAG_FIXED;
 
+    dict_ldap->ld = NULL;
     dict_ldap->ldapsource = mystrdup(ldapsource);
 
-    config_param = vstring_alloc(15);
-    vstring_sprintf(config_param, "%s_server_host", ldapsource);
+    if (ldapsource[0] == '/' || ldapsource[0] == '.') {
+	dict_load_file(ldapsource, ldapsource);
+	parser.get_str = dict_ldap_get_dict_str;
+	parser.get_int = dict_ldap_get_dict_int;
+	parser.get_bool = dict_ldap_get_dict_bool;
+    } else {
+
+	/*
+	 * msg_warn("Defining LDAP attributes in main.cf is deprecated. Use
+	 * ldap:/path/to/file instead");
+	 */
+	parser.get_str = dict_ldap_get_mail_str;
+	parser.get_int = dict_ldap_get_mail_int;
+	parser.get_bool = dict_ldap_get_mail_bool;
+    }
 
-    dict_ldap->server_host =
-	mystrdup((char *) get_mail_conf_str(vstring_str(config_param),
-					    "localhost", 0, 0));
+    server_host = parser.get_str(ldapsource, "server_host",
+				 "localhost", 0, 0);
     if (msg_verbose)
-	msg_info("%s: %s is %s", myname, vstring_str(config_param),
-		 dict_ldap->server_host);
+	msg_info("%s: %s server_host is %s", myname, ldapsource,
+		 server_host);
 
     /*
-     * get configured value of "ldapsource_server_port"; default to LDAP_PORT
-     * (389)
+     * get configured value of "server_port"; default to LDAP_PORT (389)
      */
-    vstring_sprintf(config_param, "%s_server_port", ldapsource);
     dict_ldap->server_port =
-	get_mail_conf_int(vstring_str(config_param), LDAP_PORT, 0, 0);
+	parser.get_int(ldapsource, "server_port", LDAP_PORT, 0, 0);
     if (msg_verbose)
-	msg_info("%s: %s is %d", myname, vstring_str(config_param),
+	msg_info("%s: %s server_port is %d", myname, ldapsource,
 		 dict_ldap->server_port);
 
+    /*
+     * Define LDAP Version.
+     */
+    dict_ldap->version = parser.get_int(ldapsource, "version", 2, 0, 0);
+    switch (dict_ldap->version) {
+    case 2:
+	dict_ldap->version = LDAP_VERSION2;
+	break;
+    case 3:
+	dict_ldap->version = LDAP_VERSION3;
+	break;
+    default:
+	msg_warn("%s: %s Unknown version %d.", myname, ldapsource,
+		 dict_ldap->version);
+	dict_ldap->version = LDAP_VERSION2;
+    }
+
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(LDAP_OPT_NETWORK_TIMEOUT)
+
+    /*
+     * Convert (host, port) pairs to LDAP URLs
+     */
+    url_list = vstring_alloc(32);
+    s = server_host;
+    dict_ldap->ldap_ssl = 0;
+    while ((h = mystrtok(&s, " \t")) != NULL) {
+	if (ldap_is_ldap_url(h)) {
+	    LDAPURLDesc *url_desc;
+	    int     rc;
+
+	    if ((rc = ldap_url_parse(h, &url_desc)) != 0) {
+		msg_error("%s: error parsing URL %s: %d: %s; skipping", myname,
+			  h, rc, ldap_err2string(rc));
+		continue;
+	    }
+	    if (strcasecmp(url_desc->lud_scheme, "ldap") != 0 &&
+		dict_ldap->version != LDAP_VERSION3) {
+		msg_warn("%s: URL scheme %s requires protocol version 3", myname,
+			 url_desc->lud_scheme);
+		dict_ldap->version = LDAP_VERSION3;
+	    }
+	    if (strcasecmp(url_desc->lud_scheme, "ldaps") == 0)
+		dict_ldap->ldap_ssl = 1;
+	    ldap_free_urldesc(url_desc);
+	    vstring_sprintf_append(url_list, " %s", h);
+	} else {
+	    if (strrchr(h, ':'))
+		vstring_sprintf_append(url_list, " ldap://%s", h);
+	    else
+		vstring_sprintf_append(url_list, " ldap://%s:%d", h,
+				       dict_ldap->server_port);
+	}
+    }
+    dict_ldap->server_host = mystrdup(vstring_str(url_list) + 1);
+    if (msg_verbose)
+	msg_info("%s: %s server_host URL is %s", myname, ldapsource,
+		 dict_ldap->server_host);
+    myfree(server_host);
+    vstring_free(url_list);
+#else
+    dict_ldap->server_host = server_host;
+#endif
+
     /*
      * Scope handling thanks to Carsten Hoeger of SuSE.
      */
-    vstring_sprintf(config_param, "%s_scope", ldapsource);
-    scope =
-	(char *) get_mail_conf_str(vstring_str(config_param), "sub", 0, 0);
+    scope = parser.get_str(ldapsource, "scope", "sub", 0, 0);
 
     if (strcasecmp(scope, "one") == 0) {
 	dict_ldap->scope = LDAP_SCOPE_ONELEVEL;
 	if (msg_verbose)
-	    msg_info("%s: %s is LDAP_SCOPE_ONELEVEL", myname,
-		     vstring_str(config_param));
+	    msg_info("%s: %s scope is LDAP_SCOPE_ONELEVEL", myname, ldapsource);
 
     } else if (strcasecmp(scope, "base") == 0) {
 	dict_ldap->scope = LDAP_SCOPE_BASE;
 	if (msg_verbose)
-	    msg_info("%s: %s is LDAP_SCOPE_BASE", myname,
-		     vstring_str(config_param));
+	    msg_info("%s: %s scope is LDAP_SCOPE_BASE", myname, ldapsource);
 
     } else {
 	dict_ldap->scope = LDAP_SCOPE_SUBTREE;
 	if (msg_verbose)
-	    msg_info("%s: %s is LDAP_SCOPE_SUBTREE", myname,
-		     vstring_str(config_param));
+	    msg_info("%s: %s scope is LDAP_SCOPE_SUBTREE", myname, ldapsource);
 
     }
 
     myfree(scope);
 
-    vstring_sprintf(config_param, "%s_search_base", ldapsource);
-    dict_ldap->search_base = mystrdup((char *)
-				      get_mail_conf_str(vstring_str
-							(config_param), "",
-							0, 0));
+    dict_ldap->search_base = parser.get_str(ldapsource, "search_base",
+					    "", 0, 0);
     if (msg_verbose)
-	msg_info("%s: %s is %s", myname, vstring_str(config_param),
+	msg_info("%s: %s search_base is %s", myname, ldapsource,
 		 dict_ldap->search_base);
 
-    vstring_sprintf(config_param, "%s_domain", ldapsource);
-    domainlist =
-	mystrdup((char *) get_mail_conf_str(vstring_str(config_param),
-					    "", 0, 0));
+    domainlist = parser.get_str(ldapsource, "domain", "", 0, 0);
     if (*domainlist) {
 #ifdef MATCH_FLAG_NONE
 	dict_ldap->domain = match_list_init(MATCH_FLAG_NONE,
@@ -1000,219 +1330,212 @@ DICT   *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
     myfree(domainlist);
 
     /*
-     * get configured value of "ldapsource_timeout"; default to 10 seconds
+     * get configured value of "timeout"; default to 10 seconds
      * 
      * Thanks to Manuel Guesdon for spotting that this wasn't really getting
      * set.
      */
-    vstring_sprintf(config_param, "%s_timeout", ldapsource);
     dict_ldap->timeout =
-	get_mail_conf_int(vstring_str(config_param), 10, 0, 0);
+	parser.get_int(ldapsource, "timeout", 10, 0, 0);
     if (msg_verbose)
-	msg_info("%s: %s is %d", myname, vstring_str(config_param),
+	msg_info("%s: %s timeout is %d", myname, ldapsource,
 		 dict_ldap->timeout);
 
-    vstring_sprintf(config_param, "%s_query_filter", ldapsource);
     dict_ldap->query_filter =
-	mystrdup((char *) get_mail_conf_str(vstring_str(config_param),
-					    "(mailacceptinggeneralid=%s)",
-					    0, 0));
+	parser.get_str(ldapsource, "query_filter",
+		       "(mailacceptinggeneralid=%s)", 0, 0);
     if (msg_verbose)
-	msg_info("%s: %s is %s", myname, vstring_str(config_param),
+	msg_info("%s: %s query_filter is %s", myname, ldapsource,
 		 dict_ldap->query_filter);
 
-    vstring_sprintf(config_param, "%s_result_filter", ldapsource);
     dict_ldap->result_filter =
-	mystrdup((char *) get_mail_conf_str(vstring_str(config_param),
-					    "%s",
-					    0, 0));
+	parser.get_str(ldapsource, "result_filter", "%s", 0, 0);
     if (msg_verbose)
-	msg_info("%s: %s is %s", myname, vstring_str(config_param),
+	msg_info("%s: %s result_filter is %s", myname, ldapsource,
 		 dict_ldap->result_filter);
 
     if (strcmp(dict_ldap->result_filter, "%s") == 0) {
 	myfree(dict_ldap->result_filter);
 	dict_ldap->result_filter = NULL;
     }
-    vstring_sprintf(config_param, "%s_result_attribute", ldapsource);
-    attr = mystrdup((char *) get_mail_conf_str(vstring_str(config_param),
-					       "maildrop", 0, 0));
+    attr = parser.get_str(ldapsource, "result_attribute", "maildrop", 0, 0);
     if (msg_verbose)
-	msg_info("%s: %s is %s", myname, vstring_str(config_param), attr);;
+	msg_info("%s: %s result_attribute is %s", myname, ldapsource, attr);;
     dict_ldap->result_attributes = argv_split(attr, " ,\t\r\n");
     dict_ldap->num_attributes = dict_ldap->result_attributes->argc;
+    myfree(attr);
 
-    vstring_sprintf(config_param, "%s_special_result_attribute", ldapsource);
-    attr = mystrdup((char *) get_mail_conf_str(vstring_str(config_param),
-					       "", 0, 0));
+    attr = parser.get_str(ldapsource, "special_result_attribute", "", 0, 0);
     if (msg_verbose)
-	msg_info("%s: %s is %s", myname, vstring_str(config_param), attr);
-
+	msg_info("%s: %s special_result_attribute is %s", myname, ldapsource,
+		 attr);
     if (*attr) {
 	argv_split_append(dict_ldap->result_attributes, attr, " ,\t\r\n");
     }
+    myfree(attr);
 
     /*
-     * get configured value of "ldapsource_bind"; default to true
+     * get configured value of "bind"; default to true
      */
-    vstring_sprintf(config_param, "%s_bind", ldapsource);
-    dict_ldap->bind = get_mail_conf_bool(vstring_str(config_param), 1);
+    dict_ldap->bind = parser.get_bool(ldapsource, "bind", 1);
     if (msg_verbose)
-	msg_info("%s: %s is %d", myname, vstring_str(config_param),
-		 dict_ldap->bind);
+	msg_info("%s: %s bind is %d", myname, ldapsource, dict_ldap->bind);
 
     /*
-     * get configured value of "ldapsource_bind_dn"; default to ""
+     * get configured value of "bind_dn"; default to ""
      */
-    vstring_sprintf(config_param, "%s_bind_dn", ldapsource);
-    dict_ldap->bind_dn = mystrdup((char *)
-				  get_mail_conf_str(vstring_str
-						    (config_param), "", 0,
-						    0));
+    dict_ldap->bind_dn = parser.get_str(ldapsource, "bind_dn", "", 0, 0);
     if (msg_verbose)
-	msg_info("%s: %s is %s", myname, vstring_str(config_param),
+	msg_info("%s: %s bind_dn is %s", myname, ldapsource,
 		 dict_ldap->bind_dn);
 
     /*
-     * get configured value of "ldapsource_bind_pw"; default to ""
+     * get configured value of "bind_pw"; default to ""
      */
-    vstring_sprintf(config_param, "%s_bind_pw", ldapsource);
-    dict_ldap->bind_pw = mystrdup((char *)
-				  get_mail_conf_str(vstring_str
-						    (config_param), "", 0,
-						    0));
+    dict_ldap->bind_pw = parser.get_str(ldapsource, "bind_pw", "", 0, 0);
     if (msg_verbose)
-	msg_info("%s: %s is %s", myname, vstring_str(config_param),
+	msg_info("%s: %s bind_pw is %s", myname, ldapsource,
 		 dict_ldap->bind_pw);
 
     /*
-     * get configured value of "ldapsource_cache"; default to false
+     * get configured value of "cache"; default to false
      */
-    vstring_sprintf(config_param, "%s_cache", ldapsource);
-    tmp = get_mail_conf_bool(vstring_str(config_param), 0);
+    tmp = parser.get_bool(ldapsource, "cache", 0);
     if (tmp)
-	msg_warn("%s: ignoring %s", myname, vstring_str(config_param));
+	msg_warn("%s: %s ignoring cache", myname, ldapsource);
 
     /*
-     * get configured value of "ldapsource_cache_expiry"; default to 30
-     * seconds
+     * get configured value of "cache_expiry"; default to 30 seconds
      */
-    vstring_sprintf(config_param, "%s_cache_expiry", ldapsource);
-    tmp = get_mail_conf_int(vstring_str(config_param), -1, 0, 0);
+    tmp = parser.get_int(ldapsource, "cache_expiry", -1, 0, 0);
     if (tmp >= 0)
-	msg_warn("%s: ignoring %s", myname, vstring_str(config_param));
+	msg_warn("%s: %s ignoring cache_expiry", myname, ldapsource);
 
     /*
-     * get configured value of "ldapsource_cache_size"; default to 32k
+     * get configured value of "cache_size"; default to 32k
      */
-    vstring_sprintf(config_param, "%s_cache_size", ldapsource);
-    tmp = get_mail_conf_int(vstring_str(config_param), -1, 0, 0);
+    tmp = parser.get_int(ldapsource, "cache_size", -1, 0, 0);
     if (tmp >= 0)
-	msg_warn("%s: ignoring %s", myname, vstring_str(config_param));
+	msg_warn("%s: %s ignoring cache_size", myname, ldapsource);
 
     /*
-     * get configured value of "ldapsource_recursion_limit"; default to 1000
+     * get configured value of "recursion_limit"; default to 1000
      */
-    vstring_sprintf(config_param, "%s_recursion_limit", ldapsource);
-    dict_ldap->recursion_limit = get_mail_conf_int(vstring_str(config_param),
-						   1000, 1, 0);
+    dict_ldap->recursion_limit = parser.get_int(ldapsource, "recursion_limit",
+						1000, 1, 0);
     if (msg_verbose)
-	msg_info("%s: %s is %ld", myname, vstring_str(config_param),
+	msg_info("%s: %s recursion_limit is %ld", myname, ldapsource,
 		 dict_ldap->recursion_limit);
 
     /*
-     * get configured value of "ldapsource_expansion_limit"; default to 1000
+     * get configured value of "expansion_limit"; default to 0
      */
-    vstring_sprintf(config_param, "%s_expansion_limit", ldapsource);
-    dict_ldap->expansion_limit = get_mail_conf_int(vstring_str(config_param),
-						   0, 0, 0);
+    dict_ldap->expansion_limit = parser.get_int(ldapsource, "expansion_limit",
+						0, 0, 0);
     if (msg_verbose)
-	msg_info("%s: %s is %ld", myname, vstring_str(config_param),
+	msg_info("%s: %s expansion_limit is %ld", myname, ldapsource,
 		 dict_ldap->expansion_limit);
 
     /*
-     * get configured value of "ldapsource_size_limit"; default to
-     * expansion_limit
+     * get configured value of "size_limit"; default to expansion_limit
      */
-    vstring_sprintf(config_param, "%s_size_limit", ldapsource);
-    dict_ldap->size_limit = get_mail_conf_int(vstring_str(config_param),
-					      dict_ldap->expansion_limit,
-					      0, 0);
+    dict_ldap->size_limit = parser.get_int(ldapsource, "size_limit",
+					   dict_ldap->expansion_limit,
+					   0, 0);
     if (msg_verbose)
-	msg_info("%s: %s is %ld", myname, vstring_str(config_param),
+	msg_info("%s: %s size_limit is %ld", myname, ldapsource,
 		 dict_ldap->size_limit);
 
     /*
      * Alias dereferencing suggested by Mike Mattice.
      */
-    vstring_sprintf(config_param, "%s_dereference", ldapsource);
-    dict_ldap->dereference = get_mail_conf_int(vstring_str(config_param), 0, 0,
-					       0);
-
-    /*
-     * Define LDAP Version.
-     */
-    vstring_sprintf(config_param, "%s_version", ldapsource);
-    dict_ldap->version = get_mail_conf_int(vstring_str(config_param), 2, 0,
-					   0);
-    switch (dict_ldap->version) {
-    case 2:
-	dict_ldap->version = LDAP_VERSION2;
-	break;
-    case 3:
-	dict_ldap->version = LDAP_VERSION3;
-	break;
-    default:
-	msg_warn("%s: Unknown version %d.", myname, dict_ldap->version);
-	dict_ldap->version = LDAP_VERSION2;
-    }
-
-    /*
-     * Make sure only valid options for alias dereferencing are used.
-     */
+    dict_ldap->dereference = parser.get_int(ldapsource, "dereference", 0, 0,
+					    0);
     if (dict_ldap->dereference < 0 || dict_ldap->dereference > 3) {
-	msg_warn("%s: Unrecognized value %d specified for %s; using 0",
-		 myname, dict_ldap->dereference, vstring_str(config_param));
+	msg_warn("%s: %s Unrecognized value %d specified for dereference; using 0",
+		 myname, ldapsource, dict_ldap->dereference);
 	dict_ldap->dereference = 0;
     }
     if (msg_verbose)
-	msg_info("%s: %s is %d", myname, vstring_str(config_param),
+	msg_info("%s: %s dereference is %d", myname, ldapsource,
 		 dict_ldap->dereference);
 
     /* Referral chasing */
-    vstring_sprintf(config_param, "%s_chase_referrals", ldapsource);
-    dict_ldap->chase_referrals = get_mail_conf_bool(vstring_str(config_param), 0);
+    dict_ldap->chase_referrals = parser.get_bool(ldapsource, "chase_referrals",
+						 0);
     if (msg_verbose)
-	msg_info("%s: %s is %d", myname, vstring_str(config_param),
+	msg_info("%s: %s chase_referrals is %d", myname, ldapsource,
 		 dict_ldap->chase_referrals);
 
+#ifdef LDAP_API_FEATURE_X_OPENLDAP
+
     /*
-     * Debug level.
+     * TLS options
      */
-#if defined(LDAP_OPT_DEBUG_LEVEL) && defined(LBER_OPT_LOG_PRINT_FN)
-    vstring_sprintf(config_param, "%s_debuglevel", ldapsource);
-    dict_ldap->debuglevel = get_mail_conf_int(vstring_str(config_param), 0, 0,
-					      0);
+    /* get configured value of "start_tls"; default to no */
+    dict_ldap->start_tls = parser.get_bool(ldapsource, "start_tls", 0);
     if (msg_verbose)
-	msg_info("%s: %s is %d", myname, vstring_str(config_param),
-		 dict_ldap->debuglevel);
+	msg_info("%s: %s start_tls is %d", myname, ldapsource,
+		 dict_ldap->start_tls);
+    if (dict_ldap->start_tls && dict_ldap->version < LDAP_VERSION3) {
+	msg_warn("%s: %s start_tls requires protocol version 3", myname, ldapsource);
+	dict_ldap->version = LDAP_VERSION3;
+    }
+    /* get configured value of "tls_require_cert"; default to no */
+    dict_ldap->tls_require_cert = parser.get_bool(ldapsource, "tls_require_cert", 0);
+    if (msg_verbose)
+	msg_info("%s: %s tls_require_cert is %d", myname, ldapsource,
+		 dict_ldap->tls_require_cert);
+    /* get configured value of "tls_ca_cert_file"; default "" */
+    dict_ldap->tls_ca_cert_file = parser.get_str(ldapsource, "tls_ca_cert_file",
+						 "", 0, 0);
+    if (msg_verbose)
+	msg_info("%s: %s tls_ca_cert_file is %s", myname, ldapsource,
+		 dict_ldap->tls_ca_cert_file);
+    /* get configured value of "tls_ca_cert_dir"; default "" */
+    dict_ldap->tls_ca_cert_dir = parser.get_str(ldapsource, "tls_ca_cert_dir",
+						"", 0, 0);
+    if (msg_verbose)
+	msg_info("%s: %s tls_ca_cert_dir is %s", myname, ldapsource,
+		 dict_ldap->tls_ca_cert_dir);
+    /* get configured value of "tls_cert"; default "" */
+    dict_ldap->tls_cert = parser.get_str(ldapsource, "tls_cert",
+					 "", 0, 0);
+    if (msg_verbose)
+	msg_info("%s: %s tls_cert is %s", myname, ldapsource,
+		 dict_ldap->tls_cert);
+    /* get configured value of "tls_key"; default "" */
+    dict_ldap->tls_key = parser.get_str(ldapsource, "tls_key",
+					"", 0, 0);
+    if (msg_verbose)
+	msg_info("%s: %s tls_key is %s", myname, ldapsource,
+		 dict_ldap->tls_key);
+    /* get configured value of "tls_random_file"; default "" */
+    dict_ldap->tls_random_file = parser.get_str(ldapsource,
+						"tls_random_file", "", 0, 0);
+    if (msg_verbose)
+	msg_info("%s: %s tls_random_file is %s", myname, ldapsource,
+		 dict_ldap->tls_random_file);
+    /* get configured value of "tls_cipher_suite"; default "" */
+    dict_ldap->tls_cipher_suite = parser.get_str(ldapsource,
+					      "tls_cipher_suite", "", 0, 0);
+    if (msg_verbose)
+	msg_info("%s: %s tls_cipher_suite is %s", myname, ldapsource,
+		 dict_ldap->tls_cipher_suite);
 #endif
 
-    dict_ldap_connect(dict_ldap);
-
     /*
-     * if dict_ldap_connect() set dict_errno, free dict_ldap and abort.
+     * Debug level.
      */
-    if (dict_errno) {
-	if (dict_ldap->ld)
-	    ldap_unbind(dict_ldap->ld);
-
-	myfree((char *) dict_ldap);
-	return (0);
-    }
+#if defined(LDAP_OPT_DEBUG_LEVEL) && defined(LBER_OPT_LOG_PRINT_FN)
+    dict_ldap->debuglevel = parser.get_int(ldapsource, "debuglevel", 0, 0, 0);
+    if (msg_verbose)
+	msg_info("%s: %s debuglevel is %d", myname, ldapsource,
+		 dict_ldap->debuglevel);
+#endif
 
     /*
-     * Otherwise, we're all set. Return the new dict_ldap structure.
+     * Return the new dict_ldap structure.
      */
     return (DICT_DEBUG (&dict_ldap->dict));
 }
diff --git a/postfix/src/util/file_limit.c b/postfix/src/util/file_limit.c
index 91066dacd..5cfae4e50 100644
--- a/postfix/src/util/file_limit.c
+++ b/postfix/src/util/file_limit.c
@@ -62,8 +62,8 @@ off_t   get_file_limit(void)
 #ifdef USE_ULIMIT
     if ((limit = ulimit(UL_GETFSIZE, 0)) < 0)
 	msg_fatal("ulimit: %m");
-    if (limit > INT_MAX / ULIMIT_BLOCK_SIZE)
-	limit = INT_MAX / ULIMIT_BLOCK_SIZE;
+    if (limit > OFF_T_MAX / ULIMIT_BLOCK_SIZE)
+	limit = OFF_T_MAX / ULIMIT_BLOCK_SIZE;
     return (limit * ULIMIT_BLOCK_SIZE);
 #else
     struct rlimit rlim;
@@ -71,7 +71,7 @@ off_t   get_file_limit(void)
     if (getrlimit(RLIMIT_FSIZE, &rlim) < 0)
 	msg_fatal("getrlimit: %m");
     limit = rlim.rlim_cur;
-    return (limit < 0 ? INT_MAX : rlim.rlim_cur);
+    return (limit < 0 ? OFF_T_MAX : rlim.rlim_cur);
 #endif						/* USE_ULIMIT */
 }
 
diff --git a/postfix/src/util/inet_connect.c b/postfix/src/util/inet_connect.c
index 152e49846..3c76734cd 100644
--- a/postfix/src/util/inet_connect.c
+++ b/postfix/src/util/inet_connect.c
@@ -63,6 +63,7 @@
 #include "find_inet.h"
 #include "inet_util.h"
 #include "iostuff.h"
+#include "sane_connect.h"
 #include "connect.h"
 #include "timed_connect.h"
 
@@ -114,7 +115,7 @@ int     inet_connect(const char *addr, int block_mode, int timeout)
      */
     else {
 	non_blocking(sock, block_mode);
-	if (connect(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0
+	if (sane_connect(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0
 	    && errno != EINPROGRESS) {
 	    close(sock);
 	    return (-1);
diff --git a/postfix/src/util/inet_listen.c b/postfix/src/util/inet_listen.c
index 91347c95a..2a846b39b 100644
--- a/postfix/src/util/inet_listen.c
+++ b/postfix/src/util/inet_listen.c
@@ -116,5 +116,8 @@ int     inet_listen(const char *addr, int backlog, int block_mode)
 
 int     inet_accept(int fd)
 {
-    return (sane_accept(fd, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0));
+    struct sockaddr_in sin;
+    SOCKADDR_SIZE len = sizeof(sin);
+
+    return (sane_accept(fd, (struct sockaddr *) & sin, &len));
 }
diff --git a/postfix/src/util/msg_syslog.c b/postfix/src/util/msg_syslog.c
index fb9301457..5af7cb950 100644
--- a/postfix/src/util/msg_syslog.c
+++ b/postfix/src/util/msg_syslog.c
@@ -49,6 +49,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Application-specific. */
 
@@ -57,6 +58,7 @@
 #include "msg.h"
 #include "msg_output.h"
 #include "msg_syslog.h"
+#include "safe.h"
 
  /*
   * Stay a little below the 2048-byte limit of older syslog()
@@ -167,6 +169,13 @@ void    msg_syslog_init(const char *name, int logopt, int facility)
 {
     static int first_call = 1;
 
+    /*
+     * XXX If this program is set-gid, then TZ must not be trusted.
+     * This scrubbing code is in the wrong place.
+     */
+    if (unsafe())
+	putenv("TZ=");
+    tzset();
     openlog(name, LOG_NDELAY | logopt, facility);
     if (first_call) {
 	first_call = 0;
diff --git a/postfix/src/util/sane_accept.c b/postfix/src/util/sane_accept.c
index a28e5bf93..30a3d8533 100644
--- a/postfix/src/util/sane_accept.c
+++ b/postfix/src/util/sane_accept.c
@@ -13,6 +13,9 @@
 /* DESCRIPTION
 /*	sane_accept() implements the accept(2) socket call, and maps
 /*	known harmless error results to EAGAIN.
+/*
+/*	If the buf and len arguments are not null, then additional
+/*	workarounds may be enabled that depend on the socket type.
 /* BUGS
 /*	Bizarre systems may have other harmless error results. Such
 /*	systems encourage programers to ignore error results, and
@@ -89,5 +92,21 @@ int     sane_accept(int sock, struct sockaddr * sa, SOCKADDR_SIZE *len)
 	    }
 	}
     }
+
+    /*
+     * XXX Solaris select() produces false read events, so that read() blocks
+     * forever on a blocking socket, and fails with EAGAIN on a non-blocking
+     * socket. Turning on keepalives will fix a blocking socket provided that
+     * the kernel's keepalive timer expires before the Postfix watchdog
+     * timer.
+     */
+#if defined(BROKEN_READ_SELECT_ON_TCP_SOCKET) && defined(SO_KEEPALIVE)
+    else if (sa != 0 && sa->sa_family == AF_INET) {
+	int     on = 1;
+
+	(void) setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
+			  (char *) &on, sizeof(on));
+    }
+#endif
     return (fd);
 }
diff --git a/postfix/src/util/sane_connect.c b/postfix/src/util/sane_connect.c
new file mode 100644
index 000000000..cdb2874bc
--- /dev/null
+++ b/postfix/src/util/sane_connect.c
@@ -0,0 +1,63 @@
+/*++
+/* NAME
+/*	sane_connect 3
+/* SUMMARY
+/*	sanitize connect() results
+/* SYNOPSIS
+/*	#include 
+/*
+/*	int	sane_connect(sock, buf, len)
+/*	int	sock;
+/*	struct sockaddr	*buf;
+/*	SOCKADDR_SIZE *len;
+/* DESCRIPTION
+/*	sane_connect() implements the accept(2) socket call, and maps
+/*	known harmless error results to EAGAIN.
+/* BUGS
+/*	Bizarre systems may have other harmless error results. Such
+/*	systems encourage programers to ignore error results, and
+/*	penalizes programmers who code defensively.
+/* LICENSE
+/* .ad
+/* .fi
+/*	The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*	Wietse Venema
+/*	IBM T.J. Watson Research
+/*	P.O. Box 704
+/*	Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include "sys_defs.h"
+#include 
+#include 
+
+/* Utility library. */
+
+#include "msg.h"
+#include "sane_connect.h"
+
+/* sane_connect - sanitize connect() results */
+
+int     sane_connect(int sock, struct sockaddr * sa, SOCKADDR_SIZE len)
+{
+
+    /*
+     * XXX Solaris select() produces false read events, so that read() blocks
+     * forever on a blocking socket, and fails with EAGAIN on a non-blocking
+     * socket. Turning on keepalives will fix a blocking socket provided that
+     * the kernel's keepalive timer expires before the Postfix watchdog
+     * timer.
+     */
+#if defined(BROKEN_READ_SELECT_ON_TCP_SOCKET) && defined(SO_KEEPALIVE)
+    if (sa->sa_family == AF_INET) {
+	int     on = 1;
+
+	(void) setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
+			  (char *) &on, sizeof(on));
+    }
+#endif
+    return (connect(sock, sa, len));
+}
diff --git a/postfix/src/util/sane_connect.h b/postfix/src/util/sane_connect.h
new file mode 100644
index 000000000..1f023b0e6
--- /dev/null
+++ b/postfix/src/util/sane_connect.h
@@ -0,0 +1,29 @@
+#ifndef _SANE_CONNECT_H_
+#define _SANE_CONNECT_H_
+
+/*++
+/* NAME
+/*	sane_connect 3h
+/* SUMMARY
+/*	sanitize connect() results
+/* SYNOPSIS
+/*	#include 
+/* DESCRIPTION
+/* .nf
+
+ /* External interface. */
+
+extern int sane_connect(int, struct sockaddr *, SOCKADDR_SIZE);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*	The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*	Wietse Venema
+/*	IBM T.J. Watson Research
+/*	P.O. Box 704
+/*	Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
diff --git a/postfix/src/util/sys_defs.h b/postfix/src/util/sys_defs.h
index 9223422e1..db080b1eb 100644
--- a/postfix/src/util/sys_defs.h
+++ b/postfix/src/util/sys_defs.h
@@ -261,7 +261,7 @@ extern int opterr;
 #define LOCAL_CONNECT	stream_connect
 #define LOCAL_TRIGGER	stream_trigger
 #define HAS_VOLATILE_LOCKS
-#define BROKEN_READ_SELECT_ON_BLOCKING_SOCKET
+#define BROKEN_READ_SELECT_ON_TCP_SOCKET
 
 /*
  * Allow build environment to override paths.
@@ -1087,6 +1087,17 @@ typedef int pid_t;
 #else
 #define SCANFLIKE(x,y)
 #endif
+#endif
+
+ /*
+  * Bit banging!! There is no official constant that defines the INT_MAX
+  * equivalent of the off_t type. Wietse came up with the following macro
+  * that works as long as off_t is some two's complement number.
+  */
+#include 
+#define __MAXINT__(T) ((T) (((T)1 << ((sizeof(T) * CHAR_BIT) - 1) ^ ((T) -1))))
+#ifndef OFF_T_MAX
+#define OFF_T_MAX __MAXINT__(off_t)
 #endif
 
  /*
diff --git a/postfix/src/util/timed_connect.c b/postfix/src/util/timed_connect.c
index c40fe3e63..ee4e150b1 100644
--- a/postfix/src/util/timed_connect.c
+++ b/postfix/src/util/timed_connect.c
@@ -59,6 +59,7 @@
 
 #include "msg.h"
 #include "iostuff.h"
+#include "sane_connect.h"
 #include "timed_connect.h"
 
 /* timed_connect - connect with deadline */
@@ -78,7 +79,7 @@ int     timed_connect(int sock, struct sockaddr * sa, int len, int timeout)
     /*
      * Start the connection, and handle all possible results.
      */
-    if (connect(sock, sa, len) == 0)
+    if (sane_connect(sock, sa, len) == 0)
 	return (0);
     if (errno != EINPROGRESS)
 	return (-1);
diff --git a/postfix/src/util/timed_read.c b/postfix/src/util/timed_read.c
index 1a29a69f9..509004ba3 100644
--- a/postfix/src/util/timed_read.c
+++ b/postfix/src/util/timed_read.c
@@ -48,23 +48,36 @@
 
 #include 
 #include 
+#include 
 
 /* Utility library. */
 
-#include "iostuff.h"
+#include 
+#include 
 
 /* timed_read - read with deadline */
 
 int     timed_read(int fd, void *buf, unsigned len,
 		           int timeout, void *unused_context)
 {
+    int     ret;
 
     /*
      * Wait for a limited amount of time for something to happen. If nothing
      * happens, report an ETIMEDOUT error.
+     * 
+     * XXX Solaris 8 read() fails with EAGAIN after read-select() returns
+     * success.
      */
-    if (timeout > 0 && read_wait(fd, timeout) < 0)
-	return (-1);
-    else
-	return (read(fd, buf, len));
+    for (;;) {
+	if (timeout > 0 && read_wait(fd, timeout) < 0)
+	    return (-1);
+	if ((ret = read(fd, buf, len)) < 0 && timeout > 0 && errno == EAGAIN) {
+	    msg_warn("read() returns EAGAIN on a readable file descriptor!");
+	    msg_warn("pausing to avoid going into a tight select/read loop!");
+	    sleep(1);
+	} else {
+	    return (ret);
+	}
+    }
 }
diff --git a/postfix/src/util/timed_write.c b/postfix/src/util/timed_write.c
index 723bf036d..3089a8390 100644
--- a/postfix/src/util/timed_write.c
+++ b/postfix/src/util/timed_write.c
@@ -48,23 +48,42 @@
 
 #include 
 #include 
+#include 
 
 /* Utility library. */
 
-#include "iostuff.h"
+#include 
+#include 
 
 /* timed_write - write with deadline */
 
 int     timed_write(int fd, void *buf, unsigned len,
 		            int timeout, void *unused_context)
 {
+    int     ret;
 
     /*
      * Wait for a limited amount of time for something to happen. If nothing
      * happens, report an ETIMEDOUT error.
+     * 
+     * XXX Solaris 8 read() fails with EAGAIN after read-select() returns
+     * success. The code below exists just in case their write implementation
+     * is equally broken.
+     * 
+     * This condition may also be found on systems where select() returns
+     * success on pipes with less than PIPE_BUF bytes of space, and with
+     * badly designed software where multiple writers are fighting for access
+     * to the same resource.
      */
-    if (timeout > 0 && write_wait(fd, timeout) < 0)
-	return (-1);
-    else
-	return (write(fd, buf, len));
+    for (;;) {
+	if (timeout > 0 && write_wait(fd, timeout) < 0)
+	    return (-1);
+	if ((ret = write(fd, buf, len)) < 0 && timeout > 0 && errno == EAGAIN) {
+	    msg_warn("write() returns EAGAIN on a writable file descriptor!");
+	    msg_warn("pausing to avoid going into a tight select/write loop!");
+	    sleep(1);
+	} else {
+	    return (ret);
+	}
+    }
 }
diff --git a/postfix/src/util/unix_connect.c b/postfix/src/util/unix_connect.c
index 0890f7e1c..5ae452543 100644
--- a/postfix/src/util/unix_connect.c
+++ b/postfix/src/util/unix_connect.c
@@ -50,6 +50,7 @@
 
 #include "msg.h"
 #include "iostuff.h"
+#include "sane_connect.h"
 #include "connect.h"
 #include "timed_connect.h"
 
@@ -99,7 +100,7 @@ int     unix_connect(const char *addr, int block_mode, int timeout)
      */
     else {
 	non_blocking(sock, block_mode);
-	if (connect(sock, (struct sockaddr *) & sun, sizeof(sun)) < 0
+	if (sane_connect(sock, (struct sockaddr *) & sun, sizeof(sun)) < 0
 	    && errno != EINPROGRESS) {
 	    close(sock);
 	    return (-1);