]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.11-20130530-nonprod 20130405-nonprod
authorWietse Venema <wietse@porcupine.org>
Thu, 30 May 2013 13:57:35 +0000 (09:57 -0400)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Mon, 13 Jan 2014 05:43:15 +0000 (00:43 -0500)
76 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/README_FILES/DATABASE_README
postfix/RELEASE_NOTES
postfix/WISHLIST
postfix/conf/access
postfix/conf/canonical
postfix/conf/virtual
postfix/html/DATABASE_README.html
postfix/html/access.5.html
postfix/html/canonical.5.html
postfix/html/cidr_table.5.html
postfix/html/local.8.html
postfix/html/pipe.8.html
postfix/html/postconf.5.html
postfix/html/postscreen.8.html
postfix/html/smtpd.8.html
postfix/html/trivial-rewrite.8.html
postfix/html/virtual.5.html
postfix/man/man5/access.5
postfix/man/man5/canonical.5
postfix/man/man5/cidr_table.5
postfix/man/man5/postconf.5
postfix/man/man5/virtual.5
postfix/man/man8/local.8
postfix/man/man8/pipe.8
postfix/man/man8/postscreen.8
postfix/man/man8/smtpd.8
postfix/man/man8/trivial-rewrite.8
postfix/mantools/postlink
postfix/proto/DATABASE_README.html
postfix/proto/access
postfix/proto/canonical
postfix/proto/cidr_table
postfix/proto/postconf.proto
postfix/proto/virtual
postfix/src/dns/dns_rr.c
postfix/src/global/mail_addr_find.c
postfix/src/global/mail_params.c
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/global/resolve_clnt.c
postfix/src/global/split_addr.c
postfix/src/global/split_addr.h
postfix/src/global/strip_addr.c
postfix/src/global/strip_addr.h
postfix/src/global/strip_addr.ref
postfix/src/local/bounce_workaround.c
postfix/src/local/forward.c
postfix/src/local/local.c
postfix/src/local/local_expand.c
postfix/src/local/recipient.c
postfix/src/local/resolve.c
postfix/src/oqmgr/qmgr_message.c
postfix/src/pipe/pipe.c
postfix/src/postscreen/Makefile.in
postfix/src/postscreen/postscreen.c
postfix/src/postscreen/postscreen.h
postfix/src/postscreen/postscreen_early.c
postfix/src/postscreen/postscreen_state.c
postfix/src/postscreen/postscreen_tests.c
postfix/src/posttls-finger/posttls-finger.c
postfix/src/posttls-finger/tlsmgrmem.c
postfix/src/posttls-finger/tlsmgrmem.h
postfix/src/qmgr/qmgr_message.c
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd_check.c
postfix/src/smtpd/smtpd_proxy.c
postfix/src/tls/tls_dane.c
postfix/src/tls/tls_misc.c
postfix/src/trivial-rewrite/resolve.c
postfix/src/trivial-rewrite/transport.c
postfix/src/trivial-rewrite/trivial-rewrite.c
postfix/src/util/argv.c
postfix/src/util/dict.c
postfix/src/util/poll_fd.c

index 88f1aa130f165bbba22cf4b9de3ff15046bdefb1..bd70a8bcbdb78d6703cdc28b00e2fe76a9c80738 100644 (file)
 -TNAME_CODE
 -TNAME_MASK
 -TNBBIO
+-TOPTIONS
 -TPC_DBMS_INFO
 -TPC_EVAL_CTX
 -TPC_MASTER_ENT
 -TSSL
 -TSSL_CTX
 -TSSL_SESSION
+-TSTATE
 -TSTRING_LIST
 -TSTRING_TABLE
 -TSYS_EXITS_DETAIL
 -TTLSMGR_SCACHE
 -TTLSP_STATE
 -TTLS_APPL_STATE
+-TTLS_CERTS
 -TTLS_CLIENT_INIT_PROPS
 -TTLS_CLIENT_START_PROPS
--TTLS_CERTS
 -TTLS_DANE
 -TTLS_PKEYS
 -TTLS_PRNG_SEED_INFO
 -Tsize_t
 -Tssize_t
 -Ttime_t
--TRESPONSE
--TSTATE
--TOPTIONS
index acea1db13a79f5db6ab13e7930ac98749909aa27..e608f5a925c6ff1477e37d4db5271e0faebe76d2 100644 (file)
@@ -18408,8 +18408,27 @@ Apologies for any names omitted.
        Documentation: in smtpd.c, the comment that justifies the
        454 reply for "TLS unavailable" cited the wrong RFC.
 
+20130404
+
+       Human factors: warning when a main.cf parameter has multiple
+       entries with different values.  File: util/dict.c.
+
 20130405
 
+       Feature: the recipient_delimiter parameter can now specify
+       a set of characters. A user name is now separated from its
+       address extension by the first character that matches the
+       recipient_delimiter set.  Files: proto/postconf.proto,
+       src/global/mail_addr_find.c, src/global/mail_params.c,
+       src/global/split_addr.c, src/global/split_addr.h,
+       src/global/strip_addr.c, src/global/strip_addr.h,
+       src/global/strip_addr.ref, src/local/bounce_workaround.c,
+       src/local/local.c, src/local/local_expand.c, src/local/recipient.c,
+       src/local/resolve.c, src/oqmgr/qmgr_message.c, src/pipe/pipe.c,
+       src/qmgr/qmgr_message.c, src/smtpd/smtpd.c,
+       src/smtpd/smtpd_check.c, src/trivial-rewrite/transport.c,
+       src/trivial-rewrite/trivial-rewrite.c.
+
        Feature: support for trust anchors, i.e. CA certificates
        or public keys that will be used instead of conventional
        root certificates, and revised fingerprint support.  This
@@ -18423,6 +18442,21 @@ Apologies for any names omitted.
        tls/tls_fprint.c, tls/tls_misc.c, tls/tls_verify.c,
        util/argv.c, util/argv.h.
 
+20130409
+
+       Documentation: pointers to other actions under "ACCEPT
+       ACTIONS" and "REJECT ACTIONS". File: proto/access.
+
+20130410
+
+       Cleanup: more uniform permutation in dns_rr() by Victor
+       Duchovni & Son. File: dns/dns_rr.c.
+
+20130411
+
+       Documentation: clarified text about result formats. Files:
+       proto/canonical, proto/virtual.
+
 20130414
 
        Cleanup: the SMTP client connection management code now
@@ -18515,6 +18549,17 @@ Apologies for any names omitted.
        posttls-finger/tlsmgrmem.c, posttls-finger/tlsmgrmem.h,
        tls/tls.h, tls/tls_misc.c.
 
+20130423
+
+       Bugfix (introduced: Postfix 2.0): when myhostname is not
+       listed in mydestination, the trivial-rewrite resolver may
+       log "do not list <myhostname value> in both mydestination
+       and <name of non-mydestination domain list>".  The fix is
+       to re-resolve a domain-less address after adding $myhostname
+       as the surrogate domain, so that it pops out with the right
+       address-class label.  Problem reported by Quanah Gibson-Mount.
+       File: trivial-rewrite/resolve.c.
+
 20130425
 
        Non-production fixes: revert to using proxies (sender,
@@ -18558,8 +18603,42 @@ Apologies for any names omitted.
        smtp/smtp.c, smtp/smtp.h, smtp/smtp_params.c,
        smtp/smtp_tls_policy.c, tls/tls.h, tls/tls_level.c.
 
+20130512
+
+       Feature: allow an SMTP client to skip postscreen(8) tests
+       before or after the 220 greeting, based on its DNSBL score.
+       Suggested by Rob McGee (/dev/rob0). Files: mantools/postlink,
+       proto/postconf.proto, global/mail_params.h,
+       postscreen/postscreen.c, postscreen/postscreen.h,
+       postscreen/postscreen_early.c, postscreen/postscreen_state.c,
+       postscreen/postscreen_tests.c.
+
+20130513
+
+       Bugfix (introduced: 20130512): postscreen logged no "PASS
+       NEW" event when the pregreet tests were turned off and the
+       postscreen_dnsbl_whitelist_treshold feature was turned on.
+       Reported by Rob McGee (/dev/rob0). Files: postscreen/postscreen.h,
+       postscreen/postscreen_early.c.
+
+       Bugfix (introduced: 20130512): postscreen panic because the
+       logic for dnsbl result retrieval was changed. Reported by
+       Noel Jones. File: postscreen/postscreen_early.c.
+
+20130517
+
+       Cleanup: just like the postscreen DNS block test will use
+       partial scores when some DNS lookup result is unavailable,
+       the postscreen_dnsbl_whitelist_treshold feature will now
+       use partial scores instead of ignoring them.  File:
+       postscreen/postscreen_early.c.
+
 20130518
 
+       Bugfix (introduced: 1997): memory leak after error while
+       forwarding mail through the cleanup server. Viktor found
+       one, Wietse eliminated the rest.  File: local/forward.c.
+
        Feature: posttls-finger protocol and cipher grade selection
        options.  Leave protocol debug flags active across reconnects,
        only suppress redundant logging of the certificate details.
@@ -18579,4 +18658,3 @@ Apologies for any names omitted.
        Dukhovni. Files: proto/TLS_README.html, proto/postconf.proto,
        src/global/mail_params.h, src/tls/tls.h, src/tls/tls_client.c,
        src/tls/tls_misc.c.
-
index a9fe9b06aa42147aa0e7988038af1a60b12acbb2..6ba7772fdd63a698dda769dc677aafb64a50b248 100644 (file)
@@ -99,9 +99,9 @@ performance.
     read/write access conflicts and gives the new data to Postfix once that
     data is available.
 
-  * If you change a regexp: or pcre: file then Postfix may or may not pick up
-    the file changes immediately. This is because a Postfix process reads the
-    entire file into memory once and never examines the file again.
+  * If you change a regexp:, pcre:, cidr: or texthash: file then Postfix may
+    not pick up the file changes immediately. This is because a Postfix process
+    reads the entire file into memory once and never examines the file again.
 
       o If the file is used by a short-running process such as smtpd(8),
         cleanup(8) or local(8), there is no need to execute "postfix reload"
index 76565134848c7774b7ce775136c4b01dd342dd3b..4ca9e12dcae81b9edad847a7be4c4a18bca9acac 100644 (file)
@@ -14,6 +14,30 @@ specifies the release date of a stable release or snapshot release.
 If you upgrade from Postfix 2.9 or earlier, read RELEASE_NOTES-2.10
 before proceeding.
 
+Major changes with snapshot 20130512
+====================================
+
+Allow an SMTP client to skip postscreen(8) tests based on its
+postscreen_dnsbl_sites score. 
+
+Specify a negative "postscreen_dnsbl_whitelist_threshold" to enable
+this feature.  When a client passes the threshold value without
+having failed other tests, all pending or disabled tests are flagged
+as completed.
+
+Major changes with snapshot 20130405
+====================================
+
+The recipient_delimiter parameter can now specify a set of characters.
+A user name is now separated from its address extension by the first
+character that matches the recipient_delimiter set.
+
+For example, specify "recipient_delimiter = +-" to support both the
+Postfix-style "+" and the qmail-style "-" extension delimiter.  
+
+As before, this implementation recognizes one delimiter character
+per email address, and one address extension per email address.
+
 Major changes with snapshot 20130319
 ====================================
 
index a870849aab2cc596ee872ccc56280e9cde881ea3..dc17013b0d20271564b9572779e0f16a266d4ef4 100644 (file)
@@ -2,40 +2,18 @@ Wish list:
 
        Things to do before the stable release:
 
+       Spell-check, double-word check, and HTML validator check.
+
        Remove this file from the stable release.
 
        Things to do after the stable release:
 
-       Spellcheck and double-word check.
-
-       Fix a false cache-sharing problem. After the SASL handshake,
-       the connection cache client does not store SASL credentials
-       in the destination properties; it stores them in the endpoint
-       label only.  When the connection cache client reuses the
-       connection with smtp_reuse_nexthop(), it does not restore
-       the SASL credentials.  When it saves the connection afterwards,
-       it creates a new endpoint label without SASL credentials,
-       so the authenticated connection can now be used for unrelated
-       deliveries.
+       Discourage the use of "after 220" tests in POSTSCREEN_README
+       and the documentation of individual parameter settings.
 
        Begin code revision, after DANE support stabilizes.  This
        should be one pass that changes only names and no code.
 
-       Run new source files through ccformat. If I do it now,
-       almost every block of code or comments is changed. Having
-       different formatting styles in the same project is PROBLEMATIC.
-       There is a reason why ccformat is included with source code.
-
-       Embed all statement-like macros in do { ... } while (0).
-       This is especially necessary with macros that contain an
-       "if" statement, or that contain multiple statements.
-
-       Spell-check, double-word check, and HTML validator check.
-
-       Use make(1) and cc(1) to convert the C++ like templates
-       into debuggable source code, such that each statement has
-       its own distinct line number (what a revolutionary idea).
-
        All source code must specify its original author and
        license statement. Some code modules specify Lutz Jaenicke
        as the original author and fall under his liberal license.
@@ -47,13 +25,6 @@ Wish list:
        Wietse as the original author, and Lutz Jaenicke's license,
        which is wrong.
 
-       Generally, macro and function names should make a program
-       more clear, not merely reduce the number of programmer
-       keystrokes; similar considerations hold for variable names
-       and constants. Avoid 1-letter names except "for i=1 to
-       some_bound". Instead of bare numbers use named constants
-       in function argument lists.
-
        Code clarity: replace obscure macro/function names: for
        example SMTP_X(XXX) -> VAR_SMTP(XXX), as the purpose is to
        choose between VAR_SMTP_XXX or VAR_LMTP_XXX; replace
@@ -62,13 +33,6 @@ Wish list:
        contents of a buffer with the specified length). Replace r
        with res_opt, ditto for other 1-letter names.
 
-       Unnecessary complexity: the SMTP_SESSION "tls" field is
-       mandatory (always allocated) therefore the content can be
-       a permanent part of the SMTP_SESSION structure, just like
-       SASL-related information.  This avoids silly indirections
-       all over the code, as well as awkward smtp_tls_sess_alloc()
-       error semantics.
-
        We have smtp_host_lookup, smtp_dns_resolver_options, and
        now smtp_dns_support_level.  Of these, smtp_dns_resolver_options
        is orthogonal but the rest has overlap.
index 9df9991a4238ce978ae098977dfe7859ed6a59e5..cadc57d650278f21cccffe88a7c2169e8a512e5e 100644 (file)
 #               mat is generated by address-based relay  authoriza-
 #               tion schemes such as pop-before-smtp.
 # 
+#        For other accept actions, see "OTHER ACTIONS" below.
+# 
 # REJECT ACTIONS
 #        Postfix  version  2.3  and  later  support enhanced status
 #        codes as defined in RFC 3463.  When no code  is  specified
 # 
 #               This feature is available in Postfix 2.1 and later.
 # 
+#        For other reject actions, see "OTHER ACTIONS" below.
+# 
 # OTHER ACTIONS
 #        restriction...
 #               Apply the named UCE restriction(s) (permit, reject,
index 720db18ccc890d0d5e5ff66ac7c218b25812f937..fc0c821ad1c3ed04e3d41a6abcf7e9cac860eb2b 100644 (file)
@@ -66,9 +66,9 @@
 # TABLE FORMAT
 #        The input format for the postmap(1) command is as follows:
 # 
-#        pattern result
+#        pattern address
 #               When  pattern matches a mail address, replace it by
-#               the corresponding result.
+#               the corresponding address.
 # 
 #        blank lines and comments
 #               Empty lines and whitespace-only lines are  ignored,
index 3be6ab9859a5077edef2bc8be21bb8fae4a954c6..9f4b3d770fb593181f064548b7dc4d661f6940a7 100644 (file)
@@ -65,9 +65,9 @@
 # TABLE FORMAT
 #        The input format for the postmap(1) command is as follows:
 # 
-#        pattern result
+#        pattern address, address, ...
 #               When pattern matches a mail address, replace it  by
-#               the corresponding result.
+#               the corresponding address.
 # 
 #        blank lines and comments
 #               Empty  lines and whitespace-only lines are ignored,
index 775db144522b05b9caf1da77bb20a5b65ed76e4f..68606057acc5818bd28ff33f197e7f7bc11a53fc 100644 (file)
@@ -156,7 +156,8 @@ SQL, there is no need to execute "postfix reload".  The LDAP, NIS
 or SQL server takes care of read/write access conflicts and gives
 the new data to Postfix once that data is available.  </p>
 
-<li> <p> If you change a <a href="regexp_table.5.html">regexp</a>: or <a href="pcre_table.5.html">pcre</a>: file then Postfix may or
+<li> <p> If you change a <a href="regexp_table.5.html">regexp</a>:, <a href="pcre_table.5.html">pcre</a>:, <a href="cidr_table.5.html">cidr</a>: or <a href="DATABASE_README.html#types">texthash</a>: file
+then Postfix 
 may not pick up the file changes immediately. This is because a
 Postfix process reads the entire file into memory once and never
 examines the file again.  </p>
index 0696fcdbfe10b53487192f6d97d91954656055a4..d191bd5617b10fd3f7541c96dc12ff92aba8a4f9 100644 (file)
@@ -184,6 +184,8 @@ ACCESS(5)                                                            ACCESS(5)
               mat is generated by address-based relay  authoriza-
               tion schemes such as pop-before-smtp.
 
+       For other accept actions, see "OTHER ACTIONS" below.
+
 <b>REJECT ACTIONS</b>
        Postfix  version  2.3  and  later  support enhanced status
        codes as defined in <a href="http://tools.ietf.org/html/rfc3463">RFC 3463</a>.  When no code  is  specified
@@ -254,6 +256,8 @@ ACCESS(5)                                                            ACCESS(5)
 
               This feature is available in Postfix 2.1 and later.
 
+       For other reject actions, see "OTHER ACTIONS" below.
+
 <b>OTHER ACTIONS</b>
        <i>restriction...</i>
               Apply the named UCE restriction(s) (<b>permit</b>, <b>reject</b>,
index c97f910ace308acabdb466a2d23ebf399d4d05b1..58c522cefc130ecfb9b349c952374d0ebc387aad 100644 (file)
@@ -52,7 +52,7 @@ CANONICAL(5)                                                      CANONICAL(5)
        <a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> configuration parameter spec-
        ifies a non-empty value. To get the behavior before  Post-
        fix    2.2,    specify   "<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a>   =
-       static:all".
+       <a href="DATABASE_README.html#types">static</a>:all".
 
        Typically, one would use the <a href="canonical.5.html"><b>canonical</b>(5)</a> table to replace
        login   names   by  <i>Firstname.Lastname</i>,  or  to  clean  up
@@ -72,9 +72,9 @@ CANONICAL(5)                                                      CANONICAL(5)
 <b>TABLE FORMAT</b>
        The input format for the <a href="postmap.1.html"><b>postmap</b>(1)</a> command is as follows:
 
-       <i>pattern result</i>
+       <i>pattern address</i>
               When  <i>pattern</i> matches a mail address, replace it by
-              the corresponding <i>result</i>.
+              the corresponding <i>address</i>.
 
        blank lines and comments
               Empty lines and whitespace-only lines are  ignored,
index 09689d910f9f53aeb6dbedc10587e6e4ef64df67..18cb8206a5b02e5e3fd74564879b4affc9582fd2 100644 (file)
@@ -43,6 +43,10 @@ CIDR_TABLE(5)                                                    CIDR_TABLE(5)
               address is a sequence of three to eight hexadecimal
               octet pairs separated by ":".
 
+              The  <i>network</i><b>_</b><i>mask</i>  is the number of high-order bits
+              in the <i>network</i><b>_</b><i>address</i> that the search string  must
+              match.
+
               Before  comparisons are made, lookup keys and table
               entries are converted from string to binary. There-
               fore  table  entries  will be matched regardless of
index e2cfed120f7efcacf459d75a853fa622d34a4911..ee4dff4de3fdd3b69e8c79c5a6e02e8c54edfd40 100644 (file)
@@ -608,8 +608,8 @@ LOCAL(8)                                                              LOCAL(8)
               tory.
 
        <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
-              The separator between user names and address exten-
-              sions (user+foo).
+              The set of characters that can separate a user name
+              from its address extension (user+foo).
 
        <b><a href="postconf.5.html#require_home_directory">require_home_directory</a> (no)</b>
               Require that a <a href="local.8.html"><b>local</b>(8)</a> recipient's home  directory
index 94be20a98683fcfb9e272ee20c11f31fd04191f4..afe2b5a2e2d7fa6f892033bca32a48dacfa9f315 100644 (file)
@@ -481,8 +481,8 @@ PIPE(8)                                                                PIPE(8)
               tory.
 
        <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
-              The separator between user names and address exten-
-              sions (user+foo).
+              The set of characters that can separate a user name
+              from its address extension (user+foo).
 
        <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
               The syslog facility of Postfix logging.
index d5363a1d0e61225e95bbbcc99b1ab9670a429294..0660da30bd27f052539ff3efc738e0653bf93217 100644 (file)
@@ -1451,7 +1451,9 @@ with the character set that is specified with the
 
 <dt><b>$<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a></b></dt>
 
-<dd>The system-wide recipient address extension delimiter. </dd>
+<dd>The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier). </dd>
 
 <dt><b>${name?value}</b></dt>
 
@@ -3254,7 +3256,9 @@ filtered with the character set that is specified with the
 
 <dt><b>$<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a></b></dt>
 
-<dd>The system-wide recipient address extension delimiter. </dd>
+<dd>The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier). </dd>
 
 <dt><b>${name?value}</b></dt>
 
@@ -5319,7 +5323,9 @@ The following $name expansions are done on <a href="postconf.5.html#luser_relay"
 
 <dt><b>$<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a></b></dt>
 
-<dd>The system-wide recipient address extension delimiter. </dd>
+<dd>The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier). </dd>
 
 <dt><b>$shell</b></dt>
 
@@ -7410,6 +7416,25 @@ one-letter suffix that specifies the time unit).  Time units: s
 <p> This feature is available in Postfix 2.8.  </p>
 
 
+</DD>
+
+<DT><b><a name="postscreen_dnsbl_whitelist_threshold">postscreen_dnsbl_whitelist_threshold</a>
+(default: 0)</b></DT><DD>
+
+<p> Allow a remote SMTP client to skip "before" and "after 220
+greeting" protocol tests, based on its combined DNSBL score as
+defined with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter.  </p>
+
+<p> Specify a negative value to enable this feature. When a client
+passes the <a href="postconf.5.html#postscreen_dnsbl_whitelist_threshold">postscreen_dnsbl_whitelist_threshold</a> without having
+failed other tests, all pending or disabled tests are flagged as
+completed with a time-to-live value equal to <a href="postconf.5.html#postscreen_dnsbl_ttl">postscreen_dnsbl_ttl</a>.
+When a test was already completed, its time-to-live value is updated
+if it was less than <a href="postconf.5.html#postscreen_dnsbl_ttl">postscreen_dnsbl_ttl</a>. </p>
+
+<p> This feature is available in Postfix 2.11.  </p>
+
+
 </DD>
 
 <DT><b><a name="postscreen_enforce_tls">postscreen_enforce_tls</a>
@@ -8509,22 +8534,53 @@ Example:
 <DT><b><a name="recipient_delimiter">recipient_delimiter</a>
 (default: empty)</b></DT><DD>
 
-<p>
-The separator between user names and address extensions (user+foo).
-See <a href="canonical.5.html">canonical(5)</a>, <a href="local.8.html">local(8)</a>, <a href="relocated.5.html">relocated(5)</a> and <a href="virtual.5.html">virtual(5)</a> for the
-effects this has on aliases, canonical, virtual, relocated and
-on .forward file lookups.  Basically, the software tries user+foo
-and .forward+foo before trying user and .forward.
+<p> The set of characters that can separate a user name from its
+address extension (user+foo).  See <a href="canonical.5.html">canonical(5)</a>, <a href="local.8.html">local(8)</a>, <a href="relocated.5.html">relocated(5)</a>
+and <a href="virtual.5.html">virtual(5)</a> for the effects this has on aliases, canonical,
+virtual, and relocated lookups.  Basically, the software tries
+user+foo and .forward+foo before trying user and .forward.  </p>
+
+<p> This implementation recognizes one delimiter character per email
+address, and one address extension per email address.  </p>
+
+<p> When the <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> set contains multiple characters
+(Postfix 2.11 and later), a user name is separated from its address
+extension by the first character that matches the <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a>
+set. </p>
+
+<p> When used in <a href="postconf.5.html#forward_path">forward_path</a>, ${<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a>} is replaced
+with the recipient delimiter that was found in the recipient email
+address (Postfix 2.11 and later), or it is replaced with the <a href="postconf.5.html">main.cf</a>
+<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> parameter value (Postfix 2.10 and earlier).
 </p>
 
+<p> The <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> is not applied to the mailer-daemon
+address, the postmaster address, or the double-bounce address. With
+the default "<a href="postconf.5.html#owner_request_special">owner_request_special</a> = yes" setting, the <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a>
+is also not applied to addresses with the special "owner-" prefix
+or the special "-request" suffix. </p>
+
 <p>
-Example:
+Examples:
 </p>
 
 <pre>
+# Handle Postfix-style extensions.
 <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> = +
 </pre>
 
+<pre>
+# Handle both Postfix and qmail extensions (Postfix 2.11 and later).
+recipient_delimiters = +-
+</pre>
+
+<pre>
+# Use .forward for mail without address extension, and for mail with
+# an unrecognized address extension.
+<a href="postconf.5.html#forward_path">forward_path</a> = $home/.forward${<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a>}${extension},
+    $home/.forward
+</pre>
+
 
 </DD>
 
index 12f9b02f11ed98ec2b65555c608cceb20cab6217..f746a465098ff9482f35c116268f656a9708f886 100644 (file)
@@ -245,25 +245,33 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
               The  internal  service that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> hands off
               allowed connections to.
 
+       Available in Postfix version 2.11 and later:
+
+       <b><a href="postconf.5.html#postscreen_dnsbl_whitelist_threshold">postscreen_dnsbl_whitelist_threshold</a> (0)</b>
+              Allow a remote SMTP client  to  skip  "before"  and
+              "after  220  greeting" protocol tests, based on its
+              combined  DNSBL   score   as   defined   with   the
+              <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter.
+
 <b>AFTER-GREETING TESTS</b>
-       These tests are executed  after  the  remote  SMTP  client
+       These  tests  are  executed  after  the remote SMTP client
        receives the "220 servername" greeting. If a client passes
-       all tests  during  this  phase,  it  will  receive  a  4XX
-       response  to  RCPT  TO commands until the client hangs up.
+       all  tests  during  this  phase,  it  will  receive  a 4XX
+       response to RCPT TO commands until the  client  hangs  up.
        After this, the client will be allowed to talk directly to
        a Postfix SMTP server process.
 
        <b><a href="postconf.5.html#postscreen_bare_newline_action">postscreen_bare_newline_action</a> (ignore)</b>
-              The  action  that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
-              SMTP client sends a bare  newline  character,  that
+              The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when  a  remote
+              SMTP  client  sends  a bare newline character, that
               is, a newline not preceded by carriage return.
 
        <b><a href="postconf.5.html#postscreen_bare_newline_enable">postscreen_bare_newline_enable</a> (no)</b>
-              Enable  "bare  newline"  SMTP protocol tests in the
+              Enable "bare newline" SMTP protocol  tests  in  the
               <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server.
 
        <b><a href="postconf.5.html#postscreen_disable_vrfy_command">postscreen_disable_vrfy_command</a> ($<a href="postconf.5.html#disable_vrfy_command">disable_vrfy_command</a>)</b>
-              Disable the SMTP VRFY command in the  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
+              Disable  the SMTP VRFY command in the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
               daemon.
 
        <b><a href="postconf.5.html#postscreen_forbidden_commands">postscreen_forbidden_commands</a> ($<a href="postconf.5.html#smtpd_forbidden_commands">smtpd_forbidden_commands</a>)</b>
@@ -271,159 +279,159 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
               siders in violation of the SMTP protocol.
 
        <b><a href="postconf.5.html#postscreen_helo_required">postscreen_helo_required</a> ($<a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a>)</b>
-              Require that a remote SMTP  client  sends  HELO  or
+              Require  that  a  remote  SMTP client sends HELO or
               EHLO before commencing a MAIL transaction.
 
        <b><a href="postconf.5.html#postscreen_non_smtp_command_action">postscreen_non_smtp_command_action</a> (drop)</b>
-              The  action  that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
-              SMTP client sends non-SMTP  commands  as  specified
+              The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when  a  remote
+              SMTP  client  sends  non-SMTP commands as specified
               with the <a href="postconf.5.html#postscreen_forbidden_commands">postscreen_forbidden_commands</a> parameter.
 
        <b><a href="postconf.5.html#postscreen_non_smtp_command_enable">postscreen_non_smtp_command_enable</a> (no)</b>
-              Enable    "non-SMTP    command"    tests   in   the
+              Enable   "non-SMTP   command"    tests    in    the
               <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server.
 
        <b><a href="postconf.5.html#postscreen_pipelining_action">postscreen_pipelining_action</a> (enforce)</b>
-              The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when  a  remote
-              SMTP  client  sends  multiple  commands  instead of
-              sending one command and waiting for the  server  to
+              The  action  that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
+              SMTP client  sends  multiple  commands  instead  of
+              sending  one  command and waiting for the server to
               respond.
 
        <b><a href="postconf.5.html#postscreen_pipelining_enable">postscreen_pipelining_enable</a> (no)</b>
-              Enable  "pipelining"  SMTP  protocol  tests  in the
+              Enable "pipelining"  SMTP  protocol  tests  in  the
               <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server.
 
 <b>CACHE CONTROLS</b>
        <b><a href="postconf.5.html#postscreen_cache_cleanup_interval">postscreen_cache_cleanup_interval</a> (12h)</b>
-              The amount  of  time  between  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>  cache
+              The  amount  of  time  between  <a href="postscreen.8.html"><b>postscreen</b>(8)</a> cache
               cleanup runs.
 
        <b><a href="postconf.5.html#postscreen_cache_map">postscreen_cache_map</a>                   (btree:$data_direc-</b>
        <b>tory/postscreen_cache)</b>
-              Persistent  storage  for  the  <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server
+              Persistent storage  for  the  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>  server
               decisions.
 
        <b><a href="postconf.5.html#postscreen_cache_retention_time">postscreen_cache_retention_time</a> (7d)</b>
               The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will cache an
-              expired  temporary  whitelist  entry  before  it is
+              expired temporary  whitelist  entry  before  it  is
               removed.
 
        <b><a href="postconf.5.html#postscreen_bare_newline_ttl">postscreen_bare_newline_ttl</a> (30d)</b>
-              The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use  the
+              The  amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
               result from a successful "bare newline" SMTP proto-
               col test.
 
        <b><a href="postconf.5.html#postscreen_dnsbl_ttl">postscreen_dnsbl_ttl</a> (1h)</b>
-              The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use  the
+              The  amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
               result from a successful DNS blocklist test.
 
        <b><a href="postconf.5.html#postscreen_greet_ttl">postscreen_greet_ttl</a> (1d)</b>
-              The  amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
+              The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use  the
               result from a successful PREGREET test.
 
        <b><a href="postconf.5.html#postscreen_non_smtp_command_ttl">postscreen_non_smtp_command_ttl</a> (30d)</b>
-              The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use  the
-              result  from  a  successful "non_smtp_command" SMTP
+              The  amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
+              result from a  successful  "non_smtp_command"  SMTP
               protocol test.
 
        <b><a href="postconf.5.html#postscreen_pipelining_ttl">postscreen_pipelining_ttl</a> (30d)</b>
-              The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use  the
+              The  amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
               result from a successful "pipelining" SMTP protocol
               test.
 
 <b>RESOURCE CONTROLS</b>
        <b><a href="postconf.5.html#line_length_limit">line_length_limit</a> (2048)</b>
-              Upon input, long lines are chopped up  into  pieces
-              of  at  most this length; upon delivery, long lines
+              Upon  input,  long lines are chopped up into pieces
+              of at most this length; upon delivery,  long  lines
               are reconstructed.
 
        <b><a href="postconf.5.html#postscreen_client_connection_count_limit">postscreen_client_connection_count_limit</a></b>
        <b>($<a href="postconf.5.html#smtpd_client_connection_count_limit">smtpd_client_connection_count_limit</a>)</b>
-              How many simultaneous connections any  remote  SMTP
-              client  is  allowed  to have with the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
+              How  many  simultaneous connections any remote SMTP
+              client is allowed to have  with  the  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
               daemon.
 
        <b><a href="postconf.5.html#postscreen_command_count_limit">postscreen_command_count_limit</a> (20)</b>
-              The limit on the total number of commands per  SMTP
-              session  for <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP protocol
+              The  limit on the total number of commands per SMTP
+              session for <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP  protocol
               engine.
 
        <b><a href="postconf.5.html#postscreen_command_time_limit">postscreen_command_time_limit</a> (${stress?10}${stress:300}s)</b>
-              The time limit to read an entire command line  with
+              The  time limit to read an entire command line with
               <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP protocol engine.
 
        <b><a href="postconf.5.html#postscreen_post_queue_limit">postscreen_post_queue_limit</a> ($<a href="postconf.5.html#default_process_limit">default_process_limit</a>)</b>
-              The  number of clients that can be waiting for ser-
+              The number of clients that can be waiting for  ser-
               vice from a real Postfix SMTP server process.
 
        <b><a href="postconf.5.html#postscreen_pre_queue_limit">postscreen_pre_queue_limit</a> ($<a href="postconf.5.html#default_process_limit">default_process_limit</a>)</b>
-              The number of non-whitelisted clients that  can  be
-              waiting  for  a  decision whether they will receive
+              The  number  of non-whitelisted clients that can be
+              waiting for a decision whether  they  will  receive
               service from a real Postfix SMTP server process.
 
        <b><a href="postconf.5.html#postscreen_watchdog_timeout">postscreen_watchdog_timeout</a> (10s)</b>
-              How much time a <a href="postscreen.8.html"><b>postscreen</b>(8)</a> process may  take  to
-              respond  to a remote SMTP client command or to per-
+              How  much  time a <a href="postscreen.8.html"><b>postscreen</b>(8)</a> process may take to
+              respond to a remote SMTP client command or to  per-
               form a cache operation before it is terminated by a
               built-in watchdog timer.
 
 <b>STARTTLS CONTROLS</b>
        <b><a href="postconf.5.html#postscreen_tls_security_level">postscreen_tls_security_level</a> ($<a href="postconf.5.html#smtpd_tls_security_level">smtpd_tls_security_level</a>)</b>
-              The  SMTP  TLS security level for the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
-              server; when a non-empty value is  specified,  this
+              The SMTP TLS security level for  the  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
+              server;  when  a non-empty value is specified, this
               overrides       the       obsolete       parameters
               <a href="postconf.5.html#postscreen_use_tls">postscreen_use_tls</a> and <a href="postconf.5.html#postscreen_enforce_tls">postscreen_enforce_tls</a>.
 
        <b><a href="postconf.5.html#tlsproxy_service_name">tlsproxy_service_name</a> (tlsproxy)</b>
-              The name of the <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> service entry  in  mas-
+              The  name  of the <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> service entry in mas-
               ter.cf.
 
 <b>OBSOLETE STARTTLS SUPPORT CONTROLS</b>
-       These  parameters  are  supported  for  compatibility with
+       These parameters  are  supported  for  compatibility  with
        <a href="smtpd.8.html"><b>smtpd</b>(8)</a> legacy parameters.
 
        <b><a href="postconf.5.html#postscreen_use_tls">postscreen_use_tls</a> ($<a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a>)</b>
-              Opportunistic TLS:  announce  STARTTLS  support  to
+              Opportunistic  TLS:  announce  STARTTLS  support to
               remote  SMTP  clients,  but  do  not  require  that
               clients use TLS encryption.
 
        <b><a href="postconf.5.html#postscreen_enforce_tls">postscreen_enforce_tls</a> ($<a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a>)</b>
-              Mandatory TLS: announce STARTTLS support to  remote
-              SMTP  clients,  and  require  that  clients use TLS
+              Mandatory  TLS: announce STARTTLS support to remote
+              SMTP clients, and  require  that  clients  use  TLS
               encryption.
 
 <b>MISCELLANEOUS CONTROLS</b>
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The default location of  the  Postfix  <a href="postconf.5.html">main.cf</a>  and
+              The  default  location  of  the Postfix <a href="postconf.5.html">main.cf</a> and
               <a href="master.5.html">master.cf</a> configuration files.
 
        <b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
-              The  maximal  number  of  digits  after the decimal
+              The maximal number  of  digits  after  the  decimal
               point when logging sub-second delay values.
 
        <b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
-              The location of  all  postfix  administrative  com-
+              The  location  of  all  postfix administrative com-
               mands.
 
        <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
-              The  maximum  amount  of  time that an idle Postfix
-              daemon process waits  for  an  incoming  connection
+              The maximum amount of time  that  an  idle  Postfix
+              daemon  process  waits  for  an incoming connection
               before terminating voluntarily.
 
        <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
-              The  process  ID  of  a  Postfix  command or daemon
+              The process ID  of  a  Postfix  command  or  daemon
               process.
 
        <b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
-              The process name of a  Postfix  command  or  daemon
+              The  process  name  of  a Postfix command or daemon
               process.
 
        <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
-              The  mail  system  name  that  is  prepended to the
-              process name in syslog  records,  so  that  "smtpd"
+              The mail system  name  that  is  prepended  to  the
+              process  name  in  syslog  records, so that "smtpd"
               becomes, for example, "postfix/smtpd".
 
 <b>SEE ALSO</b>
@@ -436,14 +444,14 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
        <a href="POSTSCREEN_README.html">POSTSCREEN_README</a>, Postfix Postscreen Howto
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>HISTORY</b>
        This service was introduced with Postfix version 2.8.
 
-       Many  ideas in <a href="postscreen.8.html"><b>postscreen</b>(8)</a> were explored in earlier work
-       by Michael Tokarev, in OpenBSD spamd, and in  MailChannels
+       Many ideas in <a href="postscreen.8.html"><b>postscreen</b>(8)</a> were explored in earlier  work
+       by  Michael Tokarev, in OpenBSD spamd, and in MailChannels
        Traffic Control.
 
 <b>AUTHOR(S)</b>
index dc934bb9091698fed30550a8252689f17ad60156..4b87f2212dafa247093d4eab3e08b98ca6b551b2 100644 (file)
@@ -102,11 +102,6 @@ SMTPD(8)                                                              SMTPD(8)
 
        Available in Postfix version 2.1 and later:
 
-       <b><a href="postconf.5.html#resolve_null_domain">resolve_null_domain</a> (no)</b>
-              Resolve an address that ends in the "@" null domain
-              as if the local hostname were specified, instead of
-              rejecting the address as invalid.
-
        <b><a href="postconf.5.html#smtpd_reject_unlisted_sender">smtpd_reject_unlisted_sender</a> (no)</b>
               Request  that  the Postfix SMTP server rejects mail
               from  unknown  sender  addresses,  even   when   no
@@ -1293,8 +1288,8 @@ SMTPD(8)                                                              SMTPD(8)
               tory.
 
        <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
-              The separator between user names and address exten-
-              sions (user+foo).
+              The set of characters that can separate a user name
+              from its address extension (user+foo).
 
        <b><a href="postconf.5.html#smtpd_banner">smtpd_banner</a> ($<a href="postconf.5.html#myhostname">myhostname</a> ESMTP $<a href="postconf.5.html#mail_name">mail_name</a>)</b>
               The  text  that  follows the 220 status code in the
index 6da7aced56749467ed476fb914daced52c1cffd9..e417e9d082171f0ce7a1d4b6927cd8ea2299ace8 100644 (file)
@@ -97,11 +97,15 @@ TRIVIAL-REWRITE(8)                                          TRIVIAL-REWRITE(8)
               Resolve  a recipient address safely instead of cor-
               rectly, by looking inside quotes.
 
+       Available with Postfix version 2.1 and later:
+
        <b><a href="postconf.5.html#resolve_null_domain">resolve_null_domain</a> (no)</b>
               Resolve an address that ends in the "@" null domain
               as if the local hostname were specified, instead of
               rejecting the address as invalid.
 
+       Available with Postfix version 2.3 and later:
+
        <b><a href="postconf.5.html#resolve_numeric_domain">resolve_numeric_domain</a> (no)</b>
               Resolve  "user@ipaddress"  as   "user@[ipaddress]",
               instead of rejecting the address as invalid.
@@ -133,8 +137,8 @@ TRIVIAL-REWRITE(8)                                          TRIVIAL-REWRITE(8)
               information.
 
        <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
-              The separator between user names and address exten-
-              sions (user+foo).
+              The set of characters that can separate a user name
+              from its address extension (user+foo).
 
        <b><a href="postconf.5.html#swap_bangpath">swap_bangpath</a> (yes)</b>
               Enable   the   rewriting   of   "site!user"    into
index 5306885f21b6539a5bd9ecdbe407b4a66cd00d83..e27077d0ec6bdb7e312e2e03ffceacb806bdb8e3 100644 (file)
@@ -71,9 +71,9 @@ VIRTUAL(5)                                                          VIRTUAL(5)
 <b>TABLE FORMAT</b>
        The input format for the <a href="postmap.1.html"><b>postmap</b>(1)</a> command is as follows:
 
-       <i>pattern result</i>
+       <i>pattern address, address, ...</i>
               When <i>pattern</i> matches a mail address, replace it  by
-              the corresponding <i>result</i>.
+              the corresponding <i>address</i>.
 
        blank lines and comments
               Empty  lines and whitespace-only lines are ignored,
index 64d678ad5e60d0b7e18f8125ceceaa191e9bf790..c1f45ae5872dbb908e409034a28b3e42e44db1d4 100644 (file)
@@ -172,6 +172,8 @@ Accept the address etc. that matches the pattern.
 An all-numerical result is treated as OK. This format is
 generated by address-based relay authorization schemes
 such as pop-before-smtp.
+.PP
+For other accept actions, see "OTHER ACTIONS" below.
 .SH "REJECT ACTIONS"
 .na
 .nf
@@ -237,6 +239,8 @@ response message.
 Prior to Postfix 2.6, the SMTP reply code is 450.
 .sp
 This feature is available in Postfix 2.1 and later.
+.PP
+For other reject actions, see "OTHER ACTIONS" below.
 .SH "OTHER ACTIONS"
 .na
 .nf
index 1bf8d53ebdd811f58a00c75c6a10c2f3cc3d1a5e..edf2a306fcb7c2b121b40d0ab15189aed84f7e3d 100644 (file)
@@ -73,9 +73,9 @@ lookup fields can match both upper and lower case.
 .ad
 .fi
 The input format for the \fBpostmap\fR(1) command is as follows:
-.IP "\fIpattern result\fR"
+.IP "\fIpattern address\fR"
 When \fIpattern\fR matches a mail address, replace it by the
-corresponding \fIresult\fR.
+corresponding \fIaddress\fR.
 .IP "blank lines and comments"
 Empty lines and whitespace-only lines are ignored, as
 are lines whose first non-whitespace character is a `#'.
index f25ab45cd791caf47645ed5f41a1cade24a6d92e..5619b2b09da71132d47f13217ebefbd3de57bed1 100644 (file)
@@ -43,6 +43,9 @@ An IPv4 network address is a sequence of four decimal octets
 separated by ".", and an IPv6 network address is a sequence
 of three to eight hexadecimal octet pairs separated by ":".
 
+The \fInetwork_mask\fR is the number of high-order bits in
+the \fInetwork_address\fR that the search string must match.
+
 Before comparisons are made, lookup keys and table entries
 are converted from string to binary. Therefore table entries
 will be matched regardless of redundant zero characters.
index d073fc9caf31d93de2931270e7e084f684f91a3b..d6fa80b1526474bf52ab0fa3ecf95c744fc435ec 100644 (file)
@@ -835,7 +835,9 @@ The recipient domain.
 The entire recipient localpart.
 .br
 .IP "\fB$recipient_delimiter\fR"
-The system-wide recipient address extension delimiter.
+The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier).
 .br
 .IP "\fB${name?value}\fR"
 Expands to \fIvalue\fR when \fI$name\fR is non-empty.
@@ -1919,7 +1921,9 @@ The recipient domain.
 The entire recipient localpart.
 .br
 .IP "\fB$recipient_delimiter\fR"
-The system-wide recipient address extension delimiter.
+The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier).
 .br
 .IP "\fB${name?value}\fR"
 Expands to \fIvalue\fR when \fI$name\fR is non-empty.
@@ -3073,7 +3077,9 @@ The entire recipient address localpart.
 The full recipient address.
 .br
 .IP "\fB$recipient_delimiter\fR"
-The system-wide recipient address extension delimiter.
+The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier).
 .br
 .IP "\fB$shell\fR"
 The recipient's login shell.
@@ -4458,6 +4464,19 @@ one-letter suffix that specifies the time unit).  Time units: s
 (seconds), m (minutes), h (hours), d (days), w (weeks).
 .PP
 This feature is available in Postfix 2.8.
+.SH postscreen_dnsbl_whitelist_threshold (default: 0)
+Allow a remote SMTP client to skip "before" and "after 220
+greeting" protocol tests, based on its combined DNSBL score as
+defined with the postscreen_dnsbl_sites parameter.
+.PP
+Specify a negative value to enable this feature. When a client
+passes the postscreen_dnsbl_whitelist_threshold without having
+failed other tests, all pending or disabled tests are flagged as
+completed with a time-to-live value equal to postscreen_dnsbl_ttl.
+When a test was already completed, its time-to-live value is updated
+if it was less than postscreen_dnsbl_ttl.
+.PP
+This feature is available in Postfix 2.11.
 .SH postscreen_enforce_tls (default: $smtpd_enforce_tls)
 Mandatory TLS: announce STARTTLS support to remote SMTP clients, and
 require that clients use TLS encryption.  See smtpd_postscreen_enforce_tls
@@ -5100,21 +5119,61 @@ recipient_canonical_maps = hash:/etc/postfix/recipient_canonical
 .ad
 .ft R
 .SH recipient_delimiter (default: empty)
-The separator between user names and address extensions (user+foo).
-See \fBcanonical\fR(5), \fBlocal\fR(8), \fBrelocated\fR(5) and \fBvirtual\fR(5) for the
-effects this has on aliases, canonical, virtual, relocated and
-on .forward file lookups.  Basically, the software tries user+foo
-and .forward+foo before trying user and .forward.
+The set of characters that can separate a user name from its
+address extension (user+foo).  See \fBcanonical\fR(5), \fBlocal\fR(8), \fBrelocated\fR(5)
+and \fBvirtual\fR(5) for the effects this has on aliases, canonical,
+virtual, and relocated lookups.  Basically, the software tries
+user+foo and .forward+foo before trying user and .forward.
+.PP
+This implementation recognizes one delimiter character per email
+address, and one address extension per email address.
+.PP
+When the recipient_delimiter set contains multiple characters
+(Postfix 2.11 and later), a user name is separated from its address
+extension by the first character that matches the recipient_delimiter
+set.
+.PP
+When used in forward_path, ${recipient_delimiter} is replaced
+with the recipient delimiter that was found in the recipient email
+address (Postfix 2.11 and later), or it is replaced with the main.cf
+recipient_delimiter parameter value (Postfix 2.10 and earlier).
+.PP
+The recipient_delimiter is not applied to the mailer-daemon
+address, the postmaster address, or the double-bounce address. With
+the default "owner_request_special = yes" setting, the recipient_delimiter
+is also not applied to addresses with the special "owner-" prefix
+or the special "-request" suffix.
 .PP
-Example:
+Examples:
 .PP
 .nf
 .na
 .ft C
+# Handle Postfix-style extensions.
 recipient_delimiter = +
 .fi
 .ad
 .ft R
+.PP
+.nf
+.na
+.ft C
+# Handle both Postfix and qmail extensions (Postfix 2.11 and later).
+recipient_delimiters = +-
+.fi
+.ad
+.ft R
+.PP
+.nf
+.na
+.ft C
+# Use .forward for mail without address extension, and for mail with
+# an unrecognized address extension.
+forward_path = $home/.forward${recipient_delimiter}${extension},
+    $home/.forward
+.fi
+.ad
+.ft R
 .SH reject_code (default: 554)
 The numerical Postfix SMTP server response code when a remote SMTP
 client request is rejected by the "reject" restriction.
index da139f8a1d92bc7b6655918ba162125b7da28e20..a8c80ecd4f0e079a22279eb18a64e864e756d9cd 100644 (file)
@@ -71,9 +71,9 @@ lookup fields can match both upper and lower case.
 .ad
 .fi
 The input format for the \fBpostmap\fR(1) command is as follows:
-.IP "\fIpattern result\fR"
+.IP "\fIpattern address, address, ...\fR"
 When \fIpattern\fR matches a mail address, replace it by the
-corresponding \fIresult\fR.
+corresponding \fIaddress\fR.
 .IP "blank lines and comments"
 Empty lines and whitespace-only lines are ignored, as
 are lines whose first non-whitespace character is a `#'.
index 5b6bc81b4484454eb0a1c7f1993e3019241e8134..b872ce6fe8b061a727865d4ba01cf5db50abecd7 100644 (file)
@@ -575,7 +575,8 @@ key to the lookup result.
 .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
 The location of the Postfix top-level queue directory.
 .IP "\fBrecipient_delimiter (empty)\fR"
-The separator between user names and address extensions (user+foo).
+The set of characters that can separate a user name from its
+address extension (user+foo).
 .IP "\fBrequire_home_directory (no)\fR"
 Require that a \fBlocal\fR(8) recipient's home directory exists
 before mail delivery is attempted.
index ec088ac6b5508606213bd2369e9d136550c1396f..a24a5ee48d08ed1483d0fccd661f99e6dc2cd5a0 100644 (file)
@@ -412,7 +412,8 @@ The process name of a Postfix command or daemon process.
 .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
 The location of the Postfix top-level queue directory.
 .IP "\fBrecipient_delimiter (empty)\fR"
-The separator between user names and address extensions (user+foo).
+The set of characters that can separate a user name from its
+address extension (user+foo).
 .IP "\fBsyslog_facility (mail)\fR"
 The syslog facility of Postfix logging.
 .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
index 821748de83bdb3afea920e8a819c5eac21a76754..2aa1aacb295e40a7d198386dbb32f02b3a4c149e 100644 (file)
@@ -242,6 +242,12 @@ up to 6 seconds otherwise).
 .IP "\fBsmtpd_service_name (smtpd)\fR"
 The internal service that \fBpostscreen\fR(8) hands off allowed
 connections to.
+.PP
+Available in Postfix version 2.11 and later:
+.IP "\fBpostscreen_dnsbl_whitelist_threshold (0)\fR"
+Allow a remote SMTP client to skip "before" and "after 220
+greeting" protocol tests, based on its combined DNSBL score as
+defined with the postscreen_dnsbl_sites parameter.
 .SH "AFTER-GREETING TESTS"
 .na
 .nf
index d6c8bce001efcf3e26683a43b57d8433ab051992..22e7b6603dc0ecf030a1a2e5c9b2378086b0d610 100644 (file)
@@ -106,10 +106,6 @@ commands are enclosed with <>, and that those addresses do
 not contain RFC 822 style comments or phrases.
 .PP
 Available in Postfix version 2.1 and later:
-.IP "\fBresolve_null_domain (no)\fR"
-Resolve an address that ends in the "@" null domain as if the
-local hostname were specified, instead of rejecting the address as
-invalid.
 .IP "\fBsmtpd_reject_unlisted_sender (no)\fR"
 Request that the Postfix SMTP server rejects mail from unknown
 sender addresses, even when no explicit reject_unlisted_sender
@@ -1012,7 +1008,8 @@ The process name of a Postfix command or daemon process.
 .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
 The location of the Postfix top-level queue directory.
 .IP "\fBrecipient_delimiter (empty)\fR"
-The separator between user names and address extensions (user+foo).
+The set of characters that can separate a user name from its
+address extension (user+foo).
 .IP "\fBsmtpd_banner ($myhostname ESMTP $mail_name)\fR"
 The text that follows the 220 status code in the SMTP greeting
 banner.
index ca85bd36bf19fc00629d96b564b7c71d6e67e07c..ff0b25a9965d82454178f4abc0d7eddf057d015e 100644 (file)
@@ -101,10 +101,14 @@ The text below provides only a parameter summary. See
 .IP "\fBresolve_dequoted_address (yes)\fR"
 Resolve a recipient address safely instead of correctly, by
 looking inside quotes.
+.PP
+Available with Postfix version 2.1 and later:
 .IP "\fBresolve_null_domain (no)\fR"
 Resolve an address that ends in the "@" null domain as if the
 local hostname were specified, instead of rejecting the address as
 invalid.
+.PP
+Available with Postfix version 2.3 and later:
 .IP "\fBresolve_numeric_domain (no)\fR"
 Resolve "user@ipaddress" as "user@[ipaddress]", instead of
 rejecting the address as invalid.
@@ -130,7 +134,8 @@ addresses without domain information.
 With locally submitted mail, append the string ".$mydomain" to
 addresses that have no ".domain" information.
 .IP "\fBrecipient_delimiter (empty)\fR"
-The separator between user names and address extensions (user+foo).
+The set of characters that can separate a user name from its
+address extension (user+foo).
 .IP "\fBswap_bangpath (yes)\fR"
 Enable the rewriting of "site!user" into "user@site".
 .PP
index 3edfdf06fbaf80ca7592953579e0dfca1200c578..baeb2afba1858fbdc9e9dd5edfeab240506cb2cc 100755 (executable)
@@ -968,6 +968,7 @@ while (<>) {
     s;\bpostscreen_dnsbl_reply_map\b;<a href="postconf.5.html#postscreen_dnsbl_reply_map">$&</a>;g;
     s;\bpostscreen_dnsbl_sites\b;<a href="postconf.5.html#postscreen_dnsbl_sites">$&</a>;g;
     s;\bpostscreen_dnsbl_thresh[-</bB>]*\n* *[<bB>]*old\b;<a href="postconf.5.html#postscreen_dnsbl_threshold">$&</a>;g;
+    s;\bpostscreen_dnsbl_whitelist_thresh[-</bB>]*\n* *[<bB>]*old\b;<a href="postconf.5.html#postscreen_dnsbl_whitelist_threshold">$&</a>;g;
     s;\bpostscreen_dnsbl_action\b;<a href="postconf.5.html#postscreen_dnsbl_action">$&</a>;g;
     s;\bpostscreen_dnsbl_ttl\b;<a href="postconf.5.html#postscreen_dnsbl_ttl">$&</a>;g;
     s;\bpostscreen_for[-</bB>]*\n*[ <bB>]*bidden_commands\b;<a href="postconf.5.html#postscreen_forbidden_commands">$&</a>;g;
index 591cf0d029c17f245c07881a20a65308474f9066..af0c2de95aca68863745e2ba4ab35d413dee91c4 100644 (file)
@@ -156,7 +156,8 @@ SQL, there is no need to execute "postfix reload".  The LDAP, NIS
 or SQL server takes care of read/write access conflicts and gives
 the new data to Postfix once that data is available.  </p>
 
-<li> <p> If you change a regexp: or pcre: file then Postfix may or
+<li> <p> If you change a regexp:, pcre:, cidr: or texthash: file
+then Postfix 
 may not pick up the file changes immediately. This is because a
 Postfix process reads the entire file into memory once and never
 examines the file again.  </p>
index 403e080d1a52c6c2aa77d6e3ddcd0227f44264c3..12b56a378269048f4ff87712c3d79457ae3e57e9 100644 (file)
 #      An all-numerical result is treated as OK. This format is
 #      generated by address-based relay authorization schemes
 #      such as pop-before-smtp.
+# .PP
+#      For other accept actions, see "OTHER ACTIONS" below.
 # REJECT ACTIONS
 # .ad
 # .fi
 #      Prior to Postfix 2.6, the SMTP reply code is 450.
 # .sp
 #      This feature is available in Postfix 2.1 and later.
+# .PP
+#      For other reject actions, see "OTHER ACTIONS" below.
 # OTHER ACTIONS
 # .ad
 # .fi
index cdda9181845a76ae95e7a57cb367bb6e16e087d4..6fb534816036d974374f52c10c2e6e4c74aa1009 100644 (file)
@@ -63,9 +63,9 @@
 # .ad
 # .fi
 #      The input format for the \fBpostmap\fR(1) command is as follows:
-# .IP "\fIpattern result\fR"
+# .IP "\fIpattern address\fR"
 #      When \fIpattern\fR matches a mail address, replace it by the
-#      corresponding \fIresult\fR.
+#      corresponding \fIaddress\fR.
 # .IP "blank lines and comments"
 #      Empty lines and whitespace-only lines are ignored, as
 #      are lines whose first non-whitespace character is a `#'.
index 4a24d05311cb823e6af519695faf3df8ef4a6296..0f1706ad11da3de0ba8c3873d20d3fd04533f3db 100644 (file)
@@ -35,6 +35,9 @@
 #      separated by ".", and an IPv6 network address is a sequence
 #      of three to eight hexadecimal octet pairs separated by ":".
 #
+#      The \fInetwork_mask\fR is the number of high-order bits in
+#      the \fInetwork_address\fR that the search string must match.
+#
 #      Before comparisons are made, lookup keys and table entries
 #      are converted from string to binary. Therefore table entries
 #      will be matched regardless of redundant zero characters.
index 1359d1b7cd768750c5a9b7e463a259a2f416179e..81c09725aca740ff9c6d15e8ab159ba754e1acc6 100644 (file)
@@ -1609,7 +1609,9 @@ execution_directory_expansion_filter parameter.  </p>
 
 <dt><b>$recipient_delimiter</b></dt>
 
-<dd>The system-wide recipient address extension delimiter. </dd>
+<dd>The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier). </dd>
 
 <dt><b>${name?value}</b></dt>
 
@@ -1670,7 +1672,9 @@ forward_expansion_filter parameter.  </p>
 
 <dt><b>$recipient_delimiter</b></dt>
 
-<dd>The system-wide recipient address extension delimiter. </dd>
+<dd>The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier). </dd>
 
 <dt><b>${name?value}</b></dt>
 
@@ -2404,7 +2408,9 @@ The following $name expansions are done on luser_relay:
 
 <dt><b>$recipient_delimiter</b></dt>
 
-<dd>The system-wide recipient address extension delimiter. </dd>
+<dd>The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier). </dd>
 
 <dt><b>$shell</b></dt>
 
@@ -3495,24 +3501,55 @@ Example:
 recipient_canonical_maps = hash:/etc/postfix/recipient_canonical
 </pre>
 
-%PARAM recipient_delimiter 
+%PARAM recipient_delimiter
 
-<p>
-The separator between user names and address extensions (user+foo).
-See canonical(5), local(8), relocated(5) and virtual(5) for the
-effects this has on aliases, canonical, virtual, relocated and
-on .forward file lookups.  Basically, the software tries user+foo
-and .forward+foo before trying user and .forward.
+<p> The set of characters that can separate a user name from its
+address extension (user+foo).  See canonical(5), local(8), relocated(5)
+and virtual(5) for the effects this has on aliases, canonical,
+virtual, and relocated lookups.  Basically, the software tries
+user+foo and .forward+foo before trying user and .forward.  </p>
+
+<p> This implementation recognizes one delimiter character per email
+address, and one address extension per email address.  </p>
+
+<p> When the recipient_delimiter set contains multiple characters
+(Postfix 2.11 and later), a user name is separated from its address
+extension by the first character that matches the recipient_delimiter
+set. </p>
+
+<p> When used in forward_path, ${recipient_delimiter} is replaced
+with the recipient delimiter that was found in the recipient email
+address (Postfix 2.11 and later), or it is replaced with the main.cf
+recipient_delimiter parameter value (Postfix 2.10 and earlier).
 </p>
 
+<p> The recipient_delimiter is not applied to the mailer-daemon
+address, the postmaster address, or the double-bounce address. With
+the default "owner_request_special = yes" setting, the recipient_delimiter
+is also not applied to addresses with the special "owner-" prefix
+or the special "-request" suffix. </p>
+
 <p>
-Example:
+Examples:
 </p>
-
+  
 <pre>
+# Handle Postfix-style extensions.
 recipient_delimiter = +
 </pre>
 
+<pre>
+# Handle both Postfix and qmail extensions (Postfix 2.11 and later).
+recipient_delimiters = +-
+</pre>
+
+<pre>
+# Use .forward for mail without address extension, and for mail with
+# an unrecognized address extension.
+forward_path = $home/.forward${recipient_delimiter}${extension},
+    $home/.forward
+</pre>
+
 %PARAM reject_code 554
 
 <p>
@@ -13816,6 +13853,21 @@ parameter. </p>
 
 <p> This feature is available in Postfix 2.8.  </p>
 
+%PARAM postscreen_dnsbl_whitelist_threshold 0
+
+<p> Allow a remote SMTP client to skip "before" and "after 220
+greeting" protocol tests, based on its combined DNSBL score as
+defined with the postscreen_dnsbl_sites parameter.  </p>
+
+<p> Specify a negative value to enable this feature. When a client
+passes the postscreen_dnsbl_whitelist_threshold without having
+failed other tests, all pending or disabled tests are flagged as
+completed with a time-to-live value equal to postscreen_dnsbl_ttl.
+When a test was already completed, its time-to-live value is updated
+if it was less than postscreen_dnsbl_ttl. </p>
+
+<p> This feature is available in Postfix 2.11.  </p>
+
 %PARAM postscreen_command_count_limit 20
 
 <p> The limit on the total number of commands per SMTP session for
index 8a2d28f607dbecab1be42a873e95ce13df07e4f3..fd98e2d48509c0495654c66d041d843174cd9942 100644 (file)
@@ -61,9 +61,9 @@
 # .ad
 # .fi
 #      The input format for the \fBpostmap\fR(1) command is as follows:
-# .IP "\fIpattern result\fR"
+# .IP "\fIpattern address, address, ...\fR"
 #      When \fIpattern\fR matches a mail address, replace it by the
-#      corresponding \fIresult\fR.
+#      corresponding \fIaddress\fR.
 # .IP "blank lines and comments"
 #      Empty lines and whitespace-only lines are ignored, as
 #      are lines whose first non-whitespace character is a `#'.
index 870a78f75c660630574a656fcf34377a38f389e5..4ae4eff6e169f80dc90c99e6654b57afea377099 100644 (file)
@@ -303,10 +303,12 @@ DNS_RR *dns_rr_shuffle(DNS_RR *list)
        rr_array[len] = rr;
 
     /*
-     * Shuffle resource records.
+     * Shuffle resource records. Every element has an equal chance of landing
+     * in slot 0.  After that every remaining element has an equal chance of
+     * landing in slot 1, ...  This is exactly n! states for n! permutations.
      */
-    for (i = 0; i < len; i++) {
-       r = myrand() % len;
+    for (i = 0; i < len - 1; i++) {
+       r = i + (myrand() % (len - i));         /* Victor&Son */
        rr = rr_array[i];
        rr_array[i] = rr_array[r];
        rr_array[r] = rr;
index ed8caab6dc74e3d9aa634331b26d5b709d21511a..e21dd360018da3ca0d806276167dd012de90e410 100644 (file)
@@ -109,7 +109,7 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp)
     if (*var_rcpt_delim == 0) {
        bare_key = saved_ext = 0;
     } else {
-       bare_key = strip_addr(full_key, &saved_ext, *var_rcpt_delim);
+       bare_key = strip_addr(full_key, &saved_ext, var_rcpt_delim);
     }
 
     /*
index 94ea155d7eb5bc79e006599973eda254a49e7d71..5bc95c659759aff6423b27f6f0b78107441837e7 100644 (file)
@@ -557,7 +557,7 @@ void    mail_params_init()
        VAR_MAIL_VERSION, DEF_MAIL_VERSION, &var_mail_version, 1, 0,
        VAR_DB_TYPE, DEF_DB_TYPE, &var_db_type, 1, 0,
        VAR_HASH_QUEUE_NAMES, DEF_HASH_QUEUE_NAMES, &var_hash_queue_names, 1, 0,
-       VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, 0, 1,
+       VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, 0, 0,
        VAR_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0,
        VAR_FFLUSH_DOMAINS, DEF_FFLUSH_DOMAINS, &var_fflush_domains, 0, 0,
        VAR_EXPORT_ENVIRON, DEF_EXPORT_ENVIRON, &var_export_environ, 0, 0,
index c40702f135b568c14ccf45208dcd5512591cebfb..ef78537ba14b00312446f8efe7558e5b8cd2aaeb 100644 (file)
@@ -3374,6 +3374,10 @@ extern char *var_psc_dnsbl_sites;
 #define DEF_PSC_DNSBL_THRESH   1
 extern int var_psc_dnsbl_thresh;
 
+#define VAR_PSC_DNSBL_WTHRESH  "postscreen_dnsbl_whitelist_threshold"
+#define DEF_PSC_DNSBL_WTHRESH  0
+extern int var_psc_dnsbl_wthresh;
+
 #define VAR_PSC_DNSBL_ENABLE   "postscreen_dnsbl_enable"
 #define DEF_PSC_DNSBL_ENABLE   0
 extern char *var_psc_dnsbl_enable;
index ed6467d86e37699c52615aab671ac11980918fa0..c298631554279f325aecff20b0cf1aba56797406 100644 (file)
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20130518"
+#define MAIL_RELEASE_DATE      "20130530"
 #define MAIL_VERSION_NUMBER    "2.11"
 
 #ifdef SNAPSHOT
-# define MAIL_VERSION_DATE     "-" MAIL_RELEASE_DATE
+#define MAIL_VERSION_DATE      "-" MAIL_RELEASE_DATE
 #else
-# define MAIL_VERSION_DATE     ""
+#define MAIL_VERSION_DATE      ""
 #endif
 
 #ifdef NONPROD
-# define MAIL_VERSION_PROD     "-nonprod"
+#define MAIL_VERSION_PROD      "-nonprod"
 #else
-# define MAIL_VERSION_PROD     ""
+#define MAIL_VERSION_PROD      ""
 #endif
 
 #define VAR_MAIL_VERSION       "mail_version"
index bbd1b9b3a6755c6aa7b7617b5805757002edfaf4..5b28772c16776829ab0a4dd18571c0e7560c39e9 100644 (file)
@@ -386,8 +386,11 @@ int     main(int argc, char **argv)
        VSTRING *buffer = vstring_alloc(1);
 
        while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
-           if ((addr = split_at(STR(buffer), ' ')) == 0 || *STR(buffer) == 0)
-               msg_fatal("need as input: class address");
+           addr = split_at(STR(buffer), ' ');
+           if (*STR(buffer) == 0)
+               msg_fatal("need as input: class [address]");
+           if (addr == 0)
+               addr = "";
            resolve(STR(buffer), addr, &reply);
        }
        vstring_free(buffer);
index 279ad4fb697cfa66f21c2c2844fc8e12a52fbe8f..7e7cc27c8c19e207b10bc0dd8cf203ec09378a71 100644 (file)
@@ -6,12 +6,12 @@
 /* SYNOPSIS
 /*     #include <split_addr.h>
 /*
-/*     char    *split_addr(localpart, delimiter)
+/*     char    *split_addr(localpart, delimiter_set)
 /*     char    *localpart;
-/*     int     delimiter;
+/*     const char *delimiter_set;
 /* DESCRIPTION
 /*     split_addr() null-terminates \fIlocalpart\fR at the first
-/*     occurrence of the \fIdelimiter\fR character found, and
+/*     occurrence of the \fIdelimiter\fR character(s) found, and
 /*     returns a pointer to the remainder.
 /*
 /*     Reserved addresses are not split: postmaster, mailer-daemon,
@@ -50,7 +50,7 @@
 
 /* split_addr - split address with extreme prejudice */
 
-char   *split_addr(char *localpart, int delimiter)
+char   *split_addr(char *localpart, const char *delimiter_set)
 {
     int     len;
 
@@ -67,7 +67,7 @@ char   *split_addr(char *localpart, int delimiter)
     /*
      * Backwards compatibility: don't split owner-foo or foo-request.
      */
-    if (delimiter == '-' && var_ownreq_special != 0) {
+    if (strchr(delimiter_set, '-') != 0 && var_ownreq_special != 0) {
        if (strncasecmp(localpart, "owner-", 6) == 0)
            return (0);
        if ((len = strlen(localpart) - 8) > 0
@@ -79,5 +79,10 @@ char   *split_addr(char *localpart, int delimiter)
      * Safe to split this address. Do not split the address if the result
      * would have a null localpart.
      */
-    return (delimiter == *localpart ? 0 : split_at(localpart, delimiter));
+    if ((len = strcspn(localpart, delimiter_set)) == 0 || localpart[len] == 0) {
+       return (0);
+    } else {
+       localpart[len] = 0;
+       return (localpart + len + 1);
+    }
 }
index 1c87fb99ac8d6a048df2c884be8082acca8a481d..fa89faeae7bb71c504a052ff1d53c6af78e4db95 100644 (file)
@@ -13,7 +13,7 @@
 
  /* External interface. */
 
-extern char *split_addr(char *, int);
+extern char *split_addr(char *, const char *);
 
 /* LICENSE
 /* .ad
index 803db87f8fcf7e426d2721f57914fc7c374754e2..6792d35f327f09c3c5b58d491f364fb77a58f1f5 100644 (file)
@@ -6,10 +6,10 @@
 /* SYNOPSIS
 /*     #include <strip_addr.h>
 /*
-/*     char    *strip_addr(address, extension, delimiter)
+/*     char    *strip_addr(address, extension, delimiter_set)
 /*     const char *address;
 /*     char    **extension;
-/*     int     delimiter;
+/*     const char *delimiter_set;
 /* DESCRIPTION
 /*     strip_addr() takes an address and either returns a null
 /*     pointer when the address contains no address extension,
@@ -25,8 +25,8 @@
 /*     that had to be chopped off.
 /*     The copy includes the recipient address delimiter.
 /*     The caller is expected to pass the copy to myfree().
-/* .IP delimiter
-/*     Recipient address delimiter.
+/* .IP delimiter_set
+/*     Set of recipient address delimiter characters.
 /* SEE ALSO
 /*     split_addr(3) strip extension from localpart
 /* LICENSE
@@ -56,7 +56,7 @@
 
 /* strip_addr - strip extension from address */
 
-char   *strip_addr(const char *full, char **extension, int delimiter)
+char   *strip_addr(const char *full, char **extension, const char *delimiter_set)
 {
     char   *ratsign;
     char   *extent;
@@ -66,16 +66,16 @@ char   *strip_addr(const char *full, char **extension, int delimiter)
     /*
      * A quick test to eliminate inputs without delimiter anywhere.
      */
-    if (delimiter == 0 || strchr(full, delimiter) == 0) {
+    if (*delimiter_set == 0 || full[strcspn(full, delimiter_set)] == 0) {
        stripped = saved_ext = 0;
     } else {
        stripped = mystrdup(full);
        if ((ratsign = strrchr(stripped, '@')) != 0)
            *ratsign = 0;
-       if ((extent = split_addr(stripped, delimiter)) != 0) {
+       if ((extent = split_addr(stripped, delimiter_set)) != 0) {
            extent -= 1;
            if (extension) {
-               *extent = delimiter;
+               *extent = full[strlen(stripped)];
                saved_ext = mystrdup(extent);
                *extent = 0;
            } else
@@ -105,17 +105,19 @@ int     main(int unused_argc, char **unused_argv)
 {
     char   *extension;
     char   *stripped;
-    int     delim = '-';
+    char*  delim = "+-";
+
+#define NO_DELIM       ""
 
     /*
      * Incredible. This function takes only three arguments, and the tests
      * already take more lines of code than the code being tested.
      */
-    stripped = strip_addr("foo", (char **) 0, 0);
+    stripped = strip_addr("foo", (char **) 0, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 1");
 
-    stripped = strip_addr("foo", &extension, 0);
+    stripped = strip_addr("foo", &extension, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 2");
     if (extension != 0)
@@ -131,11 +133,11 @@ int     main(int unused_argc, char **unused_argv)
     if (extension != 0)
        msg_panic("strip_addr botch 6");
 
-    stripped = strip_addr("foo@bar", (char **) 0, 0);
+    stripped = strip_addr("foo@bar", (char **) 0, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 7");
 
-    stripped = strip_addr("foo@bar", &extension, 0);
+    stripped = strip_addr("foo@bar", &extension, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 8");
     if (extension != 0)
@@ -151,11 +153,11 @@ int     main(int unused_argc, char **unused_argv)
     if (extension != 0)
        msg_panic("strip_addr botch 12");
 
-    stripped = strip_addr("foo-ext", (char **) 0, 0);
+    stripped = strip_addr("foo-ext", (char **) 0, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 13");
 
-    stripped = strip_addr("foo-ext", &extension, 0);
+    stripped = strip_addr("foo-ext", &extension, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 14");
     if (extension != 0)
@@ -178,11 +180,11 @@ int     main(int unused_argc, char **unused_argv)
     myfree(stripped);
     myfree(extension);
 
-    stripped = strip_addr("foo-ext@bar", (char **) 0, 0);
+    stripped = strip_addr("foo-ext@bar", (char **) 0, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 19");
 
-    stripped = strip_addr("foo-ext@bar", &extension, 0);
+    stripped = strip_addr("foo-ext@bar", &extension, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 20");
     if (extension != 0)
@@ -205,6 +207,16 @@ int     main(int unused_argc, char **unused_argv)
     myfree(stripped);
     myfree(extension);
 
+    stripped = strip_addr("foo+ext@bar", &extension, delim);
+    if (stripped == 0)
+       msg_panic("strip_addr botch 25");
+    if (extension == 0)
+       msg_panic("strip_addr botch 26");
+    msg_info("wanted:    foo+ext@bar -> %s %s", "foo@bar", "+ext");
+    msg_info("strip_addr foo+ext@bar -> %s %s", stripped, extension);
+    myfree(stripped);
+    myfree(extension);
+
     return (0);
 }
 
index e99c6fdf8ff6114c048d04f961b9a50f68f57493..19530e1ba2049b5bf43aff993233cda19cee5b9e 100644 (file)
@@ -13,7 +13,7 @@
 
  /* External interface. */
 
-extern char *strip_addr(const char *, char **, int);
+extern char *strip_addr(const char *, char **, const char *);
 
 /* LICENSE
 /* .ad
index 3068918caabbcdc89e833fcac192631cc70e69b7..af218e5c03105010e8a8abe0a6b0c0d05f4e28ba 100644 (file)
@@ -6,3 +6,5 @@ unknown: wanted:    foo-ext@bar -> foo@bar
 unknown: strip_addr foo-ext@bar -> foo@bar
 unknown: wanted:    foo-ext@bar -> foo@bar -ext
 unknown: strip_addr foo-ext@bar -> foo@bar -ext
+unknown: wanted:    foo+ext@bar -> foo@bar +ext
+unknown: strip_addr foo+ext@bar -> foo@bar +ext
index 8d1670c805181b98383a59024f3d9bb1c7ce427d..e7211ec552c88f83c4938067b92dcb1b16ca8f6d 100644 (file)
@@ -109,7 +109,7 @@ int     bounce_workaround(LOCAL_STATE state)
        if (alias_maps->error == 0 && owner_expansion == 0
            && (stripped_recipient = strip_addr(state.msg_attr.rcpt.address,
                                                (char **) 0,
-                                               *var_rcpt_delim)) != 0) {
+                                               var_rcpt_delim)) != 0) {
            myfree(owner_alias);
            FIND_OWNER(owner_alias, owner_expansion, stripped_recipient);
            myfree(stripped_recipient);
index 6ebe74f18d56f09722db787c4c9aa7bf2022a712..fb7da4f2ec82996bb211fd0b27b52f2b6191c489 100644 (file)
@@ -118,6 +118,11 @@ static FORWARD_INFO *forward_open(DELIVER_REQUEST *request, const char *sender)
     FORWARD_INFO *info;
     VSTREAM *cleanup;
 
+#define FORWARD_OPEN_RETURN(res) do { \
+       vstring_free(buffer); \
+       return (res); \
+    } while (0)
+
     /*
      * Contact the cleanup service and save the new mail queue id. Request
      * that the cleanup service bounces bad messages to the sender so that we
@@ -129,13 +134,13 @@ static FORWARD_INFO *forward_open(DELIVER_REQUEST *request, const char *sender)
      */
     cleanup = mail_connect(MAIL_CLASS_PUBLIC, var_cleanup_service, BLOCKING);
     if (cleanup == 0)
-       return (0);
+       FORWARD_OPEN_RETURN(0);
     close_on_exec(vstream_fileno(cleanup), CLOSE_ON_EXEC);
     if (attr_scan(cleanup, ATTR_FLAG_STRICT,
                  ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, buffer,
                  ATTR_TYPE_END) != 1) {
        vstream_fclose(cleanup);
-       return (0);
+       FORWARD_OPEN_RETURN(0);
     }
     info = (FORWARD_INFO *) mymalloc(sizeof(FORWARD_INFO));
     info->cleanup = cleanup;
@@ -190,8 +195,7 @@ static FORWARD_INFO *forward_open(DELIVER_REQUEST *request, const char *sender)
     PASS_ATTR(cleanup, MAIL_ATTR_LOG_IDENT, request->log_ident);
     PASS_ATTR(cleanup, MAIL_ATTR_RWR_CONTEXT, request->rewrite_context);
 
-    vstring_free(buffer);
-    return (info);
+    FORWARD_OPEN_RETURN(info);
 }
 
 /* forward_append - append recipient to message envelope */
index cec2312637e0814a1ed2862e6a8111446447e4ad..32da88bcabe854ec6e5f99807e1e609c73360b44 100644 (file)
 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
 /*     The location of the Postfix top-level queue directory.
 /* .IP "\fBrecipient_delimiter (empty)\fR"
-/*     The separator between user names and address extensions (user+foo).
+/*     The set of characters that can separate a user name from its
+/*     address extension (user+foo).
 /* .IP "\fBrequire_home_directory (no)\fR"
 /*     Require that a \fBlocal\fR(8) recipient's home directory exists
 /*     before mail delivery is attempted.
index db5121ee889de8eb29425dfad5da933c31853934..612e680940956358685a8ab62ce1fa46d7d266ab 100644 (file)
@@ -113,6 +113,7 @@ typedef struct {
 static const char *local_expand_lookup(const char *name, int mode, char *ptr)
 {
     LOCAL_EXP *local = (LOCAL_EXP *) ptr;
+    static char rcpt_delim[2];
 
 #define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0)
 
@@ -135,7 +136,10 @@ static const char *local_expand_lookup(const char *name, int mode, char *ptr)
            local->status |= LOCAL_EXP_EXTENSION_MATCHED;
        return (local->state->msg_attr.extension);
     } else if (STREQ(name, "recipient_delimiter")) {
-       return (*var_rcpt_delim ? var_rcpt_delim : 0);
+       rcpt_delim[0] =
+           local->state->msg_attr.local[strlen(local->state->msg_attr.user)];
+       rcpt_delim[1] = 0;
+       return (rcpt_delim[0] ? rcpt_delim : 0);
 #if 0
     } else if (STREQ(name, "client_hostname")) {
        return (local->state->msg_attr.request->client_name);
index 19214449366f52e6fad0800500ae91b2a829eee8..8017942e5029d0a31761883cf785f9886761e9e1 100644 (file)
@@ -270,7 +270,7 @@ int     deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
     state.msg_attr.user = mystrdup(state.msg_attr.local);
     if (*var_rcpt_delim) {
        state.msg_attr.extension =
-           split_addr(state.msg_attr.user, *var_rcpt_delim);
+           split_addr(state.msg_attr.user, var_rcpt_delim);
        if (state.msg_attr.extension && strchr(state.msg_attr.extension, '/')) {
            msg_warn("%s: address with illegal extension: %s",
                     state.msg_attr.queue_id, state.msg_attr.local);
index 89c330325e4c00eeace390c7a8e8ee8401ab706c..a6aa9d0356df5e76a8e5966d99af4240d327a4f6 100644 (file)
@@ -90,6 +90,7 @@ int     deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr
     int     status;
     ssize_t ext_len;
     char   *ratsign;
+    int     rcpt_delim;
 
     /*
      * Make verbose logging easier to understand.
@@ -130,8 +131,9 @@ int     deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr
         * Splice in the optional unmatched address extension.
         */
        if (state.msg_attr.unmatched) {
+           rcpt_delim = state.msg_attr.local[strlen(state.msg_attr.user)];
            if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0) {
-               VSTRING_ADDCH(reply.recipient, *var_rcpt_delim);
+               VSTRING_ADDCH(reply.recipient, rcpt_delim);
                vstring_strcat(reply.recipient, state.msg_attr.unmatched);
            } else {
                ext_len = strlen(state.msg_attr.unmatched);
@@ -139,7 +141,7 @@ int     deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr
                if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0)
                    msg_panic("%s: recipient @ botch", myname);
                memmove(ratsign + ext_len + 1, ratsign, strlen(ratsign) + 1);
-               *ratsign = *var_rcpt_delim;
+               *ratsign = rcpt_delim;
                memcpy(ratsign + 1, state.msg_attr.unmatched, ext_len);
                VSTRING_SKIP(reply.recipient);
            }
index 71955d4f3b565b848885ee660b821d486042d7a3..e2f9237410e4029b4079973a5574844e87b86d8c 100644 (file)
@@ -1175,7 +1175,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
                   : strlen(STR(reply.recipient)));
            vstring_strncpy(queue_name, STR(reply.recipient), len);
            /* Remove the address extension from the recipient localpart. */
-           if (*var_rcpt_delim && split_addr(STR(queue_name), *var_rcpt_delim))
+           if (*var_rcpt_delim && split_addr(STR(queue_name), var_rcpt_delim))
                vstring_truncate(queue_name, strlen(STR(queue_name)));
            /* Assume the recipient domain is equivalent to nexthop. */
            vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop));
index 73e9978bbd10d79f36caa75553711035c71c9ee7..b6329f02f2d285ce8af3be073d5c0837d85664f2 100644 (file)
 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
 /*     The location of the Postfix top-level queue directory.
 /* .IP "\fBrecipient_delimiter (empty)\fR"
-/*     The separator between user names and address extensions (user+foo).
+/*     The set of characters that can separate a user name from its
+/*     address extension (user+foo).
 /* .IP "\fBsyslog_facility (mail)\fR"
 /*     The syslog facility of Postfix logging.
 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
@@ -717,7 +718,7 @@ static ARGV *expand_argv(const char *service, char **argv,
                        msg_warn("no @ in recipient address: %s",
                                 rcpt_list->info[i].address);
                    if (*var_rcpt_delim)
-                       split_addr(STR(buf), *var_rcpt_delim);
+                       split_addr(STR(buf), var_rcpt_delim);
                    if (*STR(buf) == 0)
                        continue;
                    dict_update(PIPE_DICT_TABLE, PIPE_DICT_USER, STR(buf));
@@ -735,7 +736,7 @@ static ARGV *expand_argv(const char *service, char **argv,
                        msg_warn("no @ in recipient address: %s",
                                 rcpt_list->info[i].address);
                    if (*var_rcpt_delim == 0
-                     || (ext = split_addr(STR(buf), *var_rcpt_delim)) == 0)
+                     || (ext = split_addr(STR(buf), var_rcpt_delim)) == 0)
                        ext = "";               /* insert null arg */
                    dict_update(PIPE_DICT_TABLE, PIPE_DICT_EXTENSION, ext);
                }
index 4d2f8265ace170dc97bbcc7bbd1f6aac84ddc9ce..9c29a3d5544c94f5cb465c5f9f4bb668d148c7e5 100644 (file)
@@ -385,6 +385,7 @@ postscreen_tests.o: ../../include/match_list.h
 postscreen_tests.o: ../../include/msg.h
 postscreen_tests.o: ../../include/myaddrinfo.h
 postscreen_tests.o: ../../include/myflock.h
+postscreen_tests.o: ../../include/name_code.h
 postscreen_tests.o: ../../include/server_acl.h
 postscreen_tests.o: ../../include/string_list.h
 postscreen_tests.o: ../../include/sys_defs.h
index 0149b59ad78dc302fe40d6048c15885a0189daee..deff9abfabd6160a36ab9e462448bf4fa6c329c9 100644 (file)
 /* .IP "\fBsmtpd_service_name (smtpd)\fR"
 /*     The internal service that \fBpostscreen\fR(8) hands off allowed
 /*     connections to.
+/* .PP
+/*     Available in Postfix version 2.11 and later:
+/* .IP "\fBpostscreen_dnsbl_whitelist_threshold (0)\fR"
+/*     Allow a remote SMTP client to skip "before" and "after 220
+/*     greeting" protocol tests, based on its combined DNSBL score as
+/*     defined with the postscreen_dnsbl_sites parameter.
 /* AFTER-GREETING TESTS
 /* .ad
 /* .fi
@@ -465,6 +471,7 @@ int     var_psc_pregr_ttl;
 char   *var_psc_dnsbl_sites;
 char   *var_psc_dnsbl_reply;
 int     var_psc_dnsbl_thresh;
+int     var_psc_dnsbl_wthresh;
 char   *var_psc_dnsbl_action;
 int     var_psc_dnsbl_ttl;
 
@@ -1095,6 +1102,7 @@ int     main(int argc, char **argv)
     static const CONFIG_INT_TABLE int_table[] = {
        VAR_PROC_LIMIT, DEF_PROC_LIMIT, &var_proc_limit, 1, 0,
        VAR_PSC_DNSBL_THRESH, DEF_PSC_DNSBL_THRESH, &var_psc_dnsbl_thresh, 0, 0,
+       VAR_PSC_DNSBL_WTHRESH, DEF_PSC_DNSBL_WTHRESH, &var_psc_dnsbl_wthresh, 0, 0,
        VAR_PSC_CMD_COUNT, DEF_PSC_CMD_COUNT, &var_psc_cmd_count, 1, 0,
        VAR_SMTPD_CCONN_LIMIT, DEF_SMTPD_CCONN_LIMIT, &var_smtpd_cconn_limit, 0, 0,
        0,
index 3fe0a9b6bf53c23ed38b4edcfb94562da6977735..ebc048a0225ccd5d8c40ff2bdc54c5c9d7206dab 100644 (file)
   */
 #define PSC_READ_BUF_SIZE      1024
 
+ /*
+  * Numeric indices and symbolic names for tests whose time stamps and status
+  * flags can be accessed by numeric index.
+  */
+#define PSC_TINDX_PREGR        0               /* pregreet */
+#define PSC_TINDX_DNSBL        1               /* dnsbl */
+#define PSC_TINDX_PIPEL        2               /* pipelining */
+#define PSC_TINDX_NSMTP        3               /* non-smtp command */
+#define PSC_TINDX_BARLF        4               /* bare newline */
+#define PSC_TINDX_COUNT        5               /* number of tests */
+
+#define PSC_TNAME_PREGR        "pregreet"
+#define PSC_TNAME_DNSBL        "dnsbl"
+#define PSC_TNAME_PIPEL        "pipelining"
+#define PSC_TNAME_NSMTP        "non-smtp command"
+#define PSC_TNAME_BARLF        "bare newline"
+
+#define PSC_TINDX_BYTNAME(tname) (PSC_TINDX_ ## tname)
+
  /*
   * Per-session state.
   */
@@ -53,16 +72,11 @@ typedef struct {
     /* Test context. */
     struct timeval start_time;         /* start of current test */
     const char *test_name;             /* name of current test */
-    /* Before-handshake tests. */
-    time_t  pregr_stamp;               /* pregreet expiration time */
-    time_t  dnsbl_stamp;               /* dnsbl expiration time */
+    time_t  expire_time[PSC_TINDX_COUNT];      /* per-test expiration */
     VSTRING *dnsbl_reply;              /* dnsbl reject text */
+    int     dnsbl_score;               /* saved DNSBL score */
+    const char *dnsbl_name;            /* DNSBL name with largest weight */
     int     dnsbl_index;               /* dnsbl request index */
-    time_t  penal_stamp;               /* penalty expiration time */
-    /* Built-in SMTP protocol engine. */
-    time_t  pipel_stamp;               /* pipelining expiration time */
-    time_t  nsmtp_stamp;               /* non-smtp command expiration time */
-    time_t  barlf_stamp;               /* bare newline expiration time */
     const char *rcpt_reply;            /* how to reject recipients */
     int     command_count;             /* error + junk command count */
     const char *protocol;              /* SMTP or ESMTP */
@@ -76,10 +90,26 @@ typedef struct {
     const char *where;                 /* SMTP protocol state */
 } PSC_STATE;
 
+ /*
+  * Emulate legacy ad-hoc variables on top of indexable time stamps. This
+  * avoids massive scar tissue during initial feature development.
+  */
+#define pregr_stamp    expire_time[PSC_TINDX_PREGR]
+#define dnsbl_stamp    expire_time[PSC_TINDX_DNSBL]
+#define pipel_stamp    expire_time[PSC_TINDX_PIPEL]
+#define nsmtp_stamp    expire_time[PSC_TINDX_NSMTP]
+#define barlf_stamp    expire_time[PSC_TINDX_BARLF]
+
+ /*
+  * Special expiration time values.
+  */
 #define PSC_TIME_STAMP_NEW             (0)     /* test was never passed */
 #define PSC_TIME_STAMP_DISABLED                (1)     /* never passed but disabled */
 #define PSC_TIME_STAMP_INVALID         (-1)    /* must not be cached */
 
+ /*
+  * Status flags.
+  */
 #define PSC_STATE_FLAG_NOFORWARD       (1<<0)  /* don't forward this session */
 #define PSC_STATE_FLAG_USING_TLS       (1<<1)  /* using the TLS proxy */
 #define PSC_STATE_FLAG_UNUSED2         (1<<2)  /* use me! */
@@ -88,8 +118,11 @@ typedef struct {
 #define PSC_STATE_FLAG_HANGUP          (1<<5)  /* NOT a test failure */
 #define PSC_STATE_FLAG_SMTPD_X21       (1<<6)  /* hang up after command */
 #define PSC_STATE_FLAG_WLIST_FAIL      (1<<7)  /* do not whitelist */
+#define PSC_STATE_FLAG_TEST_BASE       (8)     /* start of indexable flags */
 
  /*
+  * Tests whose flags and expiration time can be accessed by numerical index.
+  * 
   * Important: every MUMBLE_TODO flag must have a MUMBLE_PASS flag, such that
   * MUMBLE_PASS == PSC_STATE_FLAGS_TODO_TO_PASS(MUMBLE_TODO).
   * 
@@ -107,39 +140,74 @@ typedef struct {
   * the result was ignored. MUMBLE_FAIL, on the other hand, is always final.
   * We use MUMBLE_SKIP to indicate that a decision was either "fail" or
   * forced "pass".
+  * 
+  * The difference between DONE and SKIP is in the beholder's eye. These flags
+  * share the same bit.
   */
 #define PSC_STATE_FLAGS_TODO_TO_PASS(todo_flags) ((todo_flags) >> 1)
 #define PSC_STATE_FLAGS_TODO_TO_DONE(todo_flags) ((todo_flags) << 1)
 
-#define PSC_STATE_FLAG_PENAL_UPDATE    (1<<6)  /* save new penalty */
-#define PSC_STATE_FLAG_PENAL_FAIL      (1<<7)  /* penalty is active */
-
-#define PSC_STATE_FLAG_PREGR_FAIL      (1<<8)  /* failed pregreet test */
-#define PSC_STATE_FLAG_PREGR_PASS      (1<<9)  /* passed pregreet test */
-#define PSC_STATE_FLAG_PREGR_TODO      (1<<10) /* pregreet test expired */
-#define PSC_STATE_FLAG_PREGR_DONE      (1<<11) /* decision is final */
-
-#define PSC_STATE_FLAG_DNSBL_FAIL      (1<<12) /* failed DNSBL test */
-#define PSC_STATE_FLAG_DNSBL_PASS      (1<<13) /* passed DNSBL test */
-#define PSC_STATE_FLAG_DNSBL_TODO      (1<<14) /* DNSBL test expired */
-#define PSC_STATE_FLAG_DNSBL_DONE      (1<<15) /* decision is final */
-
- /* Room here for one more after-handshake test. */
+#define PSC_STATE_FLAG_SHIFT_FAIL      (0)     /* failed test */
+#define PSC_STATE_FLAG_SHIFT_PASS      (1)     /* passed test */
+#define PSC_STATE_FLAG_SHIFT_TODO      (2)     /* expired test */
+#define PSC_STATE_FLAG_SHIFT_DONE      (3)     /* decision is final */
+#define PSC_STATE_FLAG_SHIFT_SKIP      (3)     /* action is already logged */
+#define PSC_STATE_FLAG_SHIFT_STRIDE    (4)     /* nr of flags per test */
 
-#define PSC_STATE_FLAG_PIPEL_FAIL      (1<<20) /* failed pipelining test */
-#define PSC_STATE_FLAG_PIPEL_PASS      (1<<21) /* passed pipelining test */
-#define PSC_STATE_FLAG_PIPEL_TODO      (1<<22) /* pipelining test expired */
-#define PSC_STATE_FLAG_PIPEL_SKIP      (1<<23) /* action is already logged */
+#define PSC_STATE_FLAG_SHIFT_BYFNAME(fname) (PSC_STATE_FLAG_SHIFT_ ## fname)
 
-#define PSC_STATE_FLAG_NSMTP_FAIL      (1<<24) /* failed non-SMTP test */
-#define PSC_STATE_FLAG_NSMTP_PASS      (1<<25) /* passed non-SMTP test */
-#define PSC_STATE_FLAG_NSMTP_TODO      (1<<26) /* non-SMTP test expired */
-#define PSC_STATE_FLAG_NSMTP_SKIP      (1<<27) /* action is already logged */
+ /*
+  * Indexable per-test flags. These are used for DNS whitelisting multiple
+  * tests, without needing per-test ad-hoc code.
+  */
+#define PSC_STATE_FLAG_BYTINDX_FNAME(tindx, fname) \
+       (1U << (PSC_STATE_FLAG_TEST_BASE \
+           + PSC_STATE_FLAG_SHIFT_STRIDE * (tindx) \
+           + PSC_STATE_FLAG_SHIFT_BYFNAME(fname)))
+
+#define PSC_STATE_FLAG_BYTINDX_FAIL(tindx) \
+       PSC_STATE_FLAG_BYTINDX_FNAME((tindx), FAIL)
+#define PSC_STATE_FLAG_BYTINDX_PASS(tindx) \
+       PSC_STATE_FLAG_BYTINDX_FNAME((tindx), PASS)
+#define PSC_STATE_FLAG_BYTINDX_TODO(tindx) \
+       PSC_STATE_FLAG_BYTINDX_FNAME((tindx), TODO)
+#define PSC_STATE_FLAG_BYTINDX_DONE(tindx) \
+       PSC_STATE_FLAG_BYTINDX_FNAME((tindx), DONE)
+#define PSC_STATE_FLAG_BYTINDX_SKIP(tindx) \
+       PSC_STATE_FLAG_BYTINDX_FNAME((tindx), SKIP)
 
-#define PSC_STATE_FLAG_BARLF_FAIL      (1<<28) /* failed bare newline test */
-#define PSC_STATE_FLAG_BARLF_PASS      (1<<29) /* passed bare newline test */
-#define PSC_STATE_FLAG_BARLF_TODO      (1<<30) /* bare newline test expired */
-#define PSC_STATE_FLAG_BARLF_SKIP      (1<<31) /* action is already logged */
+ /*
+  * Flags with distinct names. These are used in the per-test ad-hoc code.
+  */
+#define PSC_STATE_FLAG_BYTNAME_FNAME(tname, fname) \
+       (1U << (PSC_STATE_FLAG_TEST_BASE \
+           + PSC_STATE_FLAG_SHIFT_STRIDE * PSC_TINDX_BYTNAME(tname) \
+           + PSC_STATE_FLAG_SHIFT_BYFNAME(fname)))
+
+#define PSC_STATE_FLAG_PREGR_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, FAIL)
+#define PSC_STATE_FLAG_PREGR_PASS PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, PASS)
+#define PSC_STATE_FLAG_PREGR_TODO PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, TODO)
+#define PSC_STATE_FLAG_PREGR_DONE PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, DONE)
+
+#define PSC_STATE_FLAG_DNSBL_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, FAIL)
+#define PSC_STATE_FLAG_DNSBL_PASS PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, PASS)
+#define PSC_STATE_FLAG_DNSBL_TODO PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, TODO)
+#define PSC_STATE_FLAG_DNSBL_DONE PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, DONE)
+
+#define PSC_STATE_FLAG_PIPEL_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, FAIL)
+#define PSC_STATE_FLAG_PIPEL_PASS PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, PASS)
+#define PSC_STATE_FLAG_PIPEL_TODO PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, TODO)
+#define PSC_STATE_FLAG_PIPEL_SKIP PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, SKIP)
+
+#define PSC_STATE_FLAG_NSMTP_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, FAIL)
+#define PSC_STATE_FLAG_NSMTP_PASS PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, PASS)
+#define PSC_STATE_FLAG_NSMTP_TODO PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, TODO)
+#define PSC_STATE_FLAG_NSMTP_SKIP PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, SKIP)
+
+#define PSC_STATE_FLAG_BARLF_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, FAIL)
+#define PSC_STATE_FLAG_BARLF_PASS PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, PASS)
+#define PSC_STATE_FLAG_BARLF_TODO PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, TODO)
+#define PSC_STATE_FLAG_BARLF_SKIP PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, SKIP)
 
  /*
   * Aggregates for individual tests.
@@ -155,6 +223,8 @@ typedef struct {
 #define PSC_STATE_MASK_BARLF_TODO_FAIL \
        (PSC_STATE_FLAG_BARLF_TODO | PSC_STATE_FLAG_BARLF_FAIL)
 
+#define PSC_STATE_MASK_PREGR_TODO_DONE \
+       (PSC_STATE_FLAG_PREGR_TODO | PSC_STATE_FLAG_PREGR_DONE)
 #define PSC_STATE_MASK_PIPEL_TODO_SKIP \
        (PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_PIPEL_SKIP)
 #define PSC_STATE_MASK_NSMTP_TODO_SKIP \
@@ -162,6 +232,9 @@ typedef struct {
 #define PSC_STATE_MASK_BARLF_TODO_SKIP \
        (PSC_STATE_FLAG_BARLF_TODO | PSC_STATE_FLAG_BARLF_SKIP)
 
+#define PSC_STATE_MASK_PREGR_FAIL_DONE \
+       (PSC_STATE_FLAG_PREGR_FAIL | PSC_STATE_FLAG_PREGR_DONE)
+
 #define PSC_STATE_MASK_PIPEL_TODO_PASS_FAIL \
        (PSC_STATE_MASK_PIPEL_TODO_FAIL | PSC_STATE_FLAG_PIPEL_PASS)
 #define PSC_STATE_MASK_NSMTP_TODO_PASS_FAIL \
@@ -195,7 +268,7 @@ typedef struct {
   * Super-aggregates for all tests combined.
   */
 #define PSC_STATE_MASK_ANY_FAIL \
-       (PSC_STATE_FLAG_BLIST_FAIL | PSC_STATE_FLAG_PENAL_FAIL | \
+       (PSC_STATE_FLAG_BLIST_FAIL | \
        PSC_STATE_MASK_EARLY_FAIL | PSC_STATE_MASK_SMTPD_FAIL | \
        PSC_STATE_FLAG_WLIST_FAIL)
 
@@ -209,7 +282,7 @@ typedef struct {
        (PSC_STATE_MASK_ANY_TODO | PSC_STATE_MASK_ANY_FAIL)
 
 #define PSC_STATE_MASK_ANY_UPDATE \
-       (PSC_STATE_MASK_ANY_PASS | PSC_STATE_FLAG_PENAL_UPDATE)
+       (PSC_STATE_MASK_ANY_PASS)
 
  /*
   * Meta-commands for state->where that reflect the initial command processor
@@ -414,12 +487,12 @@ extern int psc_dnsbl_request(const char *, void (*) (int, char *), char *);
   * postscreen_tests.c
   */
 #define PSC_INIT_TESTS(dst) do { \
+       time_t *_it_stamp_p; \
        (dst)->flags = 0; \
-       (dst)->pregr_stamp = PSC_TIME_STAMP_INVALID; \
-       (dst)->dnsbl_stamp = PSC_TIME_STAMP_INVALID; \
-       (dst)->pipel_stamp = PSC_TIME_STAMP_INVALID; \
-       (dst)->barlf_stamp = PSC_TIME_STAMP_INVALID; \
-       (dst)->penal_stamp = PSC_TIME_STAMP_INVALID; \
+       for (_it_stamp_p = (dst)->expire_time; \
+           _it_stamp_p < (dst)->expire_time + PSC_TINDX_COUNT; \
+           _it_stamp_p++) \
+           *_it_stamp_p = PSC_TIME_STAMP_INVALID; \
     } while (0)
 #define PSC_BEGIN_TESTS(state, name) do { \
        (state)->test_name = (name); \
@@ -430,6 +503,7 @@ extern void psc_parse_tests(PSC_STATE *, const char *, time_t);
 extern char *psc_print_tests(VSTRING *, PSC_STATE *);
 extern char *psc_print_grey_key(VSTRING *, const char *, const char *,
                                        const char *, const char *);
+extern const char *psc_test_name(int);
 
 #define PSC_MIN(x, y) ((x) < (y) ? (x) : (y))
 #define PSC_MAX(x, y) ((x) > (y) ? (x) : (y))
index cd77f5afd23081463024ac028efa9271fb79543e..a540703d9cdbec563694efad8efcdf86ed99a0e1 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <sys_defs.h>
 #include <sys/socket.h>
+#include <limits.h>
 
 /* Utility library. */
 
 static char *psc_teaser_greeting;
 static VSTRING *psc_escape_buf;
 
+/* psc_whitelist_non_dnsbl - whitelist pending non-dnsbl tests */
+
+static void psc_whitelist_non_dnsbl(PSC_STATE *state)
+{
+    time_t  now;
+    int     tindx;
+
+    /*
+     * If no tests failed (we can't undo those), and if the whitelist
+     * threshold is met, flag non-dnsbl tests that are pending or disabled as
+     * successfully completed, and set their expiration times equal to the
+     * DNSBL expiration time, except for tests that would expire later.
+     * 
+     * Why flag disabled tests as passed? When a disabled test is turned on,
+     * postscreen should not apply that test to clients that are already
+     * whitelisted based on their combined DNSBL score.
+     */
+    if ((state->flags & PSC_STATE_MASK_ANY_FAIL) == 0
+       && state->dnsbl_score < var_psc_dnsbl_thresh
+       && var_psc_dnsbl_wthresh < 0
+       && state->dnsbl_score <= var_psc_dnsbl_wthresh) {
+       now = event_time();
+       for (tindx = 0; tindx < PSC_TINDX_COUNT; tindx++) {
+           if (tindx == PSC_TINDX_DNSBL)
+               continue;
+           if ((state->flags & PSC_STATE_FLAG_BYTINDX_TODO(tindx))
+               && !(state->flags & PSC_STATE_FLAG_BYTINDX_PASS(tindx))) {
+               if (msg_verbose)
+                   msg_info("skip %s test for [%s]:%s",
+                        psc_test_name(tindx), PSC_CLIENT_ADDR_PORT(state));
+               /* Wrong for deep protocol tests, but we disable those. */
+               state->flags |= PSC_STATE_FLAG_BYTINDX_DONE(tindx);
+               /* This also disables pending deep protocol tests. */
+               state->flags |= PSC_STATE_FLAG_BYTINDX_PASS(tindx);
+           }
+           /* Update expiration even if the test was completed or disabled. */
+           if (state->expire_time[tindx] < now + var_psc_dnsbl_ttl)
+               state->expire_time[tindx] = now + var_psc_dnsbl_ttl;
+       }
+    }
+}
+
 /* psc_early_event - handle pre-greet, EOF, and DNSBL results. */
 
 static void psc_early_event(int event, char *context)
@@ -58,9 +101,7 @@ static void psc_early_event(int event, char *context)
     PSC_STATE *state = (PSC_STATE *) context;
     char    read_buf[PSC_READ_BUF_SIZE];
     int     read_count;
-    int     dnsbl_score;
     DELTA_TIME elapsed;
-    const char *dnsbl_name;
 
     if (msg_verbose > 1)
        msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s",
@@ -83,15 +124,16 @@ static void psc_early_event(int event, char *context)
     switch (event) {
 
        /*
-        * We reached the end of the early tests time limit.
+        * We either reached the end of the early tests time limit, or all
+        * early tests completed before the pregreet timer would go off.
         */
     case EVENT_TIME:
 
        /*
         * Check if the SMTP client spoke before its turn.
         */
-       if ((state->flags & PSC_STATE_MASK_PREGR_TODO_FAIL)
-           == PSC_STATE_FLAG_PREGR_TODO) {
+       if ((state->flags & PSC_STATE_FLAG_PREGR_TODO) != 0
+           && (state->flags & PSC_STATE_MASK_PREGR_FAIL_DONE) == 0) {
            state->pregr_stamp = event_time() + var_psc_pregr_ttl;
            PSC_PASS_SESSION_STATE(state, "pregreet test",
                                   PSC_STATE_FLAG_PREGR_PASS);
@@ -103,35 +145,47 @@ static void psc_early_event(int event, char *context)
        }
 
        /*
+        * Collect the DNSBL score, and whitelist other tests if applicable.
+        * Note: this score will be partial when some DNS lookup did not
+        * complete before the pregreet timer expired.
+        * 
         * If the client is DNS blocklisted, drop the connection, send the
         * client to a dummy protocol engine, or continue to the next test.
         */
 #define PSC_DNSBL_FORMAT \
        "%s 5.7.1 Service unavailable; client [%s] blocked using %s\r\n"
+#define NO_DNSBL_SCORE INT_MAX
 
        if (state->flags & PSC_STATE_FLAG_DNSBL_TODO) {
-           dnsbl_score =
-               psc_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
-                                  state->dnsbl_index);
-           if (dnsbl_score < var_psc_dnsbl_thresh) {
+           if (state->dnsbl_score == NO_DNSBL_SCORE) {
+               state->dnsbl_score =
+                   psc_dnsbl_retrieve(state->smtp_client_addr,
+                                      &state->dnsbl_name,
+                                      state->dnsbl_index);
+               if (var_psc_dnsbl_wthresh < 0)
+                   psc_whitelist_non_dnsbl(state);
+           }
+           if (state->dnsbl_score < var_psc_dnsbl_thresh) {
                state->dnsbl_stamp = event_time() + var_psc_dnsbl_ttl;
                PSC_PASS_SESSION_STATE(state, "dnsbl test",
                                       PSC_STATE_FLAG_DNSBL_PASS);
            } else {
                msg_info("DNSBL rank %d for [%s]:%s",
-                        dnsbl_score, PSC_CLIENT_ADDR_PORT(state));
+                        state->dnsbl_score, PSC_CLIENT_ADDR_PORT(state));
                PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_DNSBL_FAIL);
                switch (psc_dnsbl_action) {
                case PSC_ACT_DROP:
                    state->dnsbl_reply = vstring_sprintf(vstring_alloc(100),
                                                    PSC_DNSBL_FORMAT, "521",
-                                      state->smtp_client_addr, dnsbl_name);
+                                                   state->smtp_client_addr,
+                                                        state->dnsbl_name);
                    PSC_DROP_SESSION_STATE(state, STR(state->dnsbl_reply));
                    return;
                case PSC_ACT_ENFORCE:
                    state->dnsbl_reply = vstring_sprintf(vstring_alloc(100),
                                                    PSC_DNSBL_FORMAT, "550",
-                                      state->smtp_client_addr, dnsbl_name);
+                                                   state->smtp_client_addr,
+                                                        state->dnsbl_name);
                    PSC_ENFORCE_SESSION_STATE(state, STR(state->dnsbl_reply));
                    break;
                case PSC_ACT_IGNORE:
@@ -150,7 +204,9 @@ static void psc_early_event(int event, char *context)
         * Pass the connection to a real SMTP server, or enter the dummy
         * engine for deep tests.
         */
-       if (state->flags & (PSC_STATE_FLAG_NOFORWARD | PSC_STATE_MASK_SMTPD_TODO))
+       if ((state->flags & PSC_STATE_FLAG_NOFORWARD) != 0
+           || ((state->flags & PSC_STATE_MASK_SMTPD_PASS)
+               != PSC_STATE_FLAGS_TODO_TO_PASS(state->flags & PSC_STATE_MASK_SMTPD_TODO)))
            psc_smtpd_tests(state);
        else
            psc_conclude(state);
@@ -165,8 +221,10 @@ static void psc_early_event(int event, char *context)
        if ((read_count = recv(vstream_fileno(state->smtp_client_stream),
                          read_buf, sizeof(read_buf) - 1, MSG_PEEK)) <= 0) {
            /* Avoid memory leak. */
-           if (state->flags & PSC_STATE_FLAG_DNSBL_TODO)
-               (void) psc_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
+           if (state->dnsbl_score == NO_DNSBL_SCORE
+               && (state->flags & PSC_STATE_FLAG_DNSBL_TODO))
+               (void) psc_dnsbl_retrieve(state->smtp_client_addr,
+                                         &state->dnsbl_name,
                                          state->dnsbl_index);
            /* XXX Wait for DNS replies to come in. */
            psc_hangup_event(state);
@@ -181,8 +239,10 @@ static void psc_early_event(int event, char *context)
        switch (psc_pregr_action) {
        case PSC_ACT_DROP:
            /* Avoid memory leak. */
-           if (state->flags & PSC_STATE_FLAG_DNSBL_TODO)
-               (void) psc_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
+           if (state->dnsbl_score == NO_DNSBL_SCORE
+               && (state->flags & PSC_STATE_FLAG_DNSBL_TODO))
+               (void) psc_dnsbl_retrieve(state->smtp_client_addr,
+                                         &state->dnsbl_name,
                                          state->dnsbl_index);
            PSC_DROP_SESSION_STATE(state, "521 5.5.1 Protocol error\r\n");
            return;
@@ -230,6 +290,15 @@ static void psc_early_dnsbl_event(int unused_event, char *context)
     if (msg_verbose)
        msg_info("%s: notify [%s]:%s", myname, PSC_CLIENT_ADDR_PORT(state));
 
+    /*
+     * Collect the DNSBL score, and whitelist other tests if applicable.
+     */
+    state->dnsbl_score =
+       psc_dnsbl_retrieve(state->smtp_client_addr, &state->dnsbl_name,
+                          state->dnsbl_index);
+    if (var_psc_dnsbl_wthresh < 0)
+       psc_whitelist_non_dnsbl(state);
+
     /*
      * Terminate the greet delay if we're just waiting for DNSBL lookup to
      * complete. Don't call psc_early_event directly, that would result in a
@@ -272,6 +341,7 @@ void    psc_early_tests(PSC_STATE *state)
                              (char *) state);
     else
        state->dnsbl_index = -1;
+    state->dnsbl_score = NO_DNSBL_SCORE;
 
     /*
      * Wait for the client to respond or for DNS lookup to complete.
index 5b97ce0325b0a5c1586074781276fa6a495fbce3..c7472cc627d9bffb0139456df943fcf76f53c2ef 100644 (file)
@@ -268,9 +268,6 @@ const char *psc_print_state_flags(int flags, const char *context)
        /* unused */
        "WLIST_FAIL", PSC_STATE_FLAG_WLIST_FAIL,
 
-       "PENAL_UPDATE", PSC_STATE_FLAG_PENAL_UPDATE,
-       "PENAL_FAIL", PSC_STATE_FLAG_PENAL_FAIL,
-
        "PREGR_FAIL", PSC_STATE_FLAG_PREGR_FAIL,
        "PREGR_PASS", PSC_STATE_FLAG_PREGR_PASS,
        "PREGR_TODO", PSC_STATE_FLAG_PREGR_TODO,
index 57bfd69991d9e15f745799c0d96f0cbdc266a8ce..17b7a3926149a951c637d6a160d72a03c0c6a10c 100644 (file)
@@ -27,6 +27,9 @@
 /*     const char *helo;
 /*     const char *sender;
 /*     const char *rcpt;
+/*
+/*     const char *psc_test_name(tindx)
+/*     int     tindx;
 /* DESCRIPTION
 /*     The functions in this module overwrite the per-test expiration
 /*     time stamps and all flags bits.  Some functions are implemented
@@ -54,6 +57,9 @@
 /*     This may modify the time stamps for disabled tests.
 /*
 /*     psc_print_grey_key() prints a greylist lookup key.
+/*
+/*     psc_test_name() returns the name for the specified text
+/*     index.
 /* LICENSE
 /* .ad
 /* .fi
 
 #include <sys_defs.h>
 #include <stdio.h>                     /* sscanf */
+#include <stdlib.h>                    /* strtoul */
 
 /* Utility library. */
 
 #include <msg.h>
+#include <name_code.h>
 
 /* Global library. */
 
@@ -132,7 +140,6 @@ void    psc_new_tests(PSC_STATE *state)
     state->pipel_stamp = PSC_TIME_STAMP_NEW;
     state->nsmtp_stamp = PSC_TIME_STAMP_NEW;
     state->barlf_stamp = PSC_TIME_STAMP_NEW;
-    state->penal_stamp = PSC_TIME_STAMP_NEW;
 
     /*
      * Don't flag disabled tests as "todo", because there would be no way to
@@ -156,17 +163,10 @@ void    psc_parse_tests(PSC_STATE *state,
                                const char *stamp_str,
                                time_t time_value)
 {
-    unsigned long pregr_stamp;
-    unsigned long dnsbl_stamp;
-    unsigned long pipel_stamp;
-    unsigned long nsmtp_stamp;
-    unsigned long barlf_stamp;
-    unsigned long penal_stamp;
-
-#ifdef NONPROD
-    time_t  penalty_left;
-
-#endif
+    const char *start = stamp_str;
+    char   *cp;
+    time_t *time_stamps = state->expire_time;
+    time_t *sp;
 
     /*
      * We don't know what tests have expired or have never passed.
@@ -182,37 +182,19 @@ void    psc_parse_tests(PSC_STATE *state,
      * enabled tests, but the remote SMTP client has not yet passed all those
      * tests.
      */
-    switch (sscanf(stamp_str, "%lu;%lu;%lu;%lu;%lu;%lu",
-                  &pregr_stamp, &dnsbl_stamp, &pipel_stamp, &nsmtp_stamp,
-                  &barlf_stamp, &penal_stamp)) {
-    case 0:
-       pregr_stamp = PSC_TIME_STAMP_DISABLED;
-    case 1:
-       dnsbl_stamp = PSC_TIME_STAMP_DISABLED;
-    case 2:
-       pipel_stamp = PSC_TIME_STAMP_DISABLED;
-    case 3:
-       nsmtp_stamp = PSC_TIME_STAMP_DISABLED;
-    case 4:
-       barlf_stamp = PSC_TIME_STAMP_DISABLED;
-    case 5:
-       penal_stamp = PSC_TIME_STAMP_DISABLED;
-    default:
-       break;
+    for (sp = time_stamps; sp < time_stamps + PSC_TINDX_COUNT; sp++) {
+       *sp = strtoul(start, &cp, 10);
+       if (*start == 0 || (*cp != '\0' && *cp != ';') || errno == ERANGE)
+           *sp = PSC_TIME_STAMP_DISABLED;
+       if (*sp == PSC_TIME_STAMP_NEW)
+           state->flags |= PSC_STATE_FLAG_NEW;
+       if (msg_verbose)
+           msg_info("%s -> %lu", start, (unsigned long) *sp);
+       if (*cp == ';')
+           start = cp + 1;
+       else
+           start = cp;
     }
-    state->pregr_stamp = pregr_stamp;
-    state->dnsbl_stamp = dnsbl_stamp;
-    state->pipel_stamp = pipel_stamp;
-    state->nsmtp_stamp = nsmtp_stamp;
-    state->barlf_stamp = barlf_stamp;
-    state->penal_stamp = penal_stamp;
-
-    if (pregr_stamp == PSC_TIME_STAMP_NEW
-       || dnsbl_stamp == PSC_TIME_STAMP_NEW
-       || pipel_stamp == PSC_TIME_STAMP_NEW
-       || nsmtp_stamp == PSC_TIME_STAMP_NEW
-       || barlf_stamp == PSC_TIME_STAMP_NEW)
-       state->flags |= PSC_STATE_FLAG_NEW;
 
     /*
      * Don't flag disabled tests as "todo", because there would be no way to
@@ -270,41 +252,6 @@ void    psc_parse_tests(PSC_STATE *state,
            state->flags |= PSC_STATE_FLAG_DNSBL_TODO;
     }
 #endif
-
-    /*
-     * Apply unexpired penalty for past behavior.
-     * 
-     * XXX Before we can drop connections, change this function to return
-     * success/fail, to inform the caller that the state object no longer
-     * exists.
-     */
-#ifdef NONPROD
-    if ((penalty_left = state->penal_stamp - event_time()) > 0) {
-       msg_info("PENALTY %ld for %s",
-                (long) penalty_left, state->smtp_client_addr);
-       PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_PENAL_FAIL);
-#if 0
-       switch (psc_penal_action) {
-       case PSC_ACT_DROP:
-           PSC_DROP_SESSION_STATE(state,
-                            "421 4.3.2 Service currently unavailable\r\n");
-           break;
-       case PSC_ACT_ENFORCE:
-#endif
-           PSC_ENFORCE_SESSION_STATE(state,
-                            "450 4.3.2 Service currently unavailable\r\n");
-#if 0
-           break;
-       case PSC_ACT_IGNORE:
-           PSC_UNFAIL_SESSION_STATE(state, PSC_STATE_FLAG_PENAL_FAIL);
-           break;
-       default:
-           msg_panic("%s: unknown penalty action value %d",
-                     myname, psc_penal_action);
-       }
-#endif
-    }
-#endif                                         /* NONPROD */
 }
 
 /* psc_print_tests - print postscreen cache record */
@@ -319,25 +266,6 @@ char   *psc_print_tests(VSTRING *buf, PSC_STATE *state)
     if ((state->flags & PSC_STATE_MASK_ANY_UPDATE) == 0)
        msg_panic("%s: attempt to save a no-update record", myname);
 
-    /*
-     * Don't record a client as "passed" while subject to penalty. Be sure to
-     * produce correct PASS OLD/NEW logging.
-     * 
-     * XXX This needs to be refined - we should not reset the result of tests
-     * that were passed in previous sessions, otherwise a client may never
-     * pass a multi-stage test such as greylisting. One solution is to keep
-     * the original and updated time stamps around, and to save an updated
-     * time stamp only when the corresponding "pass" flag is raised.
-     */
-#ifdef NONPROD
-    if (state->flags & PSC_STATE_FLAG_PENAL_FAIL) {
-       state->pregr_stamp = state->dnsbl_stamp = state->pipel_stamp =
-           state->nsmtp_stamp = state->barlf_stamp =
-           ((state->flags & PSC_STATE_FLAG_NEW) ?
-            PSC_TIME_STAMP_NEW : PSC_TIME_STAMP_DISABLED);
-    }
-#endif
-
     /*
      * Give disabled tests a dummy time stamp so that we don't log a client
      * with "pass new" when some disabled test becomes enabled at some later
@@ -354,13 +282,12 @@ char   *psc_print_tests(VSTRING *buf, PSC_STATE *state)
     if (var_psc_barlf_enable == 0 && state->barlf_stamp == PSC_TIME_STAMP_NEW)
        state->barlf_stamp = PSC_TIME_STAMP_DISABLED;
 
-    vstring_sprintf(buf, "%lu;%lu;%lu;%lu;%lu;%lu",
+    vstring_sprintf(buf, "%lu;%lu;%lu;%lu;%lu",
                    (unsigned long) state->pregr_stamp,
                    (unsigned long) state->dnsbl_stamp,
                    (unsigned long) state->pipel_stamp,
                    (unsigned long) state->nsmtp_stamp,
-                   (unsigned long) state->barlf_stamp,
-                   (unsigned long) state->penal_stamp);
+                   (unsigned long) state->barlf_stamp);
     return (STR(buf));
 }
 
@@ -373,3 +300,23 @@ char   *psc_print_grey_key(VSTRING *buf, const char *client,
     return (STR(vstring_sprintf(buf, "%s/%s/%s/%s",
                                client, helo, sender, rcpt)));
 }
+
+/* psc_test_name - map test index to symbolic name */
+
+const char *psc_test_name(int tindx)
+{
+    const char *myname = "psc_test_name";
+    const NAME_CODE test_name_map[] = {
+       PSC_TNAME_PREGR, PSC_TINDX_PREGR,
+       PSC_TNAME_DNSBL, PSC_TINDX_DNSBL,
+       PSC_TNAME_PIPEL, PSC_TINDX_PIPEL,
+       PSC_TNAME_NSMTP, PSC_TINDX_NSMTP,
+       PSC_TNAME_BARLF, PSC_TINDX_BARLF,
+       0, -1,
+    };
+    const char *result;
+
+    if ((result = str_name_code(test_name_map, tindx)) == 0)
+       msg_panic("%s: bad index %d", myname, tindx);
+    return (result);
+}
index fffad281ee09af41c013cc0e4a9e80152ae30b25..3ca448ac36217f83a5607cffeef6bbc2b34fb637 100644 (file)
@@ -425,8 +425,8 @@ typedef struct STATE {
     TLS_SESS_STATE *tls_context;       /* Session TLS context */
     TLS_DANE *dane;                    /* DANE TLSA validation structure */
     TLS_DANE *ddane;                   /* DANE TLSA from DNS */
-    char     *grade;                   /* Minimum cipher grade */
-    char     *protocols;               /* Protocol inclusion/exclusion */
+    char   *grade;                     /* Minimum cipher grade */
+    char   *protocols;                 /* Protocol inclusion/exclusion */
 #endif
     OPTIONS options;                   /* JCL */
 } STATE;
index 413fcfbc48078c2f864dfabc2e4d0dcee80a0836..d6b09d87c854d9a994a29fc9ef7bf2999e7eb075 100644 (file)
@@ -140,4 +140,3 @@ int     tls_mgr_delete(const char *unused_type, const char *key)
 }
 
 #endif
-
index be2946b1498b36d244e9295dbf3130e8451e3fc3..706b206b7f59855f57a396f060f0944247cb1ed8 100644 (file)
@@ -26,4 +26,3 @@ extern void tlsmgrmem_flush(void);
 /*
 /*     Viktor Dukhovni
 /*--*/
-
index 576fb2d6fe4bd1b35c6300fa0ee1382cc7d3fbe5..e6bbaf65cf5873727efee9f8649b01d7bf0d33c0 100644 (file)
@@ -1234,7 +1234,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
                   : strlen(STR(reply.recipient)));
            vstring_strncpy(queue_name, STR(reply.recipient), len);
            /* Remove the address extension from the recipient localpart. */
-           if (*var_rcpt_delim && split_addr(STR(queue_name), *var_rcpt_delim))
+           if (*var_rcpt_delim && split_addr(STR(queue_name), var_rcpt_delim))
                vstring_truncate(queue_name, strlen(STR(queue_name)));
            /* Assume the recipient domain is equivalent to nexthop. */
            vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop));
index 1f219e187c513e5640f3a33fb04349b96b6b4207..ce2b31d26cac96df6d5206a6d1f688183a8219d3 100644 (file)
 /*     not contain RFC 822 style comments or phrases.
 /* .PP
 /*     Available in Postfix version 2.1 and later:
-/* .IP "\fBresolve_null_domain (no)\fR"
-/*     Resolve an address that ends in the "@" null domain as if the
-/*     local hostname were specified, instead of rejecting the address as
-/*     invalid.
 /* .IP "\fBsmtpd_reject_unlisted_sender (no)\fR"
 /*     Request that the Postfix SMTP server rejects mail from unknown
 /*     sender addresses, even when no explicit reject_unlisted_sender
 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
 /*     The location of the Postfix top-level queue directory.
 /* .IP "\fBrecipient_delimiter (empty)\fR"
-/*     The separator between user names and address extensions (user+foo).
+/*     The set of characters that can separate a user name from its
+/*     address extension (user+foo).
 /* .IP "\fBsmtpd_banner ($myhostname ESMTP $mail_name)\fR"
 /*     The text that follows the 220 status code in the SMTP greeting
 /*     banner.
index e5b165bf14158519e8c9b4ce676c4936017be48c..a27dc701225acd7cb0ed83bdbfa49839314b2064 100644 (file)
@@ -2866,7 +2866,7 @@ static int check_mail_access(SMTPD_STATE *state, const char *table,
     if (*var_rcpt_delim == 0) {
        bare_addr = 0;
     } else {
-       bare_addr = strip_addr(addr, (char **) 0, *var_rcpt_delim);
+       bare_addr = strip_addr(addr, (char **) 0, var_rcpt_delim);
     }
 
 #define CHECK_MAIL_ACCESS_RETURN(x) \
index f77885436b1335427b2c1e326c20436dc427d9cd..aec8049745dd4c59683433dc7ff800a2c10c1401 100644 (file)
@@ -30,9 +30,6 @@
 /*     int     expect;
 /*     const char *format;
 /*
-/*     void    smtpd_proxy_disconnect(state)
-/*     SMTPD_STATE *state;
-/*
 /*     void    smtpd_proxy_free(state)
 /*     SMTPD_STATE *state;
 /*
 /*     In case of error, proxy->cmd() updates the state->error_mask
 /*     and state->err fields.
 /*
-/*     smtpd_proxy_disconnect() disconnects from a proxy server.
-/*     The last proxy server reply or error description remains
-/*     available via the proxy->buffer field.
-/*
 /*     smtpd_proxy_free() destroys a proxy server handle and resets
 /*     the state->proxy field.
 /*
index d961199bfe67cea298895575c6500779054cb14a..e9c94daf8ca72035e9adbbb75dccee8120fc70ae 100644 (file)
 #include <mymalloc.h>
 #include <stringops.h>
 #include <vstring.h>
-#include <events.h>            /* event_time() */
+#include <events.h>                    /* event_time() */
 #include <timecmp.h>
 #include <ctable.h>
 
@@ -201,22 +201,22 @@ static CTABLE *dane_cache;
 
 /* tls_dane_verbose - enable/disable verbose logging */
 
-void   tls_dane_verbose(int on)
+void    tls_dane_verbose(int on)
 {
     dane_verbose = on;
 }
 
 /* tls_dane_avail - check for availability of dane required digests */
 
-int    tls_dane_avail(void)
+int     tls_dane_avail(void)
 {
-#ifdef TLSEXT_MAXLEN_host_name                 /* DANE mandates client SNI. */
+#ifdef TLSEXT_MAXLEN_host_name         /* DANE mandates client SNI. */
     static int avail = -1;
     const EVP_MD *sha256md;
     const EVP_MD *sha512md;
     static NAME_MASK ta_dgsts[] = {
-       TLS_DANE_CC,    TLS_DANE_ENABLE_CC,
-       TLS_DANE_TAA,   TLS_DANE_ENABLE_TAA,
+       TLS_DANE_CC, TLS_DANE_ENABLE_CC,
+       TLS_DANE_TAA, TLS_DANE_ENABLE_TAA,
        0,
     };
 
@@ -239,13 +239,13 @@ int       tls_dane_avail(void)
 
     return (avail = 1);
 #else
-    return (0);
+            return (0);
 #endif
 }
 
 /* tls_dane_flush - flush the cache */
 
-void   tls_dane_flush(void)
+void    tls_dane_flush(void)
 {
     if (dane_cache)
        ctable_free(dane_cache);
@@ -256,7 +256,7 @@ void        tls_dane_flush(void)
 
 TLS_DANE *tls_dane_alloc(int flags)
 {
-    TLS_DANE *dane = (TLS_DANE *)mymalloc(sizeof(*dane));
+    TLS_DANE *dane = (TLS_DANE *) mymalloc(sizeof(*dane));
 
     dane->ta = 0;
     dane->ee = 0;
@@ -270,7 +270,7 @@ TLS_DANE *tls_dane_alloc(int flags)
 
 static void ta_cert_insert(TLS_DANE *d, X509 *x)
 {
-    TLS_CERTS *new = (TLS_CERTS *)mymalloc(sizeof(*new));
+    TLS_CERTS *new = (TLS_CERTS *) mymalloc(sizeof(*new));
 
     CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
     new->cert = x;
@@ -286,13 +286,13 @@ static void free_ta_certs(TLS_DANE *d)
     for (head = d->certs; head; head = next) {
        next = head->next;
        X509_free(head->cert);
-       myfree((char *)head);
+       myfree((char *) head);
     }
 }
 
 static void ta_pkey_insert(TLS_DANE *d, EVP_PKEY *k)
 {
-    TLS_PKEYS *new = (TLS_PKEYS *)mymalloc(sizeof(*new));
+    TLS_PKEYS *new = (TLS_PKEYS *) mymalloc(sizeof(*new));
 
     CRYPTO_add(&k->references, 1, CRYPTO_LOCK_EVP_PKEY);
     new->pkey = k;
@@ -308,7 +308,7 @@ static void free_ta_pkeys(TLS_DANE *d)
     for (head = d->pkeys; head; head = next) {
        next = head->next;
        EVP_PKEY_free(head->pkey);
-       myfree((char *)head);
+       myfree((char *) head);
     }
 }
 
@@ -320,12 +320,12 @@ static void tlsa_free(TLS_TLSA *tlsa)
        argv_free(tlsa->certs);
     if (tlsa->pkeys)
        argv_free(tlsa->pkeys);
-    myfree((char *)tlsa);
+    myfree((char *) tlsa);
 }
 
 /* tls_dane_free - free a TLS_DANE structure */
 
-void   tls_dane_free(TLS_DANE *dane)
+void    tls_dane_free(TLS_DANE *dane)
 {
     TLS_TLSA *tlsa;
     TLS_TLSA *next;
@@ -347,14 +347,14 @@ void      tls_dane_free(TLS_DANE *dane)
     free_ta_certs(dane);
     free_ta_pkeys(dane);
 
-    myfree((char *)dane);
+    myfree((char *) dane);
 }
 
 /* dane_free - ctable style */
 
 static void dane_free(void *dane, void *unused_context)
 {
-    tls_dane_free((TLS_DANE *)dane);
+    tls_dane_free((TLS_DANE *) dane);
 }
 
 /* tlsa_sort - sort digests for a single certusage */
@@ -373,6 +373,7 @@ static void tlsa_sort(TLS_TLSA *tlsa)
 
 TLS_DANE *tls_dane_final(TLS_DANE *dane)
 {
+
     /*
      * We only sort the trust anchors, see tls_serverid_digest().
      */
@@ -390,8 +391,8 @@ static TLS_TLSA **dane_locate(TLS_TLSA **tlsap, const char *mdalg)
 
     /*
      * Correct computation of the session cache serverid requires a TLSA
-     * digest list that is sorted by algorithm name.  Below we maintain
-     * the sort order (by algorithm name canonicalized to lowercase).
+     * digest list that is sorted by algorithm name.  Below we maintain the
+     * sort order (by algorithm name canonicalized to lowercase).
      */
     for (; *tlsap; tlsap = &(*tlsap)->next) {
        int     cmp = strcasecmp(mdalg, (*tlsap)->mdalg);
@@ -402,7 +403,7 @@ static TLS_TLSA **dane_locate(TLS_TLSA **tlsap, const char *mdalg)
            break;
     }
 
-    new = (TLS_TLSA *)mymalloc(sizeof(*new));
+    new = (TLS_TLSA *) mymalloc(sizeof(*new));
     new->mdalg = lowercase(mystrdup(mdalg));
     new->certs = 0;
     new->pkeys = 0;
@@ -414,8 +415,8 @@ static TLS_TLSA **dane_locate(TLS_TLSA **tlsap, const char *mdalg)
 
 /* tls_dane_split - split and append digests */
 
-void tls_dane_split(TLS_DANE *dane, int certusage, int selector,
-                   const char *mdalg, const char *digest, const char *delim)
+void    tls_dane_split(TLS_DANE *dane, int certusage, int selector,
+                  const char *mdalg, const char *digest, const char *delim)
 {
     TLS_TLSA **tlsap;
     TLS_TLSA *tlsa;
@@ -450,7 +451,7 @@ void tls_dane_split(TLS_DANE *dane, int certusage, int selector,
 /* dane_add - add a digest entry */
 
 static void dane_add(TLS_DANE *dane, int certusage, int selector,
-                    const char *mdalg, char *digest)
+                            const char *mdalg, char *digest)
 {
     TLS_TLSA **tlsap;
     TLS_TLSA *tlsa;
@@ -462,11 +463,11 @@ static void dane_add(TLS_DANE *dane, int certusage, int selector,
     switch (certusage) {
     case DNS_TLSA_USAGE_CA_CONSTRAINT:
     case DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
-       certusage = TLS_DANE_TA;        /* Collapse 0/2 -> 2 */
+       certusage = TLS_DANE_TA;                /* Collapse 0/2 -> 2 */
        break;
     case DNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT:
     case DNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE:
-       certusage = TLS_DANE_EE;        /* Collapse 1/3 -> 3 */
+       certusage = TLS_DANE_EE;                /* Collapse 1/3 -> 3 */
        break;
     }
 
@@ -498,18 +499,18 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
     uint8_t mtype;
     int     mlen;
     const unsigned char *p;
-    X509   *x = 0;             /* OpenSSL tries to re-use *x if x!=0 */
-    EVP_PKEY *k = 0;           /* OpenSSL tries to re-use *k if k!=0 */
+    X509   *x = 0;                     /* OpenSSL tries to re-use *x if x!=0 */
+    EVP_PKEY *k = 0;                   /* OpenSSL tries to re-use *k if k!=0 */
 
     if (rr == 0)
        msg_panic("null TLSA rr");
 
-    for (/* nop */; rr; rr = rr->next) {
+    for ( /* nop */ ; rr; rr = rr->next) {
        const char *mdalg = 0;
        int     mdlen;
        char   *digest;
        int     same = (strcasecmp(rr->rname, rr->qname) == 0);
-       uint8_t *ip = (uint8_t *)rr->data;
+       uint8_t *ip = (uint8_t *) rr->data;
 
 #define rcname(rr) (same ? "" : rr->qname)
 #define rarrow(rr) (same ? "" : " -> ")
@@ -521,10 +522,9 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
        /* Skip malformed */
        if ((mlen = rr->data_len - 3) < 0) {
            msg_warn("truncated length %u RR: %s%s%s IN TLSA ...",
-                    (unsigned)rr->data_len, rcname(rr), rarrow(rr), rr->rname);
+               (unsigned) rr->data_len, rcname(rr), rarrow(rr), rr->rname);
            continue;
        }
-
        switch (usage = *ip++) {
        default:
            msg_warn("unsupported certificate usage %u in RR: "
@@ -594,11 +594,11 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
                break;
            }
            dane_add(dane, usage, selector, mdalg,
-                    digest = tls_digest_encode((unsigned char *)ip, mdlen));
+                  digest = tls_digest_encode((unsigned char *) ip, mdlen));
            break;
 
        case DNS_TLSA_MATCHING_TYPE_NO_HASH_USED:
-           p = (unsigned char *)ip;
+           p = (unsigned char *) ip;
 
            /* Validate the cert or public key via d2i_mumble() */
            switch (selector) {
@@ -610,13 +610,14 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
                             usage, selector, mtype);
                    continue;
                }
+
                /*
                 * When a full trust-anchor certificate is published via DNS,
                 * we may need to use it to validate the server trust chain.
-                * Store it away for later use.  We collapse certificate usage
-                * 0/2 because MTAs don't stock a complete list of the usual
-                * browser-trusted CAs.  Thus, here (and in the public key
-                * case below) we treat the usages identically.
+                * Store it away for later use.  We collapse certificate
+                * usage 0/2 because MTAs don't stock a complete list of the
+                * usual browser-trusted CAs.  Thus, here (and in the public
+                * key case below) we treat the usages identically.
                 */
                switch (usage) {
                case DNS_TLSA_USAGE_CA_CONSTRAINT:
@@ -644,12 +645,13 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
                EVP_PKEY_free(k);
                break;
            }
+
            /*
-            * The cert or key was valid, just digest the raw object,
-            * and encode the digest value.  We choose SHA256.
+            * The cert or key was valid, just digest the raw object, and
+            * encode the digest value.  We choose SHA256.
             */
            dane_add(dane, usage, selector, sha256,
-                    digest = tls_data_fprint((char *)ip, mlen, sha256));
+                    digest = tls_data_fprint((char *) ip, mlen, sha256));
            break;
        }
        if (msg_verbose || dane_verbose)
@@ -705,13 +707,13 @@ static void *dane_lookup(const char *tlsa_fqdn, void *unused_ctx)
        break;
     }
 
-    return ((void *)tls_dane_final(dane));
+    return ((void *) tls_dane_final(dane));
 }
 
 /* tls_dane_resolve - cached map: (host, proto, port) -> TLS_DANE */
 
 TLS_DANE *tls_dane_resolve(const char *host, const char *proto,
-                                unsigned port)
+                                  unsigned port)
 {
     static VSTRING *qname;
     TLS_DANE *dane;
@@ -725,9 +727,9 @@ TLS_DANE *tls_dane_resolve(const char *host, const char *proto,
     if (qname == 0)
        qname = vstring_alloc(64);
     vstring_sprintf(qname, "_%u._%s.%s", ntohs(port), proto, host);
-    dane = (TLS_DANE *)ctable_locate(dane_cache, STR(qname));
+    dane = (TLS_DANE *) ctable_locate(dane_cache, STR(qname));
     if (timecmp(event_time(), dane->expires) > 0)
-       dane = (TLS_DANE *)ctable_refresh(dane_cache, STR(qname));
+       dane = (TLS_DANE *) ctable_refresh(dane_cache, STR(qname));
 
     if (dane->flags & TLS_DANE_FLAG_ERROR)
        return (0);
@@ -738,7 +740,7 @@ TLS_DANE *tls_dane_resolve(const char *host, const char *proto,
 
 /* tls_dane_load_trustfile - load trust anchor certs or keys from file */
 
-int    tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
+int     tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
 {
     BIO    *bp;
     char   *name = 0;
@@ -746,22 +748,22 @@ int       tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
     unsigned char *data = 0;
     long    len;
     int     tacount;
-    char   *errtype = 0;                       /* if error: cert or pkey? */
+    char   *errtype = 0;               /* if error: cert or pkey? */
 
     /* nop */
     if (tafile == 0 || *tafile == 0)
        return (1);
 
     /*
-     * On each call, PEM_read() wraps a stdio file in a BIO_NOCLOSE bio, calls
-     * PEM_read_bio() and then frees the bio.  It is just as easy to open a
-     * BIO as a stdio file, so we use BIOs and call PEM_read_bio() directly.
+     * On each call, PEM_read() wraps a stdio file in a BIO_NOCLOSE bio,
+     * calls PEM_read_bio() and then frees the bio.  It is just as easy to
+     * open a BIO as a stdio file, so we use BIOs and call PEM_read_bio()
+     * directly.
      */
     if ((bp = BIO_new_file(tafile, "r")) == NULL) {
        msg_warn("error opening trust anchor file: %s: %m", tafile);
        return (0);
     }
-
     /* Don't report old news */
     ERR_clear_error();
 
@@ -779,7 +781,7 @@ int tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
 
            if (cert && (p - data) == len) {
                selector = DNS_TLSA_SELECTOR_FULL_CERTIFICATE;
-               digest = tls_data_fprint((char *)data, len, sha256);
+               digest = tls_data_fprint((char *) data, len, sha256);
                dane_add(dane, usage, selector, sha256, digest);
                myfree(digest);
                ta_cert_insert(dane, cert);
@@ -792,7 +794,7 @@ int tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
 
            if (pkey && (p - data) == len) {
                selector = DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO;
-               digest = tls_data_fprint((char *)data, len, sha256);
+               digest = tls_data_fprint((char *) data, len, sha256);
                dane_add(dane, usage, selector, sha256, digest);
                myfree(digest);
                ta_pkey_insert(dane, pkey);
@@ -817,13 +819,11 @@ int       tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
                 tafile, errtype);
        return (0);
     }
-
     if (ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) {
        /* Reached end of PEM file */
        ERR_clear_error();
        return (tacount > 0);
     }
-
     /* Some other PEM read error */
     tls_print_errors();
     return (0);
index 93b5fb1d5532591adfaea4a1acfae76317a402d6..86f47759b90b55c66b1102b3bfc936fc9567b29c 100644 (file)
@@ -950,11 +950,12 @@ long    tls_bug_bits(void)
     }
 
     /*
-     * Allow users to set options not in SSL_OP_ALL, and not already
-     * managed via other Postfix parameters.
+     * Allow users to set options not in SSL_OP_ALL, and not already managed
+     * via other Postfix parameters.
      */
     if (*var_tls_ssl_options) {
-        long    enable;
+       long    enable;
+
        enable = long_name_mask_opt(VAR_TLS_SSL_OPTIONS, ssl_op_tweaks,
                                    var_tls_ssl_options, NAME_MASK_ANY_CASE |
                                    NAME_MASK_NUMBER | NAME_MASK_WARN);
index c0b6d9964cad33915f647247326b6dd87fa7a7d1..d9a709e30fad24eed739c6b792d2aa548bee7316 100644 (file)
@@ -324,9 +324,18 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr,
            tok822_free(tree->head);
            tree->head = 0;
        }
-       /* XXX must be localpart only, not user@domain form. */
-       if (tree->head == 0)
+       /* XXX Re-resolve the surrogate, in case already in user@domain form. */
+       if (tree->head == 0) {
            tree->head = tok822_scan(var_empty_addr, &tree->tail);
+           continue;
+       }
+
+       /* XXX Re-resolve with @$myhostname for backwards compatibility. */
+       if (domain == 0 && saved_domain == 0) {
+           tok822_sub_append(tree, tok822_alloc('@', (char *) 0));
+           tok822_sub_append(tree, tok822_scan(var_myhostname, (TOK822 **) 0));
+           continue;
+       }
 
        /*
         * We're done. There are no domains left to strip off the address,
index 29720541c82bd4683ceddb9545edd1ab3ff58136..61937ae42e20b36eba153c656fd3ca87bcb6fa9a 100644 (file)
@@ -286,7 +286,7 @@ int     transport_lookup(TRANSPORT_INFO *tp, const char *addr,
      * partial lookup keys with regular expressions.
      */
     if ((stripped_addr = strip_addr(addr, DISCARD_EXTENSION,
-                                   *var_rcpt_delim)) != 0) {
+                                   var_rcpt_delim)) != 0) {
        found = find_transport_entry(tp, stripped_addr, rcpt_domain, PARTIAL,
                                     channel, nexthop);
 
index b8cc438c2009830ff967427c0ea19bbf0a86a278..c5dbe066333a4d49b41e7d720031837a2344ace4 100644 (file)
 /* .IP "\fBresolve_dequoted_address (yes)\fR"
 /*     Resolve a recipient address safely instead of correctly, by
 /*     looking inside quotes.
+/* .PP
+/*     Available with Postfix version 2.1 and later:
 /* .IP "\fBresolve_null_domain (no)\fR"
 /*     Resolve an address that ends in the "@" null domain as if the
 /*     local hostname were specified, instead of rejecting the address as
 /*     invalid.
+/* .PP
+/*     Available with Postfix version 2.3 and later:
 /* .IP "\fBresolve_numeric_domain (no)\fR"
 /*     Resolve "user@ipaddress" as "user@[ipaddress]", instead of
 /*     rejecting the address as invalid.
 /*     With locally submitted mail, append the string ".$mydomain" to
 /*     addresses that have no ".domain" information.
 /* .IP "\fBrecipient_delimiter (empty)\fR"
-/*     The separator between user names and address extensions (user+foo).
+/*     The set of characters that can separate a user name from its
+/*     address extension (user+foo).
 /* .IP "\fBswap_bangpath (yes)\fR"
 /*     Enable the rewriting of "site!user" into "user@site".
 /* .PP
index 35bb56db5d5cc7d84cc26cfebb915bd0e749a1e0..5b2eec3eb6934bca50479066c486d145d673ca6b 100644 (file)
@@ -156,8 +156,9 @@ ARGV   *argv_alloc(ssize_t len)
 
 static int argv_cmp(const void *e1, const void *e2)
 {
-    const char *s1 = *(const char **)e1;
-    const char *s2 = *(const char **)e2;
+    const char *s1 = *(const char **) e1;
+    const char *s2 = *(const char **) e2;
+
     return strcmp(s1, s2);
 }
 
index 8d77883f53466a0a52a1f8e8c29cfff5e727462e..3c4a9b1b83f3b87de85c6bb3a3f17f0dd0ddc94b 100644 (file)
@@ -431,6 +431,7 @@ void    dict_load_fp(const char *dict_name, VSTREAM *fp)
     VSTRING *buf;
     char   *member;
     char   *val;
+    const char *old;
     int     old_lineno;
     int     lineno;
     const char *err;
@@ -455,6 +456,10 @@ void    dict_load_fp(const char *dict_name, VSTREAM *fp)
                      err, STR(buf));
        if (msg_verbose > 1)
            msg_info("%s: %s = %s", myname, member, val);
+       if ((old = dict->lookup(dict, member)) != 0
+           && strcmp(old, val) != 0)
+           msg_warn("%s, line %d: overriding earlier entry: %s=%s",
+                    VSTREAM_PATH(fp), lineno, member, old);
        if (dict->update(dict, member, val) != 0)
            msg_fatal("%s, line %d: unable to update %s:%s",
                      VSTREAM_PATH(fp), lineno, dict->type, dict->name);
index e8c7ed21f710bcb1a0986957d5cd99ab80b06126..80cd0f67daf70d63f46d4bf1766478d5c8c3547c 100644 (file)
@@ -27,8 +27,8 @@
 /*     int     true_res;
 /*     int     false_res;
 /* DESCRIPTION
-/*     The functions in this module are macros that provide a
-/*     convenient interface to poll_fd().
+/*     The read*() and write*() functions in this module are macros
+/*     that provide a convenient interface to poll_fd().
 /*
 /*     readable() asks the kernel if the specified file descriptor
 /*     is readable, i.e. a read operation would not block.
@@ -72,8 +72,8 @@
 /*     it is false. They never return an error indication.
 /*
 /*     read_wait() and write_wait() return zero when the requested
-/*     POLL_FD_READ or POLL_FD_WRITE condition is true, -1 with
-/*     errno set to ETIMEDOUT when it is false.
+/*     POLL_FD_READ or POLL_FD_WRITE condition is true, -1 (with
+/*     errno set to ETIMEDOUT) when it is false.
 /*
 /*     poll_fd() returns true_res when the requested POLL_FD_READ
 /*     or POLL_FD_WRITE condition is true, false_res when it is