]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.8-20110102
authorWietse Venema <wietse@porcupine.org>
Sun, 2 Jan 2011 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:36:49 +0000 (06:36 +0000)
82 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/Makefile.in
postfix/README_FILES/POSTSCREEN_README
postfix/README_FILES/TLS_README
postfix/RELEASE_NOTES
postfix/WISHLIST
postfix/conf/master.cf
postfix/conf/post-install
postfix/conf/postfix-files
postfix/html/Makefile.in
postfix/html/POSTSCREEN_README.html
postfix/html/TLS_README.html
postfix/html/lmtp.8.html
postfix/html/postconf.5.html
postfix/html/postfix-manuals.html
postfix/html/postfix.1.html
postfix/html/postscreen.8.html
postfix/html/smtp.8.html
postfix/html/smtpd.8.html
postfix/html/tlsproxy.8.html [new file with mode: 0644]
postfix/man/Makefile.in
postfix/man/man1/postfix.1
postfix/man/man5/postconf.5
postfix/man/man8/postscreen.8
postfix/man/man8/smtp.8
postfix/man/man8/smtpd.8
postfix/man/man8/tlsproxy.8 [new file with mode: 0644]
postfix/mantools/postlink
postfix/proto/POSTSCREEN_README.html
postfix/proto/TLS_README.html
postfix/proto/postconf.proto
postfix/src/global/ehlo_mask.c
postfix/src/global/mail_params.h
postfix/src/global/mail_proto.h
postfix/src/global/mail_version.h
postfix/src/postfix/postfix.c
postfix/src/postscreen/Makefile.in
postfix/src/postscreen/postscreen.c
postfix/src/postscreen/postscreen.h
postfix/src/postscreen/postscreen_dict.c
postfix/src/postscreen/postscreen_dnsbl.c
postfix/src/postscreen/postscreen_early.c
postfix/src/postscreen/postscreen_misc.c
postfix/src/postscreen/postscreen_send.c
postfix/src/postscreen/postscreen_smtpd.c
postfix/src/postscreen/postscreen_starttls.c [new file with mode: 0644]
postfix/src/postscreen/postscreen_state.c
postfix/src/postscreen/postscreen_tests.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtpd/smtpd.c
postfix/src/tls/tls.h
postfix/src/tls/tls_client.c
postfix/src/tls/tls_misc.c
postfix/src/tls/tls_server.c
postfix/src/tlsproxy/.indent.pro [new symlink]
postfix/src/tlsproxy/Makefile.in [new file with mode: 0644]
postfix/src/tlsproxy/tlsproxy.c [new file with mode: 0644]
postfix/src/tlsproxy/tlsproxy.h [new file with mode: 0644]
postfix/src/tlsproxy/tlsproxy_state.c [new file with mode: 0644]
postfix/src/util/Makefile.in
postfix/src/util/events.h
postfix/src/util/make_dirs.c
postfix/src/util/name_mask.c
postfix/src/util/name_mask.h
postfix/src/util/name_mask.in [new file with mode: 0644]
postfix/src/util/name_mask.ref0 [new file with mode: 0644]
postfix/src/util/name_mask.ref1 [new file with mode: 0644]
postfix/src/util/name_mask.ref2 [new file with mode: 0644]
postfix/src/util/name_mask.ref3 [new file with mode: 0644]
postfix/src/util/name_mask.ref4 [new file with mode: 0644]
postfix/src/util/name_mask.ref5 [new file with mode: 0644]
postfix/src/util/name_mask.ref6 [new file with mode: 0644]
postfix/src/util/name_mask.ref7 [new file with mode: 0644]
postfix/src/util/name_mask.ref8 [new file with mode: 0644]
postfix/src/util/name_mask.ref9 [new file with mode: 0644]
postfix/src/util/nbbio.c [new file with mode: 0644]
postfix/src/util/nbbio.h [new file with mode: 0644]
postfix/src/util/vstream.c
postfix/src/util/vstream.h
postfix/src/xsasl/xsasl_dovecot_server.c

index 88762a3a42a17ef2941d51419ed7a5f8aaeb0389..0a1fd7e81d8c672ae34da5dae410d3cecc3b2ef4 100644 (file)
 -TNAME_ASSIGNMENT
 -TNAME_CODE
 -TNAME_MASK
+-TNBBIO
 -TPEER_NAME
 -TPGSQL_NAME
 -TPICKUP_INFO
 -TPOSTMAP_KEY_STATE
 -TPOST_MAIL_STATE
 -TPRIVATE_STR_TABLE
--TPS_CALL_BACK_ENTRY
--TPS_DNSBL_HEAD
--TPS_DNSBL_SCORE
--TPS_DNSBL_SITE
--TPS_SMTPD_COMMAND
--TPS_STATE
+-TPSC_CALL_BACK_ENTRY
+-TPSC_DNSBL_HEAD
+-TPSC_DNSBL_SCORE
+-TPSC_DNSBL_SITE
+-TPSC_SMTPD_COMMAND
+-TPSC_STARTTLS
+-TPSC_STATE
 -TQMGR_ENTRY
 -TQMGR_FEEDBACK
 -TQMGR_JOB
 -TSTRING_TABLE
 -TSYS_EXITS_DETAIL
 -TTLSMGR_SCACHE
+-TTLSP_STATE
 -TTLS_APPL_STATE
 -TTLS_CLIENT_INIT_PROPS
 -TTLS_CLIENT_START_PROPS
index 6843056491fe5acf8c9c30c1604c07a6d502d852..19eef1a2e4774b0d23cc61898684560edd2c8374 100644 (file)
@@ -15666,7 +15666,7 @@ Apologies for any names omitted.
        2821 (and 5321) is vague about the VRFY request format, but
        spends lots of text on the reply format.  File: smtpd/smtpd.c.
 
-20010117
+20100117
 
        Cleanup: when a content_filter parameter or FILTER command
        specifies an empty next-hop destination, the queue manager
@@ -16263,3 +16263,79 @@ Apologies for any names omitted.
        This change eliminates an obscure bug where the SMTP server
        would wait for another $smtpd_timeout seconds after sending
        the "421 Error: timeout exceeded" message to the client.
+
+20101221
+
+       Cleanup: simplified the VSTREAM "large buffer" support by
+       dropping the Postfix 2.4 "binary compatibility" requirement.
+       Files: util/vstream.c, util/vstream.h.
+
+20101222
+
+       Cleanup: the SMTP client PIPELINING code did not account
+       for TLS protocol overhead. This could (only in theory)
+       result in deadlock when the remote SMTP server announces a
+       very small receive window after the client and server have
+       synchronized their SMTP state. Victor Duchovni.  File:
+       smtp/smtp_proto.c.
+
+20101223
+
+       Feature: with "tls_preempt_cipherlist = yes" the Postfix
+       SMTP server will preempt the remote SMTP client's cipher
+       preference order. This requires OpenSSL 0.9.7 and later.
+       Victor Duchovni. Files: src/smtpd/smtpd.c, src/tls/tls_server.c,
+       proto/TLS_README.html, proto/postconf.proto.
+
+       Future proofing: specify "tls_disable_workarounds = a list
+       or bit-mask of OpenSSL bug work-arounds to disable". This
+       may become necessary when a bug workaround is found to cause
+       problems (security or interoperability). Victor Duchovni.
+       Files: tls/tls_misc.c, proto/TLS_README.html, proto/postconf.proto.
+
+       Infrastructure: extended name_mask module feature set with
+       extensive documentation and 32-bit regression tests.  Victor
+       and Wietse.  File: util/name_mask.[hc].
+
+20101224
+
+       Cleanup: sanitized the name_mask API so that errors will be
+       ignored only upon explicit request. Files: util/name_mask.[hc],
+       src/global/ehlo_mask.c, src/smtp/smtp_proto.c,
+       src/util/name_mask.c, src/xsasl/xsasl_dovecot_server.c.
+
+       Cleanup: more TLS overhead horrors for the SMTP client's
+       PIPELINING engine. Wietse and Victor. File: smtp/smtp_proto.c.
+
+20101226
+
+       Cleanup: the SMTP client logic for pipelining the "." and
+       "QUIT" commands was bogus - the pipelining engine could not
+       know how much unacknowledged data is pending in the local
+       TCP stack.  We now ignore the buffer check for sending
+       "QUIT" after ".".  Wietse and Victor. File: smtp/smtp_proto.c.
+
+20110101
+
+       Cleanup: the Postfix SMTP server now always refreshes the
+       SASL authentication mechanism list after STARTTLS. Some
+       Dovecot versions may change their responses when they know
+       that the SMTP connection is encrypted. File: smtpd/smtpd.c.
+
+       Cleanup: the smtpd_starttls_timeout default value is now
+       stress-dependent.  Files: global/mail_params.h,
+       proto/postconf.proto.
+
+20110102
+
+       Feature: STARTTLS support for the postscreen(8) daemon.
+       With early testing feedback from Victor Duchovni and Ralf
+       Hildebrandt.  Files: postscreen/postscreen_smtpd,
+       postscreen/postscreen_starttls.c.
+
+       Feature: event-driven tlsproxy(8) daemon that translates
+       TLS <=> plaintext for postscreen(8). One tlsproxy(8) process
+       can translate traffic for multiple remote SMTP clients.
+       With early testing feedback from Victor Duchovni and Christian
+       Roessner.  Files: util/nbbio.c, tlsproxy/starttlsd.c,
+       tlsproxy/starttlsd_state.c.
index c5efb2165bae6be6b137a2b54e27061d47c542f5..8a45ddd6ffe725a8a592aff395dc9e38a15de73c 100644 (file)
@@ -9,7 +9,7 @@ DIRS    = src/util src/global src/dns src/tls src/xsasl src/milter src/master \
        src/postkick src/postlock src/postlog src/postmap src/postqueue \
        src/postsuper src/qmqpd src/spawn src/flush src/verify \
        src/virtual src/proxymap src/anvil src/scache src/discard src/tlsmgr \
-       src/postmulti src/postscreen src/dnsblog
+       src/postmulti src/postscreen src/dnsblog src/tlsproxy
 MANDIRS        = proto man html
 LIBEXEC        = libexec/post-install libexec/postfix-files libexec/postfix-script \
        libexec/postfix-wrapper libexec/main.cf libexec/master.cf \
index 686d15255dd43ba20004f20703030d6601f0b755..52ae2a09b2e3a4595db320dfa8beeafea5f101b5 100644 (file)
@@ -209,7 +209,7 @@ blocklist servers with optional filters and weight factors. These servers will
 be queried in parallel with the reverse client IP address. This test is
 disabled by default.
 
-    CAUTION: when postscreen rejects mail, it's SMTP reply contains the DNSBL
+    CAUTION: when postscreen rejects mail, its SMTP reply contains the DNSBL
     domain name. Use the postscreen_dnsbl_reply_map feature to hide "password"
     information in DNSBL domain names.
 
@@ -267,11 +267,10 @@ discussed next.
     limitation, postscreen(8) gives deep protocol tests a relatively long
     expiration time.
 
-  * postscreen(8)'s built-in SMTP engine does not implement the AUTH, STARTTLS,
-    XCLIENT, and XFORWARD features. STARTTLS and AUTH support may be added in a
-    future version. In the mean time, if you need to make these services
-    available on port 25, then do not enable the tests after the 220 server
-    greeting.
+  * postscreen(8)'s built-in SMTP engine does not implement the AUTH, XCLIENT,
+    and XFORWARD features. AUTH support may be added in a future version. In
+    the mean time, if you need to make these services available on port 25,
+    then do not enable the tests after the 220 server greeting.
 
 End-user clients should connect directly to the submission service, so that
 they never have to deal with postscreen(8)'s tests.
@@ -480,13 +479,19 @@ mail:
     /etc/postfix/master.cf:
         smtp      inet  n       -       n       -       1       postscreen
 
- 4. Uncomment the new "dnsblog unix ... dnsblog" service in master.cf. This
+ 4. Uncomment the new "tlsproxy unix ... tlsproxy" service in master.cf. This
+    service implements STARTTLS support for postscreen(8).
+
+    /etc/postfix/master.cf:
+        tlsproxy  unix  -       -       n       -       0       tlsproxy
+
+ 5. Uncomment the new "dnsblog unix ... dnsblog" service in master.cf. This
     service does DNSBL lookups for postscreen(8) and logs results.
 
     /etc/postfix/master.cf:
         dnsblog   unix  -       -       n       -       0       dnsblog
 
5. To enable DNSBL lookups, list some DNS blocklist sites in main.cf,
6. To enable DNSBL lookups, list some DNS blocklist sites in main.cf,
     separated by whitespace. Different sites can have different weights. For
     example:
 
@@ -509,7 +514,7 @@ mail:
     run postmap(1) before the file can be used, and that it does not detect
     changes after the file is read. It is new with Postfix version 2.8.
 
6. Read the new configuration with "postfix reload".
7. Read the new configuration with "postfix reload".
 
 Notes:
 
@@ -556,8 +561,8 @@ more of:
 
     When the good client comes back in a later session, it is allowed to talk
     directly to a Postfix SMTP server. See "after_220 Tests after the 220 SMTP
-    server greeting above for limitations with STARTTLS, AUTH and other
-    features that clients may need.
+    server greeting above for limitations with AUTH and other features that
+    clients may need.
 
     An unexpected benefit from "deep protocol tests" is that some "good"
     clients don't return after the 4XX reply; these clients were not so good
@@ -592,14 +597,21 @@ processes:
         #smtpd     pass  -       -       n       -       -       smtpd
         #    -o parameter=value ...
 
- 4. Uncomment the "smtp inet ... smtpd" service in master.cf, including any "-
-    o parameter=value" entries that follow.
+ 4. Comment out the "tlsproxy unix ... tlsproxy" service in master.cf,
+    including any "-o parameter=value" entries that follow.
 
     /etc/postfix/master.cf:
-        smtp      inet  n       -       n       -       -       smtpd
+        #tlsproxy  unix  -       -       n       -       0       tlsproxy
+        #    -o parameter=value ...
+
+ 5. Uncomment the "smtp inet ... smtpd" service in master.cf, including any "-
+    o parameter=value" entries that may follow.
+
+    /etc/postfix/master.cf:
+        smtp       inet  n       -       n       -       -       smtpd
             -o parameter=value ...
 
5. Read the new configuration with "postfix reload".
6. Read the new configuration with "postfix reload".
 
 H\bHi\bis\bst\bto\bor\bri\bic\bca\bal\bl n\bno\bot\bte\bes\bs a\ban\bnd\bd c\bcr\bre\bed\bdi\bit\bts\bs
 
index 241e089900524ee2e4de42978c3116020cdd68ab..e3792632ff303e2eb67656ce3eeae3ddad6bb613 100644 (file)
@@ -10,6 +10,11 @@ thousands and thousands of lines of OpenSSL library code. Assuming that OpenSSL
 is written as carefully as Wietse's own code, every 1000 lines introduce one
 additional bug into Postfix.
 
+At this time, you should no longer be using OpenSSL releases prior to the most
+recent 0.9.8 release unless all relevant security fixes have been backported to
+the earlier release by you or your O/S vendor. OpenSSL 0.9.7 and earlier are no
+longer maintained by the OpenSSL team.
+
 W\bWh\bha\bat\bt P\bPo\bos\bst\btf\bfi\bix\bx T\bTL\bLS\bS s\bsu\bup\bpp\bpo\bor\brt\bt d\bdo\boe\bes\bs f\bfo\bor\br y\byo\bou\bu
 
 Transport Layer Security (TLS, formerly called SSL) provides certificate-based
@@ -588,6 +593,23 @@ Examples:
         # Postfix >= 2.6:
         smtpd_tls_eecdh_grade = strong
 
+Postfix 2.8 and later, in combination with OpenSSL 0.9.7 and later allows TLS
+servers to preempt the TLS client's cipher preference list. This is only
+possible with SSLv3, as in SSLv2 the client chooses the cipher from a list
+supplied by the server.
+
+By default, the OpenSSL server selects the client's most preferred cipher that
+the server supports. With SSLv3 and later, the server may choose its own most
+preferred cipher that is supported (offered) by the client. Setting
+"tls_preempt_cipherlist = yes" enables server cipher preferences. The default
+OpenSSL behaviour applies with "tls_preempt_cipherlist = no".
+
+While server cipher selection may in some cases lead to a more secure or
+performant cipher choice, there is some risk of interoperability issues. In the
+past, some SSL clients have listed lower priority ciphers that they did not
+implement correctly. If the server chooses a cipher that the client prefers
+less, it may select a cipher whose client implementation is flawed.
+
 M\bMi\bis\bsc\bce\bel\bll\bla\ban\bne\beo\bou\bus\bs s\bse\ber\brv\bve\ber\br c\bco\bon\bnt\btr\bro\bol\bls\bs
 
 The smtpd_starttls_timeout parameter limits the time of Postfix SMTP server
@@ -598,6 +620,23 @@ Example:
     /etc/postfix/main.cf:
         smtpd_starttls_timeout = 300s
 
+With Postfix 2.8 and later, the tls_disable_workarounds parameter specifies a
+list or bit-mask of OpenSSL bug work-arounds to disable. This may be necessary
+if one of the work-arounds enabled by default in OpenSSL proves to pose a
+security risk, or introduces an unexpected interoperability issue. Some bug
+work-arounds known to be problematic are disabled in the default value of the
+parameter when linked with an OpenSSL library that could be vulnerable.
+
+Example:
+
+    /etc/postfix/main.cf:
+        tls_disable_workarounds = 0xFFFFFFFF
+        tls_disable_workarounds = CVE-2010-4180, LEGACY_SERVER_CONNECT
+
+Note: Disabling LEGACY_SERVER_CONNECT is not wise at this time, lots of servers
+are still unpatched and Postfix is not significantly vulnerable to the
+renegotiation issue in the TLS protocol.
+
 S\bSM\bMT\bTP\bP C\bCl\bli\bie\ben\bnt\bt s\bsp\bpe\bec\bci\bif\bfi\bic\bc s\bse\bet\btt\bti\bin\bng\bgs\bs
 
 Topics covered in this section:
index 506400c7909a4ff2d238ab70a4c7eeba44721a32..3e87926871d2b8b915465b5f11c4be3ef7d96785 100644 (file)
@@ -29,9 +29,62 @@ down.
 
 NOTE: Some postscreen parameters implement stress-dependent behavior.
 This is supported only when the default value is stress-dependent
-(that is, the default looks like ${stress?XX}${stress:YY}).  Other
-postscreen parameters always evaluate as if the stress value is 
-equal to the empty string.
+(that is, the default looks like ${stress?XX}${stress:YY}, or it
+is the $name of an smtpd_xxx parameter with a stress-dependent
+default).  Other postscreen parameters always evaluate as if the
+stress value is equal to the empty string.
+
+Incompatibility with snapshot 20110102
+======================================
+
+The smtpd_starttls_timeout default value is now stress-dependent.
+By default, TLS negotiations must now complete under overload in
+10s instead of 300s.
+
+The Postfix SMTP server now always re-computes the SASL mechanism
+list after successful completion of the STARTTLS command. Earlier
+versions only re-computed the mechanism list when the values of
+smtp_sasl_tls_security_options and smtp_sasl_security_options differ.
+This could produce incorrect results, because the Dovecot authentication
+server may change responses when the SMTP session is encrypted.
+
+Major changes with snapshot 20110102
+====================================
+
+STARTTLS support for the postscreen(8) daemon. This is implemented
+by a new tlsproxy(8) daemon that you will need to enable in master.cf
+(see POSTSCREEN_README for instructions).  tlsproxy(8) implements
+its own tlsproxy_mumble versions of TLS-related smtpd_mumble
+parameters. This leaves no confusion about which parameters will
+affect tlsproxy(8) behavior, but it adds another 25 parameters to
+the documentation.
+
+Major changes with snapshot 20101223
+====================================
+
+The new tls_disable_workarounds parameter specifies a list or
+bit-mask of OpenSSL bug work-arounds to disable. This may be necessary
+if one of the work-arounds enabled by default in OpenSSL proves to
+pose a security risk, or introduces an unexpected interoperability
+issue. Some bug work-arounds known to be problematic are disabled
+in the default value of the parameter when linked with an OpenSSL
+library that could be vulnerable. See postconf(5) and TLS_README
+for details.
+
+With "tls_preempt_cipherlist = yes" the Postfix SMTP server will
+choose its most preferred cipher that is supported (offered) by the
+client. This can lead to a more secure or performant cipher choice,
+but may also introduce interoperability problems when a client
+announces support for a cipher that does not work.  See postconf(5)
+and TLS_README for details.
+
+Major changes with snapshot 20101217
+====================================
+
+The lower-level code in the TLS engine was simplified by removing
+an unnecessary layer of data copying. OpenSSL now writes directly
+to the network. The difference in performance should be hardly
+noticeable.
 
 Incompatibility with snapshot 20101206
 ======================================
index 0e31672dada2f62fb1c39787e00c3f71a028c02b..3092ca6fce9d4586957a2e6df0cf504b32e40322 100644 (file)
@@ -4,6 +4,8 @@ Wish list:
 
        anvil rate limit for sasl_username.
 
+       encapsulate nbbio buffer access and update by tlsproxy.
+
        smtpd xclient option for sasl_username.
 
        Use different ipc time limits for email message transactions
index 82f976751e7320b9fb435a6702ec638ac890a806..213f534c9113b2df811a53c8bcfd807b501cf083 100644 (file)
@@ -12,6 +12,7 @@ smtp      inet  n       -       n       -       -       smtpd
 #smtp      inet  n       -       n       -       1       postscreen
 #smtpd     pass  -       -       n       -       -       smtpd
 #dnsblog   unix  -       -       n       -       0       dnsblog
+#tlsproxy  unix  -       -       n       -       0       tlsproxy
 #submission inet n       -       n       -       -       smtpd
 #  -o smtpd_tls_security_level=encrypt
 #  -o smtpd_sasl_auth_enable=yes
index ed9a4b57df73f0420535887a0770179966cc883a..32624c68b6cc010465b966e68f83f0034752cf47 100644 (file)
@@ -767,6 +767,16 @@ EOF
 EOF
     }
 
+    # Postfix 2.8.
+    # Add tlsproxy (unix-domain) service to master.cf.
+
+    grep '^#*tlsproxy.*tlsproxy' $config_directory/master.cf >/dev/null || {
+       echo Editing $config_directory/master.cf, adding missing entry for tlsproxy unix-domain service
+       cat >>$config_directory/master.cf <<EOF || exit 1
+#tlsproxy unix  -       -       n       -       0       tlsproxy
+EOF
+    }
+
     # Report (but do not remove) obsolete files.
 
     test -n "$obsolete" && {
index 69e18f976c16f2b1551c839e5db2eb630ff30323..d3911d633f3b7289ccd18810e9a69e5b37ee3070 100644 (file)
@@ -92,6 +92,7 @@ $daemon_directory/showq:f:root:-:755
 $daemon_directory/smtp:f:root:-:755
 $daemon_directory/smtpd:f:root:-:755
 $daemon_directory/spawn:f:root:-:755
+$daemon_directory/tlsproxy:f:root:-:755
 $daemon_directory/tlsmgr:f:root:-:755
 $daemon_directory/trivial-rewrite:f:root:-:755
 $daemon_directory/verify:f:root:-:755
@@ -201,6 +202,7 @@ $manpage_directory/man8/showq.8:f:root:-:644
 $manpage_directory/man8/smtp.8:f:root:-:644
 $manpage_directory/man8/smtpd.8:f:root:-:644
 $manpage_directory/man8/spawn.8:f:root:-:644
+$manpage_directory/man8/tlsproxy.8:f:root:-:644
 $manpage_directory/man8/tlsmgr.8:f:root:-:644
 $manpage_directory/man8/trace.8:f:root:-:644
 $manpage_directory/man8/trivial-rewrite.8:f:root:-:644
@@ -408,6 +410,7 @@ $html_directory/smtp-source.1.html:f:root:-:644
 $html_directory/smtp.8.html:h:$html_directory/lmtp.8.html:-:644
 $html_directory/smtpd.8.html:f:root:-:644
 $html_directory/spawn.8.html:f:root:-:644
+$html_directory/tlsproxy.8.html:f:root:-:644
 $html_directory/tcp_table.5.html:f:root:-:644
 $html_directory/trace.8.html:h:$html_directory/bounce.8.html:-:644
 $html_directory/transport.5.html:f:root:-:644
index cf439d3b6b9f357401c474049f0178cc09d74b22..36327f2befefd96a6b8f092bb4086a445dff098b 100644 (file)
@@ -8,7 +8,7 @@ DAEMONS =  bounce.8.html cleanup.8.html defer.8.html error.8.html local.8.html \
        oqmgr.8.html spawn.8.html flush.8.html virtual.8.html qmqpd.8.html \
        trace.8.html verify.8.html proxymap.8.html anvil.8.html \
        scache.8.html discard.8.html tlsmgr.8.html postscreen.8.html \
-       dnsblog.8.html
+       dnsblog.8.html tlsproxy.8.html
 COMMANDS= mailq.1.html newaliases.1.html postalias.1.html postcat.1.html \
        postconf.1.html postfix.1.html postkick.1.html postlock.1.html \
        postlog.1.html postdrop.1.html postmap.1.html postmulti.1.html \
@@ -131,6 +131,10 @@ smtpd.8.html: ../src/smtpd/smtpd.c
        PATH=../mantools:$$PATH; \
        srctoman $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
 
+tlsproxy.8.html: ../src/tlsproxy/tlsproxy.c
+       PATH=../mantools:$$PATH; \
+       srctoman $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
+
 virtual.8.html: ../src/virtual/virtual.c
        PATH=../mantools:$$PATH; \
        srctoman $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
index fc80d6db88d1e3ff9ecab9db9e56ce009fe0460a..f9c4e5ae3ec1aea4230f3521f972c6e6ee38ac95 100644 (file)
@@ -284,7 +284,7 @@ client IP address. This test is disabled by default. </p>
 
 <blockquote>
 <p>
-CAUTION: when postscreen rejects mail, it's SMTP reply contains the
+CAUTION: when postscreen rejects mail, its SMTP reply contains the
 DNSBL domain name. Use the <a href="postconf.5.html#postscreen_dnsbl_reply_map">postscreen_dnsbl_reply_map</a> feature to
 hide "password" information in DNSBL domain names.
 </p>
@@ -361,10 +361,10 @@ impact of this limitation, <a href="postscreen.8.html">postscreen(8)</a> gives d
 a relatively long expiration time. </p>
 
 <li> <p> <a href="postscreen.8.html">postscreen(8)</a>'s built-in SMTP engine does not implement
-the AUTH, STARTTLS, XCLIENT, and XFORWARD features.  STARTTLS and
-AUTH support may be added in a future version. In the mean time,
-if you need to make these services available on port 25, then do
-not enable the tests after the 220 server greeting. </p>
+the AUTH, XCLIENT, and XFORWARD features.  AUTH support may be added
+in a future version. In the mean time, if you need to make these
+services available on port 25, then do not enable the tests after
+the 220 server greeting. </p>
 
 </ul>
 
@@ -672,6 +672,15 @@ service in <a href="master.5.html">master.cf</a>. </p>
     smtp      inet  n       -       n       -       1       postscreen
 </pre>
 
+<li> <p> Uncomment the new "<tt>tlsproxy unix ... tlsproxy</tt>"
+service in <a href="master.5.html">master.cf</a>.  This service implements STARTTLS support for
+<a href="postscreen.8.html">postscreen(8)</a>. </p>
+
+<pre>
+/etc/postfix/<a href="master.5.html">master.cf</a>:
+    tlsproxy  unix  -       -       n       -       0       tlsproxy
+</pre>
+
 <li> <p> Uncomment the new "<tt>dnsblog  unix ... dnsblog</tt>"
 service in <a href="master.5.html">master.cf</a>.  This service does DNSBL lookups for <a href="postscreen.8.html">postscreen(8)</a>
 and logs results. </p>
@@ -775,8 +784,8 @@ disconnect. </p>
 <p> When the good client comes back in a later session, it is allowed
 to talk directly to a Postfix SMTP server.  See "after_220 <a
 href="#after_220">Tests after the 220 SMTP server greeting</a> above
-for limitations with STARTTLS, AUTH and other features that clients
-may need. </p>
+for limitations with AUTH and other features that clients may need.
+</p>
 
 <p> An unexpected benefit from "<a href="#after_220">deep protocol
 tests</a>" is that some "good" clients don't return after the 4XX
@@ -825,14 +834,23 @@ that follow. </p>
     #    -o parameter=value ...
 </pre>
 
+<li> <p> Comment out the "<tt>tlsproxy unix ... tlsproxy</tt>"
+service in <a href="master.5.html">master.cf</a>, including any "<tt>-o parameter=value</tt>"
+entries that follow. </p>
+
+<pre>
+/etc/postfix/<a href="master.5.html">master.cf</a>:
+    #tlsproxy  unix  -       -       n       -       0       tlsproxy
+    #    -o parameter=value ...
+</pre>
 
 <li> <p> Uncomment the "<tt>smtp  inet ... smtpd</tt>" service in
 <a href="master.5.html">master.cf</a>, including any "<tt>-o parameter=value</tt>" entries that
-follow.  </p>
+may follow.  </p>
 
 <pre>
 /etc/postfix/<a href="master.5.html">master.cf</a>:
-    smtp      inet  n       -       n       -       -       smtpd
+    smtp       inet  n       -       n       -       -       smtpd
         -o parameter=value ...
 </pre>
 
index edf38f78bb522bf7f9a4eaf94fe3b1c0fd96fd0b..b1cda222738997feda5e250b1985357d88f1a678 100644 (file)
@@ -27,6 +27,11 @@ code.  Assuming that OpenSSL is written as carefully as Wietse's
 own code, every 1000 lines introduce one additional bug into
 Postfix.  </p>
 
+<p> At this time, you should no longer be using OpenSSL releases prior
+to the most recent 0.9.8 release unless all relevant security fixes have
+been backported to the earlier release by you or your O/S vendor. OpenSSL
+0.9.7 and earlier are no longer maintained by the OpenSSL team. </p>
+
 <h2> What Postfix TLS support does for you </h2>
 
 <p> Transport Layer Security (TLS, formerly called SSL) provides
@@ -852,6 +857,25 @@ secure for most situations. </p>
 </pre>
 </blockquote>
 
+<p> Postfix 2.8 and later, in combination with OpenSSL 0.9.7 and later
+allows TLS servers to preempt the TLS client's cipher preference list.
+This is only possible with SSLv3, as in SSLv2 the client chooses the
+cipher from a list supplied by the server. </p>
+
+<p> By default, the OpenSSL server selects the client's most preferred
+cipher that the server supports. With SSLv3 and later, the server
+may choose its own most preferred cipher that is supported (offered)
+by the client. Setting "<a href="postconf.5.html#tls_preempts_cipherlist">tls_preempt_cipherlist</a> = yes" enables server
+cipher preferences. The default OpenSSL behaviour applies with
+"<a href="postconf.5.html#tls_preempts_cipherlist">tls_preempt_cipherlist</a> = no". </p>
+
+<p> While server cipher selection may in some cases lead to a more secure
+or performant cipher choice, there is some risk of interoperability
+issues. In the past, some SSL clients have listed lower priority ciphers
+that they did not implement correctly. If the server chooses a cipher
+that the client prefers less, it may select a cipher whose client
+implementation is flawed. </p>
+
 <h3><a name="server_misc"> Miscellaneous server controls</a> </h3>
 
 <p> The <a href="postconf.5.html#smtpd_starttls_timeout">smtpd_starttls_timeout</a> parameter limits the time of Postfix
@@ -867,6 +891,30 @@ handshake procedures.  </p>
 </pre>
 </blockquote>
 
+<p> With Postfix 2.8 and later, the <a href="postconf.5.html#tls_disable_workarounds">tls_disable_workarounds</a> parameter
+specifies a list or bit-mask of OpenSSL bug work-arounds to disable. This
+may be necessary if one of the work-arounds enabled by default in
+OpenSSL proves to pose a security risk, or introduces an unexpected
+interoperability issue. Some bug work-arounds known to be problematic
+are disabled in the default value of the parameter when linked with
+an OpenSSL library that could be vulnerable. </p>
+
+<p> Example: </p>
+<blockquote>
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    <a href="postconf.5.html#tls_disable_workarounds">tls_disable_workarounds</a> = 0xFFFFFFFF
+    <a href="postconf.5.html#tls_disable_workarounds">tls_disable_workarounds</a> = CVE-2010-4180, LEGACY_SERVER_CONNECT
+</pre>
+</blockquote>
+
+<p> Note: Disabling LEGACY_SERVER_CONNECT is not wise at this
+time, lots of servers are still unpatched and Postfix is <a
+href="http://www.postfix.org/wip.html#tls-renegotiation">not
+significantly vulnerable</a> to the renegotiation issue in the TLS
+protocol. </p>
+
 <h2> <a name="client_tls">SMTP Client specific settings</a> </h2>
 
 <p> Topics covered in this section: </p>
index 1d14126e098e6e1b2a6f58873e087e1a6e6dc53c..c613394754ea669cd69788c3cd66478f07e0c9a0 100644 (file)
@@ -551,29 +551,35 @@ SMTP(8)                                                                SMTP(8)
               an  attacker  prepends  malicious HELO, MAIL, RCPT,
               DATA commands to a Postfix SMTP client TLS session.
 
+       Available in Postfix version 2.8 and later:
+
+       <b><a href="postconf.5.html#tls_disable_workarounds">tls_disable_workarounds</a> (see 'postconf -d' output)</b>
+              List  or  bit-mask  of  OpenSSL bug work-arounds to
+              disable.
+
 <b>OBSOLETE STARTTLS CONTROLS</b>
-       The  following configuration parameters exist for compati-
+       The following configuration parameters exist for  compati-
        bility with Postfix versions before 2.3. Support for these
        will be removed in a future release.
 
        <b><a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a> (no)</b>
-              Opportunistic  mode:  use  TLS  when  a remote SMTP
-              server announces STARTTLS support,  otherwise  send
+              Opportunistic mode: use  TLS  when  a  remote  SMTP
+              server  announces  STARTTLS support, otherwise send
               the mail in the clear.
 
        <b><a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> (no)</b>
-              Enforcement  mode: require that remote SMTP servers
-              use TLS encryption, and  never  send  mail  in  the
+              Enforcement mode: require that remote SMTP  servers
+              use  TLS  encryption,  and  never  send mail in the
               clear.
 
        <b><a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> (yes)</b>
-              With  mandatory  TLS  encryption,  require that the
+              With mandatory TLS  encryption,  require  that  the
               remote SMTP server hostname matches the information
               in the remote SMTP server certificate.
 
        <b><a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> (empty)</b>
               Optional lookup tables with the Postfix SMTP client
-              TLS usage policy by  next-hop  destination  and  by
+              TLS  usage  policy  by  next-hop destination and by
               remote SMTP server hostname.
 
        <b><a href="postconf.5.html#smtp_tls_cipherlist">smtp_tls_cipherlist</a> (empty)</b>
@@ -583,27 +589,27 @@ SMTP(8)                                                                SMTP(8)
 <b>RESOURCE AND RATE CONTROLS</b>
        <b><a href="postconf.5.html#smtp_destination_concurrency_limit">smtp_destination_concurrency_limit</a>      ($<a href="postconf.5.html#default_destination_concurrency_limit">default_destina</a>-</b>
        <b><a href="postconf.5.html#default_destination_concurrency_limit">tion_concurrency_limit</a>)</b>
-              The maximal number of parallel  deliveries  to  the
-              same  destination  via  the  smtp  message delivery
+              The  maximal  number  of parallel deliveries to the
+              same destination  via  the  smtp  message  delivery
               transport.
 
        <b><a href="postconf.5.html#smtp_destination_recipient_limit">smtp_destination_recipient_limit</a>        ($<a href="postconf.5.html#default_destination_recipient_limit">default_destina</a>-</b>
        <b><a href="postconf.5.html#default_destination_recipient_limit">tion_recipient_limit</a>)</b>
-              The maximal number of recipients  per  message  for
+              The  maximal  number  of recipients per message for
               the smtp message delivery transport.
 
        <b><a href="postconf.5.html#smtp_connect_timeout">smtp_connect_timeout</a> (30s)</b>
-              The  SMTP  client  time  limit for completing a TCP
+              The SMTP client time limit  for  completing  a  TCP
               connection,  or  zero  (use  the  operating  system
               built-in time limit).
 
        <b><a href="postconf.5.html#smtp_helo_timeout">smtp_helo_timeout</a> (300s)</b>
-              The  SMTP client time limit for sending the HELO or
-              EHLO command, and for receiving the initial  server
+              The SMTP client time limit for sending the HELO  or
+              EHLO  command, and for receiving the initial server
               response.
 
        <b><a href="postconf.5.html#lmtp_lhlo_timeout">lmtp_lhlo_timeout</a> (300s)</b>
-              The  LMTP  client  time  limit for sending the LHLO
+              The LMTP client time limit  for  sending  the  LHLO
               command,  and  for  receiving  the  initial  server
               response.
 
@@ -612,30 +618,30 @@ SMTP(8)                                                                SMTP(8)
               command, and for receiving the server response.
 
        <b><a href="postconf.5.html#smtp_mail_timeout">smtp_mail_timeout</a> (300s)</b>
-              The SMTP client time limit  for  sending  the  MAIL
-              FROM   command,   and   for  receiving  the  server
+              The  SMTP  client  time  limit for sending the MAIL
+              FROM  command,  and  for   receiving   the   server
               response.
 
        <b><a href="postconf.5.html#smtp_rcpt_timeout">smtp_rcpt_timeout</a> (300s)</b>
-              The SMTP client time limit  for  sending  the  SMTP
-              RCPT  TO  command,  and  for  receiving  the server
+              The  SMTP  client  time  limit for sending the SMTP
+              RCPT TO  command,  and  for  receiving  the  server
               response.
 
        <b><a href="postconf.5.html#smtp_data_init_timeout">smtp_data_init_timeout</a> (120s)</b>
-              The SMTP client time limit  for  sending  the  SMTP
-              DATA   command,   and   for  receiving  the  server
+              The  SMTP  client  time  limit for sending the SMTP
+              DATA  command,  and  for   receiving   the   server
               response.
 
        <b><a href="postconf.5.html#smtp_data_xfer_timeout">smtp_data_xfer_timeout</a> (180s)</b>
-              The SMTP client time limit  for  sending  the  SMTP
+              The  SMTP  client  time  limit for sending the SMTP
               message content.
 
        <b><a href="postconf.5.html#smtp_data_done_timeout">smtp_data_done_timeout</a> (600s)</b>
-              The  SMTP  client  time  limit for sending the SMTP
+              The SMTP client time limit  for  sending  the  SMTP
               ".", and for receiving the server response.
 
        <b><a href="postconf.5.html#smtp_quit_timeout">smtp_quit_timeout</a> (300s)</b>
-              The SMTP client time limit  for  sending  the  QUIT
+              The  SMTP  client  time  limit for sending the QUIT
               command, and for receiving the server response.
 
        Available in Postfix version 2.1 and later:
@@ -646,12 +652,12 @@ SMTP(8)                                                                SMTP(8)
               lookups, or zero (no limit).
 
        <b><a href="postconf.5.html#smtp_mx_session_limit">smtp_mx_session_limit</a> (2)</b>
-              The  maximal  number  of SMTP sessions per delivery
-              request before giving up or delivering to  a  fall-
+              The maximal number of SMTP  sessions  per  delivery
+              request  before  giving up or delivering to a fall-
               back <a href="postconf.5.html#relayhost">relay host</a>, or zero (no limit).
 
        <b><a href="postconf.5.html#smtp_rset_timeout">smtp_rset_timeout</a> (20s)</b>
-              The  SMTP  client  time  limit for sending the RSET
+              The SMTP client time limit  for  sending  the  RSET
               command, and for receiving the server response.
 
        Available in Postfix version 2.2 and earlier:
@@ -663,11 +669,11 @@ SMTP(8)                                                                SMTP(8)
        Available in Postfix version 2.2 and later:
 
        <b><a href="postconf.5.html#smtp_connection_cache_destinations">smtp_connection_cache_destinations</a> (empty)</b>
-              Permanently  enable SMTP connection caching for the
+              Permanently enable SMTP connection caching for  the
               specified destinations.
 
        <b><a href="postconf.5.html#smtp_connection_cache_on_demand">smtp_connection_cache_on_demand</a> (yes)</b>
-              Temporarily enable SMTP connection caching while  a
+              Temporarily  enable SMTP connection caching while a
               destination has a high volume of mail in the active
               queue.
 
@@ -677,62 +683,62 @@ SMTP(8)                                                                SMTP(8)
 
        <b><a href="postconf.5.html#smtp_connection_cache_time_limit">smtp_connection_cache_time_limit</a> (2s)</b>
               When SMTP connection caching is enabled, the amount
-              of time that an unused SMTP client socket  is  kept
+              of  time  that an unused SMTP client socket is kept
               open before it is closed.
 
        Available in Postfix version 2.3 and later:
 
        <b><a href="postconf.5.html#connection_cache_protocol_timeout">connection_cache_protocol_timeout</a> (5s)</b>
-              Time  limit  for  connection cache connect, send or
+              Time limit for connection cache  connect,  send  or
               receive operations.
 
 <b>TROUBLE SHOOTING CONTROLS</b>
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The increment  in  verbose  logging  level  when  a
-              remote  client  or  server matches a pattern in the
+              The  increment  in  verbose  logging  level  when a
+              remote client or server matches a  pattern  in  the
               <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional list of remote client or  server  hostname
-              or  network address patterns that cause the verbose
-              logging level to increase by the  amount  specified
+              Optional  list  of remote client or server hostname
+              or network address patterns that cause the  verbose
+              logging  level  to increase by the amount specified
               in $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
 
        <b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
-              The  recipient  of  postmaster  notifications about
-              mail delivery problems that are caused  by  policy,
+              The recipient  of  postmaster  notifications  about
+              mail  delivery  problems that are caused by policy,
               resource, software or protocol errors.
 
        <b><a href="postconf.5.html#internal_mail_filter_classes">internal_mail_filter_classes</a> (empty)</b>
-              What  categories of Postfix-generated mail are sub-
-              ject  to   before-queue   content   inspection   by
+              What categories of Postfix-generated mail are  sub-
+              ject   to   before-queue   content   inspection  by
               <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>, <a href="postconf.5.html#header_checks">header_checks</a> and <a href="postconf.5.html#body_checks">body_checks</a>.
 
        <b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
-              The  list of error classes that are reported to the
+              The list of error classes that are reported to  the
               postmaster.
 
 <b>MISCELLANEOUS CONTROLS</b>
        <b><a href="postconf.5.html#best_mx_transport">best_mx_transport</a> (empty)</b>
-              Where the Postfix SMTP client should  deliver  mail
+              Where  the  Postfix SMTP client should deliver mail
               when it detects a "mail loops back to myself" error
               condition.
 
        <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#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              How  much time a Postfix daemon process may take to
-              handle a request  before  it  is  terminated  by  a
+              How much time a Postfix daemon process may take  to
+              handle  a  request  before  it  is  terminated by a
               built-in watchdog timer.
 
        <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#disable_dns_lookups">disable_dns_lookups</a> (no)</b>
-              Disable DNS lookups in the Postfix  SMTP  and  LMTP
+              Disable  DNS  lookups  in the Postfix SMTP and LMTP
               clients.
 
        <b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
@@ -740,7 +746,7 @@ SMTP(8)                                                                SMTP(8)
               tem receives mail on.
 
        <b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (ipv4)</b>
-              The Internet protocols Postfix will attempt to  use
+              The  Internet protocols Postfix will attempt to use
               when making or accepting connections.
 
        <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
@@ -748,87 +754,87 @@ SMTP(8)                                                                SMTP(8)
               over an internal communication channel.
 
        <b><a href="postconf.5.html#lmtp_assume_final">lmtp_assume_final</a> (no)</b>
-              When an  LMTP  server  announces  no  DSN  support,
+              When  an  LMTP  server  announces  no  DSN support,
               assume that the server performs final delivery, and
-              send  "delivered"  delivery  status   notifications
+              send   "delivered"  delivery  status  notifications
               instead of "relayed".
 
        <b><a href="postconf.5.html#lmtp_tcp_port">lmtp_tcp_port</a> (24)</b>
-              The  default  TCP port that the Postfix LMTP client
+              The default TCP port that the Postfix  LMTP  client
               connects to.
 
        <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#max_use">max_use</a> (100)</b>
-              The maximal number of incoming connections  that  a
-              Postfix  daemon  process will service before termi-
+              The  maximal  number of incoming connections that a
+              Postfix daemon process will service  before  termi-
               nating 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#proxy_interfaces">proxy_interfaces</a> (empty)</b>
               The network interface addresses that this mail sys-
-              tem  receives  mail on by way of a proxy or network
+              tem receives mail on by way of a proxy  or  network
               address translation unit.
 
        <b><a href="postconf.5.html#smtp_address_preference">smtp_address_preference</a> (ipv6)</b>
               The address type ("ipv6", "ipv4" or "any") that the
               Postfix SMTP client will try first, when a destina-
-              tion has IPv6 and  IPv4  addresses  with  equal  MX
+              tion  has  IPv6  and  IPv4  addresses with equal MX
               preference.
 
        <b><a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> (empty)</b>
-              An  optional  numerical  network  address  that the
-              Postfix SMTP client should bind to when  making  an
+              An optional  numerical  network  address  that  the
+              Postfix  SMTP  client should bind to when making an
               IPv4 connection.
 
        <b><a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> (empty)</b>
-              An  optional  numerical  network  address  that the
-              Postfix SMTP client should bind to when  making  an
+              An optional  numerical  network  address  that  the
+              Postfix  SMTP  client should bind to when making an
               IPv6 connection.
 
        <b><a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
-              The  hostname to send in the SMTP EHLO or HELO com-
+              The hostname to send in the SMTP EHLO or HELO  com-
               mand.
 
        <b><a href="postconf.5.html#lmtp_lhlo_name">lmtp_lhlo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
               The hostname to send in the LMTP LHLO command.
 
        <b><a href="postconf.5.html#smtp_host_lookup">smtp_host_lookup</a> (dns)</b>
-              What mechanisms the Postfix  SMTP  client  uses  to
+              What  mechanisms  the  Postfix  SMTP client uses to
               look up a host's IP address.
 
        <b><a href="postconf.5.html#smtp_randomize_addresses">smtp_randomize_addresses</a> (yes)</b>
-              Randomize  the  order  of  equal-preference MX host
+              Randomize the order  of  equal-preference  MX  host
               addresses.
 
        <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".
 
        Available with Postfix 2.2 and earlier:
 
        <b><a href="postconf.5.html#fallback_relay">fallback_relay</a> (empty)</b>
-              Optional list of relay hosts for SMTP  destinations
+              Optional  list of relay hosts for SMTP destinations
               that can't be found or that are unreachable.
 
        Available with Postfix 2.3 and later:
 
        <b><a href="postconf.5.html#smtp_fallback_relay">smtp_fallback_relay</a> ($<a href="postconf.5.html#fallback_relay">fallback_relay</a>)</b>
-              Optional  list of relay hosts for SMTP destinations
+              Optional list of relay hosts for SMTP  destinations
               that can't be found or that are unreachable.
 
 <b>SEE ALSO</b>
@@ -849,7 +855,7 @@ SMTP(8)                                                                SMTP(8)
        <a href="TLS_README.html">TLS_README</a>, Postfix STARTTLS howto
 
 <b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
+       The Secure Mailer license must be  distributed  with  this
        software.
 
 <b>AUTHOR(S)</b>
index 447473d1a09e3726cd09cce25b8b0d42e3a98a1f..36e036254fc6dce276ab0d6466653157604bf8c4 100644 (file)
@@ -6834,6 +6834,33 @@ protocol engine. This bounds the time to receive an entire command.
 <p> This feature is available in Postfix 2.8.  </p>
 
 
+</DD>
+
+<DT><b><a name="postscreen_discard_ehlo_keyword_address_maps">postscreen_discard_ehlo_keyword_address_maps</a>
+(default: $<a href="postconf.5.html#smtpd_discard_ehlo_keyword_address_maps">smtpd_discard_ehlo_keyword_address_maps</a>)</b></DT><DD>
+
+<p> Lookup tables, indexed by the remote SMTP client address, with
+case insensitive lists of EHLO keywords (pipelining, starttls, auth,
+etc.) that the <a href="postscreen.8.html">postscreen(8)</a> server will not send in the EHLO response
+to a remote SMTP client. See <a href="postconf.5.html#smtpd_discard_ehlo_keywords">smtpd_discard_ehlo_keywords</a> for details.
+The table is not searched by hostname for robustness reasons.  </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="postscreen_discard_ehlo_keywords">postscreen_discard_ehlo_keywords</a>
+(default: $<a href="postconf.5.html#smtpd_discard_ehlo_keywords">smtpd_discard_ehlo_keywords</a>)</b></DT><DD>
+
+<p> A case insensitive list of EHLO keywords (pipelining, starttls,
+auth, etc.) that the <a href="postscreen.8.html">postscreen(8)</a> server will not send in the EHLO
+response to a remote SMTP client. See <a href="postconf.5.html#smtpd_discard_ehlo_keywords">smtpd_discard_ehlo_keywords</a>
+for details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="postscreen_dnsbl_action">postscreen_dnsbl_action</a>
@@ -6992,6 +7019,19 @@ 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_enforce_tls">postscreen_enforce_tls</a>
+(default: $<a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a>)</b></DT><DD>
+
+<p> Mandatory TLS: announce STARTTLS support to SMTP clients, and
+require that clients use TLS encryption.  See smtpd_postscreen_enforce_tls
+for details.  </p>
+
+<p> This feature is available in Postfix 2.8 and later.
+Preferably, use <a href="postconf.5.html#postscreen_tls_security_level">postscreen_tls_security_level</a> instead. </p>
+
+
 </DD>
 
 <DT><b><a name="postscreen_forbidden_commands">postscreen_forbidden_commands</a>
@@ -7262,6 +7302,31 @@ receive a 421 reponse. </p>
 <p> This feature is available in Postfix 2.8. </p>
 
 
+</DD>
+
+<DT><b><a name="postscreen_tls_security_level">postscreen_tls_security_level</a>
+(default: $<a href="postconf.5.html#smtpd_tls_security_level">smtpd_tls_security_level</a>)</b></DT><DD>
+
+<p> The SMTP TLS security level for the <a href="postscreen.8.html">postscreen(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>. See <a href="postconf.5.html#smtpd_tls_security_level">smtpd_tls_security_level</a>
+for details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="postscreen_use_tls">postscreen_use_tls</a>
+(default: $<a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a>)</b></DT><DD>
+
+<p> Opportunistic TLS: announce STARTTLS support to SMTP clients,
+but do not require that clients use TLS encryption. </p>
+
+<p> This feature is available in Postfix 2.8 and later.
+Preferably, use <a href="postconf.5.html#postscreen_tls_security_level">postscreen_tls_security_level</a> instead. </p>
+
+
 </DD>
 
 <DT><b><a name="postscreen_watchdog_timeout">postscreen_watchdog_timeout</a>
@@ -13521,10 +13586,12 @@ server delays all responses by (number of errors) seconds. </p>
 </DD>
 
 <DT><b><a name="smtpd_starttls_timeout">smtpd_starttls_timeout</a>
-(default: 300s)</b></DT><DD>
+(default: see "postconf -d" output)</b></DT><DD>
 
 <p> The time limit for Postfix SMTP server write and read operations
-during TLS startup and shutdown handshake procedures. </p>
+during TLS startup and shutdown handshake procedures. The current
+default value is stress-dependent. Before Postfix version 2.8, it
+was fixed at 300s. </p>
 
 <p> This feature is available in Postfix 2.2 and later.  </p>
 
@@ -14749,6 +14816,68 @@ bytes (equivalent to 256 bits) is sufficient to generate a 128bit
 <p> This feature is available in Postfix 2.2 and later.  </p>
 
 
+</DD>
+
+<DT><b><a name="tls_disable_workarounds">tls_disable_workarounds</a>
+(default: see "postconf -d" output)</b></DT><DD>
+
+<p> List or bit-mask of OpenSSL bug work-arounds to disable. </p>
+
+<p> The OpenSSL toolkit includes a set of work-arounds for buggy SSL/TLS
+implementations. Applications, such as Postfix, that want to maximize
+interoperability ask the OpenSSL library to enable the full set of
+recommended work-arounds. </p>
+
+<p> From time to time, it is discovered that a work-around creates a
+security issue, and should no longer be used. If upgrading OpenSSL
+to a fixed version is not an option or an upgrade is not available
+in a timely manner, or in closed environments where no buggy clients
+or servers exist, it may be appropriate to disable some or all of the
+OpenSSL interoperability work-arounds. This parameter specifies which
+bug work-arounds to disable. </p>
+
+<p> If the value of the parameter is a hexadecimal long integer starting
+with "0x", the bug work-arounds corresponding to the bits specified in
+its value are removed from the <b>SSL_OP_ALL</b> work-around bit-mask
+(see openssl/ssl.h and SSL_CTX_set_options(3)). You can specify more
+bits than are present in SSL_OP_ALL, excess bits are ignored. Specifying
+0xFFFFFFFF disables all bug-workarounds on a 32-bit system. This should
+also be sufficient on 64-bit systems, until OpenSSL abandons support
+for 32-bit systems and starts using the high 32 bits of a 64-bit
+bug-workaround mask. </p>
+
+<p> Otherwise, the parameter is a white-space or comma separated list
+of specific named bug work-arounds chosen from the list below. It
+is possible that your OpenSSL version includes new bug work-arounds
+added after your Postfix source code was last updated, in that case
+you can only disable one of these via the hexadecimal syntax above. </p>
+
+<dl>
+<dt><b>MICROSOFT_SESS_ID_BUG</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>NETSCAPE_CHALLENGE_BUG</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>LEGACY_SERVER_CONNECT</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>NETSCAPE_REUSE_CIPHER_CHANGE_BUG</b> also aliased as
+<b>CVE-2010-4180</b>. Postfix 2.8 disables this work-around by default
+with OpenSSL versions that may predate the fix. Fixed in OpenSSL 0.9.8q
+and OpenSSL 1.0.0c.</dt>
+<dt><b>SSLREF2_REUSE_CERT_TYPE_BUG</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>MICROSOFT_BIG_SSLV3_BUFFER</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>MSIE_SSLV2_RSA_PADDING</b> also aliased as
+<b>CVE-2005-2969</b>. Postfix 2.8 disables this work-around by default
+with OpenSSL versions that may predate the fix. Fixed in OpenSSL 0.9.7h
+and OpenSSL 0.9.8a.</dt>
+<dt><b>SSLEAY_080_CLIENT_DH_BUG</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>TLS_D5_BUG</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>TLS_BLOCK_PADDING_BUG</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>TLS_ROLLBACK_BUG</b>See SSL_CTX_set_options(3). This is disabled
+in OpenSSL 0.9.7 and later. Nobody should still be using 0.9.6! </dt>
+<dt><b>DONT_INSERT_EMPTY_FRAGMENTS</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>CRYPTOPRO_TLSEXT_BUG</b>New with GOST support in OpenSSL 1.0.0.</dt>
+</dl>
+
+<p> This feature is available in Postfix 2.8 and later.  </p>
+
+
 </DD>
 
 <DT><b><a name="tls_eecdh_strong_curve">tls_eecdh_strong_curve</a>
@@ -14886,6 +15015,31 @@ change this setting. </p>
 <p> This feature is available in Postfix 2.3 and later. </p>
 
 
+</DD>
+
+<DT><b><a name="tls_preempt_cipherlist">tls_preempt_cipherlist</a>
+(default: no)</b></DT><DD>
+
+<p> With SSLv3 and later, use the server's cipher preference order
+instead of the client's cipher preference order. </p>
+
+<p> By default, the OpenSSL server selects the client's most preferred
+cipher that the server supports. With SSLv3 and later, the server may
+choose its own most preferred cipher that is supported (offered) by
+the client. Setting "<a href="postconf.5.html#tls_preempts_cipherlist">tls_preempt_cipherlist</a> = yes" enables server cipher
+preferences. </p>
+
+<p> While server cipher selection may in some cases lead to a more secure
+or performant cipher choice, there is some risk of interoperability
+issues. In the past, some SSL clients have listed lower priority ciphers
+that they did not implement correctly. If the server chooses a cipher
+that the client prefers less, it may select a cipher whose client
+implementation is flawed. </p>
+
+<p> This feature is available in Postfix 2.8 and later, in combination
+with OpenSSL 0.9.7 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="tls_random_bytes">tls_random_bytes</a>
@@ -14962,6 +15116,357 @@ gives timeout errors.  </p>
 <p> This feature is available in Postfix 2.2 and later.  </p>
 
 
+</DD>
+
+<DT><b><a name="tlsproxy_enforce_tls">tlsproxy_enforce_tls</a>
+(default: $<a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a>)</b></DT><DD>
+
+<p> Mandatory TLS: announce STARTTLS support to SMTP clients, and
+require that clients use TLS encryption. See <a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a> for
+further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_CAfile">tlsproxy_tls_CAfile</a>
+(default: $<a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a>)</b></DT><DD>
+
+<p> A file containing (PEM format) CA certificates of root CAs
+trusted to sign either remote SMTP client certificates or intermediate
+CA certificates.  See <a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_CApath">tlsproxy_tls_CApath</a>
+(default: $<a href="postconf.5.html#smtpd_tls_CApath">smtpd_tls_CApath</a>)</b></DT><DD>
+
+<p> A directory containing (PEM format) CA certificates of root CAs
+trusted to sign either remote SMTP client certificates or intermediate
+CA certificates. See <a href="postconf.5.html#smtpd_tls_CApath">smtpd_tls_CApath</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_always_issue_session_ids">tlsproxy_tls_always_issue_session_ids</a>
+(default: $<a href="postconf.5.html#smtpd_tls_always_issue_session_ids">smtpd_tls_always_issue_session_ids</a>)</b></DT><DD>
+
+<p> Force the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server to issue a TLS session id,
+even when TLS session caching is turned off. See
+<a href="postconf.5.html#smtpd_tls_always_issue_session_ids">smtpd_tls_always_issue_session_ids</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_ask_ccert">tlsproxy_tls_ask_ccert</a>
+(default: $<a href="postconf.5.html#smtpd_tls_ask_ccert">smtpd_tls_ask_ccert</a>)</b></DT><DD>
+
+<p> Ask a remote SMTP client for a client certificate. See
+<a href="postconf.5.html#smtpd_tls_ask_ccert">smtpd_tls_ask_ccert</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_ccert_verifydepth">tlsproxy_tls_ccert_verifydepth</a>
+(default: $<a href="postconf.5.html#smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verifydepth</a>)</b></DT><DD>
+
+<p> The verification depth for remote SMTP client certificates. A
+depth of 1 is sufficient if the issuing CA is listed in a local CA
+file. See <a href="postconf.5.html#smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verifydepth</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_cert_file">tlsproxy_tls_cert_file</a>
+(default: $<a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a>)</b></DT><DD>
+
+<p> File with the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server RSA certificate in PEM
+format.  This file may also contain the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server
+private RSA key.  See <a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a> for further details.  </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_ciphers">tlsproxy_tls_ciphers</a>
+(default: $<a href="postconf.5.html#smtpd_tls_ciphers">smtpd_tls_ciphers</a>)</b></DT><DD>
+
+<p> The minimum TLS cipher grade that the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server
+will use with opportunistic TLS encryption. See <a href="postconf.5.html#smtpd_tls_ciphers">smtpd_tls_ciphers</a>
+for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_dcert_file">tlsproxy_tls_dcert_file</a>
+(default: $<a href="postconf.5.html#smtpd_tls_dcert_file">smtpd_tls_dcert_file</a>)</b></DT><DD>
+
+<p> File with the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server DSA certificate in PEM
+format.  This file may also contain the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server
+private DSA key.  See <a href="postconf.5.html#smtpd_tls_dcert_file">smtpd_tls_dcert_file</a> for further details.
+</p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_dh1024_param_file">tlsproxy_tls_dh1024_param_file</a>
+(default: $<a href="postconf.5.html#smtpd_tls_dh1024_param_file">smtpd_tls_dh1024_param_file</a>)</b></DT><DD>
+
+<p> File with DH parameters that the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server
+should use with EDH ciphers. See <a href="postconf.5.html#smtpd_tls_dh1024_param_file">smtpd_tls_dh1024_param_file</a> for
+further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_dh512_param_file">tlsproxy_tls_dh512_param_file</a>
+(default: $<a href="postconf.5.html#smtpd_tls_dh512_param_file">smtpd_tls_dh512_param_file</a>)</b></DT><DD>
+
+<p> File with DH parameters that the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server
+should use with EDH ciphers. See <a href="postconf.5.html#smtpd_tls_dh512_param_file">smtpd_tls_dh512_param_file</a> for
+further details.  </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_dkey_file">tlsproxy_tls_dkey_file</a>
+(default: $<a href="postconf.5.html#smtpd_tls_dkey_file">smtpd_tls_dkey_file</a>)</b></DT><DD>
+
+<p> File with the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server DSA private key in PEM
+format.  This file may be combined with the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a>
+server DSA certificate file specified with $<a href="postconf.5.html#smtpd_tls_dcert_file">smtpd_tls_dcert_file</a>.
+See <a href="postconf.5.html#smtpd_tls_dkey_file">smtpd_tls_dkey_file</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_eccert_file">tlsproxy_tls_eccert_file</a>
+(default: $<a href="postconf.5.html#smtpd_tls_eccert_file">smtpd_tls_eccert_file</a>)</b></DT><DD>
+
+<p> File with the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server ECDSA certificate in
+PEM format.  This file may also contain the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a>
+server private ECDSA key.  See <a href="postconf.5.html#smtpd_tls_eccert_file">smtpd_tls_eccert_file</a> for further
+details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_eckey_file">tlsproxy_tls_eckey_file</a>
+(default: $<a href="postconf.5.html#smtpd_tls_eckey_file">smtpd_tls_eckey_file</a>)</b></DT><DD>
+
+<p> File with the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server ECDSA private key in
+PEM format.  This file may be combined with the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a>
+server ECDSA certificate file specified with $<a href="postconf.5.html#smtpd_tls_eccert_file">smtpd_tls_eccert_file</a>.
+See <a href="postconf.5.html#smtpd_tls_eckey_file">smtpd_tls_eckey_file</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_eecdh_grade">tlsproxy_tls_eecdh_grade</a>
+(default: $<a href="postconf.5.html#smtpd_tls_eecdh_grade">smtpd_tls_eecdh_grade</a>)</b></DT><DD>
+
+<p> The Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server security grade for ephemeral
+elliptic-curve Diffie-Hellman (EECDH) key exchange. See
+<a href="postconf.5.html#smtpd_tls_eecdh_grade">smtpd_tls_eecdh_grade</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_exclude_ciphers">tlsproxy_tls_exclude_ciphers</a>
+(default: $<a href="postconf.5.html#smtpd_tls_exclude_ciphers">smtpd_tls_exclude_ciphers</a>)</b></DT><DD>
+
+<p> List of ciphers or cipher types to exclude from the <a href="tlsproxy.8.html">tlsproxy(8)</a>
+server cipher list at all TLS security levels. See
+<a href="postconf.5.html#smtpd_tls_exclude_ciphers">smtpd_tls_exclude_ciphers</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_fingerprint_digest">tlsproxy_tls_fingerprint_digest</a>
+(default: $<a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a>)</b></DT><DD>
+
+<p> The message digest algorithm used to construct client-certificate
+fingerprints. See <a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> for further details.
+</p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_key_file">tlsproxy_tls_key_file</a>
+(default: $<a href="postconf.5.html#smtpd_tls_key_file">smtpd_tls_key_file</a>)</b></DT><DD>
+
+<p> File with the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server RSA private key in PEM
+format.  This file may be combined with the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a>
+server RSA certificate file specified with $<a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a>.
+See <a href="postconf.5.html#smtpd_tls_key_file">smtpd_tls_key_file</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_loglevel">tlsproxy_tls_loglevel</a>
+(default: $<a href="postconf.5.html#smtpd_tls_loglevel">smtpd_tls_loglevel</a>)</b></DT><DD>
+
+<p> Enable additional Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server logging of TLS
+activity.  Each logging level also includes the information that
+is logged at a lower logging level. See <a href="postconf.5.html#smtpd_tls_loglevel">smtpd_tls_loglevel</a> for
+further details.  </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_mandatory_ciphers">tlsproxy_tls_mandatory_ciphers</a>
+(default: $<a href="postconf.5.html#smtpd_tls_mandatory_ciphers">smtpd_tls_mandatory_ciphers</a>)</b></DT><DD>
+
+<p> The minimum TLS cipher grade that the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server
+will use with mandatory TLS encryption. See <a href="postconf.5.html#smtpd_tls_mandatory_ciphers">smtpd_tls_mandatory_ciphers</a>
+for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_mandatory_exclude_ciphers">tlsproxy_tls_mandatory_exclude_ciphers</a>
+(default: $<a href="postconf.5.html#smtpd_tls_mandatory_exclude_ciphers">smtpd_tls_mandatory_exclude_ciphers</a>)</b></DT><DD>
+
+<p> Additional list of ciphers or cipher types to exclude from the
+<a href="tlsproxy.8.html">tlsproxy(8)</a> server cipher list at mandatory TLS security levels.
+See <a href="postconf.5.html#smtpd_tls_mandatory_exclude_ciphers">smtpd_tls_mandatory_exclude_ciphers</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_mandatory_protocols">tlsproxy_tls_mandatory_protocols</a>
+(default: $<a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a>)</b></DT><DD>
+
+<p> The SSL/TLS protocols accepted by the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server
+with mandatory TLS encryption. If the list is empty, the server
+supports all available SSL/TLS protocol versions.  See
+<a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_protocols">tlsproxy_tls_protocols</a>
+(default: $<a href="postconf.5.html#smtpd_tls_protocols">smtpd_tls_protocols</a>)</b></DT><DD>
+
+<p> List of TLS protocols that the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server will
+exclude or include with opportunistic TLS encryption. See
+<a href="postconf.5.html#smtpd_tls_protocols">smtpd_tls_protocols</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_req_ccert">tlsproxy_tls_req_ccert</a>
+(default: $<a href="postconf.5.html#smtpd_tls_req_ccert">smtpd_tls_req_ccert</a>)</b></DT><DD>
+
+<p> With mandatory TLS encryption, require a trusted remote SMTP
+client certificate in order to allow TLS connections to proceed.
+See <a href="postconf.5.html#smtpd_tls_req_ccert">smtpd_tls_req_ccert</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_security_level">tlsproxy_tls_security_level</a>
+(default: $<a href="postconf.5.html#smtpd_tls_security_level">smtpd_tls_security_level</a>)</b></DT><DD>
+
+<p> The SMTP TLS security level for the Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server;
+when a non-empty value is specified, this overrides the obsolete
+parameters <a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a> and <a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a>. See
+<a href="postconf.5.html#smtpd_tls_security_level">smtpd_tls_security_level</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_tls_session_cache_timeout">tlsproxy_tls_session_cache_timeout</a>
+(default: $<a href="postconf.5.html#smtpd_tls_session_cache_timeout">smtpd_tls_session_cache_timeout</a>)</b></DT><DD>
+
+<p> The expiration time of Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server TLS session
+cache information. A cache cleanup is performed periodically every
+$<a href="postconf.5.html#smtpd_tls_session_cache_timeout">smtpd_tls_session_cache_timeout</a> seconds. See
+<a href="postconf.5.html#smtpd_tls_session_cache_timeout">smtpd_tls_session_cache_timeout</a> for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_use_tls">tlsproxy_use_tls</a>
+(default: $<a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a>)</b></DT><DD>
+
+<p> Opportunistic TLS: announce STARTTLS support to SMTP clients,
+but do not require that clients use TLS encryption. See <a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a>
+for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="tlsproxy_watchdog_timeout">tlsproxy_watchdog_timeout</a>
+(default: 10s)</b></DT><DD>
+
+<p> How much time a <a href="tlsproxy.8.html">tlsproxy(8)</a> process may take to process local
+or remote I/O before it is terminated by a built-in watchdog timer.
+This is a safety mechanism that prevents <a href="tlsproxy.8.html">tlsproxy(8)</a> from becoming
+non-responsive due to a bug in Postfix itself or in system software.
+To avoid false alarms and unnecessary cache corruption this limit
+cannot be set under 10s.  </p>
+
+<p> Specify a non-zero time value (an integral value plus an optional
+one-letter suffix that specifies the time unit).  Time units: s
+(seconds), m (minutes), h (hours), d (days), w (weeks).  </p>
+
+<p> This feature is available in Postfix 2.8.  </p>
+
+
 </DD>
 
 <DT><b><a name="trace_service_name">trace_service_name</a>
index 560ab63c6f2f4d1b3451a0a1e339b554ea18660f..d63c0671d4a5afd00acece5b923014fec9feb3e5 100644 (file)
@@ -198,7 +198,7 @@ the following convention:  </p>
 
 <li> <a href="pipe.8.html">pipe(8)</a>, deliver mail to non-Postfix command 
 
-<li> <a href="postscreen.8.html">postscreen(8)</a>, Postfix SMTP triage server 
+<li> <a href="postscreen.8.html">postscreen(8)</a>, Postfix zombie blocker 
 
 <li> <a href="proxymap.8.html">proxymap(8)</a>, Postfix lookup table proxy server 
 
@@ -218,6 +218,8 @@ the following convention:  </p>
 
 <li> <a href="tlsmgr.8.html">tlsmgr(8)</a>, Postfix TLS cache and randomness manager 
 
+<li> <a href="tlsproxy.8.html">tlsproxy(8)</a>, Postfix TLS proxy server 
+
 <li> <a href="trivial-rewrite.8.html">trivial-rewrite(8)</a>, Postfix address rewriting 
 
 <li> <a href="verify.8.html">verify(8)</a>, Postfix address verification 
index 72eb6c0dd5e01c5d1bfd6e3d36b4c0d257e0c8ca..ad237fcf2dfbd8f87d0d99385a2dd51940dae0d1 100644 (file)
@@ -316,7 +316,7 @@ POSTFIX(1)                                                          POSTFIX(1)
        <a href="qmgr.8.html">oqmgr(8)</a>, old Postfix queue manager
        <a href="pickup.8.html">pickup(8)</a>, Postfix local mail pickup
        <a href="pipe.8.html">pipe(8)</a>, deliver mail to non-Postfix command
-       <a href="postscreen.8.html">postscreen(8)</a>, Postfix SMTP triage server
+       <a href="postscreen.8.html">postscreen(8)</a>, Postfix zombie blocker
        <a href="proxymap.8.html">proxymap(8)</a>, Postfix lookup table proxy server
        <a href="qmgr.8.html">qmgr(8)</a>, Postfix queue manager
        <a href="qmqpd.8.html">qmqpd(8)</a>, Postfix QMQP server
@@ -326,6 +326,7 @@ POSTFIX(1)                                                          POSTFIX(1)
        <a href="smtpd.8.html">smtpd(8)</a>, Postfix SMTP server
        <a href="spawn.8.html">spawn(8)</a>, run non-Postfix server
        <a href="tlsmgr.8.html">tlsmgr(8)</a>, Postfix TLS cache and randomness manager
+       <a href="tlsproxy.8.html">tlsproxy(8)</a>, Postfix TLS proxy server
        <a href="trivial-rewrite.8.html">trivial-rewrite(8)</a>, Postfix address rewriting
        <a href="verify.8.html">verify(8)</a>, Postfix address verification
        <a href="virtual.8.html">virtual(8)</a>, Postfix virtual delivery agent
index 0e11c16c684563bdca820d052ada1dcad619e141..a4ab206fcb15b9598a53b2273e559e79bc533cff 100644 (file)
@@ -7,7 +7,7 @@
 POSTSCREEN(8)                                                    POSTSCREEN(8)
 
 <b>NAME</b>
-       postscreen - Postfix SMTP triage server
+       postscreen - Postfix zombie blocker
 
 <b>SYNOPSIS</b>
        <b>postscreen</b> [generic Postfix daemon options]
@@ -48,19 +48,30 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
        can be run chrooted at fixed low privilege.
 
 <b>STANDARDS</b>
-       <a href="http://tools.ietf.org/html/rfc5321">RFC 5321</a> (SMTP, including multi-line 220 greetings)
+       <a href="http://tools.ietf.org/html/rfc821">RFC 821</a> (SMTP protocol)
+       <a href="http://tools.ietf.org/html/rfc1123">RFC 1123</a> (Host requirements)
+       <a href="http://tools.ietf.org/html/rfc1652">RFC 1652</a> (8bit-MIME transport)
+       <a href="http://tools.ietf.org/html/rfc1869">RFC 1869</a> (SMTP service extensions)
+       <a href="http://tools.ietf.org/html/rfc1870">RFC 1870</a> (Message Size Declaration)
+       <a href="http://tools.ietf.org/html/rfc1985">RFC 1985</a> (ETRN command)
+       <a href="http://tools.ietf.org/html/rfc2034">RFC 2034</a> (SMTP Enhanced Error Codes)
+       <a href="http://tools.ietf.org/html/rfc2821">RFC 2821</a> (SMTP protocol)
        <a href="http://tools.ietf.org/html/rfc2920">RFC 2920</a> (SMTP Pipelining)
+       <a href="http://tools.ietf.org/html/rfc3207">RFC 3207</a> (STARTTLS command)
+       <a href="http://tools.ietf.org/html/rfc3461">RFC 3461</a> (SMTP DSN Extension)
+       <a href="http://tools.ietf.org/html/rfc3463">RFC 3463</a> (Enhanced Status Codes)
+       <a href="http://tools.ietf.org/html/rfc5321">RFC 5321</a> (SMTP protocol, including multi-line 220 greetings)
 
 <b>DIAGNOSTICS</b>
        Problems and transactions are logged to <b>syslogd</b>(8).
 
 <b>BUGS</b>
        The <a href="postscreen.8.html"><b>postscreen</b>(8)</a> built-in SMTP protocol engine  currently
-       does  not  announce support for STARTTLS, AUTH, XCLIENT or
-       XFORWARD.  Support for STARTTLS and AUTH may be  added  in
-       the  future.   In the mean time, if you need to make these
-       services available on port 25,  then  do  not  enable  the
-       optional "after 220 server greeting" tests.
+       does  not  announce support for AUTH, XCLIENT or XFORWARD.
+       Support for AUTH may be added in the future.  In the  mean
+       time, if you need to make these services available on port
+       25, then do not enable  the  optional  "after  220  server
+       greeting" tests.
 
        The  optional  "after  220  server greeting" tests involve
        <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP protocol engine. When  these
@@ -83,46 +94,64 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
        The  text  below  provides  only  a parameter summary. See
        <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
 
-       NOTE: Some  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>   parameters  implement  stress-
+       NOTE:  Some  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>  parameters  implement  stress-
        dependent  behavior.   This  is  supported  only  when the
-       default value is stress-dependent (that is, it looks  like
-       ${stress?X}${stress:Y}).  Other parameters always evaluate
-       as if the stress value is the empty string.
+       default parameter value is stress-dependent (that  is,  it
+       looks  like  ${stress?X}${stress:Y}, or it is the $<i>name</i> of
+       an  smtpd  parameter  with  a  stress-dependent  default).
+       Other  parameters always evaluate as if the <b>stress</b> parame-
+       ter value is the empty string.
+
+<b>COMPATIBILITY CONTROLS</b>
+       <b><a href="postconf.5.html#postscreen_discard_ehlo_keyword_address_maps">postscreen_discard_ehlo_keyword_address_maps</a>  ($<a href="postconf.5.html#smtpd_discard_ehlo_keyword_address_maps">smtpd_dis</a>-</b>
+       <b><a href="postconf.5.html#smtpd_discard_ehlo_keyword_address_maps">card_ehlo_keyword_address_maps</a>)</b>
+              Lookup tables, indexed by the  remote  SMTP  client
+              address,  with  case insensitive lists of EHLO key-
+              words (pipelining, starttls, auth, etc.)  that  the
+              <a href="postscreen.8.html"><b>postscreen</b>(8)</a>  server  will  not  send  in the EHLO
+              response to a remote SMTP client.
+
+       <b><a href="postconf.5.html#postscreen_discard_ehlo_keywords">postscreen_discard_ehlo_keywords</a> ($<a href="postconf.5.html#smtpd_discard_ehlo_keywords">smtpd_discard_ehlo_key</a>-</b>
+       <b><a href="postconf.5.html#smtpd_discard_ehlo_keywords">words</a>)</b>
+              A case insensitive list of EHLO keywords  (pipelin-
+              ing,  starttls,  auth, etc.) that the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
+              server will not send in  the  EHLO  response  to  a
+              remote SMTP client.
 
 <b>TRIAGE PARAMETERS</b>
        <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  an  SMTP
-              client  sends  a bare newline character, that is, a
+              The  action  that  <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an 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_blacklist_action">postscreen_blacklist_action</a> (ignore)</b>
-              The  action  that  <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
-              client  is   permanently   blacklisted   with   the
+              The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes  when  an  SMTP
+              client   is   permanently   blacklisted   with  the
               <a href="postconf.5.html#postscreen_blacklist_networks">postscreen_blacklist_networks</a> parameter.
 
        <b><a href="postconf.5.html#postscreen_blacklist_networks">postscreen_blacklist_networks</a> (empty)</b>
               Network addresses that are permanently blacklisted;
-              see the <a href="postconf.5.html#postscreen_blacklist_action">postscreen_blacklist_action</a>  parameter  for
+              see  the  <a href="postconf.5.html#postscreen_blacklist_action">postscreen_blacklist_action</a> parameter for
               possible actions.
 
        <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_dnsbl_action">postscreen_dnsbl_action</a> (ignore)</b>
-              The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes  when  an  SMTP
+              The  action  that  <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
               client's  combined  DNSBL  score  is  equal  to  or
-              greater than  a  threshold  (as  defined  with  the
+              greater  than  a  threshold  (as  defined  with the
               <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> and <a href="postconf.5.html#postscreen_dnsbl_threshold">postscreen_dnsbl_thresh</a>-
               <a href="postconf.5.html#postscreen_dnsbl_threshold">old</a> parameters).
 
        <b><a href="postconf.5.html#postscreen_dnsbl_reply_map">postscreen_dnsbl_reply_map</a> (empty)</b>
-              A mapping  from  actual  DNSBL  domain  name  which
-              includes  a  secret  password,  to the DNSBL domain
+              A  mapping  from  actual  DNSBL  domain  name which
+              includes a secret password,  to  the  DNSBL  domain
               name  that  postscreen  will  reply  with  when  it
               rejects mail.
 
@@ -131,16 +160,16 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
               weight factors.
 
        <b><a href="postconf.5.html#postscreen_dnsbl_threshold">postscreen_dnsbl_threshold</a> (1)</b>
-              The inclusive lower  bound  for  blocking  an  SMTP
+              The  inclusive  lower  bound  for  blocking an SMTP
               client,  based  on  its  combined  DNSBL  score  as
-              defined with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a>  parameter.
+              defined  with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter.
 
        <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>
               List of commands that the <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server con-
               siders in violation of the SMTP protocol.
 
        <b><a href="postconf.5.html#postscreen_greet_action">postscreen_greet_action</a> (ignore)</b>
-              The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes  when  an  SMTP
+              The  action  that  <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
               client speaks before its turn within the time spec-
               ified with the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> parameter.
 
@@ -148,130 +177,151 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
               The  <i>text</i>  in  the  optional  "220-<i>text</i>..."  server
               response that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> sends ahead of the real
               Postfix SMTP server's "220 text..." response, in an
-              attempt  to  confuse  bad SMTP clients so that they
+              attempt to confuse bad SMTP clients  so  that  they
               speak before their turn (pre-greet).
 
        <b><a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> (${stress?2}${stress:6}s)</b>
               The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will wait for
-              an  SMTP  client to send a command before its turn,
-              and for DNS  blocklist  lookup  results  to  arrive
-              (default:  up  to  2  seconds under stress, up to 6
+              an SMTP client to send a command before  its  turn,
+              and  for  DNS  blocklist  lookup  results to arrive
+              (default: up to 2 seconds under  stress,  up  to  6
               seconds otherwise).
 
        <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 an SMTP
-              client sends non-SMTP commands  as  specified  with
+              The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes  when  an  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  an  SMTP
-              client  sends  multiple commands instead of sending
-              one command and waiting for the server to  respond.
+              The  action  that  <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an 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><a href="postconf.5.html#postscreen_whitelist_networks">postscreen_whitelist_networks</a> ($<a href="postconf.5.html#mynetworks">mynetworks</a>)</b>
               Network addresses that are permanently whitelisted,
-              and  that  will  not  be subjected to <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
+              and that will not  be  subjected  to  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
               checks.
 
        <b><a href="postconf.5.html#smtpd_service_name">smtpd_service_name</a> (smtpd)</b>
-              The internal service  that  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>  forwards
+              The  internal  service  that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> forwards
               allowed connections to.
 
 <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:$<a href="postconf.5.html#data_directory">data_directory</a>/ps_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 cache
-              results from a successful "bare newline" SMTP  pro-
+              The amount of time that  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>  will  cache
+              results  from a successful "bare newline" SMTP pro-
               tocol 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 cache
+              The amount of time that  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>  will  cache
               results 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  cache
+              The  amount  of  time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will cache
               results 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 cache
-              results from a successful  "non_smtp_command"  SMTP
+              The amount of time that  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>  will  cache
+              results  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 cache
-              results from a successful "pipelining" SMTP  proto-
+              The amount of time that  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>  will  cache
+              results  from a successful "pipelining" SMTP proto-
               col 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 client is
+              How many simultaneous  connections  any  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 command "read" time limit  for  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s
+              The  command  "read" time limit for <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 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 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  an SMTP client command or to perform a
+              How  much  time a <a href="postscreen.8.html"><b>postscreen</b>(8)</a> process may take to
+              respond to an SMTP client command or to  perform  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
+              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>OBSOLETE STARTTLS SUPPORT CONTROLS</b>
+       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
+              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  SMTP
+              clients,  and  require that clients use TLS encryp-
+              tion.
+
 <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#ipc_timeout">ipc_timeout</a> (3600s)</b>
@@ -279,28 +329,29 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
               over an internal communication channel.
 
        <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>
        <a href="smtpd.8.html">smtpd(8)</a>, Postfix SMTP server
+       <a href="tlsproxy.8.html">tlsproxy(8)</a>, Postfix TLS proxy server
        <a href="dnsblog.8.html">dnsblog(8)</a>, temporary DNS helper
        syslogd(8), system logging
 
@@ -308,12 +359,12 @@ 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>
-       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 1d14126e098e6e1b2a6f58873e087e1a6e6dc53c..c613394754ea669cd69788c3cd66478f07e0c9a0 100644 (file)
@@ -551,29 +551,35 @@ SMTP(8)                                                                SMTP(8)
               an  attacker  prepends  malicious HELO, MAIL, RCPT,
               DATA commands to a Postfix SMTP client TLS session.
 
+       Available in Postfix version 2.8 and later:
+
+       <b><a href="postconf.5.html#tls_disable_workarounds">tls_disable_workarounds</a> (see 'postconf -d' output)</b>
+              List  or  bit-mask  of  OpenSSL bug work-arounds to
+              disable.
+
 <b>OBSOLETE STARTTLS CONTROLS</b>
-       The  following configuration parameters exist for compati-
+       The following configuration parameters exist for  compati-
        bility with Postfix versions before 2.3. Support for these
        will be removed in a future release.
 
        <b><a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a> (no)</b>
-              Opportunistic  mode:  use  TLS  when  a remote SMTP
-              server announces STARTTLS support,  otherwise  send
+              Opportunistic mode: use  TLS  when  a  remote  SMTP
+              server  announces  STARTTLS support, otherwise send
               the mail in the clear.
 
        <b><a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> (no)</b>
-              Enforcement  mode: require that remote SMTP servers
-              use TLS encryption, and  never  send  mail  in  the
+              Enforcement mode: require that remote SMTP  servers
+              use  TLS  encryption,  and  never  send mail in the
               clear.
 
        <b><a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> (yes)</b>
-              With  mandatory  TLS  encryption,  require that the
+              With mandatory TLS  encryption,  require  that  the
               remote SMTP server hostname matches the information
               in the remote SMTP server certificate.
 
        <b><a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> (empty)</b>
               Optional lookup tables with the Postfix SMTP client
-              TLS usage policy by  next-hop  destination  and  by
+              TLS  usage  policy  by  next-hop destination and by
               remote SMTP server hostname.
 
        <b><a href="postconf.5.html#smtp_tls_cipherlist">smtp_tls_cipherlist</a> (empty)</b>
@@ -583,27 +589,27 @@ SMTP(8)                                                                SMTP(8)
 <b>RESOURCE AND RATE CONTROLS</b>
        <b><a href="postconf.5.html#smtp_destination_concurrency_limit">smtp_destination_concurrency_limit</a>      ($<a href="postconf.5.html#default_destination_concurrency_limit">default_destina</a>-</b>
        <b><a href="postconf.5.html#default_destination_concurrency_limit">tion_concurrency_limit</a>)</b>
-              The maximal number of parallel  deliveries  to  the
-              same  destination  via  the  smtp  message delivery
+              The  maximal  number  of parallel deliveries to the
+              same destination  via  the  smtp  message  delivery
               transport.
 
        <b><a href="postconf.5.html#smtp_destination_recipient_limit">smtp_destination_recipient_limit</a>        ($<a href="postconf.5.html#default_destination_recipient_limit">default_destina</a>-</b>
        <b><a href="postconf.5.html#default_destination_recipient_limit">tion_recipient_limit</a>)</b>
-              The maximal number of recipients  per  message  for
+              The  maximal  number  of recipients per message for
               the smtp message delivery transport.
 
        <b><a href="postconf.5.html#smtp_connect_timeout">smtp_connect_timeout</a> (30s)</b>
-              The  SMTP  client  time  limit for completing a TCP
+              The SMTP client time limit  for  completing  a  TCP
               connection,  or  zero  (use  the  operating  system
               built-in time limit).
 
        <b><a href="postconf.5.html#smtp_helo_timeout">smtp_helo_timeout</a> (300s)</b>
-              The  SMTP client time limit for sending the HELO or
-              EHLO command, and for receiving the initial  server
+              The SMTP client time limit for sending the HELO  or
+              EHLO  command, and for receiving the initial server
               response.
 
        <b><a href="postconf.5.html#lmtp_lhlo_timeout">lmtp_lhlo_timeout</a> (300s)</b>
-              The  LMTP  client  time  limit for sending the LHLO
+              The LMTP client time limit  for  sending  the  LHLO
               command,  and  for  receiving  the  initial  server
               response.
 
@@ -612,30 +618,30 @@ SMTP(8)                                                                SMTP(8)
               command, and for receiving the server response.
 
        <b><a href="postconf.5.html#smtp_mail_timeout">smtp_mail_timeout</a> (300s)</b>
-              The SMTP client time limit  for  sending  the  MAIL
-              FROM   command,   and   for  receiving  the  server
+              The  SMTP  client  time  limit for sending the MAIL
+              FROM  command,  and  for   receiving   the   server
               response.
 
        <b><a href="postconf.5.html#smtp_rcpt_timeout">smtp_rcpt_timeout</a> (300s)</b>
-              The SMTP client time limit  for  sending  the  SMTP
-              RCPT  TO  command,  and  for  receiving  the server
+              The  SMTP  client  time  limit for sending the SMTP
+              RCPT TO  command,  and  for  receiving  the  server
               response.
 
        <b><a href="postconf.5.html#smtp_data_init_timeout">smtp_data_init_timeout</a> (120s)</b>
-              The SMTP client time limit  for  sending  the  SMTP
-              DATA   command,   and   for  receiving  the  server
+              The  SMTP  client  time  limit for sending the SMTP
+              DATA  command,  and  for   receiving   the   server
               response.
 
        <b><a href="postconf.5.html#smtp_data_xfer_timeout">smtp_data_xfer_timeout</a> (180s)</b>
-              The SMTP client time limit  for  sending  the  SMTP
+              The  SMTP  client  time  limit for sending the SMTP
               message content.
 
        <b><a href="postconf.5.html#smtp_data_done_timeout">smtp_data_done_timeout</a> (600s)</b>
-              The  SMTP  client  time  limit for sending the SMTP
+              The SMTP client time limit  for  sending  the  SMTP
               ".", and for receiving the server response.
 
        <b><a href="postconf.5.html#smtp_quit_timeout">smtp_quit_timeout</a> (300s)</b>
-              The SMTP client time limit  for  sending  the  QUIT
+              The  SMTP  client  time  limit for sending the QUIT
               command, and for receiving the server response.
 
        Available in Postfix version 2.1 and later:
@@ -646,12 +652,12 @@ SMTP(8)                                                                SMTP(8)
               lookups, or zero (no limit).
 
        <b><a href="postconf.5.html#smtp_mx_session_limit">smtp_mx_session_limit</a> (2)</b>
-              The  maximal  number  of SMTP sessions per delivery
-              request before giving up or delivering to  a  fall-
+              The maximal number of SMTP  sessions  per  delivery
+              request  before  giving up or delivering to a fall-
               back <a href="postconf.5.html#relayhost">relay host</a>, or zero (no limit).
 
        <b><a href="postconf.5.html#smtp_rset_timeout">smtp_rset_timeout</a> (20s)</b>
-              The  SMTP  client  time  limit for sending the RSET
+              The SMTP client time limit  for  sending  the  RSET
               command, and for receiving the server response.
 
        Available in Postfix version 2.2 and earlier:
@@ -663,11 +669,11 @@ SMTP(8)                                                                SMTP(8)
        Available in Postfix version 2.2 and later:
 
        <b><a href="postconf.5.html#smtp_connection_cache_destinations">smtp_connection_cache_destinations</a> (empty)</b>
-              Permanently  enable SMTP connection caching for the
+              Permanently enable SMTP connection caching for  the
               specified destinations.
 
        <b><a href="postconf.5.html#smtp_connection_cache_on_demand">smtp_connection_cache_on_demand</a> (yes)</b>
-              Temporarily enable SMTP connection caching while  a
+              Temporarily  enable SMTP connection caching while a
               destination has a high volume of mail in the active
               queue.
 
@@ -677,62 +683,62 @@ SMTP(8)                                                                SMTP(8)
 
        <b><a href="postconf.5.html#smtp_connection_cache_time_limit">smtp_connection_cache_time_limit</a> (2s)</b>
               When SMTP connection caching is enabled, the amount
-              of time that an unused SMTP client socket  is  kept
+              of  time  that an unused SMTP client socket is kept
               open before it is closed.
 
        Available in Postfix version 2.3 and later:
 
        <b><a href="postconf.5.html#connection_cache_protocol_timeout">connection_cache_protocol_timeout</a> (5s)</b>
-              Time  limit  for  connection cache connect, send or
+              Time limit for connection cache  connect,  send  or
               receive operations.
 
 <b>TROUBLE SHOOTING CONTROLS</b>
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The increment  in  verbose  logging  level  when  a
-              remote  client  or  server matches a pattern in the
+              The  increment  in  verbose  logging  level  when a
+              remote client or server matches a  pattern  in  the
               <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional list of remote client or  server  hostname
-              or  network address patterns that cause the verbose
-              logging level to increase by the  amount  specified
+              Optional  list  of remote client or server hostname
+              or network address patterns that cause the  verbose
+              logging  level  to increase by the amount specified
               in $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
 
        <b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
-              The  recipient  of  postmaster  notifications about
-              mail delivery problems that are caused  by  policy,
+              The recipient  of  postmaster  notifications  about
+              mail  delivery  problems that are caused by policy,
               resource, software or protocol errors.
 
        <b><a href="postconf.5.html#internal_mail_filter_classes">internal_mail_filter_classes</a> (empty)</b>
-              What  categories of Postfix-generated mail are sub-
-              ject  to   before-queue   content   inspection   by
+              What categories of Postfix-generated mail are  sub-
+              ject   to   before-queue   content   inspection  by
               <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>, <a href="postconf.5.html#header_checks">header_checks</a> and <a href="postconf.5.html#body_checks">body_checks</a>.
 
        <b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
-              The  list of error classes that are reported to the
+              The list of error classes that are reported to  the
               postmaster.
 
 <b>MISCELLANEOUS CONTROLS</b>
        <b><a href="postconf.5.html#best_mx_transport">best_mx_transport</a> (empty)</b>
-              Where the Postfix SMTP client should  deliver  mail
+              Where  the  Postfix SMTP client should deliver mail
               when it detects a "mail loops back to myself" error
               condition.
 
        <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#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              How  much time a Postfix daemon process may take to
-              handle a request  before  it  is  terminated  by  a
+              How much time a Postfix daemon process may take  to
+              handle  a  request  before  it  is  terminated by a
               built-in watchdog timer.
 
        <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#disable_dns_lookups">disable_dns_lookups</a> (no)</b>
-              Disable DNS lookups in the Postfix  SMTP  and  LMTP
+              Disable  DNS  lookups  in the Postfix SMTP and LMTP
               clients.
 
        <b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
@@ -740,7 +746,7 @@ SMTP(8)                                                                SMTP(8)
               tem receives mail on.
 
        <b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (ipv4)</b>
-              The Internet protocols Postfix will attempt to  use
+              The  Internet protocols Postfix will attempt to use
               when making or accepting connections.
 
        <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
@@ -748,87 +754,87 @@ SMTP(8)                                                                SMTP(8)
               over an internal communication channel.
 
        <b><a href="postconf.5.html#lmtp_assume_final">lmtp_assume_final</a> (no)</b>
-              When an  LMTP  server  announces  no  DSN  support,
+              When  an  LMTP  server  announces  no  DSN support,
               assume that the server performs final delivery, and
-              send  "delivered"  delivery  status   notifications
+              send   "delivered"  delivery  status  notifications
               instead of "relayed".
 
        <b><a href="postconf.5.html#lmtp_tcp_port">lmtp_tcp_port</a> (24)</b>
-              The  default  TCP port that the Postfix LMTP client
+              The default TCP port that the Postfix  LMTP  client
               connects to.
 
        <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#max_use">max_use</a> (100)</b>
-              The maximal number of incoming connections  that  a
-              Postfix  daemon  process will service before termi-
+              The  maximal  number of incoming connections that a
+              Postfix daemon process will service  before  termi-
               nating 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#proxy_interfaces">proxy_interfaces</a> (empty)</b>
               The network interface addresses that this mail sys-
-              tem  receives  mail on by way of a proxy or network
+              tem receives mail on by way of a proxy  or  network
               address translation unit.
 
        <b><a href="postconf.5.html#smtp_address_preference">smtp_address_preference</a> (ipv6)</b>
               The address type ("ipv6", "ipv4" or "any") that the
               Postfix SMTP client will try first, when a destina-
-              tion has IPv6 and  IPv4  addresses  with  equal  MX
+              tion  has  IPv6  and  IPv4  addresses with equal MX
               preference.
 
        <b><a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> (empty)</b>
-              An  optional  numerical  network  address  that the
-              Postfix SMTP client should bind to when  making  an
+              An optional  numerical  network  address  that  the
+              Postfix  SMTP  client should bind to when making an
               IPv4 connection.
 
        <b><a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> (empty)</b>
-              An  optional  numerical  network  address  that the
-              Postfix SMTP client should bind to when  making  an
+              An optional  numerical  network  address  that  the
+              Postfix  SMTP  client should bind to when making an
               IPv6 connection.
 
        <b><a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
-              The  hostname to send in the SMTP EHLO or HELO com-
+              The hostname to send in the SMTP EHLO or HELO  com-
               mand.
 
        <b><a href="postconf.5.html#lmtp_lhlo_name">lmtp_lhlo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
               The hostname to send in the LMTP LHLO command.
 
        <b><a href="postconf.5.html#smtp_host_lookup">smtp_host_lookup</a> (dns)</b>
-              What mechanisms the Postfix  SMTP  client  uses  to
+              What  mechanisms  the  Postfix  SMTP client uses to
               look up a host's IP address.
 
        <b><a href="postconf.5.html#smtp_randomize_addresses">smtp_randomize_addresses</a> (yes)</b>
-              Randomize  the  order  of  equal-preference MX host
+              Randomize the order  of  equal-preference  MX  host
               addresses.
 
        <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".
 
        Available with Postfix 2.2 and earlier:
 
        <b><a href="postconf.5.html#fallback_relay">fallback_relay</a> (empty)</b>
-              Optional list of relay hosts for SMTP  destinations
+              Optional  list of relay hosts for SMTP destinations
               that can't be found or that are unreachable.
 
        Available with Postfix 2.3 and later:
 
        <b><a href="postconf.5.html#smtp_fallback_relay">smtp_fallback_relay</a> ($<a href="postconf.5.html#fallback_relay">fallback_relay</a>)</b>
-              Optional  list of relay hosts for SMTP destinations
+              Optional list of relay hosts for SMTP  destinations
               that can't be found or that are unreachable.
 
 <b>SEE ALSO</b>
@@ -849,7 +855,7 @@ SMTP(8)                                                                SMTP(8)
        <a href="TLS_README.html">TLS_README</a>, Postfix STARTTLS howto
 
 <b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
+       The Secure Mailer license must be  distributed  with  this
        software.
 
 <b>AUTHOR(S)</b>
index b2e67efb2792192215f3fdeb39824b10c5d33f0a..e942ab4d065b070889b5ea3f6cd29d2671b9181b 100644 (file)
@@ -556,19 +556,30 @@ SMTPD(8)                                                              SMTPD(8)
               The elliptic curve used by the SMTP server for max-
               imally strong ephemeral ECDH key exchange.
 
+       Available in Postfix version 2.8 and later:
+
+       <b><a href="postconf.5.html#tls_preempts_cipherlist">tls_preempt_cipherlist</a> (no)</b>
+              With SSLv3 and later, use the server's cipher pref-
+              erence order instead of the client's cipher prefer-
+              ence order.
+
+       <b><a href="postconf.5.html#tls_disable_workarounds">tls_disable_workarounds</a> (see 'postconf -d' output)</b>
+              List  or  bit-mask  of  OpenSSL bug work-arounds to
+              disable.
+
 <b>OBSOLETE STARTTLS CONTROLS</b>
-       The  following configuration parameters exist for compati-
+       The following configuration parameters exist for  compati-
        bility with Postfix versions before 2.3. Support for these
        will be removed in a future release.
 
        <b><a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a> (no)</b>
-              Opportunistic  TLS:  announce  STARTTLS  support to
-              SMTP clients, but do not require that  clients  use
+              Opportunistic TLS:  announce  STARTTLS  support  to
+              SMTP  clients,  but do not require that clients use
               TLS encryption.
 
        <b><a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a> (no)</b>
-              Mandatory  TLS:  announce  STARTTLS support to SMTP
-              clients, and require that clients use  TLS  encryp-
+              Mandatory TLS: announce STARTTLS  support  to  SMTP
+              clients,  and  require that clients use TLS encryp-
               tion.
 
        <b><a href="postconf.5.html#smtpd_tls_cipherlist">smtpd_tls_cipherlist</a> (empty)</b>
@@ -576,64 +587,64 @@ SMTPD(8)                                                              SMTPD(8)
               server TLS cipher list.
 
 <b>VERP SUPPORT CONTROLS</b>
-       With VERP style delivery,  each  recipient  of  a  message
+       With  VERP  style  delivery,  each  recipient of a message
        receives a customized copy of the message with his/her own
-       recipient address encoded in the envelope sender  address.
+       recipient  address encoded in the envelope sender address.
        The <a href="VERP_README.html">VERP_README</a> file describes configuration and operation
-       details of Postfix support for  variable  envelope  return
+       details  of  Postfix  support for variable envelope return
        path addresses.  VERP style delivery is requested with the
-       SMTP XVERP command or with the "sendmail -V"  command-line
-       option  and is available in Postfix version 1.1 and later.
+       SMTP  XVERP command or with the "sendmail -V" command-line
+       option and is available in Postfix version 1.1 and  later.
 
        <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a> (+=)</b>
               The two default VERP delimiter characters.
 
        <b><a href="postconf.5.html#verp_delimiter_filter">verp_delimiter_filter</a> (-=+)</b>
-              The characters Postfix accepts  as  VERP  delimiter
-              characters  on the Postfix <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command line
+              The  characters  Postfix  accepts as VERP delimiter
+              characters on the Postfix <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command  line
               and in SMTP commands.
 
        Available in Postfix version 1.1 and 2.0:
 
        <b><a href="postconf.5.html#authorized_verp_clients">authorized_verp_clients</a> ($<a href="postconf.5.html#mynetworks">mynetworks</a>)</b>
-              What SMTP clients are allowed to specify the  XVERP
+              What  SMTP clients are allowed to specify the XVERP
               command.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtpd_authorized_verp_clients">smtpd_authorized_verp_clients</a> ($<a href="postconf.5.html#authorized_verp_clients">authorized_verp_clients</a>)</b>
-              What  SMTP clients are allowed to specify the XVERP
+              What SMTP clients are allowed to specify the  XVERP
               command.
 
 <b>TROUBLE SHOOTING CONTROLS</b>
-       The <a href="DEBUG_README.html">DEBUG_README</a> document describes how to debug parts  of
-       the  Postfix mail system. The methods vary from making the
-       software log a lot of detail, to running some daemon  pro-
+       The  <a href="DEBUG_README.html">DEBUG_README</a> document describes how to debug parts of
+       the Postfix mail system. The methods vary from making  the
+       software  log a lot of detail, to running some daemon pro-
        cesses under control of a call tracer or debugger.
 
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The  increment  in  verbose  logging  level  when a
-              remote client or server matches a  pattern  in  the
+              The increment  in  verbose  logging  level  when  a
+              remote  client  or  server matches a pattern in the
               <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional  list  of remote client or server hostname
-              or network address patterns that cause the  verbose
-              logging  level  to increase by the amount specified
+              Optional list of remote client or  server  hostname
+              or  network address patterns that cause the verbose
+              logging level to increase by the  amount  specified
               in $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
 
        <b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
-              The recipient  of  postmaster  notifications  about
-              mail  delivery  problems that are caused by policy,
+              The  recipient  of  postmaster  notifications about
+              mail delivery problems that are caused  by  policy,
               resource, software or protocol errors.
 
        <b><a href="postconf.5.html#internal_mail_filter_classes">internal_mail_filter_classes</a> (empty)</b>
-              What categories of Postfix-generated mail are  sub-
-              ject   to   before-queue   content   inspection  by
+              What  categories of Postfix-generated mail are sub-
+              ject  to   before-queue   content   inspection   by
               <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>, <a href="postconf.5.html#header_checks">header_checks</a> and <a href="postconf.5.html#body_checks">body_checks</a>.
 
        <b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
-              The list of error classes that are reported to  the
+              The  list of error classes that are reported to the
               postmaster.
 
        <b><a href="postconf.5.html#soft_bounce">soft_bounce</a> (no)</b>
@@ -643,22 +654,22 @@ SMTPD(8)                                                              SMTPD(8)
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtpd_authorized_xclient_hosts">smtpd_authorized_xclient_hosts</a> (empty)</b>
-              What SMTP clients are allowed to  use  the  XCLIENT
+              What  SMTP  clients  are allowed to use the XCLIENT
               feature.
 
 <b>KNOWN VERSUS UNKNOWN RECIPIENT CONTROLS</b>
-       As  of  Postfix  version 2.0, the SMTP server rejects mail
-       for unknown recipients. This prevents the mail queue  from
-       clogging  up  with  undeliverable  MAILER-DAEMON messages.
-       Additional  information  on   this   topic   is   in   the
+       As of Postfix version 2.0, the SMTP  server  rejects  mail
+       for  unknown recipients. This prevents the mail queue from
+       clogging up  with  undeliverable  MAILER-DAEMON  messages.
+       Additional   information   on   this   topic   is  in  the
        <a href="LOCAL_RECIPIENT_README.html">LOCAL_RECIPIENT_README</a> and <a href="ADDRESS_CLASS_README.html">ADDRESS_CLASS_README</a> documents.
 
        <b><a href="postconf.5.html#show_user_unknown_table_name">show_user_unknown_table_name</a> (yes)</b>
-              Display the name of  the  recipient  table  in  the
+              Display  the  name  of  the  recipient table in the
               "User unknown" responses.
 
        <b><a href="postconf.5.html#canonical_maps">canonical_maps</a> (empty)</b>
-              Optional  address mapping lookup tables for message
+              Optional address mapping lookup tables for  message
               headers and envelopes.
 
        <b><a href="postconf.5.html#recipient_canonical_maps">recipient_canonical_maps</a> (empty)</b>
@@ -669,7 +680,7 @@ SMTPD(8)                                                              SMTPD(8)
 
        <b><a href="postconf.5.html#mydestination">mydestination</a>  ($<a href="postconf.5.html#myhostname">myhostname</a>,  localhost.$<a href="postconf.5.html#mydomain">mydomain</a>,  local-</b>
        <b>host)</b>
-              The  list  of  domains  that  are delivered via the
+              The list of domains  that  are  delivered  via  the
               $<a href="postconf.5.html#local_transport">local_transport</a> mail delivery transport.
 
        <b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
@@ -678,146 +689,146 @@ SMTPD(8)                                                              SMTPD(8)
 
        <b><a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> (empty)</b>
               The network interface addresses that this mail sys-
-              tem receives mail on by way of a proxy  or  network
+              tem  receives  mail on by way of a proxy or network
               address translation unit.
 
        <b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (ipv4)</b>
-              The  Internet protocols Postfix will attempt to use
+              The Internet protocols Postfix will attempt to  use
               when making or accepting connections.
 
        <b><a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a>             (<a href="proxymap.8.html">proxy</a>:unix:passwd.byname</b>
        <b>$<a href="postconf.5.html#alias_maps">alias_maps</a>)</b>
-              Lookup tables with all names or addresses of  local
-              recipients:  a  recipient address is local when its
-              domain matches $<a href="postconf.5.html#mydestination">mydestination</a>, $<a href="postconf.5.html#inet_interfaces">inet_interfaces</a>  or
+              Lookup  tables with all names or addresses of local
+              recipients: a recipient address is local  when  its
+              domain  matches $<a href="postconf.5.html#mydestination">mydestination</a>, $<a href="postconf.5.html#inet_interfaces">inet_interfaces</a> or
               $<a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a>.
 
        <b><a href="postconf.5.html#unknown_local_recipient_reject_code">unknown_local_recipient_reject_code</a> (550)</b>
-              The  numerical  Postfix  SMTP  server response code
-              when   a   recipient   address   is   local,    and
-              $<a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a>  specifies  a  list of lookup
+              The numerical Postfix  SMTP  server  response  code
+              when    a   recipient   address   is   local,   and
+              $<a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a> specifies a  list  of  lookup
               tables that does not match the recipient.
 
-       Parameters concerning known/unknown  recipients  of  relay
+       Parameters  concerning  known/unknown  recipients of relay
        destinations:
 
        <b><a href="postconf.5.html#relay_domains">relay_domains</a> ($<a href="postconf.5.html#mydestination">mydestination</a>)</b>
-              What  destination  domains (and subdomains thereof)
+              What destination domains (and  subdomains  thereof)
               this system will relay mail to.
 
        <b><a href="postconf.5.html#relay_recipient_maps">relay_recipient_maps</a> (empty)</b>
-              Optional lookup tables with all valid addresses  in
+              Optional  lookup tables with all valid addresses in
               the domains that match $<a href="postconf.5.html#relay_domains">relay_domains</a>.
 
        <b><a href="postconf.5.html#unknown_relay_recipient_reject_code">unknown_relay_recipient_reject_code</a> (550)</b>
               The numerical Postfix SMTP server reply code when a
-              recipient  address  matches   $<a href="postconf.5.html#relay_domains">relay_domains</a>,   and
-              <a href="postconf.5.html#relay_recipient_maps">relay_recipient_maps</a>  specifies  a  list  of lookup
+              recipient   address   matches  $<a href="postconf.5.html#relay_domains">relay_domains</a>,  and
+              <a href="postconf.5.html#relay_recipient_maps">relay_recipient_maps</a> specifies  a  list  of  lookup
               tables that does not match the recipient address.
 
-       Parameters concerning known/unknown recipients in  virtual
+       Parameters  concerning known/unknown recipients in virtual
        alias domains:
 
        <b><a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a> ($<a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a>)</b>
               Postfix is final destination for the specified list
-              of virtual alias  domains,  that  is,  domains  for
-              which  all  addresses  are  aliased to addresses in
+              of  virtual  alias  domains,  that  is, domains for
+              which all addresses are  aliased  to  addresses  in
               other local or remote domains.
 
        <b><a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> ($<a href="postconf.5.html#virtual_maps">virtual_maps</a>)</b>
-              Optional lookup tables  that  alias  specific  mail
-              addresses  or  domains  to  other  local  or remote
+              Optional  lookup  tables  that  alias specific mail
+              addresses or  domains  to  other  local  or  remote
               address.
 
        <b><a href="postconf.5.html#unknown_virtual_alias_reject_code">unknown_virtual_alias_reject_code</a> (550)</b>
               The SMTP server reply code when a recipient address
-              matches     $<a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a>,    and    $<a href="postconf.5.html#virtual_alias_maps">vir</a>-
-              <a href="postconf.5.html#virtual_alias_maps">tual_alias_maps</a> specifies a list of  lookup  tables
+              matches    $<a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a>,    and     $<a href="postconf.5.html#virtual_alias_maps">vir</a>-
+              <a href="postconf.5.html#virtual_alias_maps">tual_alias_maps</a>  specifies  a list of lookup tables
               that does not match the recipient address.
 
-       Parameters  concerning known/unknown recipients in virtual
+       Parameters concerning known/unknown recipients in  virtual
        mailbox domains:
 
        <b><a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a> ($<a href="postconf.5.html#virtual_mailbox_maps">virtual_mailbox_maps</a>)</b>
               Postfix is final destination for the specified list
-              of   domains;  mail  is  delivered  via  the  $<a href="postconf.5.html#virtual_transport">vir</a>-
+              of  domains;  mail  is  delivered  via  the   $<a href="postconf.5.html#virtual_transport">vir</a>-
               <a href="postconf.5.html#virtual_transport">tual_transport</a> mail delivery transport.
 
        <b><a href="postconf.5.html#virtual_mailbox_maps">virtual_mailbox_maps</a> (empty)</b>
-              Optional lookup tables with all valid addresses  in
+              Optional  lookup tables with all valid addresses in
               the domains that match $<a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a>.
 
        <b><a href="postconf.5.html#unknown_virtual_mailbox_reject_code">unknown_virtual_mailbox_reject_code</a> (550)</b>
               The SMTP server reply code when a recipient address
-              matches   $<a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a>,    and    $<a href="postconf.5.html#virtual_mailbox_maps">vir</a>-
+              matches    $<a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a>,    and   $<a href="postconf.5.html#virtual_mailbox_maps">vir</a>-
               <a href="postconf.5.html#virtual_mailbox_maps">tual_mailbox_maps</a> specifies a list of lookup tables
               that does not match the recipient address.
 
 <b>RESOURCE AND RATE CONTROLS</b>
-       The following parameters limit resource usage by the  SMTP
+       The  following parameters limit resource usage by the SMTP
        server and/or control client request rates.
 
        <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#queue_minfree">queue_minfree</a> (0)</b>
-              The  minimal  amount  of free space in bytes in the
+              The minimal amount of free space in  bytes  in  the
               queue file system that is needed to receive mail.
 
        <b><a href="postconf.5.html#message_size_limit">message_size_limit</a> (10240000)</b>
-              The maximal size in bytes of a  message,  including
+              The  maximal  size in bytes of a message, including
               envelope information.
 
        <b><a href="postconf.5.html#smtpd_recipient_limit">smtpd_recipient_limit</a> (1000)</b>
-              The  maximal  number of recipients that the Postfix
+              The maximal number of recipients that  the  Postfix
               SMTP server accepts per message delivery request.
 
        <b><a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a> (normal: 300s, overload: 10s)</b>
-              The time limit for sending a  Postfix  SMTP  server
-              response  and  for  receiving  a remote SMTP client
+              The  time  limit  for sending a Postfix SMTP server
+              response and for receiving  a  remote  SMTP  client
               request.
 
        <b><a href="postconf.5.html#smtpd_history_flush_threshold">smtpd_history_flush_threshold</a> (100)</b>
-              The maximal number of lines  in  the  Postfix  SMTP
-              server  command  history  before it is flushed upon
+              The  maximal  number  of  lines in the Postfix SMTP
+              server command history before it  is  flushed  upon
               receipt of EHLO, RSET, or end of DATA.
 
        Available in Postfix version 2.3 and later:
 
        <b><a href="postconf.5.html#smtpd_peername_lookup">smtpd_peername_lookup</a> (yes)</b>
               Attempt to look up the remote SMTP client hostname,
-              and  verify  that  the  name  matches the client IP
+              and verify that the  name  matches  the  client  IP
               address.
 
        The per SMTP client connection count and request rate lim-
        its are implemented in co-operation with the <a href="anvil.8.html"><b>anvil</b>(8)</a> ser-
-       vice, and are available in Postfix version 2.2 and  later.
+       vice,  and are available in Postfix version 2.2 and later.
 
        <b><a href="postconf.5.html#smtpd_client_connection_count_limit">smtpd_client_connection_count_limit</a> (50)</b>
-              How  many  simultaneous  connections  any client is
+              How many simultaneous  connections  any  client  is
               allowed to make to this service.
 
        <b><a href="postconf.5.html#smtpd_client_connection_rate_limit">smtpd_client_connection_rate_limit</a> (0)</b>
               The  maximal  number  of  connection  attempts  any
-              client  is allowed to make to this service per time
+              client is allowed to make to this service per  time
               unit.
 
        <b><a href="postconf.5.html#smtpd_client_message_rate_limit">smtpd_client_message_rate_limit</a> (0)</b>
-              The maximal number  of  message  delivery  requests
-              that  any client is allowed to make to this service
+              The  maximal  number  of  message delivery requests
+              that any client is allowed to make to this  service
               per time unit, regardless of whether or not Postfix
               actually accepts those messages.
 
        <b><a href="postconf.5.html#smtpd_client_recipient_rate_limit">smtpd_client_recipient_rate_limit</a> (0)</b>
-              The  maximal number of recipient addresses that any
-              client is allowed to send to this service per  time
+              The maximal number of recipient addresses that  any
+              client  is allowed to send to this service per time
               unit, regardless of whether or not Postfix actually
               accepts those recipients.
 
        <b><a href="postconf.5.html#smtpd_client_event_limit_exceptions">smtpd_client_event_limit_exceptions</a> ($<a href="postconf.5.html#mynetworks">mynetworks</a>)</b>
-              Clients      that      are      excluded       from
+              Clients       that      are      excluded      from
               smtpd_client_*_count/rate_limit restrictions.
 
        Available in Postfix version 2.3 and later:
@@ -828,52 +839,52 @@ SMTPD(8)                                                              SMTPD(8)
               tiate with this service per time unit.
 
 <b>TARPIT CONTROLS</b>
-       When  a  remote SMTP client makes errors, the Postfix SMTP
-       server can insert delays before responding. This can  help
-       to  slow  down  run-away  software.   The behavior is con-
-       trolled by an error counter  that  counts  the  number  of
-       errors  within an SMTP session that a client makes without
+       When a remote SMTP client makes errors, the  Postfix  SMTP
+       server  can insert delays before responding. This can help
+       to slow down run-away  software.   The  behavior  is  con-
+       trolled  by  an  error  counter  that counts the number of
+       errors within an SMTP session that a client makes  without
        delivering mail.
 
        <b><a href="postconf.5.html#smtpd_error_sleep_time">smtpd_error_sleep_time</a> (1s)</b>
               With Postfix version 2.1 and later: the SMTP server
-              response  delay  after  a client has made more than
-              $<a href="postconf.5.html#smtpd_soft_error_limit">smtpd_soft_error_limit</a>  errors,  and  fewer   than
-              $<a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a>  errors, without delivering
+              response delay after a client has  made  more  than
+              $<a href="postconf.5.html#smtpd_soft_error_limit">smtpd_soft_error_limit</a>   errors,  and  fewer  than
+              $<a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a> errors, without  delivering
               mail.
 
        <b><a href="postconf.5.html#smtpd_soft_error_limit">smtpd_soft_error_limit</a> (10)</b>
-              The number  of  errors  a  remote  SMTP  client  is
-              allowed  to make without delivering mail before the
+              The  number  of  errors  a  remote  SMTP  client is
+              allowed to make without delivering mail before  the
               Postfix SMTP server slows down all its responses.
 
        <b><a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a> (normal: 20, overload: 1)</b>
-              The maximal number of errors a remote  SMTP  client
+              The  maximal  number of errors a remote SMTP client
               is allowed to make without delivering mail.
 
        <b><a href="postconf.5.html#smtpd_junk_command_limit">smtpd_junk_command_limit</a> (normal: 100, overload: 1)</b>
-              The  number  of  junk commands (NOOP, VRFY, ETRN or
+              The number of junk commands (NOOP,  VRFY,  ETRN  or
               RSET) that a remote SMTP client can send before the
-              Postfix  SMTP  server starts to increment the error
+              Postfix SMTP server starts to increment  the  error
               counter with each junk command.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtpd_recipient_overshoot_limit">smtpd_recipient_overshoot_limit</a> (1000)</b>
-              The number of recipients that a remote SMTP  client
-              can  send  in  excess  of  the limit specified with
+              The  number of recipients that a remote SMTP client
+              can send in excess  of  the  limit  specified  with
               $<a href="postconf.5.html#smtpd_recipient_limit">smtpd_recipient_limit</a>,  before  the  Postfix  SMTP
-              server  increments  the per-session error count for
+              server increments the per-session error  count  for
               each excess recipient.
 
 <b>ACCESS POLICY DELEGATION CONTROLS</b>
-       As of version 2.1, Postfix can be configured  to  delegate
-       access  policy  decisions  to an external server that runs
-       outside Postfix.  See  the  file  <a href="SMTPD_POLICY_README.html">SMTPD_POLICY_README</a>  for
+       As  of  version 2.1, Postfix can be configured to delegate
+       access policy decisions to an external  server  that  runs
+       outside  Postfix.   See  the  file <a href="SMTPD_POLICY_README.html">SMTPD_POLICY_README</a> for
        more information.
 
        <b><a href="postconf.5.html#smtpd_policy_service_max_idle">smtpd_policy_service_max_idle</a> (300s)</b>
-              The  time  after which an idle SMTPD policy service
+              The time after which an idle SMTPD  policy  service
               connection is closed.
 
        <b><a href="postconf.5.html#smtpd_policy_service_max_ttl">smtpd_policy_service_max_ttl</a> (1000s)</b>
@@ -881,151 +892,151 @@ SMTPD(8)                                                              SMTPD(8)
               connection is closed.
 
        <b><a href="postconf.5.html#smtpd_policy_service_timeout">smtpd_policy_service_timeout</a> (100s)</b>
-              The  time  limit  for  connecting to, writing to or
+              The time limit for connecting  to,  writing  to  or
               receiving from a delegated SMTPD policy server.
 
 <b>ACCESS CONTROLS</b>
-       The <a href="SMTPD_ACCESS_README.html">SMTPD_ACCESS_README</a> document gives an introduction  to
+       The  <a href="SMTPD_ACCESS_README.html">SMTPD_ACCESS_README</a> document gives an introduction to
        all the SMTP server access control features.
 
        <b><a href="postconf.5.html#smtpd_delay_reject">smtpd_delay_reject</a> (yes)</b>
-              Wait  until  the  RCPT TO command before evaluating
+              Wait until the RCPT TO  command  before  evaluating
               $<a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a>,    $smtpd_helo_restric-
               tions and $<a href="postconf.5.html#smtpd_sender_restrictions">smtpd_sender_restrictions</a>, or wait until
-              the     ETRN     command     before      evaluating
+              the      ETRN     command     before     evaluating
               $<a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a> and $smtpd_helo_restric-
               tions.
 
-       <b><a href="postconf.5.html#parent_domain_matches_subdomains">parent_domain_matches_subdomains</a> (see 'postconf  -d'  out-</b>
+       <b><a href="postconf.5.html#parent_domain_matches_subdomains">parent_domain_matches_subdomains</a>  (see  'postconf -d' out-</b>
        <b>put)</b>
               What   Postfix   features   match   subdomains   of
               "domain.tld" automatically, instead of requiring an
               explicit ".domain.tld" pattern.
 
        <b><a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a> (empty)</b>
-              Optional SMTP server  access  restrictions  in  the
+              Optional  SMTP  server  access  restrictions in the
               context of a client SMTP connection request.
 
        <b><a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> (no)</b>
               Require that a remote SMTP client introduces itself
-              with the HELO or EHLO command  before  sending  the
-              MAIL  command  or  other commands that require EHLO
+              with  the  HELO  or EHLO command before sending the
+              MAIL command or other commands  that  require  EHLO
               negotiation.
 
        <b><a href="postconf.5.html#smtpd_helo_restrictions">smtpd_helo_restrictions</a> (empty)</b>
-              Optional restrictions that the Postfix SMTP  server
+              Optional  restrictions that the Postfix SMTP server
               applies in the context of the SMTP HELO command.
 
        <b><a href="postconf.5.html#smtpd_sender_restrictions">smtpd_sender_restrictions</a> (empty)</b>
-              Optional  restrictions that the Postfix SMTP server
+              Optional restrictions that the Postfix SMTP  server
               applies in the context of the MAIL FROM command.
 
        <b><a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a>           (<a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>,</b>
        <b><a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a>)</b>
               The  access  restrictions  that  the  Postfix  SMTP
-              server  applies  in the context of the RCPT TO com-
+              server applies in the context of the RCPT  TO  com-
               mand.
 
        <b><a href="postconf.5.html#smtpd_etrn_restrictions">smtpd_etrn_restrictions</a> (empty)</b>
-              Optional SMTP server  access  restrictions  in  the
+              Optional  SMTP  server  access  restrictions in the
               context of a client ETRN request.
 
        <b><a href="postconf.5.html#allow_untrusted_routing">allow_untrusted_routing</a> (no)</b>
-              Forward    mail   with   sender-specified   routing
-              (user[@%!]remote[@%!]site) from  untrusted  clients
+              Forward   mail   with   sender-specified    routing
+              (user[@%!]remote[@%!]site)  from  untrusted clients
               to destinations matching $<a href="postconf.5.html#relay_domains">relay_domains</a>.
 
        <b><a href="postconf.5.html#smtpd_restriction_classes">smtpd_restriction_classes</a> (empty)</b>
-              User-defined  aliases for groups of access restric-
+              User-defined aliases for groups of access  restric-
               tions.
 
        <b><a href="postconf.5.html#smtpd_null_access_lookup_key">smtpd_null_access_lookup_key</a> (</b>&lt;&gt;<b>)</b>
-              The lookup key to be used in SMTP <a href="access.5.html"><b>access</b>(5)</a>  tables
+              The  lookup key to be used in SMTP <a href="access.5.html"><b>access</b>(5)</a> tables
               instead of the null sender address.
 
        <b><a href="postconf.5.html#permit_mx_backup_networks">permit_mx_backup_networks</a> (empty)</b>
               Restrict  the  use  of  the  <a href="postconf.5.html#permit_mx_backup">permit_mx_backup</a>  SMTP
-              access feature to only  domains  whose  primary  MX
+              access  feature  to  only  domains whose primary MX
               hosts match the listed networks.
 
        Available in Postfix version 2.0 and later:
 
        <b><a href="postconf.5.html#smtpd_data_restrictions">smtpd_data_restrictions</a> (empty)</b>
-              Optional  access restrictions that the Postfix SMTP
+              Optional access restrictions that the Postfix  SMTP
               server applies in the context of the SMTP DATA com-
               mand.
 
        <b><a href="postconf.5.html#smtpd_expansion_filter">smtpd_expansion_filter</a> (see 'postconf -d' output)</b>
-              What  characters are allowed in $name expansions of
+              What characters are allowed in $name expansions  of
               RBL reply templates.
 
        Available in Postfix version 2.1 and later:
 
        <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
-              explicit <a href="postconf.5.html#reject_unlisted_sender">reject_unlisted_sender</a> access  restriction
+              Request  that  the Postfix SMTP server rejects mail
+              from  unknown  sender  addresses,  even   when   no
+              explicit  <a href="postconf.5.html#reject_unlisted_sender">reject_unlisted_sender</a> access restriction
               is specified.
 
        <b><a href="postconf.5.html#smtpd_reject_unlisted_recipient">smtpd_reject_unlisted_recipient</a> (yes)</b>
-              Request  that  the Postfix SMTP server rejects mail
+              Request that the Postfix SMTP server  rejects  mail
               for  unknown  recipient  addresses,  even  when  no
-              explicit  <a href="postconf.5.html#reject_unlisted_recipient">reject_unlisted_recipient</a> access restric-
+              explicit <a href="postconf.5.html#reject_unlisted_recipient">reject_unlisted_recipient</a> access  restric-
               tion is specified.
 
        Available in Postfix version 2.2 and later:
 
        <b><a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a> (empty)</b>
-              Optional access restrictions that the Postfix  SMTP
-              server  applies  in the context of the SMTP END-OF-
+              Optional  access restrictions that the Postfix SMTP
+              server applies in the context of the  SMTP  END-OF-
               DATA command.
 
 <b>SENDER AND RECIPIENT ADDRESS VERIFICATION CONTROLS</b>
-       Postfix  version  2.1  introduces  sender  and   recipient
-       address  verification.   This  feature  is  implemented by
-       sending probe email messages that are not actually  deliv-
-       ered.   This  feature  is requested via the reject_unveri-
-       fied_sender   and    <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipient</a>    access
-       restrictions.   The status of verification probes is main-
+       Postfix   version  2.1  introduces  sender  and  recipient
+       address verification.   This  feature  is  implemented  by
+       sending  probe email messages that are not actually deliv-
+       ered.  This feature is requested  via  the  reject_unveri-
+       fied_sender    and    <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipient</a>   access
+       restrictions.  The status of verification probes is  main-
        tained by the <a href="verify.8.html"><b>verify</b>(8)</a> server.  See the file <a href="ADDRESS_VERIFICATION_README.html">ADDRESS_VER</a>-
-       <a href="ADDRESS_VERIFICATION_README.html">IFICATION_README</a>  for  information  about how to configure
+       <a href="ADDRESS_VERIFICATION_README.html">IFICATION_README</a> for information about  how  to  configure
        and operate the Postfix sender/recipient address verifica-
        tion service.
 
        <b><a href="postconf.5.html#address_verify_poll_count">address_verify_poll_count</a> (normal: 3, overload: 1)</b>
-              How  many  times to query the <a href="verify.8.html"><b>verify</b>(8)</a> service for
-              the completion of an address  verification  request
+              How many times to query the <a href="verify.8.html"><b>verify</b>(8)</a>  service  for
+              the  completion  of an address verification request
               in progress.
 
        <b><a href="postconf.5.html#address_verify_poll_delay">address_verify_poll_delay</a> (3s)</b>
-              The  delay between queries for the completion of an
+              The delay between queries for the completion of  an
               address verification request in progress.
 
        <b><a href="postconf.5.html#address_verify_sender">address_verify_sender</a> ($<a href="postconf.5.html#double_bounce_sender">double_bounce_sender</a>)</b>
-              The sender address to use in  address  verification
+              The  sender  address to use in address verification
               probes; prior to Postfix 2.5 the default was "post-
               master".
 
        <b><a href="postconf.5.html#unverified_sender_reject_code">unverified_sender_reject_code</a> (450)</b>
-              The numerical Postfix  SMTP  server  response  code
-              when   a  recipient  address  is  rejected  by  the
+              The  numerical  Postfix  SMTP  server response code
+              when  a  recipient  address  is  rejected  by   the
               <a href="postconf.5.html#reject_unverified_sender">reject_unverified_sender</a> restriction.
 
        <b><a href="postconf.5.html#unverified_recipient_reject_code">unverified_recipient_reject_code</a> (450)</b>
-              The numerical Postfix SMTP server response  when  a
+              The  numerical  Postfix SMTP server response when a
               recipient address is rejected by the reject_unveri-
               fied_recipient restriction.
 
        Available in Postfix version 2.6 and later:
 
        <b><a href="postconf.5.html#unverified_sender_defer_code">unverified_sender_defer_code</a> (450)</b>
-              The numerical Postfix  SMTP  server  response  code
-              when  a  sender address probe fails due to a tempo-
+              The  numerical  Postfix  SMTP  server response code
+              when a sender address probe fails due to  a  tempo-
               rary error condition.
 
        <b><a href="postconf.5.html#unverified_recipient_defer_code">unverified_recipient_defer_code</a> (450)</b>
-              The numerical Postfix SMTP server response  when  a
-              recipient  address  probe  fails due to a temporary
+              The  numerical  Postfix SMTP server response when a
+              recipient address probe fails due  to  a  temporary
               error condition.
 
        <b><a href="postconf.5.html#unverified_sender_reject_reason">unverified_sender_reject_reason</a> (empty)</b>
@@ -1039,7 +1050,7 @@ SMTPD(8)                                                              SMTPD(8)
        <b><a href="postconf.5.html#unverified_sender_tempfail_action">unverified_sender_tempfail_action</a>           ($<a href="postconf.5.html#reject_tempfail_action">reject_temp</a>-</b>
        <b><a href="postconf.5.html#reject_tempfail_action">fail_action</a>)</b>
               The Postfix SMTP server's action when <a href="postconf.5.html#reject_unverified_sender">reject_unver</a>-
-              <a href="postconf.5.html#reject_unverified_sender">ified_sender</a>  fails due to a temporary error condi-
+              <a href="postconf.5.html#reject_unverified_sender">ified_sender</a> fails due to a temporary error  condi-
               tion.
 
        <b><a href="postconf.5.html#unverified_recipient_tempfail_action">unverified_recipient_tempfail_action</a>        ($<a href="postconf.5.html#reject_tempfail_action">reject_temp</a>-</b>
@@ -1049,7 +1060,7 @@ SMTPD(8)                                                              SMTPD(8)
               dition.
 
 <b>ACCESS CONTROL RESPONSES</b>
-       The following  parameters  control  numerical  SMTP  reply
+       The  following  parameters  control  numerical  SMTP reply
        codes and/or text responses.
 
        <b><a href="postconf.5.html#access_map_reject_code">access_map_reject_code</a> (554)</b>
@@ -1057,18 +1068,18 @@ SMTPD(8)                                                              SMTPD(8)
               an <a href="access.5.html"><b>access</b>(5)</a> map "reject" action.
 
        <b><a href="postconf.5.html#defer_code">defer_code</a> (450)</b>
-              The numerical Postfix  SMTP  server  response  code
-              when  a  remote  SMTP client request is rejected by
+              The  numerical  Postfix  SMTP  server response code
+              when a remote SMTP client request  is  rejected  by
               the "defer" restriction.
 
        <b><a href="postconf.5.html#invalid_hostname_reject_code">invalid_hostname_reject_code</a> (501)</b>
-              The numerical Postfix  SMTP  server  response  code
-              when  the  client HELO or EHLO command parameter is
-              rejected   by   the    <a href="postconf.5.html#reject_invalid_helo_hostname">reject_invalid_helo_hostname</a>
+              The  numerical  Postfix  SMTP  server response code
+              when the client HELO or EHLO command  parameter  is
+              rejected    by   the   <a href="postconf.5.html#reject_invalid_helo_hostname">reject_invalid_helo_hostname</a>
               restriction.
 
        <b><a href="postconf.5.html#maps_rbl_reject_code">maps_rbl_reject_code</a> (554)</b>
-              The  numerical  Postfix  SMTP  server response code
+              The numerical Postfix  SMTP  server  response  code
               when a remote SMTP client request is blocked by the
               <a href="postconf.5.html#reject_rbl_client">reject_rbl_client</a>,             <a href="postconf.5.html#reject_rhsbl_client">reject_rhsbl_client</a>,
               <a href="postconf.5.html#reject_rhsbl_reverse_client">reject_rhsbl_reverse_client</a>, <a href="postconf.5.html#reject_rhsbl_sender">reject_rhsbl_sender</a> or
@@ -1076,53 +1087,53 @@ SMTPD(8)                                                              SMTPD(8)
 
        <b><a href="postconf.5.html#non_fqdn_reject_code">non_fqdn_reject_code</a> (504)</b>
               The numerical Postfix SMTP server reply code when a
-              client    request    is     rejected     by     the
+              client     request     is     rejected    by    the
               <a href="postconf.5.html#reject_non_fqdn_helo_hostname">reject_non_fqdn_helo_hostname</a>,
               <a href="postconf.5.html#reject_non_fqdn_sender">reject_non_fqdn_sender</a> or <a href="postconf.5.html#reject_non_fqdn_recipient">reject_non_fqdn_recipient</a>
               restriction.
 
        <b><a href="postconf.5.html#plaintext_reject_code">plaintext_reject_code</a> (450)</b>
-              The  numerical  Postfix  SMTP  server response code
-              when a request is  rejected  by  the  <b>reject_plain-</b>
+              The numerical Postfix  SMTP  server  response  code
+              when  a  request  is  rejected by the <b>reject_plain-</b>
               <b>text_session</b> restriction.
 
        <b><a href="postconf.5.html#reject_code">reject_code</a> (554)</b>
-              The  numerical  Postfix  SMTP  server response code
-              when a remote SMTP client request  is  rejected  by
+              The numerical Postfix  SMTP  server  response  code
+              when  a  remote  SMTP client request is rejected by
               the "reject" restriction.
 
        <b><a href="postconf.5.html#relay_domains_reject_code">relay_domains_reject_code</a> (554)</b>
-              The  numerical  Postfix  SMTP  server response code
-              when  a  client  request   is   rejected   by   the
+              The numerical Postfix  SMTP  server  response  code
+              when   a   client   request   is  rejected  by  the
               <a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a> recipient restriction.
 
        <b><a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> (450)</b>
-              The  numerical  Postfix  SMTP  server response code
-              when a sender or recipient address is  rejected  by
+              The numerical Postfix  SMTP  server  response  code
+              when  a  sender or recipient address is rejected by
               the         <a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a>         or
               <a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a> restriction.
 
        <b><a href="postconf.5.html#unknown_client_reject_code">unknown_client_reject_code</a> (450)</b>
-              The numerical Postfix  SMTP  server  response  code
-              when  a  client without valid address &lt;=&gt; name map-
+              The  numerical  Postfix  SMTP  server response code
+              when a client without valid address &lt;=&gt;  name  map-
               ping is rejected by the reject_unknown_client_host-
               name restriction.
 
        <b><a href="postconf.5.html#unknown_hostname_reject_code">unknown_hostname_reject_code</a> (450)</b>
-              The  numerical  Postfix  SMTP  server response code
-              when the hostname specified with the HELO  or  EHLO
-              command        is       rejected       by       the
+              The numerical Postfix  SMTP  server  response  code
+              when  the  hostname specified with the HELO or EHLO
+              command       is       rejected       by        the
               <a href="postconf.5.html#reject_unknown_helo_hostname">reject_unknown_helo_hostname</a> restriction.
 
        Available in Postfix version 2.0 and later:
 
        <b><a href="postconf.5.html#default_rbl_reply">default_rbl_reply</a> (see 'postconf -d' output)</b>
-              The default SMTP server  response  template  for  a
-              request  that  is rejected by an RBL-based restric-
+              The  default  SMTP  server  response template for a
+              request that is rejected by an  RBL-based  restric-
               tion.
 
        <b><a href="postconf.5.html#multi_recipient_bounce_reject_code">multi_recipient_bounce_reject_code</a> (550)</b>
-              The numerical Postfix  SMTP  server  response  code
+              The  numerical  Postfix  SMTP  server response code
               when a remote SMTP client request is blocked by the
               <a href="postconf.5.html#reject_multi_recipient_bounce">reject_multi_recipient_bounce</a> restriction.
 
@@ -1133,38 +1144,38 @@ SMTPD(8)                                                              SMTPD(8)
 
        <b><a href="postconf.5.html#access_map_defer_code">access_map_defer_code</a> (450)</b>
               The numerical Postfix SMTP server response code for
-              an  <a href="access.5.html"><b>access</b>(5)</a>   map   "defer"   action,   including
+              an   <a href="access.5.html"><b>access</b>(5)</a>   map   "defer"   action,  including
               "<a href="postconf.5.html#defer_if_permit">defer_if_permit</a>" or "<a href="postconf.5.html#defer_if_reject">defer_if_reject</a>".
 
        <b><a href="postconf.5.html#reject_tempfail_action">reject_tempfail_action</a> (<a href="postconf.5.html#defer_if_permit">defer_if_permit</a>)</b>
               The Postfix SMTP server's action when a reject-type
-              restriction fails due to a temporary  error  condi-
+              restriction  fails  due to a temporary error condi-
               tion.
 
        <b><a href="postconf.5.html#unknown_helo_hostname_tempfail_action">unknown_helo_hostname_tempfail_action</a>       ($<a href="postconf.5.html#reject_tempfail_action">reject_temp</a>-</b>
        <b><a href="postconf.5.html#reject_tempfail_action">fail_action</a>)</b>
-              The    Postfix    SMTP    server's    action   when
+              The   Postfix    SMTP    server's    action    when
               <a href="postconf.5.html#reject_unknown_helo_hostname">reject_unknown_helo_hostname</a> fails due to an tempo-
               rary error condition.
 
        <b><a href="postconf.5.html#unknown_address_tempfail_action">unknown_address_tempfail_action</a> ($<a href="postconf.5.html#reject_tempfail_action">reject_tempfail_action</a>)</b>
-              The    Postfix    SMTP    server's    action   when
+              The   Postfix    SMTP    server's    action    when
               <a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a>                     or
-              <a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a>  fail due to a tem-
+              <a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a> fail due to a  tem-
               porary error condition.
 
 <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#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              How  much time a Postfix daemon process may take to
-              handle a request  before  it  is  terminated  by  a
+              How much time a Postfix daemon process may take  to
+              handle  a  request  before  it  is  terminated by a
               built-in watchdog timer.
 
        <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#double_bounce_sender">double_bounce_sender</a> (double-bounce)</b>
@@ -1185,37 +1196,37 @@ SMTPD(8)                                                              SMTPD(8)
               and most Postfix daemon processes.
 
        <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#max_use">max_use</a> (100)</b>
-              The  maximal  number of incoming connections that a
-              Postfix daemon process will service  before  termi-
+              The maximal number of incoming connections  that  a
+              Postfix  daemon  process will service before termi-
               nating voluntarily.
 
        <b><a href="postconf.5.html#myhostname">myhostname</a> (see 'postconf -d' output)</b>
               The internet hostname of this mail system.
 
        <b><a href="postconf.5.html#mynetworks">mynetworks</a> (see 'postconf -d' output)</b>
-              The  list  of "trusted" SMTP clients that have more
+              The list of "trusted" SMTP clients that  have  more
               privileges than "strangers".
 
        <b><a href="postconf.5.html#myorigin">myorigin</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
               The domain name that locally-posted mail appears to
-              come  from,  and that locally posted mail is deliv-
+              come from, and that locally posted mail  is  deliv-
               ered to.
 
        <b><a href="postconf.5.html#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#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
-              The location of the Postfix top-level queue  direc-
+              The  location of the Postfix top-level queue direc-
               tory.
 
        <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
@@ -1223,28 +1234,28 @@ SMTPD(8)                                                              SMTPD(8)
               sions (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
+              The  text  that  follows the 220 status code in the
               SMTP greeting banner.
 
        <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".
 
        Available in Postfix version 2.2 and later:
 
        <b><a href="postconf.5.html#smtpd_forbidden_commands">smtpd_forbidden_commands</a> (CONNECT, GET, POST)</b>
               List of commands that cause the Postfix SMTP server
-              to immediately terminate the  session  with  a  221
+              to  immediately  terminate  the  session with a 221
               code.
 
        Available in Postfix version 2.5 and later:
 
        <b><a href="postconf.5.html#smtpd_client_port_logging">smtpd_client_port_logging</a> (no)</b>
-              Enable  logging  of  the remote SMTP client port in
+              Enable logging of the remote SMTP  client  port  in
               addition to the hostname and IP address.
 
 <b>SEE ALSO</b>
@@ -1274,7 +1285,7 @@ SMTPD(8)                                                              SMTPD(8)
        <a href="XFORWARD_README.html">XFORWARD_README</a>, Postfix XFORWARD extension
 
 <b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
+       The Secure Mailer license must be  distributed  with  this
        software.
 
 <b>AUTHOR(S)</b>
diff --git a/postfix/html/tlsproxy.8.html b/postfix/html/tlsproxy.8.html
new file mode 100644 (file)
index 0000000..d174809
--- /dev/null
@@ -0,0 +1,246 @@
+<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
+        "http://www.w3.org/TR/html4/loose.dtd">
+<html> <head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+<title> Postfix manual - tlsproxy(8) </title>
+</head> <body> <pre>
+TLSPROXY(8)                                                        TLSPROXY(8)
+
+<b>NAME</b>
+       tlsproxy - Postfix TLS proxy
+
+<b>SYNOPSIS</b>
+       <b>tlsproxy</b> [generic Postfix daemon options]
+
+<b>DESCRIPTION</b>
+       The <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server implements a server-side TLS proxy.
+       Its  primary  use  is  to   talk   plaintext   SMTP   with
+       <a href="postscreen.8.html"><b>postscreen</b>(8)</a>,  and to talk SMTP-over-TLS with remote SMTP
+       clients whose whitelist status has expired, but it  should
+       also work for non-SMTP protocols.
+
+       Although  one  <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> process can serve multiple ses-
+       sions at the same time, it is a good  idea  to  allow  the
+       number  of  processes  to  increase with load, so that the
+       service remains available.
+
+<b>PROTOCOL EXAMPLE</b>
+       The example below  involves  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>.  However,  the
+       <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a>  server  is agnostic of the application proto-
+       col, and the example is easily adapted to  other  applica-
+       tions.
+
+       The <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server sends the remote SMTP client end-
+       point  string,  the  requested  role  (server),  and   the
+       requested  timeout  to  <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a>.   <a href="postscreen.8.html"><b>postscreen</b>(8)</a>  then
+       receives a "TLS available"  indication  from  <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a>.
+       If  the  TLS service is available, <a href="postscreen.8.html"><b>postscreen</b>(8)</a> sends the
+       remote SMTP client file  descriptor  to  <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a>,  and
+       sends  the  plaintext  220  greeting  to  the  remote SMTP
+       client.  This triggers TLS negotiations between the remote
+       SMTP  client and <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a>.  Upon completion of the TLS-
+       level handshake, <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> translates between  plaintext
+       from/to  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>  and  ciphertext to/from the remote
+       SMTP client.
+
+<b>SECURITY</b>
+       The <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server is  moderately  security-sensitive.
+       It  talks to untrusted clients on the network. The process
+       can be run chrooted at fixed low privilege.
+
+<b>DIAGNOSTICS</b>
+       Problems and transactions are logged to <b>syslogd</b>(8).
+
+<b>CONFIGURATION PARAMETERS</b>
+       Changes to <a href="postconf.5.html"><b>main.cf</b></a> are not  picked  up  automatically,  as
+       <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> processes may run for a long time depending on
+       mail server load.  Use the  command  "<b>postfix  reload</b>"  to
+       speed up a change.
+
+       The  text  below  provides  only  a parameter summary. See
+       <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
+
+<b>STARTTLS SUPPORT CONTROLS</b>
+       <b><a href="postconf.5.html#tlsproxy_tls_CAfile">tlsproxy_tls_CAfile</a> ($<a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a>)</b>
+              A file containing (PEM format) CA  certificates  of
+              root  CAs trusted to sign either remote SMTP client
+              certificates or intermediate CA certificates.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_CApath">tlsproxy_tls_CApath</a> ($<a href="postconf.5.html#smtpd_tls_CApath">smtpd_tls_CApath</a>)</b>
+              A directory containing (PEM format) CA certificates
+              of  root  CAs  trusted  to  sign either remote SMTP
+              client certificates  or  intermediate  CA  certifi-
+              cates.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_always_issue_session_ids">tlsproxy_tls_always_issue_session_ids</a></b>
+       <b>($<a href="postconf.5.html#smtpd_tls_always_issue_session_ids">smtpd_tls_always_issue_session_ids</a>)</b>
+              Force the Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server to issue a TLS
+              session id, even when TLS session caching is turned
+              off.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_ask_ccert">tlsproxy_tls_ask_ccert</a> ($<a href="postconf.5.html#smtpd_tls_ask_ccert">smtpd_tls_ask_ccert</a>)</b>
+              Ask  a remote SMTP client for a client certificate.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_ccert_verifydepth">tlsproxy_tls_ccert_verifydepth</a>   ($<a href="postconf.5.html#smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verify</a>-</b>
+       <b><a href="postconf.5.html#smtpd_tls_ccert_verifydepth">depth</a>)</b>
+              The verification depth for remote SMTP client  cer-
+              tificates.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_cert_file">tlsproxy_tls_cert_file</a> ($<a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a>)</b>
+              File  with  the Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server RSA cer-
+              tificate in PEM format.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_ciphers">tlsproxy_tls_ciphers</a> ($<a href="postconf.5.html#smtpd_tls_ciphers">smtpd_tls_ciphers</a>)</b>
+              The minimum  TLS  cipher  grade  that  the  Postfix
+              <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a>  server will use with opportunistic TLS
+              encryption.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_dcert_file">tlsproxy_tls_dcert_file</a> ($<a href="postconf.5.html#smtpd_tls_dcert_file">smtpd_tls_dcert_file</a>)</b>
+              File with the Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server  DSA  cer-
+              tificate in PEM format.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_dh1024_param_file">tlsproxy_tls_dh1024_param_file</a></b>
+       <b>($<a href="postconf.5.html#smtpd_tls_dh1024_param_file">smtpd_tls_dh1024_param_file</a>)</b>
+              File   with   DH   parameters   that   the  Postfix
+              <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server should use with EDH ciphers.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_dh512_param_file">tlsproxy_tls_dh512_param_file</a></b>
+       <b>($<a href="postconf.5.html#smtpd_tls_dh512_param_file">smtpd_tls_dh512_param_file</a>)</b>
+              File  with   DH   parameters   that   the   Postfix
+              <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server should use with EDH ciphers.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_dkey_file">tlsproxy_tls_dkey_file</a> ($<a href="postconf.5.html#smtpd_tls_dkey_file">smtpd_tls_dkey_file</a>)</b>
+              File  with  the Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server DSA pri-
+              vate key in PEM format.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_eccert_file">tlsproxy_tls_eccert_file</a> ($<a href="postconf.5.html#smtpd_tls_eccert_file">smtpd_tls_eccert_file</a>)</b>
+              File with the Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server ECDSA cer-
+              tificate in PEM format.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_eckey_file">tlsproxy_tls_eckey_file</a> ($<a href="postconf.5.html#smtpd_tls_eckey_file">smtpd_tls_eckey_file</a>)</b>
+              File with the Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server ECDSA pri-
+              vate key in PEM format.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_eecdh_grade">tlsproxy_tls_eecdh_grade</a> ($<a href="postconf.5.html#smtpd_tls_eecdh_grade">smtpd_tls_eecdh_grade</a>)</b>
+              The Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server security  grade  for
+              ephemeral elliptic-curve Diffie-Hellman (EECDH) key
+              exchange.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_exclude_ciphers">tlsproxy_tls_exclude_ciphers</a> ($<a href="postconf.5.html#smtpd_tls_exclude_ciphers">smtpd_tls_exclude_ciphers</a>)</b>
+              List of ciphers or cipher types to exclude from the
+              <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a>  server cipher list at all TLS security
+              levels.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_fingerprint_digest">tlsproxy_tls_fingerprint_digest</a>        ($<a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_finger</a>-</b>
+       <b><a href="postconf.5.html#smtpd_tls_fingerprint_digest">print_digest</a>)</b>
+              The message  digest  algorithm  used  to  construct
+              client-certificate fingerprints.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_key_file">tlsproxy_tls_key_file</a> ($<a href="postconf.5.html#smtpd_tls_key_file">smtpd_tls_key_file</a>)</b>
+              File  with  the Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server RSA pri-
+              vate key in PEM format.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_loglevel">tlsproxy_tls_loglevel</a> ($<a href="postconf.5.html#smtpd_tls_loglevel">smtpd_tls_loglevel</a>)</b>
+              Enable additional Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a>  server  log-
+              ging of TLS activity.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_mandatory_ciphers">tlsproxy_tls_mandatory_ciphers</a>          ($<a href="postconf.5.html#smtpd_tls_mandatory_ciphers">smtpd_tls_manda</a>-</b>
+       <b><a href="postconf.5.html#smtpd_tls_mandatory_ciphers">tory_ciphers</a>)</b>
+              The  minimum  TLS  cipher  grade  that  the Postfix
+              <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server  will  use  with  mandatory  TLS
+              encryption.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_mandatory_exclude_ciphers">tlsproxy_tls_mandatory_exclude_ciphers</a>  ($<a href="postconf.5.html#smtpd_tls_mandatory_exclude_ciphers">smtpd_tls_manda</a>-</b>
+       <b><a href="postconf.5.html#smtpd_tls_mandatory_exclude_ciphers">tory_exclude_ciphers</a>)</b>
+              Additional  list  of  ciphers  or  cipher  types to
+              exclude from the <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server cipher list  at
+              mandatory TLS security levels.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_mandatory_protocols">tlsproxy_tls_mandatory_protocols</a>        ($<a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_manda</a>-</b>
+       <b><a href="postconf.5.html#smtpd_tls_mandatory_protocols">tory_protocols</a>)</b>
+              The  SSL/TLS  protocols  accepted  by  the  Postfix
+              <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server with mandatory TLS encryption.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_protocols">tlsproxy_tls_protocols</a> ($<a href="postconf.5.html#smtpd_tls_protocols">smtpd_tls_protocols</a>)</b>
+              List of TLS protocols that the Postfix  <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a>
+              server  will  exclude or include with opportunistic
+              TLS encryption.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_req_ccert">tlsproxy_tls_req_ccert</a> ($<a href="postconf.5.html#smtpd_tls_req_ccert">smtpd_tls_req_ccert</a>)</b>
+              With mandatory TLS encryption,  require  a  trusted
+              remote  SMTP  client  certificate in order to allow
+              TLS connections to proceed.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_security_level">tlsproxy_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   Postfix
+              <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server; when a non-empty value is spec-
+              ified,  this  overrides  the  obsolete   parameters
+              <a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a> and <a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a>.
+
+       <b><a href="postconf.5.html#tlsproxy_tls_session_cache_timeout">tlsproxy_tls_session_cache_timeout</a>        ($<a href="postconf.5.html#smtpd_tls_session_cache_timeout">smtpd_tls_ses</a>-</b>
+       <b><a href="postconf.5.html#smtpd_tls_session_cache_timeout">sion_cache_timeout</a>)</b>
+              The  expiration  time of Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server
+              TLS session cache information.
+
+<b>OBSOLETE STARTTLS SUPPORT CONTROLS</b>
+       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#tlsproxy_use_tls">tlsproxy_use_tls</a> ($<a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a>)</b>
+              Opportunistic  TLS:  announce  STARTTLS  support to
+              SMTP clients, but do not require that  clients  use
+              TLS encryption.
+
+       <b><a href="postconf.5.html#tlsproxy_enforce_tls">tlsproxy_enforce_tls</a> ($<a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a>)</b>
+              Mandatory  TLS:  announce  STARTTLS support to SMTP
+              clients, and require that clients use  TLS  encryp-
+              tion.
+
+<b>RESOURCE CONTROLS</b>
+       <b><a href="postconf.5.html#tlsproxy_watchdog_timeout">tlsproxy_watchdog_timeout</a> (10s)</b>
+              How  much  time  a  <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> process may take to
+              process local or remote I/O before it is terminated
+              by a built-in watchdog timer.
+
+<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
+              <a href="master.5.html">master.cf</a> configuration files.
+
+       <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
+              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
+              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"
+              becomes, for example, "postfix/smtpd".
+
+<b>SEE ALSO</b>
+       <a href="postscreen.8.html">postscreen(8)</a>, Postfix zombie blocker
+       <a href="smtpd.8.html">smtpd(8)</a>, Postfix SMTP server
+       <a href="postconf.5.html">postconf(5)</a>, configuration parameters
+       syslogd(5), system logging
+
+<b>LICENSE</b>
+       The Secure Mailer license must be  distributed  with  this
+       software.
+
+<b>HISTORY</b>
+       This service was introduced with Postfix version 2.8.
+
+<b>AUTHOR(S)</b>
+       Wietse Venema
+       IBM T.J. Watson Research
+       P.O. Box 704
+       Yorktown Heights, NY 10598, USA
+
+                                                                   TLSPROXY(8)
+</pre> </body> </html>
index 4ab5008daf1e134b2b737778db1aebd748825d7e..912ace4099674fbe9ce521f9cb799da8b6808084 100644 (file)
@@ -8,7 +8,7 @@ DAEMONS = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/error.8 man8/local.8 \
        man8/oqmgr.8 man8/spawn.8 man8/flush.8 man8/virtual.8 man8/qmqpd.8 \
        man8/verify.8 man8/trace.8 man8/proxymap.8 man8/anvil.8 \
        man8/scache.8 man8/discard.8 man8/tlsmgr.8 man8/postscreen.8 \
-       man8/dnsblog.8
+       man8/dnsblog.8 man8/tlsproxy.8
 COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
        man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.1 \
        man1/postmap.1 man1/postmulti.1 man1/postqueue.1 man1/postsuper.1 \
@@ -147,6 +147,11 @@ man8/smtpd.8: ../src/smtpd/smtpd.c
            (cmp -s junk $? || mv junk $?) && rm -f junk
        ../mantools/srctoman $? >$@
 
+man8/tlsproxy.8: ../src/tlsproxy/tlsproxy.c
+       ../mantools/fixman ../proto/postconf.proto $? >junk && \
+           (cmp -s junk $? || mv junk $?) && rm -f junk
+       ../mantools/srctoman $? >$@
+
 man8/virtual.8: ../src/virtual/virtual.c
        ../mantools/fixman ../proto/postconf.proto $? >junk && \
            (cmp -s junk $? || mv junk $?) && rm -f junk
index fc20df6dd2131bd2cdc74a173409eb4467933aa8..ac87b590f2af571a229d44a8f21721ea236d2c81 100644 (file)
@@ -274,7 +274,7 @@ master(8), Postfix master daemon
 oqmgr(8), old Postfix queue manager
 pickup(8), Postfix local mail pickup
 pipe(8), deliver mail to non-Postfix command
-postscreen(8), Postfix SMTP triage server
+postscreen(8), Postfix zombie blocker
 proxymap(8), Postfix lookup table proxy server
 qmgr(8), Postfix queue manager
 qmqpd(8), Postfix QMQP server
@@ -284,6 +284,7 @@ smtp(8), lmtp(8), Postfix SMTP+LMTP client
 smtpd(8), Postfix SMTP server
 spawn(8), run non-Postfix server
 tlsmgr(8), Postfix TLS cache and randomness manager
+tlsproxy(8), Postfix TLS proxy server
 trivial-rewrite(8), Postfix address rewriting
 verify(8), Postfix address verification
 virtual(8), Postfix virtual delivery agent
index 3e7023f9e2f22805987a6da0441e9f3fd5fc5ff8..66beefb092c9e98e116c8bfeb8d9c8c46305ac69 100644 (file)
@@ -3845,6 +3845,21 @@ Disable the SMTP VRFY command in the \fBpostscreen\fR(8) daemon.  See
 disable_vrfy_command for details.
 .PP
 This feature is available in Postfix 2.8.
+.SH postscreen_discard_ehlo_keyword_address_maps (default: $smtpd_discard_ehlo_keyword_address_maps)
+Lookup tables, indexed by the remote SMTP client address, with
+case insensitive lists of EHLO keywords (pipelining, starttls, auth,
+etc.) that the \fBpostscreen\fR(8) server will not send in the EHLO response
+to a remote SMTP client. See smtpd_discard_ehlo_keywords for details.
+The table is not searched by hostname for robustness reasons.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH postscreen_discard_ehlo_keywords (default: $smtpd_discard_ehlo_keywords)
+A case insensitive list of EHLO keywords (pipelining, starttls,
+auth, etc.) that the \fBpostscreen\fR(8) server will not send in the EHLO
+response to a remote SMTP client. See smtpd_discard_ehlo_keywords
+for details.
+.PP
+This feature is available in Postfix 2.8 and later.
 .SH postscreen_dnsbl_action (default: ignore)
 The action that \fBpostscreen\fR(8) takes when an SMTP client's combined
 DNSBL score is equal to or greater than a threshold (as defined
@@ -3972,6 +3987,13 @@ 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_enforce_tls (default: $smtpd_enforce_tls)
+Mandatory TLS: announce STARTTLS support to SMTP clients, and
+require that clients use TLS encryption.  See smtpd_postscreen_enforce_tls
+for details.
+.PP
+This feature is available in Postfix 2.8 and later.
+Preferably, use postscreen_tls_security_level instead.
 .SH postscreen_forbidden_commands (default: $smtpd_forbidden_commands)
 List of commands that the \fBpostscreen\fR(8) server considers in
 violation of the SMTP protocol. See smtpd_forbidden_commands for
@@ -4127,6 +4149,19 @@ process. When this queue is full, all non-whitelisted clients will
 receive a 421 reponse.
 .PP
 This feature is available in Postfix 2.8.
+.SH postscreen_tls_security_level (default: $smtpd_tls_security_level)
+The SMTP TLS security level for the \fBpostscreen\fR(8) server; when
+a non-empty value is specified, this overrides the obsolete parameters
+postscreen_use_tls and postscreen_enforce_tls. See smtpd_tls_security_level
+for details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH postscreen_use_tls (default: $smtpd_use_tls)
+Opportunistic TLS: announce STARTTLS support to SMTP clients,
+but do not require that clients use TLS encryption.
+.PP
+This feature is available in Postfix 2.8 and later.
+Preferably, use postscreen_tls_security_level instead.
 .SH postscreen_watchdog_timeout (default: 10s)
 How much time a \fBpostscreen\fR(8) process may take to respond to
 an SMTP client command or to perform a cache operation before it
@@ -8451,9 +8486,11 @@ delays all responses by $smtpd_error_sleep_time seconds.
 .IP \(bu
 With Postfix versions 2.0 and earlier, the Postfix SMTP
 server delays all responses by (number of errors) seconds.
-.SH smtpd_starttls_timeout (default: 300s)
+.SH smtpd_starttls_timeout (default: see "postconf -d" output)
 The time limit for Postfix SMTP server write and read operations
-during TLS startup and shutdown handshake procedures.
+during TLS startup and shutdown handshake procedures. The current
+default value is stress-dependent. Before Postfix version 2.8, it
+was fixed at 300s.
 .PP
 This feature is available in Postfix 2.2 and later.
 .SH smtpd_timeout (default: normal: 300s, overload: 10s)
@@ -9389,6 +9426,58 @@ bytes (equivalent to 256 bits) is sufficient to generate a 128bit
 (or 168bit) session key.
 .PP
 This feature is available in Postfix 2.2 and later.
+.SH tls_disable_workarounds (default: see "postconf -d" output)
+List or bit-mask of OpenSSL bug work-arounds to disable.
+.PP
+The OpenSSL toolkit includes a set of work-arounds for buggy SSL/TLS
+implementations. Applications, such as Postfix, that want to maximize
+interoperability ask the OpenSSL library to enable the full set of
+recommended work-arounds.
+.PP
+From time to time, it is discovered that a work-around creates a
+security issue, and should no longer be used. If upgrading OpenSSL
+to a fixed version is not an option or an upgrade is not available
+in a timely manner, or in closed environments where no buggy clients
+or servers exist, it may be appropriate to disable some or all of the
+OpenSSL interoperability work-arounds. This parameter specifies which
+bug work-arounds to disable.
+.PP
+If the value of the parameter is a hexadecimal long integer starting
+with "0x", the bug work-arounds corresponding to the bits specified in
+its value are removed from the \fBSSL_OP_ALL\fR work-around bit-mask
+(see openssl/ssl.h and SSL_CTX_\fBset_options\fR(3)). You can specify more
+bits than are present in SSL_OP_ALL, excess bits are ignored. Specifying
+0xFFFFFFFF disables all bug-workarounds on a 32-bit system. This should
+also be sufficient on 64-bit systems, until OpenSSL abandons support
+for 32-bit systems and starts using the high 32 bits of a 64-bit
+bug-workaround mask.
+.PP
+Otherwise, the parameter is a white-space or comma separated list
+of specific named bug work-arounds chosen from the list below. It
+is possible that your OpenSSL version includes new bug work-arounds
+added after your Postfix source code was last updated, in that case
+you can only disable one of these via the hexadecimal syntax above.
+.IP "\fBMICROSOFT_SESS_ID_BUG\fRSee SSL_CTX_\fBset_options\fR(3)"
+.IP "\fBNETSCAPE_CHALLENGE_BUG\fRSee SSL_CTX_\fBset_options\fR(3)"
+.IP "\fBLEGACY_SERVER_CONNECT\fRSee SSL_CTX_\fBset_options\fR(3)"
+.IP "\fBNETSCAPE_REUSE_CIPHER_CHANGE_BUG\fR also aliased as
+\fBCVE-2010-4180\fR. Postfix 2.8 disables this work-around by default
+with OpenSSL versions that may predate the fix. Fixed in OpenSSL 0.9.8q
+and OpenSSL 1.0.0c."
+.IP "\fBSSLREF2_REUSE_CERT_TYPE_BUG\fRSee SSL_CTX_\fBset_options\fR(3)"
+.IP "\fBMICROSOFT_BIG_SSLV3_BUFFER\fRSee SSL_CTX_\fBset_options\fR(3)"
+.IP "\fBMSIE_SSLV2_RSA_PADDING\fR also aliased as
+\fBCVE-2005-2969\fR. Postfix 2.8 disables this work-around by default
+with OpenSSL versions that may predate the fix. Fixed in OpenSSL 0.9.7h
+and OpenSSL 0.9.8a."
+.IP "\fBSSLEAY_080_CLIENT_DH_BUG\fRSee SSL_CTX_\fBset_options\fR(3)"
+.IP "\fBTLS_D5_BUG\fRSee SSL_CTX_\fBset_options\fR(3)"
+.IP "\fBTLS_BLOCK_PADDING_BUG\fRSee SSL_CTX_\fBset_options\fR(3)"
+.IP "\fBTLS_ROLLBACK_BUG\fRSee SSL_CTX_\fBset_options\fR(3). This is disabled
+in OpenSSL 0.9.7 and later. Nobody should still be using 0.9.6!"
+.IP "\fBDONT_INSERT_EMPTY_FRAGMENTS\fRSee SSL_CTX_\fBset_options\fR(3)"
+.IP "\fBCRYPTOPRO_TLSEXT_BUG\fRNew with GOST support in OpenSSL 1.0.0."
+This feature is available in Postfix 2.8 and later.
 .SH tls_eecdh_strong_curve (default: prime256v1)
 The elliptic curve used by the SMTP server for sensibly strong
 ephemeral ECDH key exchange. This curve is used by the Postfix SMTP
@@ -9484,6 +9573,25 @@ lmtp_tls_mandatory_ciphers.  You are strongly encouraged to not
 change this setting.
 .PP
 This feature is available in Postfix 2.3 and later.
+.SH tls_preempt_cipherlist (default: no)
+With SSLv3 and later, use the server's cipher preference order
+instead of the client's cipher preference order.
+.PP
+By default, the OpenSSL server selects the client's most preferred
+cipher that the server supports. With SSLv3 and later, the server may
+choose its own most preferred cipher that is supported (offered) by
+the client. Setting "tls_preempt_cipherlist = yes" enables server cipher
+preferences.
+.PP
+While server cipher selection may in some cases lead to a more secure
+or performant cipher choice, there is some risk of interoperability
+issues. In the past, some SSL clients have listed lower priority ciphers
+that they did not implement correctly. If the server chooses a cipher
+that the client prefers less, it may select a cipher whose client
+implementation is flawed.
+.PP
+This feature is available in Postfix 2.8 and later, in combination
+with OpenSSL 0.9.7 and later.
 .SH tls_random_bytes (default: 32)
 The number of bytes that \fBtlsmgr\fR(8) reads from $tls_random_source
 when (re)seeding the in-memory pseudo random number generator (PRNG)
@@ -9530,6 +9638,187 @@ Note: on OpenBSD systems specify /dev/arandom when /dev/urandom
 gives timeout errors.
 .PP
 This feature is available in Postfix 2.2 and later.
+.SH tlsproxy_enforce_tls (default: $smtpd_enforce_tls)
+Mandatory TLS: announce STARTTLS support to SMTP clients, and
+require that clients use TLS encryption. See smtpd_enforce_tls for
+further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_CAfile (default: $smtpd_tls_CAfile)
+A file containing (PEM format) CA certificates of root CAs
+trusted to sign either remote SMTP client certificates or intermediate
+CA certificates.  See smtpd_tls_CAfile for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_CApath (default: $smtpd_tls_CApath)
+A directory containing (PEM format) CA certificates of root CAs
+trusted to sign either remote SMTP client certificates or intermediate
+CA certificates. See smtpd_tls_CApath for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_always_issue_session_ids (default: $smtpd_tls_always_issue_session_ids)
+Force the Postfix \fBtlsproxy\fR(8) server to issue a TLS session id,
+even when TLS session caching is turned off. See
+smtpd_tls_always_issue_session_ids for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_ask_ccert (default: $smtpd_tls_ask_ccert)
+Ask a remote SMTP client for a client certificate. See
+smtpd_tls_ask_ccert for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_ccert_verifydepth (default: $smtpd_tls_ccert_verifydepth)
+The verification depth for remote SMTP client certificates. A
+depth of 1 is sufficient if the issuing CA is listed in a local CA
+file. See smtpd_tls_ccert_verifydepth for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_cert_file (default: $smtpd_tls_cert_file)
+File with the Postfix \fBtlsproxy\fR(8) server RSA certificate in PEM
+format.  This file may also contain the Postfix \fBtlsproxy\fR(8) server
+private RSA key.  See smtpd_tls_cert_file for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_ciphers (default: $smtpd_tls_ciphers)
+The minimum TLS cipher grade that the Postfix \fBtlsproxy\fR(8) server
+will use with opportunistic TLS encryption. See smtpd_tls_ciphers
+for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_dcert_file (default: $smtpd_tls_dcert_file)
+File with the Postfix \fBtlsproxy\fR(8) server DSA certificate in PEM
+format.  This file may also contain the Postfix \fBtlsproxy\fR(8) server
+private DSA key.  See smtpd_tls_dcert_file for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_dh1024_param_file (default: $smtpd_tls_dh1024_param_file)
+File with DH parameters that the Postfix \fBtlsproxy\fR(8) server
+should use with EDH ciphers. See smtpd_tls_dh1024_param_file for
+further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_dh512_param_file (default: $smtpd_tls_dh512_param_file)
+File with DH parameters that the Postfix \fBtlsproxy\fR(8) server
+should use with EDH ciphers. See smtpd_tls_dh512_param_file for
+further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_dkey_file (default: $smtpd_tls_dkey_file)
+File with the Postfix \fBtlsproxy\fR(8) server DSA private key in PEM
+format.  This file may be combined with the Postfix \fBtlsproxy\fR(8)
+server DSA certificate file specified with $smtpd_tls_dcert_file.
+See smtpd_tls_dkey_file for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_eccert_file (default: $smtpd_tls_eccert_file)
+File with the Postfix \fBtlsproxy\fR(8) server ECDSA certificate in
+PEM format.  This file may also contain the Postfix \fBtlsproxy\fR(8)
+server private ECDSA key.  See smtpd_tls_eccert_file for further
+details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_eckey_file (default: $smtpd_tls_eckey_file)
+File with the Postfix \fBtlsproxy\fR(8) server ECDSA private key in
+PEM format.  This file may be combined with the Postfix \fBtlsproxy\fR(8)
+server ECDSA certificate file specified with $smtpd_tls_eccert_file.
+See smtpd_tls_eckey_file for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_eecdh_grade (default: $smtpd_tls_eecdh_grade)
+The Postfix \fBtlsproxy\fR(8) server security grade for ephemeral
+elliptic-curve Diffie-Hellman (EECDH) key exchange. See
+smtpd_tls_eecdh_grade for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_exclude_ciphers (default: $smtpd_tls_exclude_ciphers)
+List of ciphers or cipher types to exclude from the \fBtlsproxy\fR(8)
+server cipher list at all TLS security levels. See
+smtpd_tls_exclude_ciphers for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_fingerprint_digest (default: $smtpd_tls_fingerprint_digest)
+The message digest algorithm used to construct client-certificate
+fingerprints. See smtpd_tls_fingerprint_digest for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_key_file (default: $smtpd_tls_key_file)
+File with the Postfix \fBtlsproxy\fR(8) server RSA private key in PEM
+format.  This file may be combined with the Postfix \fBtlsproxy\fR(8)
+server RSA certificate file specified with $smtpd_tls_cert_file.
+See smtpd_tls_key_file for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_loglevel (default: $smtpd_tls_loglevel)
+Enable additional Postfix \fBtlsproxy\fR(8) server logging of TLS
+activity.  Each logging level also includes the information that
+is logged at a lower logging level. See smtpd_tls_loglevel for
+further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_mandatory_ciphers (default: $smtpd_tls_mandatory_ciphers)
+The minimum TLS cipher grade that the Postfix \fBtlsproxy\fR(8) server
+will use with mandatory TLS encryption. See smtpd_tls_mandatory_ciphers
+for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_mandatory_exclude_ciphers (default: $smtpd_tls_mandatory_exclude_ciphers)
+Additional list of ciphers or cipher types to exclude from the
+\fBtlsproxy\fR(8) server cipher list at mandatory TLS security levels.
+See smtpd_tls_mandatory_exclude_ciphers for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_mandatory_protocols (default: $smtpd_tls_mandatory_protocols)
+The SSL/TLS protocols accepted by the Postfix \fBtlsproxy\fR(8) server
+with mandatory TLS encryption. If the list is empty, the server
+supports all available SSL/TLS protocol versions.  See
+smtpd_tls_mandatory_protocols for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_protocols (default: $smtpd_tls_protocols)
+List of TLS protocols that the Postfix \fBtlsproxy\fR(8) server will
+exclude or include with opportunistic TLS encryption. See
+smtpd_tls_protocols for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_req_ccert (default: $smtpd_tls_req_ccert)
+With mandatory TLS encryption, require a trusted remote SMTP
+client certificate in order to allow TLS connections to proceed.
+See smtpd_tls_req_ccert for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_security_level (default: $smtpd_tls_security_level)
+The SMTP TLS security level for the Postfix \fBtlsproxy\fR(8) server;
+when a non-empty value is specified, this overrides the obsolete
+parameters smtpd_use_tls and smtpd_enforce_tls. See
+smtpd_tls_security_level for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_tls_session_cache_timeout (default: $smtpd_tls_session_cache_timeout)
+The expiration time of Postfix \fBtlsproxy\fR(8) server TLS session
+cache information. A cache cleanup is performed periodically every
+$smtpd_tls_session_cache_timeout seconds. See
+smtpd_tls_session_cache_timeout for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_use_tls (default: $smtpd_use_tls)
+Opportunistic TLS: announce STARTTLS support to SMTP clients,
+but do not require that clients use TLS encryption. See smtpd_use_tls
+for further details.
+.PP
+This feature is available in Postfix 2.8 and later.
+.SH tlsproxy_watchdog_timeout (default: 10s)
+How much time a \fBtlsproxy\fR(8) process may take to process local
+or remote I/O before it is terminated by a built-in watchdog timer.
+This is a safety mechanism that prevents \fBtlsproxy\fR(8) from becoming
+non-responsive due to a bug in Postfix itself or in system software.
+To avoid false alarms and unnecessary cache corruption this limit
+cannot be set under 10s.
+.PP
+Specify a non-zero time value (an integral value plus an optional
+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 trace_service_name (default: trace)
 The name of the trace service. This service is implemented by the
 \fBbounce\fR(8) daemon and maintains a record
index 7ff72096d4c7ec3885672149fe85b7be487be5a0..f8acab13562ccd73a68e2b2654acf0b20d6444c9 100644 (file)
@@ -4,7 +4,7 @@
 .SH NAME
 postscreen
 \-
-Postfix SMTP triage server
+Postfix zombie blocker
 .SH "SYNOPSIS"
 .na
 .nf
@@ -51,8 +51,19 @@ can be run chrooted at fixed low privilege.
 .SH "STANDARDS"
 .na
 .nf
-RFC 5321 (SMTP, including multi-line 220 greetings)
+RFC 821 (SMTP protocol)
+RFC 1123 (Host requirements)
+RFC 1652 (8bit-MIME transport)
+RFC 1869 (SMTP service extensions)
+RFC 1870 (Message Size Declaration)
+RFC 1985 (ETRN command)
+RFC 2034 (SMTP Enhanced Error Codes)
+RFC 2821 (SMTP protocol)
 RFC 2920 (SMTP Pipelining)
+RFC 3207 (STARTTLS command)
+RFC 3461 (SMTP DSN Extension)
+RFC 3463 (Enhanced Status Codes)
+RFC 5321 (SMTP protocol, including multi-line 220 greetings)
 .SH DIAGNOSTICS
 .ad
 .fi
@@ -61,9 +72,9 @@ Problems and transactions are logged to \fBsyslogd\fR(8).
 .ad
 .fi
 The \fBpostscreen\fR(8) built-in SMTP protocol engine
-currently does not announce support for STARTTLS, AUTH,
-XCLIENT or XFORWARD.
-Support for STARTTLS and AUTH may be added in the future.
+currently does not announce support for AUTH, XCLIENT or
+XFORWARD.
+Support for AUTH may be added in the future.
 In the mean time, if you need to make these services available
 on port 25, then do not enable the optional "after 220
 server greeting" tests.
@@ -93,11 +104,27 @@ change.
 The text below provides only a parameter summary. See
 \fBpostconf\fR(5) for more details including examples.
 
-NOTE: Some \fBpostscreen\fR(8)  parameters implement
+NOTE: Some \fBpostscreen\fR(8) parameters implement
 stress-dependent behavior.  This is supported only when the
-default value is stress-dependent (that is, it looks like
-${stress?X}${stress:Y}).  Other parameters always evaluate
-as if the stress value is the empty string.
+default parameter value is stress-dependent (that is, it
+looks like ${stress?X}${stress:Y}, or it is the $\fIname\fR
+of an smtpd parameter with a stress-dependent default).
+Other parameters always evaluate as if the \fBstress\fR
+parameter value is the empty string.
+.SH "COMPATIBILITY CONTROLS"
+.na
+.nf
+.ad
+.fi
+.IP "\fBpostscreen_discard_ehlo_keyword_address_maps ($smtpd_discard_ehlo_keyword_address_maps)\fR"
+Lookup tables, indexed by the remote SMTP client address, with
+case insensitive lists of EHLO keywords (pipelining, starttls, auth,
+etc.) that the \fBpostscreen\fR(8) server will not send in the EHLO response
+to a remote SMTP client.
+.IP "\fBpostscreen_discard_ehlo_keywords ($smtpd_discard_ehlo_keywords)\fR"
+A case insensitive list of EHLO keywords (pipelining, starttls,
+auth, etc.) that the \fBpostscreen\fR(8) server will not send in the EHLO
+response to a remote SMTP client.
 .SH "TRIAGE PARAMETERS"
 .na
 .nf
@@ -230,6 +257,28 @@ process.
 How much time a \fBpostscreen\fR(8) process may take to respond to
 an SMTP client command or to perform a cache operation before it
 is terminated by a built-in watchdog timer.
+.SH "STARTTLS CONTROLS"
+.na
+.nf
+.ad
+.fi
+.IP "\fBpostscreen_tls_security_level ($smtpd_tls_security_level)\fR"
+The SMTP TLS security level for the \fBpostscreen\fR(8) server; when
+a non-empty value is specified, this overrides the obsolete parameters
+postscreen_use_tls and postscreen_enforce_tls.
+.SH "OBSOLETE STARTTLS SUPPORT CONTROLS"
+.na
+.nf
+.ad
+.fi
+These parameters are supported for compatibility with
+\fBsmtpd\fR(8) legacy parameters.
+.IP "\fBpostscreen_use_tls ($smtpd_use_tls)\fR"
+Opportunistic TLS: announce STARTTLS support to SMTP clients,
+but do not require that clients use TLS encryption.
+.IP "\fBpostscreen_enforce_tls ($smtpd_enforce_tls)\fR"
+Mandatory TLS: announce STARTTLS support to SMTP clients, and
+require that clients use TLS encryption.
 .SH "MISCELLANEOUS CONTROLS"
 .na
 .nf
@@ -262,6 +311,7 @@ records, so that "smtpd" becomes, for example, "postfix/smtpd".
 .na
 .nf
 smtpd(8), Postfix SMTP server
+tlsproxy(8), Postfix TLS proxy server
 dnsblog(8), temporary DNS helper
 syslogd(8), system logging
 .SH "README FILES"
index 79c14c9b2f616331b2642d1201f6c380b83406d9..524edb3d56a71985fe9db616db0128a5506de1fd 100644 (file)
@@ -443,6 +443,10 @@ Available in Postfix version 2.7 and later:
 Try to detect a mail hijacking attack based on a TLS protocol
 vulnerability (CVE-2009-3555), where an attacker prepends malicious
 HELO, MAIL, RCPT, DATA commands to a Postfix SMTP client TLS session.
+.PP
+Available in Postfix version 2.8 and later:
+.IP "\fBtls_disable_workarounds (see 'postconf -d' output)\fR"
+List or bit-mask of OpenSSL bug work-arounds to disable.
 .SH "OBSOLETE STARTTLS CONTROLS"
 .na
 .nf
index 378605914318d8c0e9ef531892440dce3fc6942e..1dd8cc5ae1553b55286642413e470c8d95c08403 100644 (file)
@@ -451,6 +451,13 @@ ephemeral ECDH key exchange.
 .IP "\fBtls_eecdh_ultra_curve (secp384r1)\fR"
 The elliptic curve used by the SMTP server for maximally strong
 ephemeral ECDH key exchange.
+.PP
+Available in Postfix version 2.8 and later:
+.IP "\fBtls_preempt_cipherlist (no)\fR"
+With SSLv3 and later, use the server's cipher preference order
+instead of the client's cipher preference order.
+.IP "\fBtls_disable_workarounds (see 'postconf -d' output)\fR"
+List or bit-mask of OpenSSL bug work-arounds to disable.
 .SH "OBSOLETE STARTTLS CONTROLS"
 .na
 .nf
diff --git a/postfix/man/man8/tlsproxy.8 b/postfix/man/man8/tlsproxy.8
new file mode 100644 (file)
index 0000000..aaf6576
--- /dev/null
@@ -0,0 +1,215 @@
+.TH TLSPROXY 8 
+.ad
+.fi
+.SH NAME
+tlsproxy
+\-
+Postfix TLS proxy
+.SH "SYNOPSIS"
+.na
+.nf
+\fBtlsproxy\fR [generic Postfix daemon options]
+.SH DESCRIPTION
+.ad
+.fi
+The \fBtlsproxy\fR(8) server implements a server-side TLS
+proxy. Its primary use is to talk plaintext SMTP with
+\fBpostscreen\fR(8), and to talk SMTP-over-TLS with remote
+SMTP clients whose whitelist status has expired, but it
+should also work for non-SMTP protocols.
+
+Although one \fBtlsproxy\fR(8) process can serve multiple
+sessions at the same time, it is a good idea to allow the
+number of processes to increase with load, so that the
+service remains available.
+.SH "PROTOCOL EXAMPLE"
+.na
+.nf
+.ad
+.fi
+The example below involves \fBpostscreen\fR(8). However,
+the \fBtlsproxy\fR(8) server is agnostic of the application
+protocol, and the example is easily adapted to other
+applications.
+
+The \fBpostscreen\fR(8) server sends the remote SMTP client
+endpoint string, the requested role (server), and the
+requested timeout to \fBtlsproxy\fR(8).  \fBpostscreen\fR(8)
+then receives a "TLS available" indication from \fBtlsproxy\fR(8).
+If the TLS service is available, \fBpostscreen\fR(8) sends
+the remote SMTP client file descriptor to \fBtlsproxy\fR(8),
+and sends the plaintext 220 greeting to the remote SMTP
+client.  This triggers TLS negotiations between the remote
+SMTP client and \fBtlsproxy\fR(8).  Upon completion of the
+TLS-level handshake, \fBtlsproxy\fR(8) translates between
+plaintext from/to \fBpostscreen\fR(8) and ciphertext to/from
+the remote SMTP client.
+.SH "SECURITY"
+.na
+.nf
+.ad
+.fi
+The \fBtlsproxy\fR(8) server is moderately security-sensitive.
+It talks to untrusted clients on the network. The process
+can be run chrooted at fixed low privilege.
+.SH DIAGNOSTICS
+.ad
+.fi
+Problems and transactions are logged to \fBsyslogd\fR(8).
+.SH "CONFIGURATION PARAMETERS"
+.na
+.nf
+.ad
+.fi
+Changes to \fBmain.cf\fR are not picked up automatically,
+as \fBtlsproxy\fR(8) processes may run for a long time
+depending on mail server load.  Use the command "\fBpostfix
+reload\fR" to speed up a change.
+
+The text below provides only a parameter summary. See
+\fBpostconf\fR(5) for more details including examples.
+.SH "STARTTLS SUPPORT CONTROLS"
+.na
+.nf
+.ad
+.fi
+.IP "\fBtlsproxy_tls_CAfile ($smtpd_tls_CAfile)\fR"
+A file containing (PEM format) CA certificates of root CAs
+trusted to sign either remote SMTP client certificates or intermediate
+CA certificates.
+.IP "\fBtlsproxy_tls_CApath ($smtpd_tls_CApath)\fR"
+A directory containing (PEM format) CA certificates of root CAs
+trusted to sign either remote SMTP client certificates or intermediate
+CA certificates.
+.IP "\fBtlsproxy_tls_always_issue_session_ids ($smtpd_tls_always_issue_session_ids)\fR"
+Force the Postfix \fBtlsproxy\fR(8) server to issue a TLS session id,
+even when TLS session caching is turned off.
+.IP "\fBtlsproxy_tls_ask_ccert ($smtpd_tls_ask_ccert)\fR"
+Ask a remote SMTP client for a client certificate.
+.IP "\fBtlsproxy_tls_ccert_verifydepth ($smtpd_tls_ccert_verifydepth)\fR"
+The verification depth for remote SMTP client certificates.
+.IP "\fBtlsproxy_tls_cert_file ($smtpd_tls_cert_file)\fR"
+File with the Postfix \fBtlsproxy\fR(8) server RSA certificate in PEM
+format.
+.IP "\fBtlsproxy_tls_ciphers ($smtpd_tls_ciphers)\fR"
+The minimum TLS cipher grade that the Postfix \fBtlsproxy\fR(8) server
+will use with opportunistic TLS encryption.
+.IP "\fBtlsproxy_tls_dcert_file ($smtpd_tls_dcert_file)\fR"
+File with the Postfix \fBtlsproxy\fR(8) server DSA certificate in PEM
+format.
+.IP "\fBtlsproxy_tls_dh1024_param_file ($smtpd_tls_dh1024_param_file)\fR"
+File with DH parameters that the Postfix \fBtlsproxy\fR(8) server
+should use with EDH ciphers.
+.IP "\fBtlsproxy_tls_dh512_param_file ($smtpd_tls_dh512_param_file)\fR"
+File with DH parameters that the Postfix \fBtlsproxy\fR(8) server
+should use with EDH ciphers.
+.IP "\fBtlsproxy_tls_dkey_file ($smtpd_tls_dkey_file)\fR"
+File with the Postfix \fBtlsproxy\fR(8) server DSA private key in PEM
+format.
+.IP "\fBtlsproxy_tls_eccert_file ($smtpd_tls_eccert_file)\fR"
+File with the Postfix \fBtlsproxy\fR(8) server ECDSA certificate in
+PEM format.
+.IP "\fBtlsproxy_tls_eckey_file ($smtpd_tls_eckey_file)\fR"
+File with the Postfix \fBtlsproxy\fR(8) server ECDSA private key in
+PEM format.
+.IP "\fBtlsproxy_tls_eecdh_grade ($smtpd_tls_eecdh_grade)\fR"
+The Postfix \fBtlsproxy\fR(8) server security grade for ephemeral
+elliptic-curve Diffie-Hellman (EECDH) key exchange.
+.IP "\fBtlsproxy_tls_exclude_ciphers ($smtpd_tls_exclude_ciphers)\fR"
+List of ciphers or cipher types to exclude from the \fBtlsproxy\fR(8)
+server cipher list at all TLS security levels.
+.IP "\fBtlsproxy_tls_fingerprint_digest ($smtpd_tls_fingerprint_digest)\fR"
+The message digest algorithm used to construct client-certificate
+fingerprints.
+.IP "\fBtlsproxy_tls_key_file ($smtpd_tls_key_file)\fR"
+File with the Postfix \fBtlsproxy\fR(8) server RSA private key in PEM
+format.
+.IP "\fBtlsproxy_tls_loglevel ($smtpd_tls_loglevel)\fR"
+Enable additional Postfix \fBtlsproxy\fR(8) server logging of TLS
+activity.
+.IP "\fBtlsproxy_tls_mandatory_ciphers ($smtpd_tls_mandatory_ciphers)\fR"
+The minimum TLS cipher grade that the Postfix \fBtlsproxy\fR(8) server
+will use with mandatory TLS encryption.
+.IP "\fBtlsproxy_tls_mandatory_exclude_ciphers ($smtpd_tls_mandatory_exclude_ciphers)\fR"
+Additional list of ciphers or cipher types to exclude from the
+\fBtlsproxy\fR(8) server cipher list at mandatory TLS security levels.
+.IP "\fBtlsproxy_tls_mandatory_protocols ($smtpd_tls_mandatory_protocols)\fR"
+The SSL/TLS protocols accepted by the Postfix \fBtlsproxy\fR(8) server
+with mandatory TLS encryption.
+.IP "\fBtlsproxy_tls_protocols ($smtpd_tls_protocols)\fR"
+List of TLS protocols that the Postfix \fBtlsproxy\fR(8) server will
+exclude or include with opportunistic TLS encryption.
+.IP "\fBtlsproxy_tls_req_ccert ($smtpd_tls_req_ccert)\fR"
+With mandatory TLS encryption, require a trusted remote SMTP
+client certificate in order to allow TLS connections to proceed.
+.IP "\fBtlsproxy_tls_security_level ($smtpd_tls_security_level)\fR"
+The SMTP TLS security level for the Postfix \fBtlsproxy\fR(8) server;
+when a non-empty value is specified, this overrides the obsolete
+parameters smtpd_use_tls and smtpd_enforce_tls.
+.IP "\fBtlsproxy_tls_session_cache_timeout ($smtpd_tls_session_cache_timeout)\fR"
+The expiration time of Postfix \fBtlsproxy\fR(8) server TLS session
+cache information.
+.SH "OBSOLETE STARTTLS SUPPORT CONTROLS"
+.na
+.nf
+.ad
+.fi
+These parameters are supported for compatibility with
+\fBsmtpd\fR(8) legacy parameters.
+.IP "\fBtlsproxy_use_tls ($smtpd_use_tls)\fR"
+Opportunistic TLS: announce STARTTLS support to SMTP clients,
+but do not require that clients use TLS encryption.
+.IP "\fBtlsproxy_enforce_tls ($smtpd_enforce_tls)\fR"
+Mandatory TLS: announce STARTTLS support to SMTP clients, and
+require that clients use TLS encryption.
+.SH "RESOURCE CONTROLS"
+.na
+.nf
+.ad
+.fi
+.IP "\fBtlsproxy_watchdog_timeout (10s)\fR"
+How much time a \fBtlsproxy\fR(8) process may take to process local
+or remote I/O before it is terminated by a built-in watchdog timer.
+.SH "MISCELLANEOUS CONTROLS"
+.na
+.nf
+.ad
+.fi
+.IP "\fBconfig_directory (see 'postconf -d' output)\fR"
+The default location of the Postfix main.cf and master.cf
+configuration files.
+.IP "\fBprocess_id (read-only)\fR"
+The process ID of a Postfix command or daemon process.
+.IP "\fBprocess_name (read-only)\fR"
+The process name of a Postfix command or daemon process.
+.IP "\fBsyslog_facility (mail)\fR"
+The syslog facility of Postfix logging.
+.IP "\fBsyslog_name (see 'postconf -d' output)\fR"
+The mail system name that is prepended to the process name in syslog
+records, so that "smtpd" becomes, for example, "postfix/smtpd".
+.SH "SEE ALSO"
+.na
+.nf
+postscreen(8), Postfix zombie blocker
+smtpd(8), Postfix SMTP server
+postconf(5), configuration parameters
+syslogd(5), system logging
+.SH "LICENSE"
+.na
+.nf
+.ad
+.fi
+The Secure Mailer license must be distributed with this software.
+.SH "HISTORY"
+.na
+.nf
+.ad
+.fi
+This service was introduced with Postfix version 2.8.
+.SH "AUTHOR(S)"
+.na
+.nf
+Wietse Venema
+IBM T.J. Watson Research
+P.O. Box 704
+Yorktown Heights, NY 10598, USA
index a20e3c2079e89d8f3e23604e02a7b06faf9bd6d5..937495de4b001bc620bac613690e981c1f54710b 100755 (executable)
@@ -497,8 +497,8 @@ while (<>) {
     s;\bsmtpd_data_restrictions\b;<a href="postconf.5.html#smtpd_data_restrictions">$&</a>;g;
     s;\bsmtpd_delay_open_until_valid_rcpt\b;<a href="postconf.5.html#smtpd_delay_open_until_valid_rcpt">$&</a>;g;
     s;\bsmtpd_delay_reject\b;<a href="postconf.5.html#smtpd_delay_reject">$&</a>;g;
-    s;\bsmtpd_discard_ehlo_keyword_address_maps\b;<a href="postconf.5.html#smtpd_discard_ehlo_keyword_address_maps">$&</a>;g;
-    s;\bsmtpd_discard_ehlo_keywords\b;<a href="postconf.5.html#smtpd_discard_ehlo_keywords">$&</a>;g;
+    s;\bsmtpd_dis[-</bB>]*\n* *[<bB>]*card_ehlo_key[-</bB>]*\n* *[<bB>]*word_address_maps\b;<a href="postconf.5.html#smtpd_discard_ehlo_keyword_address_maps">$&</a>;g;
+    s;\bsmtpd_dis[-</bB>]*\n* *[<bB>]*card_ehlo_key[-</bB>]*\n* *[<bB>]*words\b;<a href="postconf.5.html#smtpd_discard_ehlo_keywords">$&</a>;g;
     s;\bsmtpd_end_of_data_restrictions\b;<a href="postconf.5.html#smtpd_end_of_data_restrictions">$&</a>;g;
     s;\bsmtpd_error_sleep_time\b;<a href="postconf.5.html#smtpd_error_sleep_time">$&</a>;g;
     s;\bsmtpd_etrn_restrictions\b;<a href="postconf.5.html#smtpd_etrn_restrictions">$&</a>;g;
@@ -639,15 +639,15 @@ while (<>) {
     s;\bsmtpd_tls_CApath\b;<a href="postconf.5.html#smtpd_tls_CApath">$&</a>;g;
     s;\bsmtpd_tls_ask_ccert\b;<a href="postconf.5.html#smtpd_tls_ask_ccert">$&</a>;g;
     s;\bsmtpd_tls_auth_only\b;<a href="postconf.5.html#smtpd_tls_auth_only">$&</a>;g;
-    s;\bsmtpd_tls_ccert_verifydepth\b;<a href="postconf.5.html#smtpd_tls_ccert_verifydepth">$&</a>;g;
+    s;\bsmtpd_tls_ccert_verify[-</bB>]*\n*[ <bB>]*depth\b;<a href="postconf.5.html#smtpd_tls_ccert_verifydepth">$&</a>;g;
     s;\bsmtpd_tls_cert_file\b;<a href="postconf.5.html#smtpd_tls_cert_file">$&</a>;g;
     s;\bsmtpd_tls_cipherlist\b;<a href="postconf.5.html#smtpd_tls_cipherlist">$&</a>;g;
     s;\bsmtpd_tls_exclude_ciphers\b;<a href="postconf.5.html#smtpd_tls_exclude_ciphers">$&</a>;g;
-    s;\bsmtpd_tls_fingerprint_digest\b;<a href="postconf.5.html#smtpd_tls_fingerprint_digest">$&</a>;g;
+    s;\bsmtpd_tls_finger[-</bB>]*\n*[ <bB>]*print_digest\b;<a href="postconf.5.html#smtpd_tls_fingerprint_digest">$&</a>;g;
     s;\bsmtpd_tls_protocols\b;<a href="postconf.5.html#smtpd_tls_protocols">$&</a>;g;
     s;\bsmtpd_tls_ciphers\b;<a href="postconf.5.html#smtpd_tls_ciphers">$&</a>;g;
-    s;\bsmtpd_tls_mandatory_ciphers\b;<a href="postconf.5.html#smtpd_tls_mandatory_ciphers">$&</a>;g;
-    s;\bsmtpd_tls_mandatory_exclude_ciphers\b;<a href="postconf.5.html#smtpd_tls_mandatory_exclude_ciphers">$&</a>;g;
+    s;\bsmtpd_tls_manda[-</bB>]*\n*[ <bB>]*tory_ciphers\b;<a href="postconf.5.html#smtpd_tls_mandatory_ciphers">$&</a>;g;
+    s;\bsmtpd_tls_manda[-</bB>]*\n*[ <bB>]*tory_exclude_ciphers\b;<a href="postconf.5.html#smtpd_tls_mandatory_exclude_ciphers">$&</a>;g;
     s;\bsmtpd_tls_dcert_file\b;<a href="postconf.5.html#smtpd_tls_dcert_file">$&</a>;g;
     s;\bsmtpd_tls_eccert_file\b;<a href="postconf.5.html#smtpd_tls_eccert_file">$&</a>;g;
     s;\bsmtpd_tls_eckey_file\b;<a href="postconf.5.html#smtpd_tls_eckey_file">$&</a>;g;
@@ -658,11 +658,11 @@ while (<>) {
     s;\bsmtpd_tls_key_file\b;<a href="postconf.5.html#smtpd_tls_key_file">$&</a>;g;
     s;\bsmtpd_tls_security_level\b;<a href="postconf.5.html#smtpd_tls_security_level">$&</a>;g;
     s;\bsmtpd_tls_loglevel\b;<a href="postconf.5.html#smtpd_tls_loglevel">$&</a>;g;
-    s;\bsmtpd_tls_mandatory_protocols\b;<a href="postconf.5.html#smtpd_tls_mandatory_protocols">$&</a>;g;
+    s;\bsmtpd_tls_manda[-</bB>]*\n*[ <bB>]*tory_protocols\b;<a href="postconf.5.html#smtpd_tls_mandatory_protocols">$&</a>;g;
     s;\bsmtpd_tls_received_header\b;<a href="postconf.5.html#smtpd_tls_received_header">$&</a>;g;
     s;\bsmtpd_tls_req_ccert\b;<a href="postconf.5.html#smtpd_tls_req_ccert">$&</a>;g;
-    s;\bsmtpd_tls_session_cache_database\b;<a href="postconf.5.html#smtpd_tls_session_cache_database">$&</a>;g;
-    s;\bsmtpd_tls_session_cache_timeout\b;<a href="postconf.5.html#smtpd_tls_session_cache_timeout">$&</a>;g;
+    s;\bsmtpd_tls_ses[-</bB>]*\n*[ <bB>]*sion_cache_database\b;<a href="postconf.5.html#smtpd_tls_session_cache_database">$&</a>;g;
+    s;\bsmtpd_tls_ses[-</bB>]*\n*[ <bB>]*sion_cache_timeout\b;<a href="postconf.5.html#smtpd_tls_session_cache_timeout">$&</a>;g;
     s;\bsmtpd_tls_always_issue_session_ids\b;<a href="postconf.5.html#smtpd_tls_always_issue_session_ids">$&</a>;g;
     s;\bsmtpd_tls_wrappermode\b;<a href="postconf.5.html#smtpd_tls_wrappermode">$&</a>;g;
     s;\bsmtpd_use_tls\b;<a href="postconf.5.html#smtpd_use_tls">$&</a>;g;
@@ -680,6 +680,8 @@ while (<>) {
     s;\btls_null_cipherlist\b;<a href="postconf.5.html#tls_null_cipherlist">$&</a>;g;
     s;\btls_eecdh_strong_curve\b;<a href="postconf.5.html#tls_eecdh_strong_curve">$&</a>;g;
     s;\btls_eecdh_ultra_curve\b;<a href="postconf.5.html#tls_eecdh_ultra_curve">$&</a>;g;
+    s;\btls_preempt_cipherlist\b;<a href="postconf.5.html#tls_preempts_cipherlist">$&</a>;g;
+    s;\btls_disable_workarounds\b;<a href="postconf.5.html#tls_disable_workarounds">$&</a>;g;
     s;\btls_append_default_CA\b;<a href="postconf.5.html#tls_append_default_CA">$&</a>;g;
  
     s;\bfrozen_delivered_to\b;<a href="postconf.5.html#frozen_delivered_to">$&</a>;g;
@@ -735,6 +737,7 @@ while (<>) {
     s/[<bB>]*smtp[<\/bB>]*\(8\)/<a href="smtp.8.html">$&<\/a>/g;
     s/[<bB>]*smtpd[<\/bB>]*\(8\)/<a href="smtpd.8.html">$&<\/a>/g;
     s/[<bB>]*spawn[<\/bB>]*\(8\)/<a href="spawn.8.html">$&<\/a>/g;
+    s/[<bB>]*tlsproxy[<\/bB>]*\(8\)/<a href="tlsproxy.8.html">$&<\/a>/g;
     s/[<bB>]*tlsmgr[<\/bB>]*\(8\)/<a href="tlsmgr.8.html">$&<\/a>/g;
     s/[<bB>]*trace[<\/bB>]*\(8\)/<a href="trace.8.html">$&<\/a>/g;
     s/[<bB>]*trivial- *<br> *rewrite[<\/bB>]*\(8\)/<a href="trivial-rewrite.8.html">$&<\/a>/g;
@@ -945,6 +948,40 @@ while (<>) {
     s;\bpostscreen_black[-</bB>]*\n*[ <bB>]*list_networks\b;<a href="postconf.5.html#postscreen_blacklist_networks">$&</a>;g;
     s;\bpostscreen_black[-</bB>]*\n*[ <bB>]*list_action\b;<a href="postconf.5.html#postscreen_blacklist_action">$&</a>;g;
     s;\bpostscreen_client_connection_count_limit\b;<a href="postconf.5.html#postscreen_client_connection_count_limit">$&</a>;g;
+    s;\bpostscreen_tls_security_level\b;<a href="postconf.5.html#postscreen_tls_security_level">$&</a>;g;
+    s;\bpostscreen_enforce_tls\b;<a href="postconf.5.html#postscreen_enforce_tls">$&</a>;g;
+    s;\bpostscreen_use_tls\b;<a href="postconf.5.html#postscreen_use_tls">$&</a>;g;
+    s;\bpostscreen_discard_ehlo_keyword_address_maps\b;<a href="postconf.5.html#postscreen_discard_ehlo_keyword_address_maps">$&</a>;g;
+    s;\bpostscreen_discard_ehlo_keywords\b;<a href="postconf.5.html#postscreen_discard_ehlo_keywords">$&</a>;g;
+
+    s;\btlsproxy_watchdog_timeout\b;<a href="postconf.5.html#tlsproxy_watchdog_timeout">$&</a>;g;
+    s;\btlsproxy_enforce_tls\b;<a href="postconf.5.html#tlsproxy_enforce_tls">$&</a>;g;
+    s;\btlsproxy_tls_CAfile\b;<a href="postconf.5.html#tlsproxy_tls_CAfile">$&</a>;g;
+    s;\btlsproxy_tls_CApath\b;<a href="postconf.5.html#tlsproxy_tls_CApath">$&</a>;g;
+    s;\btlsproxy_tls_always_issue_session_ids\b;<a href="postconf.5.html#tlsproxy_tls_always_issue_session_ids">$&</a>;g;
+    s;\btlsproxy_tls_ask_ccert\b;<a href="postconf.5.html#tlsproxy_tls_ask_ccert">$&</a>;g;
+    s;\btlsproxy_tls_ccert_verifydepth\b;<a href="postconf.5.html#tlsproxy_tls_ccert_verifydepth">$&</a>;g;
+    s;\btlsproxy_tls_cert_file\b;<a href="postconf.5.html#tlsproxy_tls_cert_file">$&</a>;g;
+    s;\btlsproxy_tls_ciphers\b;<a href="postconf.5.html#tlsproxy_tls_ciphers">$&</a>;g;
+    s;\btlsproxy_tls_dcert_file\b;<a href="postconf.5.html#tlsproxy_tls_dcert_file">$&</a>;g;
+    s;\btlsproxy_tls_dh1024_param_file\b;<a href="postconf.5.html#tlsproxy_tls_dh1024_param_file">$&</a>;g;
+    s;\btlsproxy_tls_dh512_param_file\b;<a href="postconf.5.html#tlsproxy_tls_dh512_param_file">$&</a>;g;
+    s;\btlsproxy_tls_dkey_file\b;<a href="postconf.5.html#tlsproxy_tls_dkey_file">$&</a>;g;
+    s;\btlsproxy_tls_eccert_file\b;<a href="postconf.5.html#tlsproxy_tls_eccert_file">$&</a>;g;
+    s;\btlsproxy_tls_eckey_file\b;<a href="postconf.5.html#tlsproxy_tls_eckey_file">$&</a>;g;
+    s;\btlsproxy_tls_eecdh_grade\b;<a href="postconf.5.html#tlsproxy_tls_eecdh_grade">$&</a>;g;
+    s;\btlsproxy_tls_exclude_ciphers\b;<a href="postconf.5.html#tlsproxy_tls_exclude_ciphers">$&</a>;g;
+    s;\btlsproxy_tls_fingerprint_digest\b;<a href="postconf.5.html#tlsproxy_tls_fingerprint_digest">$&</a>;g;
+    s;\btlsproxy_tls_key_file\b;<a href="postconf.5.html#tlsproxy_tls_key_file">$&</a>;g;
+    s;\btlsproxy_tls_loglevel\b;<a href="postconf.5.html#tlsproxy_tls_loglevel">$&</a>;g;
+    s;\btlsproxy_tls_mandatory_ciphers\b;<a href="postconf.5.html#tlsproxy_tls_mandatory_ciphers">$&</a>;g;
+    s;\btlsproxy_tls_mandatory_exclude_ciphers\b;<a href="postconf.5.html#tlsproxy_tls_mandatory_exclude_ciphers">$&</a>;g;
+    s;\btlsproxy_tls_mandatory_protocols\b;<a href="postconf.5.html#tlsproxy_tls_mandatory_protocols">$&</a>;g;
+    s;\btlsproxy_tls_protocols\b;<a href="postconf.5.html#tlsproxy_tls_protocols">$&</a>;g;
+    s;\btlsproxy_tls_req_ccert\b;<a href="postconf.5.html#tlsproxy_tls_req_ccert">$&</a>;g;
+    s;\btlsproxy_tls_security_level\b;<a href="postconf.5.html#tlsproxy_tls_security_level">$&</a>;g;
+    s;\btlsproxy_tls_session_cache_timeout\b;<a href="postconf.5.html#tlsproxy_tls_session_cache_timeout">$&</a>;g;
+    s;\btlsproxy_use_tls\b;<a href="postconf.5.html#tlsproxy_use_tls">$&</a>;g;
 
     # Hyperlink URLs and RFC documents
 
index 97c62b11c52847fa91e528bc89c0ec122ea1b67c..e744ef554cf1060c28cc26554e256343dbf4049d 100644 (file)
@@ -284,7 +284,7 @@ client IP address. This test is disabled by default. </p>
 
 <blockquote>
 <p>
-CAUTION: when postscreen rejects mail, it's SMTP reply contains the
+CAUTION: when postscreen rejects mail, its SMTP reply contains the
 DNSBL domain name. Use the postscreen_dnsbl_reply_map feature to
 hide "password" information in DNSBL domain names.
 </p>
@@ -361,10 +361,10 @@ impact of this limitation, postscreen(8) gives deep protocol tests
 a relatively long expiration time. </p>
 
 <li> <p> postscreen(8)'s built-in SMTP engine does not implement
-the AUTH, STARTTLS, XCLIENT, and XFORWARD features.  STARTTLS and
-AUTH support may be added in a future version. In the mean time,
-if you need to make these services available on port 25, then do
-not enable the tests after the 220 server greeting. </p>
+the AUTH, XCLIENT, and XFORWARD features.  AUTH support may be added
+in a future version. In the mean time, if you need to make these
+services available on port 25, then do not enable the tests after
+the 220 server greeting. </p>
 
 </ul>
 
@@ -672,6 +672,15 @@ service in master.cf. </p>
     smtp      inet  n       -       n       -       1       postscreen
 </pre>
 
+<li> <p> Uncomment the new "<tt>tlsproxy unix ... tlsproxy</tt>"
+service in master.cf.  This service implements STARTTLS support for
+postscreen(8). </p>
+
+<pre>
+/etc/postfix/master.cf:
+    tlsproxy  unix  -       -       n       -       0       tlsproxy
+</pre>
+
 <li> <p> Uncomment the new "<tt>dnsblog  unix ... dnsblog</tt>"
 service in master.cf.  This service does DNSBL lookups for postscreen(8)
 and logs results. </p>
@@ -775,8 +784,8 @@ disconnect. </p>
 <p> When the good client comes back in a later session, it is allowed
 to talk directly to a Postfix SMTP server.  See "after_220 <a
 href="#after_220">Tests after the 220 SMTP server greeting</a> above
-for limitations with STARTTLS, AUTH and other features that clients
-may need. </p>
+for limitations with AUTH and other features that clients may need.
+</p>
 
 <p> An unexpected benefit from "<a href="#after_220">deep protocol
 tests</a>" is that some "good" clients don't return after the 4XX
@@ -825,14 +834,23 @@ that follow. </p>
     #    -o parameter=value ...
 </pre>
 
+<li> <p> Comment out the "<tt>tlsproxy unix ... tlsproxy</tt>"
+service in master.cf, including any "<tt>-o parameter=value</tt>"
+entries that follow. </p>
+
+<pre>
+/etc/postfix/master.cf:
+    #tlsproxy  unix  -       -       n       -       0       tlsproxy
+    #    -o parameter=value ...
+</pre>
 
 <li> <p> Uncomment the "<tt>smtp  inet ... smtpd</tt>" service in
 master.cf, including any "<tt>-o parameter=value</tt>" entries that
-follow.  </p>
+may follow.  </p>
 
 <pre>
 /etc/postfix/master.cf:
-    smtp      inet  n       -       n       -       -       smtpd
+    smtp       inet  n       -       n       -       -       smtpd
         -o parameter=value ...
 </pre>
 
index b75bf9ed07c634fedc063f1be7ff460a3570cbcf..3a7a2ffcdca3e0a392f40f4a4bd4994170dcc8a2 100644 (file)
@@ -27,6 +27,11 @@ code.  Assuming that OpenSSL is written as carefully as Wietse's
 own code, every 1000 lines introduce one additional bug into
 Postfix.  </p>
 
+<p> At this time, you should no longer be using OpenSSL releases prior
+to the most recent 0.9.8 release unless all relevant security fixes have
+been backported to the earlier release by you or your O/S vendor. OpenSSL
+0.9.7 and earlier are no longer maintained by the OpenSSL team. </p>
+
 <h2> What Postfix TLS support does for you </h2>
 
 <p> Transport Layer Security (TLS, formerly called SSL) provides
@@ -852,6 +857,25 @@ secure for most situations. </p>
 </pre>
 </blockquote>
 
+<p> Postfix 2.8 and later, in combination with OpenSSL 0.9.7 and later
+allows TLS servers to preempt the TLS client's cipher preference list.
+This is only possible with SSLv3, as in SSLv2 the client chooses the
+cipher from a list supplied by the server. </p>
+
+<p> By default, the OpenSSL server selects the client's most preferred
+cipher that the server supports. With SSLv3 and later, the server
+may choose its own most preferred cipher that is supported (offered)
+by the client. Setting "tls_preempt_cipherlist = yes" enables server
+cipher preferences. The default OpenSSL behaviour applies with
+"tls_preempt_cipherlist = no". </p>
+
+<p> While server cipher selection may in some cases lead to a more secure
+or performant cipher choice, there is some risk of interoperability
+issues. In the past, some SSL clients have listed lower priority ciphers
+that they did not implement correctly. If the server chooses a cipher
+that the client prefers less, it may select a cipher whose client
+implementation is flawed. </p>
+
 <h3><a name="server_misc"> Miscellaneous server controls</a> </h3>
 
 <p> The smtpd_starttls_timeout parameter limits the time of Postfix
@@ -867,6 +891,30 @@ handshake procedures.  </p>
 </pre>
 </blockquote>
 
+<p> With Postfix 2.8 and later, the tls_disable_workarounds parameter
+specifies a list or bit-mask of OpenSSL bug work-arounds to disable. This
+may be necessary if one of the work-arounds enabled by default in
+OpenSSL proves to pose a security risk, or introduces an unexpected
+interoperability issue. Some bug work-arounds known to be problematic
+are disabled in the default value of the parameter when linked with
+an OpenSSL library that could be vulnerable. </p>
+
+<p> Example: </p>
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+    tls_disable_workarounds = 0xFFFFFFFF
+    tls_disable_workarounds = CVE-2010-4180, LEGACY_SERVER_CONNECT
+</pre>
+</blockquote>
+
+<p> Note: Disabling LEGACY_SERVER_CONNECT is not wise at this
+time, lots of servers are still unpatched and Postfix is <a
+href="http://www.postfix.org/wip.html#tls-renegotiation">not
+significantly vulnerable</a> to the renegotiation issue in the TLS
+protocol. </p>
+
 <h2> <a name="client_tls">SMTP Client specific settings</a> </h2>
 
 <p> Topics covered in this section: </p>
index cb9fe1bf4c135b64734fd7c40e2c40a29859c86d..0a44cfdfcaa83a41dfb6a54c6cecbcd3f2a55572 100644 (file)
@@ -9072,10 +9072,12 @@ smtpd_tls_dh512_param_file = /etc/postfix/dh_512.pem
 
 <p>This feature is available with Postfix version 2.2.</p>
 
-%PARAM smtpd_starttls_timeout 300s
+%PARAM smtpd_starttls_timeout see "postconf -d" output
 
 <p> The time limit for Postfix SMTP server write and read operations
-during TLS startup and shutdown handshake procedures. </p>
+during TLS startup and shutdown handshake procedures. The current
+default value is stress-dependent. Before Postfix version 2.8, it
+was fixed at 300s. </p>
 
 <p> This feature is available in Postfix 2.2 and later.  </p>
 
@@ -13457,3 +13459,366 @@ Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
 The default time unit is s (seconds).
 </p>
 
+%PARAM tls_preempt_cipherlist no
+
+<p> With SSLv3 and later, use the server's cipher preference order
+instead of the client's cipher preference order. </p>
+
+<p> By default, the OpenSSL server selects the client's most preferred
+cipher that the server supports. With SSLv3 and later, the server may
+choose its own most preferred cipher that is supported (offered) by
+the client. Setting "tls_preempt_cipherlist = yes" enables server cipher
+preferences. </p>
+
+<p> While server cipher selection may in some cases lead to a more secure
+or performant cipher choice, there is some risk of interoperability
+issues. In the past, some SSL clients have listed lower priority ciphers
+that they did not implement correctly. If the server chooses a cipher
+that the client prefers less, it may select a cipher whose client
+implementation is flawed. </p>
+
+<p> This feature is available in Postfix 2.8 and later, in combination
+with OpenSSL 0.9.7 and later. </p>
+
+%PARAM tls_disable_workarounds see "postconf -d" output
+
+<p> List or bit-mask of OpenSSL bug work-arounds to disable. </p>
+
+<p> The OpenSSL toolkit includes a set of work-arounds for buggy SSL/TLS
+implementations. Applications, such as Postfix, that want to maximize
+interoperability ask the OpenSSL library to enable the full set of
+recommended work-arounds. </p>
+
+<p> From time to time, it is discovered that a work-around creates a
+security issue, and should no longer be used. If upgrading OpenSSL
+to a fixed version is not an option or an upgrade is not available
+in a timely manner, or in closed environments where no buggy clients
+or servers exist, it may be appropriate to disable some or all of the
+OpenSSL interoperability work-arounds. This parameter specifies which
+bug work-arounds to disable. </p>
+
+<p> If the value of the parameter is a hexadecimal long integer starting
+with "0x", the bug work-arounds corresponding to the bits specified in
+its value are removed from the <b>SSL_OP_ALL</b> work-around bit-mask
+(see openssl/ssl.h and SSL_CTX_set_options(3)). You can specify more
+bits than are present in SSL_OP_ALL, excess bits are ignored. Specifying
+0xFFFFFFFF disables all bug-workarounds on a 32-bit system. This should
+also be sufficient on 64-bit systems, until OpenSSL abandons support
+for 32-bit systems and starts using the high 32 bits of a 64-bit
+bug-workaround mask. </p>
+
+<p> Otherwise, the parameter is a white-space or comma separated list
+of specific named bug work-arounds chosen from the list below. It
+is possible that your OpenSSL version includes new bug work-arounds
+added after your Postfix source code was last updated, in that case
+you can only disable one of these via the hexadecimal syntax above. </p>
+
+<dl>
+<dt><b>MICROSOFT_SESS_ID_BUG</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>NETSCAPE_CHALLENGE_BUG</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>LEGACY_SERVER_CONNECT</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>NETSCAPE_REUSE_CIPHER_CHANGE_BUG</b> also aliased as
+<b>CVE-2010-4180</b>. Postfix 2.8 disables this work-around by default
+with OpenSSL versions that may predate the fix. Fixed in OpenSSL 0.9.8q
+and OpenSSL 1.0.0c.</dt>
+<dt><b>SSLREF2_REUSE_CERT_TYPE_BUG</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>MICROSOFT_BIG_SSLV3_BUFFER</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>MSIE_SSLV2_RSA_PADDING</b> also aliased as
+<b>CVE-2005-2969</b>. Postfix 2.8 disables this work-around by default
+with OpenSSL versions that may predate the fix. Fixed in OpenSSL 0.9.7h
+and OpenSSL 0.9.8a.</dt>
+<dt><b>SSLEAY_080_CLIENT_DH_BUG</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>TLS_D5_BUG</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>TLS_BLOCK_PADDING_BUG</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>TLS_ROLLBACK_BUG</b>See SSL_CTX_set_options(3). This is disabled
+in OpenSSL 0.9.7 and later. Nobody should still be using 0.9.6! </dt>
+<dt><b>DONT_INSERT_EMPTY_FRAGMENTS</b>See SSL_CTX_set_options(3)</dt>
+<dt><b>CRYPTOPRO_TLSEXT_BUG</b>New with GOST support in OpenSSL 1.0.0.</dt>
+</dl>
+
+<p> This feature is available in Postfix 2.8 and later.  </p>
+
+%PARAM tlsproxy_watchdog_timeout 10s
+
+<p> How much time a tlsproxy(8) process may take to process local
+or remote I/O before it is terminated by a built-in watchdog timer.
+This is a safety mechanism that prevents tlsproxy(8) from becoming
+non-responsive due to a bug in Postfix itself or in system software.
+To avoid false alarms and unnecessary cache corruption this limit
+cannot be set under 10s.  </p>
+
+<p> Specify a non-zero time value (an integral value plus an optional
+one-letter suffix that specifies the time unit).  Time units: s
+(seconds), m (minutes), h (hours), d (days), w (weeks).  </p>
+
+<p> This feature is available in Postfix 2.8.  </p>
+
+%PARAM postscreen_discard_ehlo_keywords $smtpd_discard_ehlo_keywords
+
+<p> A case insensitive list of EHLO keywords (pipelining, starttls,
+auth, etc.) that the postscreen(8) server will not send in the EHLO
+response to a remote SMTP client. See smtpd_discard_ehlo_keywords
+for details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM postscreen_discard_ehlo_keyword_address_maps $smtpd_discard_ehlo_keyword_address_maps
+
+<p> Lookup tables, indexed by the remote SMTP client address, with
+case insensitive lists of EHLO keywords (pipelining, starttls, auth,
+etc.) that the postscreen(8) server will not send in the EHLO response
+to a remote SMTP client. See smtpd_discard_ehlo_keywords for details.
+The table is not searched by hostname for robustness reasons.  </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM postscreen_use_tls $smtpd_use_tls
+
+<p> Opportunistic TLS: announce STARTTLS support to SMTP clients,
+but do not require that clients use TLS encryption. </p>
+
+<p> This feature is available in Postfix 2.8 and later. 
+Preferably, use postscreen_tls_security_level instead. </p>
+
+%PARAM postscreen_enforce_tls $smtpd_enforce_tls
+
+<p> Mandatory TLS: announce STARTTLS support to SMTP clients, and
+require that clients use TLS encryption.  See smtpd_postscreen_enforce_tls
+for details.  </p>
+
+<p> This feature is available in Postfix 2.8 and later.
+Preferably, use postscreen_tls_security_level instead. </p>
+
+%PARAM postscreen_tls_security_level $smtpd_tls_security_level
+
+<p> The SMTP TLS security level for the postscreen(8) server; when
+a non-empty value is specified, this overrides the obsolete parameters
+postscreen_use_tls and postscreen_enforce_tls. See smtpd_tls_security_level
+for details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_enforce_tls $smtpd_enforce_tls
+
+<p> Mandatory TLS: announce STARTTLS support to SMTP clients, and
+require that clients use TLS encryption. See smtpd_enforce_tls for
+further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_CAfile $smtpd_tls_CAfile
+
+<p> A file containing (PEM format) CA certificates of root CAs
+trusted to sign either remote SMTP client certificates or intermediate
+CA certificates.  See smtpd_tls_CAfile for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_CApath $smtpd_tls_CApath
+
+<p> A directory containing (PEM format) CA certificates of root CAs
+trusted to sign either remote SMTP client certificates or intermediate
+CA certificates. See smtpd_tls_CApath for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_always_issue_session_ids $smtpd_tls_always_issue_session_ids
+
+<p> Force the Postfix tlsproxy(8) server to issue a TLS session id,
+even when TLS session caching is turned off. See
+smtpd_tls_always_issue_session_ids for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_ask_ccert $smtpd_tls_ask_ccert
+
+<p> Ask a remote SMTP client for a client certificate. See
+smtpd_tls_ask_ccert for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_ccert_verifydepth $smtpd_tls_ccert_verifydepth
+
+<p> The verification depth for remote SMTP client certificates. A
+depth of 1 is sufficient if the issuing CA is listed in a local CA
+file. See smtpd_tls_ccert_verifydepth for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_cert_file $smtpd_tls_cert_file
+
+<p> File with the Postfix tlsproxy(8) server RSA certificate in PEM
+format.  This file may also contain the Postfix tlsproxy(8) server
+private RSA key.  See smtpd_tls_cert_file for further details.  </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_ciphers $smtpd_tls_ciphers
+
+<p> The minimum TLS cipher grade that the Postfix tlsproxy(8) server
+will use with opportunistic TLS encryption. See smtpd_tls_ciphers
+for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_dcert_file $smtpd_tls_dcert_file
+
+<p> File with the Postfix tlsproxy(8) server DSA certificate in PEM
+format.  This file may also contain the Postfix tlsproxy(8) server
+private DSA key.  See smtpd_tls_dcert_file for further details.
+</p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_dh1024_param_file $smtpd_tls_dh1024_param_file
+
+<p> File with DH parameters that the Postfix tlsproxy(8) server
+should use with EDH ciphers. See smtpd_tls_dh1024_param_file for
+further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_dh512_param_file $smtpd_tls_dh512_param_file
+
+<p> File with DH parameters that the Postfix tlsproxy(8) server
+should use with EDH ciphers. See smtpd_tls_dh512_param_file for
+further details.  </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_dkey_file $smtpd_tls_dkey_file
+
+<p> File with the Postfix tlsproxy(8) server DSA private key in PEM
+format.  This file may be combined with the Postfix tlsproxy(8)
+server DSA certificate file specified with $smtpd_tls_dcert_file.
+See smtpd_tls_dkey_file for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_eccert_file $smtpd_tls_eccert_file
+
+<p> File with the Postfix tlsproxy(8) server ECDSA certificate in
+PEM format.  This file may also contain the Postfix tlsproxy(8)
+server private ECDSA key.  See smtpd_tls_eccert_file for further
+details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_eckey_file $smtpd_tls_eckey_file
+
+<p> File with the Postfix tlsproxy(8) server ECDSA private key in
+PEM format.  This file may be combined with the Postfix tlsproxy(8)
+server ECDSA certificate file specified with $smtpd_tls_eccert_file.
+See smtpd_tls_eckey_file for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_eecdh_grade $smtpd_tls_eecdh_grade
+
+<p> The Postfix tlsproxy(8) server security grade for ephemeral
+elliptic-curve Diffie-Hellman (EECDH) key exchange. See
+smtpd_tls_eecdh_grade for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_exclude_ciphers $smtpd_tls_exclude_ciphers
+
+<p> List of ciphers or cipher types to exclude from the tlsproxy(8)
+server cipher list at all TLS security levels. See
+smtpd_tls_exclude_ciphers for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_fingerprint_digest $smtpd_tls_fingerprint_digest
+
+<p> The message digest algorithm used to construct client-certificate
+fingerprints. See smtpd_tls_fingerprint_digest for further details.
+</p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_key_file $smtpd_tls_key_file
+
+<p> File with the Postfix tlsproxy(8) server RSA private key in PEM
+format.  This file may be combined with the Postfix tlsproxy(8)
+server RSA certificate file specified with $smtpd_tls_cert_file.
+See smtpd_tls_key_file for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_loglevel $smtpd_tls_loglevel
+
+<p> Enable additional Postfix tlsproxy(8) server logging of TLS
+activity.  Each logging level also includes the information that
+is logged at a lower logging level. See smtpd_tls_loglevel for
+further details.  </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_mandatory_ciphers $smtpd_tls_mandatory_ciphers
+
+<p> The minimum TLS cipher grade that the Postfix tlsproxy(8) server
+will use with mandatory TLS encryption. See smtpd_tls_mandatory_ciphers
+for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_mandatory_exclude_ciphers $smtpd_tls_mandatory_exclude_ciphers
+
+<p> Additional list of ciphers or cipher types to exclude from the
+tlsproxy(8) server cipher list at mandatory TLS security levels.
+See smtpd_tls_mandatory_exclude_ciphers for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_mandatory_protocols $smtpd_tls_mandatory_protocols
+
+<p> The SSL/TLS protocols accepted by the Postfix tlsproxy(8) server
+with mandatory TLS encryption. If the list is empty, the server
+supports all available SSL/TLS protocol versions.  See
+smtpd_tls_mandatory_protocols for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_protocols $smtpd_tls_protocols
+
+<p> List of TLS protocols that the Postfix tlsproxy(8) server will
+exclude or include with opportunistic TLS encryption. See
+smtpd_tls_protocols for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_req_ccert $smtpd_tls_req_ccert
+
+<p> With mandatory TLS encryption, require a trusted remote SMTP
+client certificate in order to allow TLS connections to proceed.
+See smtpd_tls_req_ccert for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_security_level $smtpd_tls_security_level
+
+<p> The SMTP TLS security level for the Postfix tlsproxy(8) server;
+when a non-empty value is specified, this overrides the obsolete
+parameters smtpd_use_tls and smtpd_enforce_tls. See
+smtpd_tls_security_level for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_tls_session_cache_timeout $smtpd_tls_session_cache_timeout
+
+<p> The expiration time of Postfix tlsproxy(8) server TLS session
+cache information. A cache cleanup is performed periodically every
+$smtpd_tls_session_cache_timeout seconds. See
+smtpd_tls_session_cache_timeout for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
+%PARAM tlsproxy_use_tls $smtpd_use_tls
+
+<p> Opportunistic TLS: announce STARTTLS support to SMTP clients,
+but do not require that clients use TLS encryption. See smtpd_use_tls
+for further details. </p>
+
+<p> This feature is available in Postfix 2.8 and later. </p>
+
index d7501934b89216b2e9315be0cf2229b8e272d631..9c60dc74949b15cfb0e76df1317c610e27653d5a 100644 (file)
@@ -90,7 +90,7 @@ int     ehlo_mask(const char *mask_str)
      * can switch between Postfix versions without trouble.
      */
     return (name_mask_opt("ehlo string mask", ehlo_mask_table,
-                         mask_str, NAME_MASK_ANY_CASE));
+                         mask_str, NAME_MASK_ANY_CASE | NAME_MASK_IGNORE));
 }
 
 /* str_ehlo_mask - mask to string */
index c88067ebd569e80900dfe35f029fab634c51d1b1..a0796063ba1e3c0793186b450e67580781f6d663 100644 (file)
@@ -1137,7 +1137,7 @@ extern char *var_smtpd_banner;
 extern int var_smtpd_tmout;
 
 #define VAR_SMTPD_STARTTLS_TMOUT "smtpd_starttls_timeout"
-#define DEF_SMTPD_STARTTLS_TMOUT "300s"
+#define DEF_SMTPD_STARTTLS_TMOUT "${stress?10}${stress:300}s"
 extern int var_smtpd_starttls_tmout;
 
 #define VAR_SMTPD_RCPT_LIMIT   "smtpd_recipient_limit"
@@ -2988,6 +2988,39 @@ extern char *var_tls_eecdh_strong;
 #define DEF_TLS_EECDH_ULTRA    "secp384r1"
 extern char *var_tls_eecdh_ultra;
 
+#define VAR_TLS_PREEMPT_CLIST  "tls_preempt_cipherlist"
+#define DEF_TLS_PREEMPT_CLIST  0
+extern bool var_tls_preempt_clist;
+
+#ifdef USE_TLS
+
+ /*
+  * The tweak for CVE-2005-2969 is needed in some versions prior to 1.0.0
+  */
+#if (OPENSSL_VERSION_NUMBER < 0x1000000fL)
+#define TLS_BUG_TWEAK_A        " CVE-2005-2969"
+#else
+#define TLS_BUG_TWEAK_A ""
+#endif
+
+ /*
+  * The tweak for CVE-2010-4180 is needed in some versions prior to 1.0.1
+  */
+#if (OPENSSL_VERSION_NUMBER < 0x1000100fL)
+#define TLS_BUG_TWEAK_B        " CVE-2010-4180"
+#else
+#define TLS_BUG_TWEAK_B        " "
+#endif
+
+#else /* USE_TLS */
+#define TLS_BUG_TWEAK_A        ""
+#define TLS_BUG_TWEAK_B        " "
+#endif /* USE_TLS */
+
+#define VAR_TLS_BUG_TWEAKS     "tls_disable_workarounds"
+#define DEF_TLS_BUG_TWEAKS     ((TLS_BUG_TWEAK_A TLS_BUG_TWEAK_B)+1)
+extern char *var_tls_bug_tweaks;
+
  /*
   * Sendmail-style mail filter support.
   */
@@ -3226,154 +3259,301 @@ extern char *var_multi_cntrl_cmds;
  /*
   * postscreen(8)
   */
-#define VAR_PS_CACHE_MAP       "postscreen_cache_map"
-#define DEF_PS_CACHE_MAP       "btree:$data_directory/ps_cache"
-extern char *var_ps_cache_map;
+#define VAR_PSC_CACHE_MAP      "postscreen_cache_map"
+#define DEF_PSC_CACHE_MAP      "btree:$data_directory/psc_cache"
+extern char *var_psc_cache_map;
 
 #define VAR_SMTPD_SERVICE      "smtpd_service"
 #define DEF_SMTPD_SERVICE      "smtpd"
 extern char *var_smtpd_service;
 
-#define VAR_PS_POST_QLIMIT     "postscreen_post_queue_limit"
-#define DEF_PS_POST_QLIMIT     "$" VAR_PROC_LIMIT
-extern int var_ps_post_queue_limit;
+#define VAR_PSC_POST_QLIMIT    "postscreen_post_queue_limit"
+#define DEF_PSC_POST_QLIMIT    "$" VAR_PROC_LIMIT
+extern int var_psc_post_queue_limit;
+
+#define VAR_PSC_PRE_QLIMIT     "postscreen_pre_queue_limit"
+#define DEF_PSC_PRE_QLIMIT     "$" VAR_PROC_LIMIT
+extern int var_psc_pre_queue_limit;
+
+#define VAR_PSC_CACHE_RET      "postscreen_cache_retention_time"
+#define DEF_PSC_CACHE_RET      "7d"
+extern int var_psc_cache_ret;
+
+#define VAR_PSC_CACHE_SCAN     "postscreen_cache_cleanup_interval"
+#define DEF_PSC_CACHE_SCAN     "12h"
+extern int var_psc_cache_scan;
 
-#define VAR_PS_PRE_QLIMIT      "postscreen_pre_queue_limit"
-#define DEF_PS_PRE_QLIMIT      "$" VAR_PROC_LIMIT
-extern int var_ps_pre_queue_limit;
+#define VAR_PSC_GREET_WAIT     "postscreen_greet_wait"
+#define DEF_PSC_GREET_WAIT     "${stress?2}${stress:6}s"
+extern int var_psc_greet_wait;
 
-#define VAR_PS_CACHE_RET       "postscreen_cache_retention_time"
-#define DEF_PS_CACHE_RET       "7d"
-extern int var_ps_cache_ret;
+#define VAR_PSC_PREGR_BANNER   "postscreen_greet_banner"
+#define DEF_PSC_PREGR_BANNER   "$" VAR_SMTPD_BANNER
+extern char *var_psc_pregr_banner;
 
-#define VAR_PS_CACHE_SCAN      "postscreen_cache_cleanup_interval"
-#define DEF_PS_CACHE_SCAN      "12h"
-extern int var_ps_cache_scan;
+#define VAR_PSC_PREGR_ENABLE   "postscreen_greet_enable"
+#define DEF_PSC_PREGR_ENABLE   no
+extern char *var_psc_pregr_enable;
 
-#define VAR_PS_GREET_WAIT      "postscreen_greet_wait"
-#define DEF_PS_GREET_WAIT      "${stress?2}${stress:6}s"
-extern int var_ps_greet_wait;
+#define VAR_PSC_PREGR_ACTION   "postscreen_greet_action"
+#define DEF_PSC_PREGR_ACTION   "ignore"
+extern char *var_psc_pregr_action;
 
-#define VAR_PS_PREGR_BANNER    "postscreen_greet_banner"
-#define DEF_PS_PREGR_BANNER    "$" VAR_SMTPD_BANNER
-extern char *var_ps_pregr_banner;
+#define VAR_PSC_PREGR_TTL      "postscreen_greet_ttl"
+#define DEF_PSC_PREGR_TTL      "1d"
+extern int var_psc_pregr_ttl;
 
-#define VAR_PS_PREGR_ENABLE    "postscreen_greet_enable"
-#define DEF_PS_PREGR_ENABLE    no
-extern char *var_ps_pregr_enable;
+#define VAR_PSC_DNSBL_SITES    "postscreen_dnsbl_sites"
+#define DEF_PSC_DNSBL_SITES    ""
+extern char *var_psc_dnsbl_sites;
 
-#define VAR_PS_PREGR_ACTION    "postscreen_greet_action"
-#define DEF_PS_PREGR_ACTION    "ignore"
-extern char *var_ps_pregr_action;
+#define VAR_PSC_DNSBL_THRESH   "postscreen_dnsbl_threshold"
+#define DEF_PSC_DNSBL_THRESH   1
+extern int var_psc_dnsbl_thresh;
 
-#define VAR_PS_PREGR_TTL       "postscreen_greet_ttl"
-#define DEF_PS_PREGR_TTL       "1d"
-extern int var_ps_pregr_ttl;
+#define VAR_PSC_DNSBL_ENABLE   "postscreen_dnsbl_enable"
+#define DEF_PSC_DNSBL_ENABLE   0
+extern char *var_psc_dnsbl_enable;
 
-#define VAR_PS_DNSBL_SITES     "postscreen_dnsbl_sites"
-#define DEF_PS_DNSBL_SITES     ""
-extern char *var_ps_dnsbl_sites;
+#define VAR_PSC_DNSBL_ACTION   "postscreen_dnsbl_action"
+#define DEF_PSC_DNSBL_ACTION   "ignore"
+extern char *var_psc_dnsbl_action;
 
-#define VAR_PS_DNSBL_THRESH    "postscreen_dnsbl_threshold"
-#define DEF_PS_DNSBL_THRESH    1
-extern int var_ps_dnsbl_thresh;
+#define VAR_PSC_DNSBL_TTL      "postscreen_dnsbl_ttl"
+#define DEF_PSC_DNSBL_TTL      "1h"
+extern int var_psc_dnsbl_ttl;
 
-#define VAR_PS_DNSBL_ENABLE    "postscreen_dnsbl_enable"
-#define DEF_PS_DNSBL_ENABLE    0
-extern char *var_ps_dnsbl_enable;
+#define        VAR_PSC_DNSBL_REPLY     "postscreen_dnsbl_reply_map"
+#define        DEF_PSC_DNSBL_REPLY     ""
+extern char *var_psc_dnsbl_reply;
 
-#define VAR_PS_DNSBL_ACTION    "postscreen_dnsbl_action"
-#define DEF_PS_DNSBL_ACTION    "ignore"
-extern char *var_ps_dnsbl_action;
+#define VAR_PSC_PIPEL_ENABLE   "postscreen_pipelining_enable"
+#define DEF_PSC_PIPEL_ENABLE   0
+extern bool var_psc_pipel_enable;
 
-#define VAR_PS_DNSBL_TTL       "postscreen_dnsbl_ttl"
-#define DEF_PS_DNSBL_TTL       "1h"
-extern int var_ps_dnsbl_ttl;
+#define VAR_PSC_PIPEL_ACTION   "postscreen_pipelining_action"
+#define DEF_PSC_PIPEL_ACTION   "enforce"
+extern char *var_psc_pipel_action;
 
-#define        VAR_PS_DNSBL_REPLY      "postscreen_dnsbl_reply_map"
-#define        DEF_PS_DNSBL_REPLY      ""
-extern char *var_ps_dnsbl_reply;
+#define VAR_PSC_PIPEL_TTL      "postscreen_pipelining_ttl"
+#define DEF_PSC_PIPEL_TTL      "30d"
+extern int var_psc_pipel_ttl;
 
-#define VAR_PS_PIPEL_ENABLE    "postscreen_pipelining_enable"
-#define DEF_PS_PIPEL_ENABLE    0
-extern bool var_ps_pipel_enable;
+#define VAR_PSC_NSMTP_ENABLE   "postscreen_non_smtp_command_enable"
+#define DEF_PSC_NSMTP_ENABLE   0
+extern bool var_psc_nsmtp_enable;
 
-#define VAR_PS_PIPEL_ACTION    "postscreen_pipelining_action"
-#define DEF_PS_PIPEL_ACTION    "enforce"
-extern char *var_ps_pipel_action;
+#define VAR_PSC_NSMTP_ACTION   "postscreen_non_smtp_command_action"
+#define DEF_PSC_NSMTP_ACTION   "drop"
+extern char *var_psc_nsmtp_action;
 
-#define VAR_PS_PIPEL_TTL       "postscreen_pipelining_ttl"
-#define DEF_PS_PIPEL_TTL       "30d"
-extern int var_ps_pipel_ttl;
+#define VAR_PSC_NSMTP_TTL      "postscreen_non_smtp_command_ttl"
+#define DEF_PSC_NSMTP_TTL      "30d"
+extern int var_psc_nsmtp_ttl;
 
-#define VAR_PS_NSMTP_ENABLE    "postscreen_non_smtp_command_enable"
-#define DEF_PS_NSMTP_ENABLE    0
-extern bool var_ps_nsmtp_enable;
+#define VAR_PSC_BARLF_ENABLE   "postscreen_bare_newline_enable"
+#define DEF_PSC_BARLF_ENABLE   0
+extern bool var_psc_barlf_enable;
 
-#define VAR_PS_NSMTP_ACTION    "postscreen_non_smtp_command_action"
-#define DEF_PS_NSMTP_ACTION    "drop"
-extern char *var_ps_nsmtp_action;
+#define VAR_PSC_BARLF_ACTION   "postscreen_bare_newline_action"
+#define DEF_PSC_BARLF_ACTION   "ignore"
+extern char *var_psc_barlf_action;
 
-#define VAR_PS_NSMTP_TTL       "postscreen_non_smtp_command_ttl"
-#define DEF_PS_NSMTP_TTL       "30d"
-extern int var_ps_nsmtp_ttl;
+#define VAR_PSC_BARLF_TTL      "postscreen_bare_newline_ttl"
+#define DEF_PSC_BARLF_TTL      "30d"
+extern int var_psc_barlf_ttl;
 
-#define VAR_PS_BARLF_ENABLE    "postscreen_bare_newline_enable"
-#define DEF_PS_BARLF_ENABLE    0
-extern bool var_ps_barlf_enable;
+#define VAR_PSC_WLIST_NETS     "postscreen_whitelist_networks"
+#define DEF_PSC_WLIST_NETS     "$" VAR_MYNETWORKS
+extern char *var_psc_wlist_nets;
 
-#define VAR_PS_BARLF_ACTION    "postscreen_bare_newline_action"
-#define DEF_PS_BARLF_ACTION    "ignore"
-extern char *var_ps_barlf_action;
+#define VAR_PSC_BLIST_NETS     "postscreen_blacklist_networks"
+#define DEF_PSC_BLIST_NETS     ""
+extern char *var_psc_blist_nets;
 
-#define VAR_PS_BARLF_TTL       "postscreen_bare_newline_ttl"
-#define DEF_PS_BARLF_TTL       "30d"
-extern int var_ps_barlf_ttl;
+#define VAR_PSC_BLIST_ACTION   "postscreen_blacklist_action"
+#define DEF_PSC_BLIST_ACTION   "ignore"
+extern char *var_psc_blist_nets;
 
-#define VAR_PS_WLIST_NETS      "postscreen_whitelist_networks"
-#define DEF_PS_WLIST_NETS      "$" VAR_MYNETWORKS
-extern char *var_ps_wlist_nets;
+#define VAR_PSC_CMD_COUNT      "postscreen_command_count_limit"
+#define DEF_PSC_CMD_COUNT      20
+extern int var_psc_cmd_count;
 
-#define VAR_PS_BLIST_NETS      "postscreen_blacklist_networks"
-#define DEF_PS_BLIST_NETS      ""
-extern char *var_ps_blist_nets;
+#define VAR_PSC_CMD_TIME               "postscreen_command_time_limit"
+#define DEF_PSC_CMD_TIME               DEF_SMTPD_TMOUT
+extern char *var_psc_cmd_time;
 
-#define VAR_PS_BLIST_ACTION    "postscreen_blacklist_action"
-#define DEF_PS_BLIST_ACTION    "ignore"
-extern char *var_ps_blist_nets;
+#define VAR_PSC_WATCHDOG               "postscreen_watchdog_timeout"
+#define DEF_PSC_WATCHDOG               "10s"
+extern int var_psc_watchdog;
 
-#define VAR_PS_CMD_COUNT       "postscreen_command_count_limit"
-#define DEF_PS_CMD_COUNT       20
-extern int var_ps_cmd_count;
+#define VAR_PSC_EHLO_DIS_WORDS "postscreen_discard_ehlo_keywords"
+#define DEF_PSC_EHLO_DIS_WORDS "$" VAR_SMTPD_EHLO_DIS_WORDS
+extern char *var_psc_ehlo_dis_words;
 
-#define VAR_PS_CMD_TIME                "postscreen_command_time_limit"
-#define DEF_PS_CMD_TIME                DEF_SMTPD_TMOUT
-extern char *var_ps_cmd_time;
+#define VAR_PSC_EHLO_DIS_MAPS  "postscreen_discard_ehlo_keyword_address_maps"
+#define DEF_PSC_EHLO_DIS_MAPS  "$" VAR_SMTPD_EHLO_DIS_MAPS
+extern char *var_psc_ehlo_dis_maps;
 
-#define VAR_PS_WATCHDOG                "postscreen_watchdog_timeout"
-#define DEF_PS_WATCHDOG                "10s"
-extern int var_ps_watchdog;
+#define VAR_PSC_TLS_LEVEL      "postscreen_tls_security_level"
+#define DEF_PSC_TLS_LEVEL      "$" VAR_SMTPD_TLS_LEVEL
+extern char *var_psc_tls_level;
 
-#define VAR_PS_FORBID_CMDS     "postscreen_forbidden_commands"
-#define DEF_PS_FORBID_CMDS     "$" VAR_SMTPD_FORBID_CMDS
-extern char *var_ps_forbid_cmds;
+#define VAR_PSC_USE_TLS                "postscreen_use_tls"
+#define DEF_PSC_USE_TLS                "$" VAR_SMTPD_USE_TLS
+extern bool var_psc_use_tls;
 
-#define VAR_PS_HELO_REQUIRED   "postscreen_helo_required"
-#define DEF_PS_HELO_REQUIRED   "$" VAR_HELO_REQUIRED
-extern bool var_ps_helo_required;
+#define VAR_PSC_ENFORCE_TLS    "postscreen_enforce_tls"
+#define DEF_PSC_ENFORCE_TLS    "$" VAR_SMTPD_ENFORCE_TLS
+extern bool var_psc_enforce_tls;
 
-#define VAR_PS_DISABLE_VRFY    "postscreen_disable_vrfy_command"
-#define DEF_PS_DISABLE_VRFY    "$" VAR_DISABLE_VRFY_CMD
-extern bool var_ps_disable_vrfy;
+#define VAR_PSC_FORBID_CMDS    "postscreen_forbidden_commands"
+#define DEF_PSC_FORBID_CMDS    "$" VAR_SMTPD_FORBID_CMDS
+extern char *var_psc_forbid_cmds;
 
-#define VAR_PS_CCONN_LIMIT     "postscreen_client_connection_count_limit"
-#define DEF_PS_CCONN_LIMIT     "$" VAR_SMTPD_CCONN_LIMIT
-extern int var_ps_cconn_limit;
+#define VAR_PSC_HELO_REQUIRED  "postscreen_helo_required"
+#define DEF_PSC_HELO_REQUIRED  "$" VAR_HELO_REQUIRED
+extern bool var_psc_helo_required;
+
+#define VAR_PSC_DISABLE_VRFY   "postscreen_disable_vrfy_command"
+#define DEF_PSC_DISABLE_VRFY   "$" VAR_DISABLE_VRFY_CMD
+extern bool var_psc_disable_vrfy;
+
+#define VAR_PSC_CCONN_LIMIT    "postscreen_client_connection_count_limit"
+#define DEF_PSC_CCONN_LIMIT    "$" VAR_SMTPD_CCONN_LIMIT
+extern int var_psc_cconn_limit;
 
 #define VAR_DNSBLOG_DELAY      "dnsblog_reply_delay"
 #define DEF_DNSBLOG_DELAY      "0s"
 extern int var_dnsblog_delay;
 
+#define VAR_TLSP_WATCHDOG      "tlsproxy_watchdog_timeout"
+#define DEF_TLSP_WATCHDOG      "10s"
+extern int var_tlsp_watchdog;
+
+#define VAR_TLSP_TLS_LEVEL     "tlsproxy_tls_security_level"
+#define DEF_TLSP_TLS_LEVEL     "$" VAR_SMTPD_TLS_LEVEL
+extern char *var_tlsp_tls_level;
+
+#define VAR_TLSP_USE_TLS       "tlsproxy_use_tls"
+#define DEF_TLSP_USE_TLS       "$" VAR_SMTPD_USE_TLS
+extern bool var_tlsp_use_tls;
+
+#define VAR_TLSP_ENFORCE_TLS   "tlsproxy_enforce_tls"
+#define DEF_TLSP_ENFORCE_TLS   "$" VAR_SMTPD_ENFORCE_TLS
+extern bool var_tlsp_enforce_tls;
+
+#define VAR_TLSP_TLS_ACERT     "tlsproxy_tls_ask_ccert"
+#define DEF_TLSP_TLS_ACERT     "$" VAR_SMTPD_TLS_ACERT
+extern bool var_tlsp_tls_ask_ccert;
+
+#define VAR_TLSP_TLS_RCERT     "tlsproxy_tls_req_ccert"
+#define DEF_TLSP_TLS_RCERT     "$" VAR_SMTPD_TLS_RCERT
+extern bool var_tlsp_tls_req_ccert;
+
+#define VAR_TLSP_TLS_CCERT_VD  "tlsproxy_tls_ccert_verifydepth"
+#define DEF_TLSP_TLS_CCERT_VD  "$" VAR_SMTPD_TLS_CCERT_VD
+extern int var_tlsp_tls_ccert_vd;
+
+#define VAR_TLSP_TLS_CERT_FILE "tlsproxy_tls_cert_file"
+#define DEF_TLSP_TLS_CERT_FILE "$" VAR_SMTPD_TLS_CERT_FILE
+extern char *var_tlsp_tls_cert_file;
+
+#define VAR_TLSP_TLS_KEY_FILE  "tlsproxy_tls_key_file"
+#define DEF_TLSP_TLS_KEY_FILE  "$" VAR_SMTPD_TLS_KEY_FILE
+extern char *var_tlsp_tls_key_file;
+
+#define VAR_TLSP_TLS_DCERT_FILE "tlsproxy_tls_dcert_file"
+#define DEF_TLSP_TLS_DCERT_FILE        "$" VAR_SMTPD_TLS_DCERT_FILE
+extern char *var_tlsp_tls_dcert_file;
+
+#define VAR_TLSP_TLS_DKEY_FILE "tlsproxy_tls_dkey_file"
+#define DEF_TLSP_TLS_DKEY_FILE "$" VAR_SMTPD_TLS_DKEY_FILE
+extern char *var_tlsp_tls_dkey_file;
+
+#define VAR_TLSP_TLS_ECCERT_FILE "tlsproxy_tls_eccert_file"
+#define DEF_TLSP_TLS_ECCERT_FILE       "$" VAR_SMTPD_TLS_ECCERT_FILE
+extern char *var_tlsp_tls_eccert_file;
+
+#define VAR_TLSP_TLS_ECKEY_FILE        "tlsproxy_tls_eckey_file"
+#define DEF_TLSP_TLS_ECKEY_FILE        "$" VAR_SMTPD_TLS_ECKEY_FILE
+extern char *var_tlsp_tls_eckey_file;
+
+#define DEF_TLSP_TLS_ECKEY_FILE        "$" VAR_SMTPD_TLS_ECKEY_FILE
+extern char *var_tlsp_tls_eckey_file;
+
+#define VAR_TLSP_TLS_CA_FILE   "tlsproxy_tls_CAfile"
+#define DEF_TLSP_TLS_CA_FILE   "$" VAR_SMTPD_TLS_CA_FILE
+extern char *var_tlsp_tls_CAfile;
+
+#define VAR_TLSP_TLS_CA_PATH   "tlsproxy_tls_CApath"
+#define DEF_TLSP_TLS_CA_PATH   "$" VAR_SMTPD_TLS_CA_PATH
+extern char *var_tlsp_tls_CApath;
+
+#define VAR_TLSP_TLS_PROTO     "tlsproxy_tls_protocols"
+#define DEF_TLSP_TLS_PROTO     "$" VAR_SMTPD_TLS_PROTO
+extern char *var_tlsp_tls_proto;
+
+#define VAR_TLSP_TLS_MAND_PROTO        "tlsproxy_tls_mandatory_protocols"
+#define DEF_TLSP_TLS_MAND_PROTO        "$" VAR_SMTPD_TLS_MAND_PROTO
+extern char *var_tlsp_tls_mand_proto;
+
+#define VAR_TLSP_TLS_CIPH      "tlsproxy_tls_ciphers"
+#define DEF_TLSP_TLS_CIPH      "$" VAR_SMTPD_TLS_CIPH
+extern char *var_tlsp_tls_ciph;
+
+#define VAR_TLSP_TLS_MAND_CIPH "tlsproxy_tls_mandatory_ciphers"
+#define DEF_TLSP_TLS_MAND_CIPH "$" VAR_SMTPD_TLS_MAND_CIPH
+extern char *var_tlsp_tls_mand_ciph;
+
+#define VAR_TLSP_TLS_EXCL_CIPH  "tlsproxy_tls_exclude_ciphers"
+#define DEF_TLSP_TLS_EXCL_CIPH "$" VAR_SMTPD_TLS_EXCL_CIPH
+extern char *var_tlsp_tls_excl_ciph;
+
+#define VAR_TLSP_TLS_MAND_EXCL  "tlsproxy_tls_mandatory_exclude_ciphers"
+#define DEF_TLSP_TLS_MAND_EXCL "$" VAR_SMTPD_TLS_MAND_EXCL
+extern char *var_tlsp_tls_mand_excl;
+
+#define VAR_TLSP_TLS_FPT_DGST  "tlsproxy_tls_fingerprint_digest"
+#define DEF_TLSP_TLS_FPT_DGST  "$" VAR_SMTPD_TLS_FPT_DGST
+extern char *var_tlsp_tls_fpt_dgst;
+
+#define VAR_TLSP_TLS_512_FILE  "tlsproxy_tls_dh512_param_file"
+#define DEF_TLSP_TLS_512_FILE  "$" VAR_SMTPD_TLS_512_FILE
+extern char *var_tlsp_tls_dh512_param_file;
+
+#define VAR_TLSP_TLS_1024_FILE "tlsproxy_tls_dh1024_param_file"
+#define DEF_TLSP_TLS_1024_FILE "$" VAR_SMTPD_TLS_1024_FILE
+extern char *var_tlsp_tls_dh1024_param_file;
+
+#define VAR_TLSP_TLS_EECDH     "tlsproxy_tls_eecdh_grade"
+#ifdef SNAPSHOT
+#define DEF_TLSP_TLS_EECDH     "$" VAR_SMTPD_TLS_EECDH
+#else
+#define DEF_TLSP_TLS_EECDH     "$" VAR_SMTPD_TLS_EECDH
+#endif
+extern char *var_tlsp_tls_eecdh;
+
+#define VAR_TLSP_TLS_LOGLEVEL  "tlsproxy_tls_loglevel"
+#define DEF_TLSP_TLS_LOGLEVEL  "$" VAR_SMTPD_TLS_LOGLEVEL
+extern int var_tlsp_tls_loglevel;
+
+#define VAR_TLSP_TLS_RECHEAD   "tlsproxy_tls_received_header"
+#define DEF_TLSP_TLS_RECHEAD   "$" VAR_SMTPD_TLS_RECHEAD
+extern bool var_tlsp_tls_received_header;
+
+#define VAR_TLSP_TLS_SCACHE_DB "tlsproxy_tls_session_cache_database"
+#define DEF_TLSP_TLS_SCACHE_DB "$" VAR_SMTPD_TLS_SCACHE_DB
+extern char *var_tlsp_tls_scache_db;
+
+#define VAR_TLSP_TLS_SCACHTIME "tlsproxy_tls_session_cache_timeout"
+#define DEF_TLSP_TLS_SCACHTIME "$" VAR_SMTPD_TLS_SCACHTIME
+extern int var_tlsp_tls_scache_timeout;
+
+#define VAR_TLSP_TLS_SET_SESSID        "tlsproxy_tls_always_issue_session_ids"
+#define DEF_TLSP_TLS_SET_SESSID        "$" VAR_SMTPD_TLS_SET_SESSID
+extern bool var_tlsp_tls_set_sessid;
+
 /* LICENSE
 /* .ad
 /* .fi
index c8b0e6a58cf1c2c9297fee427cd6f0dbd934e26e..c3c97b5added0ef0c9a2a41f117ead41da61b882 100644 (file)
@@ -236,6 +236,15 @@ extern char *mail_pathname(const char *, const char *);
 #define MAIL_ATTR_DSN_NOTIFY   "notify_flags"  /* dsn notify flags */
 #define MAIL_ATTR_DSN_ORCPT    "dsn_orig_rcpt" /* dsn original recipient */
 
+ /*
+  * PROXY support.
+  */
+#define MAIL_ATTR_REMOTE_ENDPT "remote_endpoint"       /* name[addr]:port */
+#define MAIL_ATTR_ROLE         "role"  /* requested role */
+#define MAIL_ATTR_ROLE_SERVER  "server"
+#define MAIL_ATTR_ROLE_CLIENT  "client"
+#define MAIL_ATTR_TIMEOUT      "timeout"
+
 /* LICENSE
 /* .ad
 /* .fi
index 0f4ffef5873e408158804ed5604b181692deb380..c1e99f217368d78cbd9bb0c57208272cc4b79ab9 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20101217"
+#define MAIL_RELEASE_DATE      "20110102"
 #define MAIL_VERSION_NUMBER    "2.8"
 
 #ifdef SNAPSHOT
index b2ed3109412f7de2b31f0ce6ff487589bd08ff15..1e5f2f7ff9955329a2167463e2b9c27d319549cc 100644 (file)
 /*     oqmgr(8), old Postfix queue manager
 /*     pickup(8), Postfix local mail pickup
 /*     pipe(8), deliver mail to non-Postfix command
-/*     postscreen(8), Postfix SMTP triage server
+/*     postscreen(8), Postfix zombie blocker
 /*     proxymap(8), Postfix lookup table proxy server
 /*     qmgr(8), Postfix queue manager
 /*     qmqpd(8), Postfix QMQP server
 /*     smtpd(8), Postfix SMTP server
 /*     spawn(8), run non-Postfix server
 /*     tlsmgr(8), Postfix TLS cache and randomness manager
+/*     tlsproxy(8), Postfix TLS proxy server
 /*     trivial-rewrite(8), Postfix address rewriting
 /*     verify(8), Postfix address verification
 /*     virtual(8), Postfix virtual delivery agent
index 227e211a5713866442001dd0863cfe4f06befbbe..b856fc5ff7052c4f6722be362e065439b96983a4 100644 (file)
@@ -1,10 +1,12 @@
 SHELL  = /bin/sh
 SRCS   = postscreen.c postscreen_dict.c postscreen_dnsbl.c \
        postscreen_early.c postscreen_smtpd.c postscreen_misc.c \
-       postscreen_state.c postscreen_tests.c postscreen_send.c
+       postscreen_state.c postscreen_tests.c postscreen_send.c \
+       postscreen_starttls.c
 OBJS   = postscreen.o postscreen_dict.o postscreen_dnsbl.o \
        postscreen_early.o postscreen_smtpd.o postscreen_misc.o \
-       postscreen_state.o postscreen_tests.o postscreen_send.o
+       postscreen_state.o postscreen_tests.o postscreen_send.o \
+       postscreen_starttls.o
 HDRS   = 
 TESTSRC        =
 DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
@@ -12,7 +14,8 @@ CFLAGS        = $(DEBUG) $(OPT) $(DEFS)
 TESTPROG= 
 PROG   = postscreen
 INC_DIR = ../../include
-LIBS   = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a
+LIBS   = ../../lib/libmaster.a ../../lib/libtls.a ../../lib/libglobal.a \
+       ../../lib/libutil.a
 
 .c.o:; $(CC) $(CFLAGS) -c $*.c
 
@@ -192,24 +195,52 @@ postscreen_smtpd.o: ../../include/argv.h
 postscreen_smtpd.o: ../../include/attr.h
 postscreen_smtpd.o: ../../include/dict.h
 postscreen_smtpd.o: ../../include/dict_cache.h
+postscreen_smtpd.o: ../../include/ehlo_mask.h
 postscreen_smtpd.o: ../../include/events.h
 postscreen_smtpd.o: ../../include/htable.h
 postscreen_smtpd.o: ../../include/iostuff.h
 postscreen_smtpd.o: ../../include/is_header.h
 postscreen_smtpd.o: ../../include/mail_params.h
 postscreen_smtpd.o: ../../include/mail_proto.h
+postscreen_smtpd.o: ../../include/maps.h
 postscreen_smtpd.o: ../../include/match_list.h
 postscreen_smtpd.o: ../../include/match_ops.h
 postscreen_smtpd.o: ../../include/msg.h
 postscreen_smtpd.o: ../../include/mymalloc.h
+postscreen_smtpd.o: ../../include/name_code.h
+postscreen_smtpd.o: ../../include/name_mask.h
 postscreen_smtpd.o: ../../include/string_list.h
 postscreen_smtpd.o: ../../include/stringops.h
 postscreen_smtpd.o: ../../include/sys_defs.h
+postscreen_smtpd.o: ../../include/tls.h
 postscreen_smtpd.o: ../../include/vbuf.h
 postscreen_smtpd.o: ../../include/vstream.h
 postscreen_smtpd.o: ../../include/vstring.h
 postscreen_smtpd.o: postscreen.h
 postscreen_smtpd.o: postscreen_smtpd.c
+postscreen_starttls.o: ../../include/addr_match_list.h
+postscreen_starttls.o: ../../include/argv.h
+postscreen_starttls.o: ../../include/attr.h
+postscreen_starttls.o: ../../include/connect.h
+postscreen_starttls.o: ../../include/dict.h
+postscreen_starttls.o: ../../include/dict_cache.h
+postscreen_starttls.o: ../../include/events.h
+postscreen_starttls.o: ../../include/htable.h
+postscreen_starttls.o: ../../include/iostuff.h
+postscreen_starttls.o: ../../include/mail_params.h
+postscreen_starttls.o: ../../include/mail_proto.h
+postscreen_starttls.o: ../../include/match_list.h
+postscreen_starttls.o: ../../include/match_ops.h
+postscreen_starttls.o: ../../include/msg.h
+postscreen_starttls.o: ../../include/mymalloc.h
+postscreen_starttls.o: ../../include/string_list.h
+postscreen_starttls.o: ../../include/stringops.h
+postscreen_starttls.o: ../../include/sys_defs.h
+postscreen_starttls.o: ../../include/vbuf.h
+postscreen_starttls.o: ../../include/vstream.h
+postscreen_starttls.o: ../../include/vstring.h
+postscreen_starttls.o: postscreen.h
+postscreen_starttls.o: postscreen_starttls.c
 postscreen_state.o: ../../include/addr_match_list.h
 postscreen_state.o: ../../include/argv.h
 postscreen_state.o: ../../include/attr.h
index fed34fb4f6c248f420bbabf3ec90fb9bf110e4e9..f40f25e01ece02942564149d0116b7ec04b2ebe1 100644 (file)
@@ -2,7 +2,7 @@
 /* NAME
 /*     postscreen 8
 /* SUMMARY
-/*     Postfix SMTP triage server
+/*     Postfix zombie blocker
 /* SYNOPSIS
 /*     \fBpostscreen\fR [generic Postfix daemon options]
 /* DESCRIPTION
 /*     It talks to untrusted clients on the network. The process
 /*     can be run chrooted at fixed low privilege.
 /* STANDARDS
-/*     RFC 5321 (SMTP, including multi-line 220 greetings)
+/*     RFC 821 (SMTP protocol)
+/*     RFC 1123 (Host requirements)
+/*     RFC 1652 (8bit-MIME transport)
+/*     RFC 1869 (SMTP service extensions)
+/*     RFC 1870 (Message Size Declaration)
+/*     RFC 1985 (ETRN command)
+/*     RFC 2034 (SMTP Enhanced Error Codes)
+/*     RFC 2821 (SMTP protocol)
 /*     RFC 2920 (SMTP Pipelining)
+/*     RFC 3207 (STARTTLS command)
+/*     RFC 3461 (SMTP DSN Extension)
+/*     RFC 3463 (Enhanced Status Codes)
+/*     RFC 5321 (SMTP protocol, including multi-line 220 greetings)
 /* DIAGNOSTICS
 /*     Problems and transactions are logged to \fBsyslogd\fR(8).
 /* BUGS
 /*     The \fBpostscreen\fR(8) built-in SMTP protocol engine
-/*     currently does not announce support for STARTTLS, AUTH,
-/*     XCLIENT or XFORWARD.
-/*     Support for STARTTLS and AUTH may be added in the future.
+/*     currently does not announce support for AUTH, XCLIENT or
+/*     XFORWARD.
+/*     Support for AUTH may be added in the future.
 /*     In the mean time, if you need to make these services available
 /*     on port 25, then do not enable the optional "after 220
 /*     server greeting" tests.
 /*     The text below provides only a parameter summary. See
 /*     \fBpostconf\fR(5) for more details including examples.
 /*
-/*     NOTE: Some \fBpostscreen\fR(8)  parameters implement
+/*     NOTE: Some \fBpostscreen\fR(8) parameters implement
 /*     stress-dependent behavior.  This is supported only when the
-/*     default value is stress-dependent (that is, it looks like
-/*     ${stress?X}${stress:Y}).  Other parameters always evaluate
-/*     as if the stress value is the empty string.
+/*     default parameter value is stress-dependent (that is, it
+/*     looks like ${stress?X}${stress:Y}, or it is the $\fIname\fR
+/*     of an smtpd parameter with a stress-dependent default).
+/*     Other parameters always evaluate as if the \fBstress\fR
+/*     parameter value is the empty string.
+/* COMPATIBILITY CONTROLS
+/* .ad
+/* .fi
+/* .IP "\fBpostscreen_discard_ehlo_keyword_address_maps ($smtpd_discard_ehlo_keyword_address_maps)\fR"
+/*     Lookup tables, indexed by the remote SMTP client address, with
+/*     case insensitive lists of EHLO keywords (pipelining, starttls, auth,
+/*     etc.) that the \fBpostscreen\fR(8) server will not send in the EHLO response
+/*     to a remote SMTP client.
+/* .IP "\fBpostscreen_discard_ehlo_keywords ($smtpd_discard_ehlo_keywords)\fR"
+/*     A case insensitive list of EHLO keywords (pipelining, starttls,
+/*     auth, etc.) that the \fBpostscreen\fR(8) server will not send in the EHLO
+/*     response to a remote SMTP client.
 /* TRIAGE PARAMETERS
 /* .ad
 /* .fi
 /*     How much time a \fBpostscreen\fR(8) process may take to respond to
 /*     an SMTP client command or to perform a cache operation before it
 /*     is terminated by a built-in watchdog timer.
+/* STARTTLS CONTROLS
+/* .ad
+/* .fi
+/* .IP "\fBpostscreen_tls_security_level ($smtpd_tls_security_level)\fR"
+/*     The SMTP TLS security level for the \fBpostscreen\fR(8) server; when
+/*     a non-empty value is specified, this overrides the obsolete parameters
+/*     postscreen_use_tls and postscreen_enforce_tls.
+/* OBSOLETE STARTTLS SUPPORT CONTROLS
+/* .ad
+/* .fi
+/*     These parameters are supported for compatibility with
+/*     \fBsmtpd\fR(8) legacy parameters.
+/* .IP "\fBpostscreen_use_tls ($smtpd_use_tls)\fR"
+/*     Opportunistic TLS: announce STARTTLS support to SMTP clients,
+/*     but do not require that clients use TLS encryption.
+/* .IP "\fBpostscreen_enforce_tls ($smtpd_enforce_tls)\fR"
+/*     Mandatory TLS: announce STARTTLS support to SMTP clients, and
+/*     require that clients use TLS encryption.
 /* MISCELLANEOUS CONTROLS
 /* .ad
 /* .fi
 /*     records, so that "smtpd" becomes, for example, "postfix/smtpd".
 /* SEE ALSO
 /*     smtpd(8), Postfix SMTP server
+/*     tlsproxy(8), Postfix TLS proxy server
 /*     dnsblog(8), temporary DNS helper
 /*     syslogd(8), system logging
 /* README FILES
 int     var_proc_limit;
 char   *var_smtpd_service;
 char   *var_smtpd_banner;
-char   *var_smtpd_forbid_cmds;
 bool    var_disable_vrfy_cmd;
 bool    var_helo_required;
 
-char   *var_ps_forbid_cmds;
-
-bool    var_ps_disable_vrfy;
-bool    var_ps_helo_required;
-
-char   *var_ps_cache_map;
-int     var_ps_cache_scan;
-int     var_ps_cache_ret;
-int     var_ps_post_queue_limit;
-int     var_ps_pre_queue_limit;
-int     var_ps_watchdog;
-
-char   *var_ps_wlist_nets;
-char   *var_ps_blist_nets;
-char   *var_ps_blist_action;
-
-char   *var_ps_greet_ttl;
-int     var_ps_greet_wait;
-
-char   *var_ps_pregr_banner;
-char   *var_ps_pregr_action;
-int     var_ps_pregr_ttl;
-
-char   *var_ps_dnsbl_sites;
-char   *var_ps_dnsbl_reply;
-int     var_ps_dnsbl_thresh;
-char   *var_ps_dnsbl_action;
-int     var_ps_dnsbl_ttl;
-
-bool    var_ps_pipel_enable;
-char   *var_ps_pipel_action;
-int     var_ps_pipel_ttl;
-
-bool    var_ps_nsmtp_enable;
-char   *var_ps_nsmtp_action;
-int     var_ps_nsmtp_ttl;
-
-bool    var_ps_barlf_enable;
-char   *var_ps_barlf_action;
-int     var_ps_barlf_ttl;
-
-int     var_ps_cmd_count;
-char   *var_ps_cmd_time;
+char   *var_smtpd_forbid_cmds;
+char   *var_psc_forbid_cmds;
+
+char   *var_smtpd_ehlo_dis_words;
+char   *var_smtpd_ehlo_dis_maps;
+char   *var_psc_ehlo_dis_words;
+char   *var_psc_ehlo_dis_maps;
+
+char   *var_smtpd_tls_level;
+bool    var_smtpd_use_tls;
+bool    var_smtpd_enforce_tls;
+char   *var_psc_tls_level;
+bool    var_psc_use_tls;
+bool    var_psc_enforce_tls;
+
+bool    var_psc_disable_vrfy;
+bool    var_psc_helo_required;
+
+char   *var_psc_cache_map;
+int     var_psc_cache_scan;
+int     var_psc_cache_ret;
+int     var_psc_post_queue_limit;
+int     var_psc_pre_queue_limit;
+int     var_psc_watchdog;
+
+char   *var_psc_wlist_nets;
+char   *var_psc_blist_nets;
+char   *var_psc_blist_action;
+
+char   *var_psc_greet_ttl;
+int     var_psc_greet_wait;
+
+char   *var_psc_pregr_banner;
+char   *var_psc_pregr_action;
+int     var_psc_pregr_ttl;
+
+char   *var_psc_dnsbl_sites;
+char   *var_psc_dnsbl_reply;
+int     var_psc_dnsbl_thresh;
+char   *var_psc_dnsbl_action;
+int     var_psc_dnsbl_ttl;
+
+bool    var_psc_pipel_enable;
+char   *var_psc_pipel_action;
+int     var_psc_pipel_ttl;
+
+bool    var_psc_nsmtp_enable;
+char   *var_psc_nsmtp_action;
+int     var_psc_nsmtp_ttl;
+
+bool    var_psc_barlf_enable;
+char   *var_psc_barlf_action;
+int     var_psc_barlf_ttl;
+
+int     var_psc_cmd_count;
+char   *var_psc_cmd_time;
 
 int     var_smtpd_cconn_limit;
-int     var_ps_cconn_limit;
+int     var_psc_cconn_limit;
 
  /*
   * Global variables.
   */
-int     ps_check_queue_length;         /* connections being checked */
-int     ps_post_queue_length;          /* being sent to real SMTPD */
-DICT_CACHE *ps_cache_map;              /* cache table handle */
-VSTRING *ps_temp;                      /* scratchpad */
-char   *ps_smtpd_service_name;         /* path to real SMTPD */
-int     ps_pregr_action;               /* PS_ACT_DROP/ENFORCE/etc */
-int     ps_dnsbl_action;               /* PS_ACT_DROP/ENFORCE/etc */
-int     ps_pipel_action;               /* PS_ACT_DROP/ENFORCE/etc */
-int     ps_nsmtp_action;               /* PS_ACT_DROP/ENFORCE/etc */
-int     ps_barlf_action;               /* PS_ACT_DROP/ENFORCE/etc */
-int     ps_min_ttl;                    /* Update with new tests! */
-int     ps_max_ttl;                    /* Update with new tests! */
-STRING_LIST *ps_forbid_cmds;           /* CONNECT GET POST */
-int     ps_stress_greet_wait;          /* stressed greet wait */
-int     ps_normal_greet_wait;          /* stressed greet wait */
-int     ps_stress_cmd_time_limit;      /* stressed command limit */
-int     ps_normal_cmd_time_limit;      /* normal command time limit */
-int     ps_stress;                     /* stress level */
-int     ps_check_queue_length_lowat;   /* stress low-water mark */
-int     ps_check_queue_length_hiwat;   /* stress high-water mark */
-DICT   *ps_dnsbl_reply;                        /* DNSBL name mapper */
-HTABLE *ps_client_concurrency;         /* per-client concurrency */
+int     psc_check_queue_length;                /* connections being checked */
+int     psc_post_queue_length;         /* being sent to real SMTPD */
+DICT_CACHE *psc_cache_map;             /* cache table handle */
+VSTRING *psc_temp;                     /* scratchpad */
+char   *psc_smtpd_service_name;                /* path to real SMTPD */
+int     psc_pregr_action;              /* PSC_ACT_DROP/ENFORCE/etc */
+int     psc_dnsbl_action;              /* PSC_ACT_DROP/ENFORCE/etc */
+int     psc_pipel_action;              /* PSC_ACT_DROP/ENFORCE/etc */
+int     psc_nsmtp_action;              /* PSC_ACT_DROP/ENFORCE/etc */
+int     psc_barlf_action;              /* PSC_ACT_DROP/ENFORCE/etc */
+int     psc_min_ttl;                   /* Update with new tests! */
+int     psc_max_ttl;                   /* Update with new tests! */
+STRING_LIST *psc_forbid_cmds;          /* CONNECT GET POST */
+int     psc_stress_greet_wait;         /* stressed greet wait */
+int     psc_normal_greet_wait;         /* stressed greet wait */
+int     psc_stress_cmd_time_limit;     /* stressed command limit */
+int     psc_normal_cmd_time_limit;     /* normal command time limit */
+int     psc_stress;                    /* stress level */
+int     psc_check_queue_length_lowat;  /* stress low-water mark */
+int     psc_check_queue_length_hiwat;  /* stress high-water mark */
+DICT   *psc_dnsbl_reply;               /* DNSBL name mapper */
+HTABLE *psc_client_concurrency;                /* per-client concurrency */
 
  /*
   * Local variables.
   */
-static ADDR_MATCH_LIST *ps_wlist_nets; /* permanently whitelisted networks */
-static ADDR_MATCH_LIST *ps_blist_nets; /* permanently blacklisted networks */
-static int ps_blist_action;            /* PS_ACT_DROP/ENFORCE/etc */
+static ADDR_MATCH_LIST *psc_wlist_nets;        /* permanently whitelisted networks */
+static ADDR_MATCH_LIST *psc_blist_nets;        /* permanently blacklisted networks */
+static int psc_blist_action;           /* PSC_ACT_DROP/ENFORCE/etc */
 
-/* ps_dump - dump some statistics before exit */
+/* psc_dump - dump some statistics before exit */
 
-static void ps_dump(void)
+static void psc_dump(void)
 {
 
     /*
@@ -398,15 +454,15 @@ static void ps_dump(void)
      * distinguish between "postfix reload" (we should restart) or "maximal
      * idle time reached" (we could finish the cache cleanup first).
      */
-    if (ps_cache_map) {
-       dict_cache_close(ps_cache_map);
-       ps_cache_map = 0;
+    if (psc_cache_map) {
+       dict_cache_close(psc_cache_map);
+       psc_cache_map = 0;
     }
 }
 
-/* ps_drain - delayed exit after "postfix reload" */
+/* psc_drain - delayed exit after "postfix reload" */
 
-static void ps_drain(char *unused_service, char **unused_argv)
+static void psc_drain(char *unused_service, char **unused_argv)
 {
     int     count;
 
@@ -427,9 +483,9 @@ static void ps_drain(char *unused_service, char **unused_argv)
      * XXX Some Berkeley DB versions break with close-after-fork. Every new
      * version is an improvement over its predecessor.
      */
-    if (ps_cache_map != 0) {
-       dict_cache_close(ps_cache_map);
-       ps_cache_map = 0;
+    if (psc_cache_map != 0) {
+       dict_cache_close(psc_cache_map);
+       psc_cache_map = 0;
     }
     for (count = 0; /* see below */ ; count++) {
        if (count >= 5) {
@@ -444,14 +500,14 @@ static void ps_drain(char *unused_service, char **unused_argv)
     }
 }
 
-/* ps_service - handle new client connection */
+/* psc_service - handle new client connection */
 
-static void ps_service(VSTREAM *smtp_client_stream,
-                              char *unused_service,
-                              char **unused_argv)
+static void psc_service(VSTREAM *smtp_client_stream,
+                               char *unused_service,
+                               char **unused_argv)
 {
-    const char *myname = "ps_service";
-    PS_STATE *state;
+    const char *myname = "psc_service";
+    PSC_STATE *state;
     struct sockaddr_storage addr_storage;
     SOCKADDR_SIZE addr_storage_len = sizeof(addr_storage);
     MAI_HOSTADDR_STR smtp_client_addr;
@@ -475,7 +531,7 @@ static void ps_service(VSTREAM *smtp_client_stream,
      * connections so we have to invoke getpeername() to find out the remote
      * address and port.
      */
-#define PS_SERVICE_DISCONNECT_AND_RETURN(stream) do { \
+#define PSC_SERVICE_DISCONNECT_AND_RETURN(stream) do { \
        event_server_disconnect(stream); \
        return; \
     } while (0);
@@ -486,10 +542,10 @@ static void ps_service(VSTREAM *smtp_client_stream,
     if (getpeername(vstream_fileno(smtp_client_stream), (struct sockaddr *)
                    & addr_storage, &addr_storage_len) < 0) {
        msg_warn("getpeername: %m -- dropping this connection");
-       ps_send_reply(vstream_fileno(smtp_client_stream),
-                     "unknown_address", "unknown_port",
-                     "421 4.3.2 No system resources\r\n");
-       PS_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
+       psc_send_reply(vstream_fileno(smtp_client_stream),
+                      "unknown_address", "unknown_port",
+                      "421 4.3.2 No system resources\r\n");
+       PSC_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
     }
 
     /*
@@ -502,17 +558,17 @@ static void ps_service(VSTREAM *smtp_client_stream,
        msg_warn("cannot convert client address/port to string: %s"
                 " -- dropping this connection",
                 MAI_STRERROR(aierr));
-       ps_send_reply(vstream_fileno(smtp_client_stream),
-                     "unknown_address", "unknown_port",
-                     "421 4.3.2 No system resources\r\n");
-       PS_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
+       psc_send_reply(vstream_fileno(smtp_client_stream),
+                      "unknown_address", "unknown_port",
+                      "421 4.3.2 No system resources\r\n");
+       PSC_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
     }
     if (strncasecmp("::ffff:", smtp_client_addr.buf, 7) == 0)
        memmove(smtp_client_addr.buf, smtp_client_addr.buf + 7,
                sizeof(smtp_client_addr.buf) - 7);
     if (msg_verbose > 1)
        msg_info("%s: sq=%d cq=%d connect from [%s]:%s",
-                myname, ps_post_queue_length, ps_check_queue_length,
+                myname, psc_post_queue_length, psc_check_queue_length,
                 smtp_client_addr.buf, smtp_client_port.buf);
 
     msg_info("CONNECT from [%s]:%s", smtp_client_addr.buf, smtp_client_port.buf);
@@ -521,30 +577,30 @@ static void ps_service(VSTREAM *smtp_client_stream,
      * Bundle up all the loose session pieces. This zeroes all flags and time
      * stamps.
      */
-    state = ps_new_session_state(smtp_client_stream, smtp_client_addr.buf,
-                                smtp_client_port.buf);
+    state = psc_new_session_state(smtp_client_stream, smtp_client_addr.buf,
+                                 smtp_client_port.buf);
 
     /*
      * Reply with 421 when the client has too many open connections.
      */
-    if (var_ps_cconn_limit > 0
-       && state->client_concurrency > var_ps_cconn_limit) {
+    if (var_psc_cconn_limit > 0
+       && state->client_concurrency > var_psc_cconn_limit) {
        msg_info("NOQUEUE: reject: CONNECT from [%s]:%s: too many connections",
                 state->smtp_client_addr, state->smtp_client_port);
-       PS_DROP_SESSION_STATE(state,
-                             "421 4.7.0 Error: too many connections\r\n");
+       PSC_DROP_SESSION_STATE(state,
+                              "421 4.7.0 Error: too many connections\r\n");
        return;
     }
 
     /*
      * Reply with 421 when we can't forward more connections.
      */
-    if (var_ps_post_queue_limit > 0
-       && ps_post_queue_length >= var_ps_post_queue_limit) {
+    if (var_psc_post_queue_limit > 0
+       && psc_post_queue_length >= var_psc_post_queue_limit) {
        msg_info("NOQUEUE: reject: CONNECT from [%s]:%s: all server ports busy",
                 state->smtp_client_addr, state->smtp_client_port);
-       PS_DROP_SESSION_STATE(state,
-                             "421 4.3.2 All server ports are busy\r\n");
+       PSC_DROP_SESSION_STATE(state,
+                              "421 4.3.2 All server ports are busy\r\n");
        return;
     }
 
@@ -552,10 +608,10 @@ static void ps_service(VSTREAM *smtp_client_stream,
      * The permanent whitelist has highest precedence (never block mail from
      * whitelisted sites, and never run tests against those sites).
      */
-    if (ps_wlist_nets != 0
-      && ps_addr_match_list_match(ps_wlist_nets, state->smtp_client_addr)) {
-       msg_info("WHITELISTED [%s]:%s", PS_CLIENT_ADDR_PORT(state));
-       ps_conclude(state);
+    if (psc_wlist_nets != 0
+    && psc_addr_match_list_match(psc_wlist_nets, state->smtp_client_addr)) {
+       msg_info("WHITELISTED [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
+       psc_conclude(state);
        return;
     }
 
@@ -564,26 +620,26 @@ static void ps_service(VSTREAM *smtp_client_stream,
      * permanently blacklisted, send some generic reply and hang up
      * immediately, or run more tests for logging purposes.
      */
-    if (ps_blist_nets != 0
-      && ps_addr_match_list_match(ps_blist_nets, state->smtp_client_addr)) {
-       msg_info("BLACKLISTED [%s]:%s", PS_CLIENT_ADDR_PORT(state));
-       PS_FAIL_SESSION_STATE(state, PS_STATE_FLAG_BLIST_FAIL);
-       switch (ps_blist_action) {
-       case PS_ACT_DROP:
-           PS_DROP_SESSION_STATE(state,
+    if (psc_blist_nets != 0
+    && psc_addr_match_list_match(psc_blist_nets, state->smtp_client_addr)) {
+       msg_info("BLACKLISTED [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
+       PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_BLIST_FAIL);
+       switch (psc_blist_action) {
+       case PSC_ACT_DROP:
+           PSC_DROP_SESSION_STATE(state,
                             "521 5.3.2 Service currently unavailable\r\n");
            return;
-       case PS_ACT_ENFORCE:
-           PS_ENFORCE_SESSION_STATE(state,
+       case PSC_ACT_ENFORCE:
+           PSC_ENFORCE_SESSION_STATE(state,
                             "550 5.3.2 Service currently unavailable\r\n");
            break;
-       case PS_ACT_IGNORE:
-           PS_UNFAIL_SESSION_STATE(state, PS_STATE_FLAG_BLIST_FAIL);
-           /* Not: PS_PASS_SESSION_STATE. Repeat this test the next time. */
+       case PSC_ACT_IGNORE:
+           PSC_UNFAIL_SESSION_STATE(state, PSC_STATE_FLAG_BLIST_FAIL);
+           /* Not: PSC_PASS_SESSION_STATE. Repeat this test the next time. */
            break;
        default:
            msg_panic("%s: unknown blacklist action value %d",
-                     myname, ps_blist_action);
+                     myname, psc_blist_action);
        }
     }
 
@@ -593,38 +649,39 @@ static void ps_service(VSTREAM *smtp_client_stream,
      * tests. Whitelist the client when all enabled test results are still
      * valid.
      */
-    if ((state->flags & PS_STATE_MASK_ANY_FAIL) == 0
-       && ps_cache_map != 0
-       && (stamp_str = ps_cache_lookup(ps_cache_map, state->smtp_client_addr)) != 0) {
+    if ((state->flags & PSC_STATE_MASK_ANY_FAIL) == 0
+       && psc_cache_map != 0
+       && (stamp_str = psc_cache_lookup(psc_cache_map, state->smtp_client_addr)) != 0) {
        saved_flags = state->flags;
-       ps_parse_tests(state, stamp_str, event_time());
+       psc_parse_tests(state, stamp_str, event_time());
        state->flags |= saved_flags;
        if (msg_verbose)
            msg_info("%s: cached + recent flags: %s",
-                    myname, ps_print_state_flags(state->flags, myname));
-       if ((state->flags & PS_STATE_MASK_ANY_TODO_FAIL) == 0) {
-           msg_info("PASS OLD [%s]:%s", PS_CLIENT_ADDR_PORT(state));
-           ps_conclude(state);
+                    myname, psc_print_state_flags(state->flags, myname));
+       if ((state->flags & PSC_STATE_MASK_ANY_TODO_FAIL) == 0) {
+           msg_info("PASS OLD [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
+           psc_conclude(state);
            return;
        }
     } else {
        saved_flags = state->flags;
-       ps_new_tests(state);
+       psc_new_tests(state);
        state->flags |= saved_flags;
        if (msg_verbose)
            msg_info("%s: new + recent flags: %s",
-                    myname, ps_print_state_flags(state->flags, myname));
+                    myname, psc_print_state_flags(state->flags, myname));
     }
 
     /*
      * Reply with 421 when we can't analyze more connections.
      */
-    if (var_ps_pre_queue_limit > 0
-       && ps_check_queue_length - ps_post_queue_length >= var_ps_pre_queue_limit) {
+    if (var_psc_pre_queue_limit > 0
+       && psc_check_queue_length - psc_post_queue_length
+       >= var_psc_pre_queue_limit) {
        msg_info("reject: connect from [%s]:%s: all screening ports busy",
                 state->smtp_client_addr, state->smtp_client_port);
-       PS_DROP_SESSION_STATE(state,
-                             "421 4.3.2 All screening ports are busy\r\n");
+       PSC_DROP_SESSION_STATE(state,
+                              "421 4.3.2 All screening ports are busy\r\n");
        return;
     }
 
@@ -644,21 +701,21 @@ static void ps_service(VSTREAM *smtp_client_stream,
      * If the client has no up-to-date results for some tests, do those tests
      * first. Otherwise, skip the tests and hand off the connection.
      */
-    if (state->flags & PS_STATE_MASK_EARLY_TODO)
-       ps_early_tests(state);
-    else if (state->flags & (PS_STATE_MASK_SMTPD_TODO | PS_STATE_FLAG_NOFORWARD))
-       ps_smtpd_tests(state);
+    if (state->flags & PSC_STATE_MASK_EARLY_TODO)
+       psc_early_tests(state);
+    else if (state->flags & (PSC_STATE_MASK_SMTPD_TODO | PSC_STATE_FLAG_NOFORWARD))
+       psc_smtpd_tests(state);
     else
-       ps_conclude(state);
+       psc_conclude(state);
 }
 
-/* ps_cache_validator - validate one cache entry */
+/* psc_cache_validator - validate one cache entry */
 
-static int ps_cache_validator(const char *client_addr,
-                                     const char *stamp_str,
-                                     char *unused_context)
+static int psc_cache_validator(const char *client_addr,
+                                      const char *stamp_str,
+                                      char *unused_context)
 {
-    PS_STATE dummy;
+    PSC_STATE dummy;
 
     /*
      * This function is called by the cache cleanup pseudo thread.
@@ -668,8 +725,8 @@ static int ps_cache_validator(const char *client_addr,
      * silly logging we remove the cache entry only after all tests have
      * expired longer ago than the cache retention time.
      */
-    ps_parse_tests(&dummy, stamp_str, event_time() - var_ps_cache_ret);
-    return ((dummy.flags & PS_STATE_MASK_ANY_TODO) == 0);
+    psc_parse_tests(&dummy, stamp_str, event_time() - var_psc_cache_ret);
+    return ((dummy.flags & PSC_STATE_MASK_ANY_TODO) == 0);
 }
 
 /* pre_jail_init - pre-jail initialization */
@@ -682,16 +739,19 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
      * Open read-only maps before dropping privilege, for consistency with
      * other Postfix daemons.
      */
-    if (*var_ps_wlist_nets)
-       ps_wlist_nets = addr_match_list_init(MATCH_FLAG_NONE, var_ps_wlist_nets);
-
-    if (*var_ps_blist_nets)
-       ps_blist_nets = addr_match_list_init(MATCH_FLAG_NONE, var_ps_blist_nets);
-    if (*var_ps_forbid_cmds)
-       ps_forbid_cmds = string_list_init(MATCH_FLAG_NONE, var_ps_forbid_cmds);
-    if (*var_ps_dnsbl_reply)
-       ps_dnsbl_reply = dict_open(var_ps_dnsbl_reply, O_RDONLY,
-                                  DICT_FLAG_DUP_WARN);
+    if (*var_psc_wlist_nets)
+       psc_wlist_nets =
+           addr_match_list_init(MATCH_FLAG_NONE, var_psc_wlist_nets);
+
+    if (*var_psc_blist_nets)
+       psc_blist_nets = addr_match_list_init(MATCH_FLAG_NONE,
+                                             var_psc_blist_nets);
+    if (*var_psc_forbid_cmds)
+       psc_forbid_cmds = string_list_init(MATCH_FLAG_NONE,
+                                          var_psc_forbid_cmds);
+    if (*var_psc_dnsbl_reply)
+       psc_dnsbl_reply = dict_open(var_psc_dnsbl_reply, O_RDONLY,
+                                   DICT_FLAG_DUP_WARN);
 
     /*
      * Never, ever, get killed by a master signal, as that would corrupt the
@@ -717,18 +777,45 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
      * 
      * Start the cache maintenance pseudo thread after dropping privileges.
      */
-#define PS_DICT_OPEN_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE)
+#define PSC_DICT_OPEN_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE)
 
-    if (*var_ps_cache_map)
-       ps_cache_map =
-           dict_cache_open(data_redirect_map(redirect, var_ps_cache_map),
-                           O_CREAT | O_RDWR, PS_DICT_OPEN_FLAGS);
+    if (*var_psc_cache_map)
+       psc_cache_map =
+           dict_cache_open(data_redirect_map(redirect, var_psc_cache_map),
+                           O_CREAT | O_RDWR, PSC_DICT_OPEN_FLAGS);
 
     /*
      * Clean up and restore privilege.
      */
     vstring_free(redirect);
     RESTORE_SAVED_EUGID();
+
+    /*
+     * Initialize the dummy SMTP engine.
+     */
+    psc_smtpd_pre_jail_init();
+}
+
+/* pre_accept - see if tables have changed */
+
+static void pre_accept(char *unused_name, char **unused_argv)
+{
+    static time_t last_event_time;
+    time_t  new_event_time;
+    const char *name;
+
+    /*
+     * If some table has changed then stop accepting new connections. Don't
+     * check the tables more than once a second.
+     */
+    new_event_time = event_time();
+    if (new_event_time >= last_event_time + 1
+       && (name = dict_changed_name()) != 0) {
+       msg_info("table %s has changed - finishing in the background", name);
+       event_server_drain();
+    } else {
+       last_event_time = new_event_time;
+    }
 }
 
 /* post_jail_init - post-jail initialization */
@@ -736,10 +823,10 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
 static void post_jail_init(char *unused_name, char **unused_argv)
 {
     const NAME_CODE actions[] = {
-       PS_NAME_ACT_DROP, PS_ACT_DROP,
-       PS_NAME_ACT_ENFORCE, PS_ACT_ENFORCE,
-       PS_NAME_ACT_IGNORE, PS_ACT_IGNORE,
-       PS_NAME_ACT_CONT, PS_ACT_IGNORE,/* compatibility */
+       PSC_NAME_ACT_DROP, PSC_ACT_DROP,
+       PSC_NAME_ACT_ENFORCE, PSC_ACT_ENFORCE,
+       PSC_NAME_ACT_IGNORE, PSC_ACT_IGNORE,
+       PSC_NAME_ACT_CONT, PSC_ACT_IGNORE,      /* compatibility */
        0, -1,
     };
     int     cache_flags;
@@ -754,31 +841,37 @@ static void post_jail_init(char *unused_name, char **unused_argv)
     /*
      * Other one-time initialization.
      */
-    ps_temp = vstring_alloc(10);
-    vstring_sprintf(ps_temp, "%s/%s", MAIL_CLASS_PRIVATE, var_smtpd_service);
-    ps_smtpd_service_name = mystrdup(STR(ps_temp));
-    ps_dnsbl_init();
-    ps_early_init();
-    ps_smtpd_init();
-
-    if ((ps_blist_action = name_code(actions, NAME_CODE_FLAG_NONE,
-                                    var_ps_blist_action)) < 0)
-       msg_fatal("bad %s value: %s", VAR_PS_BLIST_ACTION, var_ps_blist_action);
-    if ((ps_dnsbl_action = name_code(actions, NAME_CODE_FLAG_NONE,
-                                    var_ps_dnsbl_action)) < 0)
-       msg_fatal("bad %s value: %s", VAR_PS_DNSBL_ACTION, var_ps_dnsbl_action);
-    if ((ps_pregr_action = name_code(actions, NAME_CODE_FLAG_NONE,
-                                    var_ps_pregr_action)) < 0)
-       msg_fatal("bad %s value: %s", VAR_PS_PREGR_ACTION, var_ps_pregr_action);
-    if ((ps_pipel_action = name_code(actions, NAME_CODE_FLAG_NONE,
-                                    var_ps_pipel_action)) < 0)
-       msg_fatal("bad %s value: %s", VAR_PS_PIPEL_ACTION, var_ps_pipel_action);
-    if ((ps_nsmtp_action = name_code(actions, NAME_CODE_FLAG_NONE,
-                                    var_ps_nsmtp_action)) < 0)
-       msg_fatal("bad %s value: %s", VAR_PS_NSMTP_ACTION, var_ps_nsmtp_action);
-    if ((ps_barlf_action = name_code(actions, NAME_CODE_FLAG_NONE,
-                                    var_ps_barlf_action)) < 0)
-       msg_fatal("bad %s value: %s", VAR_PS_BARLF_ACTION, var_ps_barlf_action);
+    psc_temp = vstring_alloc(10);
+    vstring_sprintf(psc_temp, "%s/%s", MAIL_CLASS_PRIVATE, var_smtpd_service);
+    psc_smtpd_service_name = mystrdup(STR(psc_temp));
+    psc_dnsbl_init();
+    psc_early_init();
+    psc_smtpd_init();
+
+    if ((psc_blist_action = name_code(actions, NAME_CODE_FLAG_NONE,
+                                     var_psc_blist_action)) < 0)
+       msg_fatal("bad %s value: %s", VAR_PSC_BLIST_ACTION,
+                 var_psc_blist_action);
+    if ((psc_dnsbl_action = name_code(actions, NAME_CODE_FLAG_NONE,
+                                     var_psc_dnsbl_action)) < 0)
+       msg_fatal("bad %s value: %s", VAR_PSC_DNSBL_ACTION,
+                 var_psc_dnsbl_action);
+    if ((psc_pregr_action = name_code(actions, NAME_CODE_FLAG_NONE,
+                                     var_psc_pregr_action)) < 0)
+       msg_fatal("bad %s value: %s", VAR_PSC_PREGR_ACTION,
+                 var_psc_pregr_action);
+    if ((psc_pipel_action = name_code(actions, NAME_CODE_FLAG_NONE,
+                                     var_psc_pipel_action)) < 0)
+       msg_fatal("bad %s value: %s", VAR_PSC_PIPEL_ACTION,
+                 var_psc_pipel_action);
+    if ((psc_nsmtp_action = name_code(actions, NAME_CODE_FLAG_NONE,
+                                     var_psc_nsmtp_action)) < 0)
+       msg_fatal("bad %s value: %s", VAR_PSC_NSMTP_ACTION,
+                 var_psc_nsmtp_action);
+    if ((psc_barlf_action = name_code(actions, NAME_CODE_FLAG_NONE,
+                                     var_psc_barlf_action)) < 0)
+       msg_fatal("bad %s value: %s", VAR_PSC_BARLF_ACTION,
+                 var_psc_barlf_action);
 
     /*
      * Start the cache maintenance pseudo thread last. Early cleanup makes
@@ -788,52 +881,52 @@ static void post_jail_init(char *unused_name, char **unused_argv)
     cache_flags = DICT_CACHE_FLAG_STATISTICS;
     if (msg_verbose > 1)
        cache_flags |= DICT_CACHE_FLAG_VERBOSE;
-    if (ps_cache_map != 0 && var_ps_cache_scan > 0)
-       dict_cache_control(ps_cache_map,
+    if (psc_cache_map != 0 && var_psc_cache_scan > 0)
+       dict_cache_control(psc_cache_map,
                           DICT_CACHE_CTL_FLAGS, cache_flags,
-                          DICT_CACHE_CTL_INTERVAL, var_ps_cache_scan,
-                          DICT_CACHE_CTL_VALIDATOR, ps_cache_validator,
+                          DICT_CACHE_CTL_INTERVAL, var_psc_cache_scan,
+                          DICT_CACHE_CTL_VALIDATOR, psc_cache_validator,
                           DICT_CACHE_CTL_CONTEXT, (char *) 0,
                           DICT_CACHE_CTL_END);
 
     /*
      * Pre-compute the minimal and maximal TTL.
      */
-    ps_min_ttl =
-       PS_MIN(PS_MIN(var_ps_pregr_ttl, var_ps_dnsbl_ttl),
-              PS_MIN(PS_MIN(var_ps_pipel_ttl, var_ps_nsmtp_ttl),
-                     var_ps_barlf_ttl));
-    ps_max_ttl =
-       PS_MAX(PS_MAX(var_ps_pregr_ttl, var_ps_dnsbl_ttl),
-              PS_MAX(PS_MAX(var_ps_pipel_ttl, var_ps_nsmtp_ttl),
-                     var_ps_barlf_ttl));
+    psc_min_ttl =
+       PSC_MIN(PSC_MIN(var_psc_pregr_ttl, var_psc_dnsbl_ttl),
+               PSC_MIN(PSC_MIN(var_psc_pipel_ttl, var_psc_nsmtp_ttl),
+                       var_psc_barlf_ttl));
+    psc_max_ttl =
+       PSC_MAX(PSC_MAX(var_psc_pregr_ttl, var_psc_dnsbl_ttl),
+               PSC_MAX(PSC_MAX(var_psc_pipel_ttl, var_psc_nsmtp_ttl),
+                       var_psc_barlf_ttl));
 
     /*
      * Pre-compute the stress and normal command time limits.
      */
     mail_conf_update(VAR_STRESS, "yes");
-    ps_stress_cmd_time_limit =
-       get_mail_conf_time(VAR_PS_CMD_TIME, DEF_PS_CMD_TIME, 1, 0);
-    ps_stress_greet_wait =
-       get_mail_conf_time(VAR_PS_GREET_WAIT, DEF_PS_GREET_WAIT, 1, 0);
+    psc_stress_cmd_time_limit =
+       get_mail_conf_time(VAR_PSC_CMD_TIME, DEF_PSC_CMD_TIME, 1, 0);
+    psc_stress_greet_wait =
+       get_mail_conf_time(VAR_PSC_GREET_WAIT, DEF_PSC_GREET_WAIT, 1, 0);
 
     mail_conf_update(VAR_STRESS, "");
-    ps_normal_cmd_time_limit =
-       get_mail_conf_time(VAR_PS_CMD_TIME, DEF_PS_CMD_TIME, 1, 0);
-    ps_normal_greet_wait =
-       get_mail_conf_time(VAR_PS_GREET_WAIT, DEF_PS_GREET_WAIT, 1, 0);
+    psc_normal_cmd_time_limit =
+       get_mail_conf_time(VAR_PSC_CMD_TIME, DEF_PSC_CMD_TIME, 1, 0);
+    psc_normal_greet_wait =
+       get_mail_conf_time(VAR_PSC_GREET_WAIT, DEF_PSC_GREET_WAIT, 1, 0);
 
-    ps_check_queue_length_lowat = .7 * var_ps_pre_queue_limit;
-    ps_check_queue_length_hiwat = .9 * var_ps_pre_queue_limit;
+    psc_check_queue_length_lowat = .7 * var_psc_pre_queue_limit;
+    psc_check_queue_length_hiwat = .9 * var_psc_pre_queue_limit;
     if (msg_verbose)
-       msg_info(VAR_PS_CMD_TIME ": stress=%d normal=%d lowat=%d hiwat=%d",
-                ps_stress_cmd_time_limit, ps_normal_cmd_time_limit,
-                ps_check_queue_length_lowat, ps_check_queue_length_hiwat);
+       msg_info(VAR_PSC_CMD_TIME ": stress=%d normal=%d lowat=%d hiwat=%d",
+                psc_stress_cmd_time_limit, psc_normal_cmd_time_limit,
+                psc_check_queue_length_lowat, psc_check_queue_length_hiwat);
 
     /*
      * Per-client concurrency.
      */
-    ps_client_concurrency = htable_create(var_ps_pre_queue_limit);
+    psc_client_concurrency = htable_create(var_psc_pre_queue_limit);
 }
 
 MAIL_VERSION_STAMP_DECLARE;
@@ -851,61 +944,71 @@ int     main(int argc, char **argv)
        VAR_SMTPD_SERVICE, DEF_SMTPD_SERVICE, &var_smtpd_service, 1, 0,
        VAR_SMTPD_BANNER, DEF_SMTPD_BANNER, &var_smtpd_banner, 1, 0,
        VAR_SMTPD_FORBID_CMDS, DEF_SMTPD_FORBID_CMDS, &var_smtpd_forbid_cmds, 0, 0,
-       VAR_PS_CACHE_MAP, DEF_PS_CACHE_MAP, &var_ps_cache_map, 0, 0,
-       VAR_PS_PREGR_BANNER, DEF_PS_PREGR_BANNER, &var_ps_pregr_banner, 0, 0,
-       VAR_PS_PREGR_ACTION, DEF_PS_PREGR_ACTION, &var_ps_pregr_action, 1, 0,
-       VAR_PS_DNSBL_SITES, DEF_PS_DNSBL_SITES, &var_ps_dnsbl_sites, 0, 0,
-       VAR_PS_DNSBL_ACTION, DEF_PS_DNSBL_ACTION, &var_ps_dnsbl_action, 1, 0,
-       VAR_PS_PIPEL_ACTION, DEF_PS_PIPEL_ACTION, &var_ps_pipel_action, 1, 0,
-       VAR_PS_NSMTP_ACTION, DEF_PS_NSMTP_ACTION, &var_ps_nsmtp_action, 1, 0,
-       VAR_PS_BARLF_ACTION, DEF_PS_BARLF_ACTION, &var_ps_barlf_action, 1, 0,
-       VAR_PS_WLIST_NETS, DEF_PS_WLIST_NETS, &var_ps_wlist_nets, 0, 0,
-       VAR_PS_BLIST_NETS, DEF_PS_BLIST_NETS, &var_ps_blist_nets, 0, 0,
-       VAR_PS_BLIST_ACTION, DEF_PS_BLIST_ACTION, &var_ps_blist_action, 1, 0,
-       VAR_PS_FORBID_CMDS, DEF_PS_FORBID_CMDS, &var_ps_forbid_cmds, 0, 0,
-       VAR_PS_DNSBL_REPLY, DEF_PS_DNSBL_REPLY, &var_ps_dnsbl_reply, 0, 0,
+       VAR_SMTPD_EHLO_DIS_WORDS, DEF_SMTPD_EHLO_DIS_WORDS, &var_smtpd_ehlo_dis_words, 0, 0,
+       VAR_SMTPD_EHLO_DIS_MAPS, DEF_SMTPD_EHLO_DIS_MAPS, &var_smtpd_ehlo_dis_maps, 0, 0,
+       VAR_SMTPD_TLS_LEVEL, DEF_SMTPD_TLS_LEVEL, &var_smtpd_tls_level, 0, 0,
+       VAR_PSC_CACHE_MAP, DEF_PSC_CACHE_MAP, &var_psc_cache_map, 0, 0,
+       VAR_PSC_PREGR_BANNER, DEF_PSC_PREGR_BANNER, &var_psc_pregr_banner, 0, 0,
+       VAR_PSC_PREGR_ACTION, DEF_PSC_PREGR_ACTION, &var_psc_pregr_action, 1, 0,
+       VAR_PSC_DNSBL_SITES, DEF_PSC_DNSBL_SITES, &var_psc_dnsbl_sites, 0, 0,
+       VAR_PSC_DNSBL_ACTION, DEF_PSC_DNSBL_ACTION, &var_psc_dnsbl_action, 1, 0,
+       VAR_PSC_PIPEL_ACTION, DEF_PSC_PIPEL_ACTION, &var_psc_pipel_action, 1, 0,
+       VAR_PSC_NSMTP_ACTION, DEF_PSC_NSMTP_ACTION, &var_psc_nsmtp_action, 1, 0,
+       VAR_PSC_BARLF_ACTION, DEF_PSC_BARLF_ACTION, &var_psc_barlf_action, 1, 0,
+       VAR_PSC_WLIST_NETS, DEF_PSC_WLIST_NETS, &var_psc_wlist_nets, 0, 0,
+       VAR_PSC_BLIST_NETS, DEF_PSC_BLIST_NETS, &var_psc_blist_nets, 0, 0,
+       VAR_PSC_BLIST_ACTION, DEF_PSC_BLIST_ACTION, &var_psc_blist_action, 1, 0,
+       VAR_PSC_FORBID_CMDS, DEF_PSC_FORBID_CMDS, &var_psc_forbid_cmds, 0, 0,
+       VAR_PSC_EHLO_DIS_WORDS, DEF_PSC_EHLO_DIS_WORDS, &var_psc_ehlo_dis_words, 0, 0,
+       VAR_PSC_EHLO_DIS_MAPS, DEF_PSC_EHLO_DIS_MAPS, &var_psc_ehlo_dis_maps, 0, 0,
+       VAR_PSC_DNSBL_REPLY, DEF_PSC_DNSBL_REPLY, &var_psc_dnsbl_reply, 0, 0,
+       VAR_PSC_TLS_LEVEL, DEF_PSC_TLS_LEVEL, &var_psc_tls_level, 0, 0,
        0,
     };
     static const CONFIG_INT_TABLE int_table[] = {
        VAR_PROC_LIMIT, DEF_PROC_LIMIT, &var_proc_limit, 1, 0,
-       VAR_PS_DNSBL_THRESH, DEF_PS_DNSBL_THRESH, &var_ps_dnsbl_thresh, 0, 0,
-       VAR_PS_CMD_COUNT, DEF_PS_CMD_COUNT, &var_ps_cmd_count, 1, 0,
+       VAR_PSC_DNSBL_THRESH, DEF_PSC_DNSBL_THRESH, &var_psc_dnsbl_thresh, 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,
     };
     static const CONFIG_NINT_TABLE nint_table[] = {
-       VAR_PS_POST_QLIMIT, DEF_PS_POST_QLIMIT, &var_ps_post_queue_limit, 5, 0,
-       VAR_PS_PRE_QLIMIT, DEF_PS_PRE_QLIMIT, &var_ps_pre_queue_limit, 10, 0,
-       VAR_PS_CCONN_LIMIT, DEF_PS_CCONN_LIMIT, &var_ps_cconn_limit, 0, 0,
+       VAR_PSC_POST_QLIMIT, DEF_PSC_POST_QLIMIT, &var_psc_post_queue_limit, 5, 0,
+       VAR_PSC_PRE_QLIMIT, DEF_PSC_PRE_QLIMIT, &var_psc_pre_queue_limit, 10, 0,
+       VAR_PSC_CCONN_LIMIT, DEF_PSC_CCONN_LIMIT, &var_psc_cconn_limit, 0, 0,
        0,
     };
     static const CONFIG_TIME_TABLE time_table[] = {
-       VAR_PS_GREET_WAIT, DEF_PS_GREET_WAIT, &var_ps_greet_wait, 1, 0,
-       VAR_PS_PREGR_TTL, DEF_PS_PREGR_TTL, &var_ps_pregr_ttl, 1, 0,
-       VAR_PS_DNSBL_TTL, DEF_PS_DNSBL_TTL, &var_ps_dnsbl_ttl, 1, 0,
-       VAR_PS_PIPEL_TTL, DEF_PS_PIPEL_TTL, &var_ps_pipel_ttl, 1, 0,
-       VAR_PS_NSMTP_TTL, DEF_PS_NSMTP_TTL, &var_ps_nsmtp_ttl, 1, 0,
-       VAR_PS_BARLF_TTL, DEF_PS_BARLF_TTL, &var_ps_barlf_ttl, 1, 0,
-       VAR_PS_CACHE_RET, DEF_PS_CACHE_RET, &var_ps_cache_ret, 1, 0,
-       VAR_PS_CACHE_SCAN, DEF_PS_CACHE_SCAN, &var_ps_cache_scan, 1, 0,
-       VAR_PS_WATCHDOG, DEF_PS_WATCHDOG, &var_ps_watchdog, 10, 0,
+       VAR_PSC_GREET_WAIT, DEF_PSC_GREET_WAIT, &var_psc_greet_wait, 1, 0,
+       VAR_PSC_PREGR_TTL, DEF_PSC_PREGR_TTL, &var_psc_pregr_ttl, 1, 0,
+       VAR_PSC_DNSBL_TTL, DEF_PSC_DNSBL_TTL, &var_psc_dnsbl_ttl, 1, 0,
+       VAR_PSC_PIPEL_TTL, DEF_PSC_PIPEL_TTL, &var_psc_pipel_ttl, 1, 0,
+       VAR_PSC_NSMTP_TTL, DEF_PSC_NSMTP_TTL, &var_psc_nsmtp_ttl, 1, 0,
+       VAR_PSC_BARLF_TTL, DEF_PSC_BARLF_TTL, &var_psc_barlf_ttl, 1, 0,
+       VAR_PSC_CACHE_RET, DEF_PSC_CACHE_RET, &var_psc_cache_ret, 1, 0,
+       VAR_PSC_CACHE_SCAN, DEF_PSC_CACHE_SCAN, &var_psc_cache_scan, 1, 0,
+       VAR_PSC_WATCHDOG, DEF_PSC_WATCHDOG, &var_psc_watchdog, 10, 0,
        0,
     };
     static const CONFIG_BOOL_TABLE bool_table[] = {
        VAR_HELO_REQUIRED, DEF_HELO_REQUIRED, &var_helo_required,
        VAR_DISABLE_VRFY_CMD, DEF_DISABLE_VRFY_CMD, &var_disable_vrfy_cmd,
-       VAR_PS_PIPEL_ENABLE, DEF_PS_PIPEL_ENABLE, &var_ps_pipel_enable,
-       VAR_PS_NSMTP_ENABLE, DEF_PS_NSMTP_ENABLE, &var_ps_nsmtp_enable,
-       VAR_PS_BARLF_ENABLE, DEF_PS_BARLF_ENABLE, &var_ps_barlf_enable,
+       VAR_SMTPD_USE_TLS, DEF_SMTPD_USE_TLS, &var_smtpd_use_tls,
+       VAR_SMTPD_ENFORCE_TLS, DEF_SMTPD_ENFORCE_TLS, &var_smtpd_enforce_tls,
+       VAR_PSC_PIPEL_ENABLE, DEF_PSC_PIPEL_ENABLE, &var_psc_pipel_enable,
+       VAR_PSC_NSMTP_ENABLE, DEF_PSC_NSMTP_ENABLE, &var_psc_nsmtp_enable,
+       VAR_PSC_BARLF_ENABLE, DEF_PSC_BARLF_ENABLE, &var_psc_barlf_enable,
        0,
     };
     static const CONFIG_RAW_TABLE raw_table[] = {
-       VAR_PS_CMD_TIME, DEF_PS_CMD_TIME, &var_ps_cmd_time, 1, 0,
+       VAR_PSC_CMD_TIME, DEF_PSC_CMD_TIME, &var_psc_cmd_time, 1, 0,
        0,
     };
     static const CONFIG_NBOOL_TABLE nbool_table[] = {
-       VAR_PS_HELO_REQUIRED, DEF_PS_HELO_REQUIRED, &var_ps_helo_required,
-       VAR_PS_DISABLE_VRFY, DEF_PS_DISABLE_VRFY, &var_ps_disable_vrfy,
+       VAR_PSC_HELO_REQUIRED, DEF_PSC_HELO_REQUIRED, &var_psc_helo_required,
+       VAR_PSC_DISABLE_VRFY, DEF_PSC_DISABLE_VRFY, &var_psc_disable_vrfy,
+       VAR_PSC_USE_TLS, DEF_PSC_USE_TLS, &var_psc_use_tls,
+       VAR_PSC_ENFORCE_TLS, DEF_PSC_ENFORCE_TLS, &var_psc_enforce_tls,
        0,
     };
 
@@ -914,7 +1017,7 @@ int     main(int argc, char **argv)
      */
     MAIL_VERSION_STAMP_ALLOCATE;
 
-    event_server_main(argc, argv, ps_service,
+    event_server_main(argc, argv, psc_service,
                      MAIL_SERVER_STR_TABLE, str_table,
                      MAIL_SERVER_INT_TABLE, int_table,
                      MAIL_SERVER_NINT_TABLE, nint_table,
@@ -924,9 +1027,10 @@ int     main(int argc, char **argv)
                      MAIL_SERVER_NBOOL_TABLE, nbool_table,
                      MAIL_SERVER_PRE_INIT, pre_jail_init,
                      MAIL_SERVER_POST_INIT, post_jail_init,
+                     MAIL_SERVER_PRE_ACCEPT, pre_accept,
                      MAIL_SERVER_SOLITARY,
-                     MAIL_SERVER_SLOW_EXIT, ps_drain,
-                     MAIL_SERVER_EXIT, ps_dump,
-                     MAIL_SERVER_WATCHDOG, &var_ps_watchdog,
+                     MAIL_SERVER_SLOW_EXIT, psc_drain,
+                     MAIL_SERVER_EXIT, psc_dump,
+                     MAIL_SERVER_WATCHDOG, &var_psc_watchdog,
                      0);
 }
index a93a036bb4e8e2dea8ef4aa3df38d63547c70ebf..c0885be85890656b9c57be2fd0d62f60d187ee1c 100644 (file)
@@ -30,7 +30,7 @@
  /*
   * Preliminary stuff, to be fixed.
   */
-#define PS_READ_BUF_SIZE       1024
+#define PSC_READ_BUF_SIZE      1024
 
  /*
   * Per-session state.
@@ -64,23 +64,25 @@ typedef struct {
     char   *sender;                    /* MAIL FROM */
     VSTRING *cmd_buffer;               /* command read buffer */
     int     read_state;                        /* command read state machine */
-} PS_STATE;
-
-#define PS_TIME_STAMP_NEW              (0)     /* test was never passed */
-#define PS_TIME_STAMP_DISABLED         (1)     /* never passed but disabled */
-#define PS_TIME_STAMP_INVALID          (-1)    /* must not be cached */
-
-#define PS_STATE_FLAG_NOFORWARD                (1<<0)  /* don't forward this session */
-#define PS_STATE_FLAG_UNUSED1          (1<<1)  /* use me! */
-#define PS_STATE_FLAG_UNUSED2          (1<<2)  /* use me! */
-#define PS_STATE_FLAG_NEW              (1<<3)  /* some test was never passed */
-#define PS_STATE_FLAG_BLIST_FAIL       (1<<4)  /* blacklisted */
-#define PS_STATE_FLAG_HANGUP           (1<<5)  /* NOT a test failure */
-#define PS_STATE_FLAG_CACHE_EXPIRED    (1<<6)  /* cache retention expired */
+    /* smtpd(8) compatibility */
+    int     ehlo_discard_mask;         /* EHLO filter */
+} PSC_STATE;
+
+#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 */
+
+#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! */
+#define PSC_STATE_FLAG_NEW             (1<<3)  /* some test was never passed */
+#define PSC_STATE_FLAG_BLIST_FAIL      (1<<4)  /* blacklisted */
+#define PSC_STATE_FLAG_HANGUP          (1<<5)  /* NOT a test failure */
+#define PSC_STATE_FLAG_CACHE_EXPIRED   (1<<6)  /* cache retention expired */
 
  /*
   * Important: every MUMBLE_TODO flag must have a MUMBLE_PASS flag, such that
-  * MUMBLE_PASS == PS_STATE_FLAGS_TODO_TO_PASS(MUMBLE_TODO).
+  * MUMBLE_PASS == PSC_STATE_FLAGS_TODO_TO_PASS(MUMBLE_TODO).
   * 
   * MUMBLE_TODO flags must not be cleared once raised. The _TODO_TO_PASS and
   * _TODO_TO_DONE macros depend on this to decide that a group of tests is
@@ -97,107 +99,107 @@ typedef struct {
   * We use MUMBLE_SKIP to indicate that a decision was either "fail" or
   * forced "pass".
   */
-#define PS_STATE_FLAGS_TODO_TO_PASS(todo_flags) ((todo_flags) >> 1)
-#define PS_STATE_FLAGS_TODO_TO_DONE(todo_flags) ((todo_flags) << 1)
+#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 PS_STATE_FLAG_PENAL_UPDATE     (1<<6)  /* save new penalty */
-#define PS_STATE_FLAG_PENAL_FAIL       (1<<7)  /* penalty is active */
+#define PSC_STATE_FLAG_PENAL_UPDATE    (1<<6)  /* save new penalty */
+#define PSC_STATE_FLAG_PENAL_FAIL      (1<<7)  /* penalty is active */
 
-#define PS_STATE_FLAG_PREGR_FAIL       (1<<8)  /* failed pregreet test */
-#define PS_STATE_FLAG_PREGR_PASS       (1<<9)  /* passed pregreet test */
-#define PS_STATE_FLAG_PREGR_TODO       (1<<10) /* pregreet test expired */
-#define PS_STATE_FLAG_PREGR_DONE       (1<<11) /* decision is final */
+#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 PS_STATE_FLAG_DNSBL_FAIL       (1<<12) /* failed DNSBL test */
-#define PS_STATE_FLAG_DNSBL_PASS       (1<<13) /* passed DNSBL test */
-#define PS_STATE_FLAG_DNSBL_TODO       (1<<14) /* DNSBL test expired */
-#define PS_STATE_FLAG_DNSBL_DONE       (1<<15) /* 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 PS_STATE_FLAG_PIPEL_FAIL       (1<<20) /* failed pipelining test */
-#define PS_STATE_FLAG_PIPEL_PASS       (1<<21) /* passed pipelining test */
-#define PS_STATE_FLAG_PIPEL_TODO       (1<<22) /* pipelining test expired */
-#define PS_STATE_FLAG_PIPEL_SKIP       (1<<23) /* action is already logged */
+#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 PS_STATE_FLAG_NSMTP_FAIL       (1<<24) /* failed non-SMTP test */
-#define PS_STATE_FLAG_NSMTP_PASS       (1<<25) /* passed non-SMTP test */
-#define PS_STATE_FLAG_NSMTP_TODO       (1<<26) /* non-SMTP test expired */
-#define PS_STATE_FLAG_NSMTP_SKIP       (1<<27) /* action is already logged */
+#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 */
 
-#define PS_STATE_FLAG_BARLF_FAIL       (1<<28) /* failed bare newline test */
-#define PS_STATE_FLAG_BARLF_PASS       (1<<29) /* passed bare newline test */
-#define PS_STATE_FLAG_BARLF_TODO       (1<<30) /* bare newline test expired */
-#define PS_STATE_FLAG_BARLF_SKIP       (1<<31) /* action is already logged */
+#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 */
 
  /*
   * Aggregates for individual tests.
   */
-#define PS_STATE_MASK_PREGR_TODO_FAIL \
-       (PS_STATE_FLAG_PREGR_TODO | PS_STATE_FLAG_PREGR_FAIL)
-#define PS_STATE_MASK_DNSBL_TODO_FAIL \
-       (PS_STATE_FLAG_DNSBL_TODO | PS_STATE_FLAG_DNSBL_FAIL)
-#define PS_STATE_MASK_PIPEL_TODO_FAIL \
-       (PS_STATE_FLAG_PIPEL_TODO | PS_STATE_FLAG_PIPEL_FAIL)
-#define PS_STATE_MASK_NSMTP_TODO_FAIL \
-       (PS_STATE_FLAG_NSMTP_TODO | PS_STATE_FLAG_NSMTP_FAIL)
-#define PS_STATE_MASK_BARLF_TODO_FAIL \
-       (PS_STATE_FLAG_BARLF_TODO | PS_STATE_FLAG_BARLF_FAIL)
-
-#define PS_STATE_MASK_PIPEL_TODO_SKIP \
-       (PS_STATE_FLAG_PIPEL_TODO | PS_STATE_FLAG_PIPEL_SKIP)
-#define PS_STATE_MASK_NSMTP_TODO_SKIP \
-       (PS_STATE_FLAG_NSMTP_TODO | PS_STATE_FLAG_NSMTP_SKIP)
-#define PS_STATE_MASK_BARLF_TODO_SKIP \
-       (PS_STATE_FLAG_BARLF_TODO | PS_STATE_FLAG_BARLF_SKIP)
-
-#define PS_STATE_MASK_PIPEL_TODO_PASS_FAIL \
-       (PS_STATE_MASK_PIPEL_TODO_FAIL | PS_STATE_FLAG_PIPEL_PASS)
-#define PS_STATE_MASK_NSMTP_TODO_PASS_FAIL \
-       (PS_STATE_MASK_NSMTP_TODO_FAIL | PS_STATE_FLAG_NSMTP_PASS)
-#define PS_STATE_MASK_BARLF_TODO_PASS_FAIL \
-       (PS_STATE_MASK_BARLF_TODO_FAIL | PS_STATE_FLAG_BARLF_PASS)
+#define PSC_STATE_MASK_PREGR_TODO_FAIL \
+       (PSC_STATE_FLAG_PREGR_TODO | PSC_STATE_FLAG_PREGR_FAIL)
+#define PSC_STATE_MASK_DNSBL_TODO_FAIL \
+       (PSC_STATE_FLAG_DNSBL_TODO | PSC_STATE_FLAG_DNSBL_FAIL)
+#define PSC_STATE_MASK_PIPEL_TODO_FAIL \
+       (PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_PIPEL_FAIL)
+#define PSC_STATE_MASK_NSMTP_TODO_FAIL \
+       (PSC_STATE_FLAG_NSMTP_TODO | PSC_STATE_FLAG_NSMTP_FAIL)
+#define PSC_STATE_MASK_BARLF_TODO_FAIL \
+       (PSC_STATE_FLAG_BARLF_TODO | PSC_STATE_FLAG_BARLF_FAIL)
+
+#define PSC_STATE_MASK_PIPEL_TODO_SKIP \
+       (PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_PIPEL_SKIP)
+#define PSC_STATE_MASK_NSMTP_TODO_SKIP \
+       (PSC_STATE_FLAG_NSMTP_TODO | PSC_STATE_FLAG_NSMTP_SKIP)
+#define PSC_STATE_MASK_BARLF_TODO_SKIP \
+       (PSC_STATE_FLAG_BARLF_TODO | PSC_STATE_FLAG_BARLF_SKIP)
+
+#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 \
+       (PSC_STATE_MASK_NSMTP_TODO_FAIL | PSC_STATE_FLAG_NSMTP_PASS)
+#define PSC_STATE_MASK_BARLF_TODO_PASS_FAIL \
+       (PSC_STATE_MASK_BARLF_TODO_FAIL | PSC_STATE_FLAG_BARLF_PASS)
 
  /*
   * Separate aggregates for early tests and deep tests.
   */
-#define PS_STATE_MASK_EARLY_DONE \
-       (PS_STATE_FLAG_PREGR_DONE | PS_STATE_FLAG_DNSBL_DONE)
-#define PS_STATE_MASK_EARLY_TODO \
-       (PS_STATE_FLAG_PREGR_TODO | PS_STATE_FLAG_DNSBL_TODO)
-#define PS_STATE_MASK_EARLY_PASS \
-       (PS_STATE_FLAG_PREGR_PASS | PS_STATE_FLAG_DNSBL_PASS)
-#define PS_STATE_MASK_EARLY_FAIL \
-       (PS_STATE_FLAG_PREGR_FAIL | PS_STATE_FLAG_DNSBL_FAIL)
-
-#define PS_STATE_MASK_SMTPD_TODO \
-       (PS_STATE_FLAG_PIPEL_TODO | PS_STATE_FLAG_NSMTP_TODO | \
-       PS_STATE_FLAG_BARLF_TODO)
-#define PS_STATE_MASK_SMTPD_PASS \
-       (PS_STATE_FLAG_PIPEL_PASS | PS_STATE_FLAG_NSMTP_PASS | \
-       PS_STATE_FLAG_BARLF_PASS)
-#define PS_STATE_MASK_SMTPD_FAIL \
-       (PS_STATE_FLAG_PIPEL_FAIL | PS_STATE_FLAG_NSMTP_FAIL | \
-       PS_STATE_FLAG_BARLF_FAIL)
+#define PSC_STATE_MASK_EARLY_DONE \
+       (PSC_STATE_FLAG_PREGR_DONE | PSC_STATE_FLAG_DNSBL_DONE)
+#define PSC_STATE_MASK_EARLY_TODO \
+       (PSC_STATE_FLAG_PREGR_TODO | PSC_STATE_FLAG_DNSBL_TODO)
+#define PSC_STATE_MASK_EARLY_PASS \
+       (PSC_STATE_FLAG_PREGR_PASS | PSC_STATE_FLAG_DNSBL_PASS)
+#define PSC_STATE_MASK_EARLY_FAIL \
+       (PSC_STATE_FLAG_PREGR_FAIL | PSC_STATE_FLAG_DNSBL_FAIL)
+
+#define PSC_STATE_MASK_SMTPD_TODO \
+       (PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_NSMTP_TODO | \
+       PSC_STATE_FLAG_BARLF_TODO)
+#define PSC_STATE_MASK_SMTPD_PASS \
+       (PSC_STATE_FLAG_PIPEL_PASS | PSC_STATE_FLAG_NSMTP_PASS | \
+       PSC_STATE_FLAG_BARLF_PASS)
+#define PSC_STATE_MASK_SMTPD_FAIL \
+       (PSC_STATE_FLAG_PIPEL_FAIL | PSC_STATE_FLAG_NSMTP_FAIL | \
+       PSC_STATE_FLAG_BARLF_FAIL)
 
  /*
   * Super-aggregates for all tests combined.
   */
-#define PS_STATE_MASK_ANY_FAIL \
-       (PS_STATE_FLAG_BLIST_FAIL | PS_STATE_FLAG_PENAL_FAIL | \
-       PS_STATE_MASK_EARLY_FAIL | PS_STATE_MASK_SMTPD_FAIL)
+#define PSC_STATE_MASK_ANY_FAIL \
+       (PSC_STATE_FLAG_BLIST_FAIL | PSC_STATE_FLAG_PENAL_FAIL | \
+       PSC_STATE_MASK_EARLY_FAIL | PSC_STATE_MASK_SMTPD_FAIL)
 
-#define PS_STATE_MASK_ANY_PASS \
-       (PS_STATE_MASK_EARLY_PASS | PS_STATE_MASK_SMTPD_PASS)
+#define PSC_STATE_MASK_ANY_PASS \
+       (PSC_STATE_MASK_EARLY_PASS | PSC_STATE_MASK_SMTPD_PASS)
 
-#define PS_STATE_MASK_ANY_TODO \
-       (PS_STATE_MASK_EARLY_TODO | PS_STATE_MASK_SMTPD_TODO)
+#define PSC_STATE_MASK_ANY_TODO \
+       (PSC_STATE_MASK_EARLY_TODO | PSC_STATE_MASK_SMTPD_TODO)
 
-#define PS_STATE_MASK_ANY_TODO_FAIL \
-       (PS_STATE_MASK_ANY_TODO | PS_STATE_MASK_ANY_FAIL)
+#define PSC_STATE_MASK_ANY_TODO_FAIL \
+       (PSC_STATE_MASK_ANY_TODO | PSC_STATE_MASK_ANY_FAIL)
 
-#define PS_STATE_MASK_ANY_UPDATE \
-       (PS_STATE_MASK_ANY_PASS | PS_STATE_FLAG_PENAL_UPDATE)
+#define PSC_STATE_MASK_ANY_UPDATE \
+       (PSC_STATE_MASK_ANY_PASS | PSC_STATE_FLAG_PENAL_UPDATE)
 
  /*
   * See log_adhoc.c for discussion.
@@ -207,7 +209,7 @@ typedef struct {
     int     dt_usec;                   /* make sure it's signed */
 } DELTA_TIME;
 
-#define PS_CALC_DELTA(x, y, z) \
+#define PSC_CALC_DELTA(x, y, z) \
     do { \
        (x).dt_sec = (y).tv_sec - (z).tv_sec; \
        (x).dt_usec = (y).tv_usec - (z).tv_usec; \
@@ -229,25 +231,25 @@ typedef struct {
   * Event management.
   */
 
-/* PS_READ_EVENT_REQUEST - prepare for transition to next state */
+/* PSC_READ_EVENT_REQUEST - prepare for transition to next state */
 
-#define PS_READ_EVENT_REQUEST(fd, action, context, timeout) do { \
+#define PSC_READ_EVENT_REQUEST(fd, action, context, timeout) do { \
        if (msg_verbose > 1) \
            msg_info("%s: read-request fd=%d", myname, (fd)); \
        event_enable_read((fd), (action), (context)); \
        event_request_timer((action), (context), (timeout)); \
     } while (0)
 
-#define PS_READ_EVENT_REQUEST2(fd, read_act, time_act, context, timeout) do { \
+#define PSC_READ_EVENT_REQUEST2(fd, read_act, time_act, context, timeout) do { \
        if (msg_verbose > 1) \
            msg_info("%s: read-request fd=%d", myname, (fd)); \
        event_enable_read((fd), (read_act), (context)); \
        event_request_timer((time_act), (context), (timeout)); \
     } while (0)
 
-/* PS_CLEAR_EVENT_REQUEST - complete state transition */
+/* PSC_CLEAR_EVENT_REQUEST - complete state transition */
 
-#define PS_CLEAR_EVENT_REQUEST(fd, time_act, context) do { \
+#define PSC_CLEAR_EVENT_REQUEST(fd, time_act, context) do { \
        if (msg_verbose > 1) \
            msg_info("%s: clear-request fd=%d", myname, (fd)); \
        event_disable_readwrite(fd); \
@@ -257,55 +259,55 @@ typedef struct {
  /*
   * Failure enforcement policies.
   */
-#define PS_NAME_ACT_DROP       "drop"
-#define PS_NAME_ACT_ENFORCE    "enforce"
-#define PS_NAME_ACT_IGNORE     "ignore"
-#define PS_NAME_ACT_CONT       "continue"
+#define PSC_NAME_ACT_DROP      "drop"
+#define PSC_NAME_ACT_ENFORCE   "enforce"
+#define PSC_NAME_ACT_IGNORE    "ignore"
+#define PSC_NAME_ACT_CONT      "continue"
 
-#define PS_ACT_DROP            1
-#define PS_ACT_ENFORCE         2
-#define PS_ACT_IGNORE          3
+#define PSC_ACT_DROP           1
+#define PSC_ACT_ENFORCE                2
+#define PSC_ACT_IGNORE         3
 
  /*
   * Global variables.
   */
-extern int ps_check_queue_length;      /* connections being checked */
-extern int ps_post_queue_length;       /* being sent to real SMTPD */
-extern DICT_CACHE *ps_cache_map;       /* cache table handle */
-extern VSTRING *ps_temp;               /* scratchpad */
-extern char *ps_smtpd_service_name;    /* path to real SMTPD */
-extern int ps_pregr_action;            /* PS_ACT_DROP etc. */
-extern int ps_dnsbl_action;            /* PS_ACT_DROP etc. */
-extern int ps_pipel_action;            /* PS_ACT_DROP etc. */
-extern int ps_nsmtp_action;            /* PS_ACT_DROP etc. */
-extern int ps_barlf_action;            /* PS_ACT_DROP etc. */
-extern int ps_min_ttl;                 /* Update with new tests! */
-extern int ps_max_ttl;                 /* Update with new tests! */
-extern STRING_LIST *ps_forbid_cmds;    /* CONNECT GET POST */
-extern int ps_stress_greet_wait;       /* stressed greet wait */
-extern int ps_normal_greet_wait;       /* stressed greet wait */
-extern int ps_stress_cmd_time_limit;   /* stressed command limit */
-extern int ps_normal_cmd_time_limit;   /* normal command time limit */
-extern int ps_stress;                  /* stress level */
-extern int ps_check_queue_length_lowat;        /* stress low-water mark */
-extern int ps_check_queue_length_hiwat;        /* stress high-water mark */
-extern DICT *ps_dnsbl_reply;           /* DNSBL name mapper */
-extern HTABLE *ps_client_concurrency;  /* per-client concurrency */
-
-#define PS_EFF_GREET_WAIT \
-       (ps_stress ? ps_stress_greet_wait : ps_normal_greet_wait)
-#define PS_EFF_CMD_TIME_LIMIT \
-       (ps_stress ? ps_stress_cmd_time_limit : ps_normal_cmd_time_limit)
+extern int psc_check_queue_length;     /* connections being checked */
+extern int psc_post_queue_length;      /* being sent to real SMTPD */
+extern DICT_CACHE *psc_cache_map;      /* cache table handle */
+extern VSTRING *psc_temp;              /* scratchpad */
+extern char *psc_smtpd_service_name;   /* path to real SMTPD */
+extern int psc_pregr_action;           /* PSC_ACT_DROP etc. */
+extern int psc_dnsbl_action;           /* PSC_ACT_DROP etc. */
+extern int psc_pipel_action;           /* PSC_ACT_DROP etc. */
+extern int psc_nsmtp_action;           /* PSC_ACT_DROP etc. */
+extern int psc_barlf_action;           /* PSC_ACT_DROP etc. */
+extern int psc_min_ttl;                        /* Update with new tests! */
+extern int psc_max_ttl;                        /* Update with new tests! */
+extern STRING_LIST *psc_forbid_cmds;   /* CONNECT GET POST */
+extern int psc_stress_greet_wait;      /* stressed greet wait */
+extern int psc_normal_greet_wait;      /* stressed greet wait */
+extern int psc_stress_cmd_time_limit;  /* stressed command limit */
+extern int psc_normal_cmd_time_limit;  /* normal command time limit */
+extern int psc_stress;                 /* stress level */
+extern int psc_check_queue_length_lowat;/* stress low-water mark */
+extern int psc_check_queue_length_hiwat;/* stress high-water mark */
+extern DICT *psc_dnsbl_reply;          /* DNSBL name mapper */
+extern HTABLE *psc_client_concurrency; /* per-client concurrency */
+
+#define PSC_EFF_GREET_WAIT \
+       (psc_stress ? psc_stress_greet_wait : psc_normal_greet_wait)
+#define PSC_EFF_CMD_TIME_LIMIT \
+       (psc_stress ? psc_stress_cmd_time_limit : psc_normal_cmd_time_limit)
 
  /*
   * String plumbing macros.
   */
-#define PS_STRING_UPDATE(str, text) do { \
+#define PSC_STRING_UPDATE(str, text) do { \
        if (str) myfree(str); \
        (str) = ((text) ? mystrdup(text) : 0); \
     } while (0)
 
-#define PS_STRING_RESET(str) do { \
+#define PSC_STRING_RESET(str) do { \
        if (str) { \
            myfree(str); \
            (str) = 0; \
@@ -321,126 +323,133 @@ extern HTABLE *ps_client_concurrency;   /* per-client concurrency */
  /*
   * postscreen_state.c
   */
-#define PS_CLIENT_ADDR_PORT(state) \
+#define PSC_CLIENT_ADDR_PORT(state) \
        (state)->smtp_client_addr, (state)->smtp_client_port
 
-#define PS_PASS_SESSION_STATE(state, what, bits) do { \
+#define PSC_PASS_SESSION_STATE(state, what, bits) do { \
        if (msg_verbose) \
-           msg_info("PASS %s [%s]:%s", (what), PS_CLIENT_ADDR_PORT(state)); \
+           msg_info("PASS %s [%s]:%s", (what), PSC_CLIENT_ADDR_PORT(state)); \
        (state)->flags |= (bits); \
     } while (0)
-#define PS_FAIL_SESSION_STATE(state, bits) do { \
+#define PSC_FAIL_SESSION_STATE(state, bits) do { \
        if (msg_verbose) \
-           msg_info("FAIL [%s]:%s", PS_CLIENT_ADDR_PORT(state)); \
+           msg_info("FAIL [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
        (state)->flags |= (bits); \
     } while (0)
-#define PS_SKIP_SESSION_STATE(state, what, bits) do { \
+#define PSC_SKIP_SESSION_STATE(state, what, bits) do { \
        if (msg_verbose) \
-           msg_info("SKIP %s [%s]:%s", (what), PS_CLIENT_ADDR_PORT(state)); \
+           msg_info("SKIP %s [%s]:%s", (what), PSC_CLIENT_ADDR_PORT(state)); \
        (state)->flags |= (bits); \
     } while (0)
-#define PS_DROP_SESSION_STATE(state, reply) do { \
+#define PSC_DROP_SESSION_STATE(state, reply) do { \
        if (msg_verbose) \
-           msg_info("DROP [%s]:%s", PS_CLIENT_ADDR_PORT(state)); \
-       (state)->flags |= PS_STATE_FLAG_NOFORWARD; \
+           msg_info("DROP [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
+       (state)->flags |= PSC_STATE_FLAG_NOFORWARD; \
        (state)->final_reply = (reply); \
-       ps_conclude(state); \
+       psc_conclude(state); \
     } while (0)
-#define PS_ENFORCE_SESSION_STATE(state, reply) do { \
+#define PSC_ENFORCE_SESSION_STATE(state, reply) do { \
        if (msg_verbose) \
-           msg_info("ENFORCE [%s]:%s", PS_CLIENT_ADDR_PORT(state)); \
+           msg_info("ENFORCE [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
        (state)->rcpt_reply = (reply); \
-       (state)->flags |= PS_STATE_FLAG_NOFORWARD; \
+       (state)->flags |= PSC_STATE_FLAG_NOFORWARD; \
     } while (0)
-#define PS_UNPASS_SESSION_STATE(state, bits) do { \
+#define PSC_UNPASS_SESSION_STATE(state, bits) do { \
        if (msg_verbose) \
-           msg_info("UNPASS [%s]:%s", PS_CLIENT_ADDR_PORT(state)); \
+           msg_info("UNPASS [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
        (state)->flags &= ~(bits); \
     } while (0)
-#define PS_UNFAIL_SESSION_STATE(state, bits) do { \
+#define PSC_UNFAIL_SESSION_STATE(state, bits) do { \
        if (msg_verbose) \
-           msg_info("UNFAIL [%s]:%s", PS_CLIENT_ADDR_PORT(state)); \
+           msg_info("UNFAIL [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
        (state)->flags &= ~(bits); \
     } while (0)
-#define PS_ADD_SERVER_STATE(state, fd) do { \
+#define PSC_ADD_SERVER_STATE(state, fd) do { \
        (state)->smtp_server_fd = (fd); \
-       ps_post_queue_length++; \
+       psc_post_queue_length++; \
     } while (0)
-#define PS_DEL_CLIENT_STATE(state) do { \
+#define PSC_DEL_CLIENT_STATE(state) do { \
        event_server_disconnect((state)->smtp_client_stream); \
        (state)->smtp_client_stream = 0; \
-       ps_check_queue_length--; \
+       psc_check_queue_length--; \
     } while (0)
-extern PS_STATE *ps_new_session_state(VSTREAM *, const char *, const char *);
-extern void ps_free_session_state(PS_STATE *);
-extern const char *ps_print_state_flags(int, const char *);
+extern PSC_STATE *psc_new_session_state(VSTREAM *, const char *, const char *);
+extern void psc_free_session_state(PSC_STATE *);
+extern const char *psc_print_state_flags(int, const char *);
 
  /*
   * postscreen_dict.c
   */
-extern int ps_addr_match_list_match(ADDR_MATCH_LIST *, const char *);
-extern const char *ps_cache_lookup(DICT_CACHE *, const char *);
-extern void ps_cache_update(DICT_CACHE *, const char *, const char *);
+extern int psc_addr_match_list_match(ADDR_MATCH_LIST *, const char *);
+extern const char *psc_cache_lookup(DICT_CACHE *, const char *);
+extern void psc_cache_update(DICT_CACHE *, const char *, const char *);
 
  /*
   * postscreen_dnsbl.c
   */
-extern void ps_dnsbl_init(void);
-extern int ps_dnsbl_retrieve(const char *, const char **, int);
-extern int ps_dnsbl_request(const char *, void (*) (int, char *), char *);
+extern void psc_dnsbl_init(void);
+extern int psc_dnsbl_retrieve(const char *, const char **, int);
+extern int psc_dnsbl_request(const char *, void (*) (int, char *), char *);
 
  /*
   * postscreen_tests.c
   */
-#define PS_INIT_TESTS(dst) do { \
+#define PSC_INIT_TESTS(dst) do { \
        (dst)->flags = 0; \
-       (dst)->pregr_stamp = PS_TIME_STAMP_INVALID; \
-       (dst)->dnsbl_stamp = PS_TIME_STAMP_INVALID; \
-       (dst)->pipel_stamp = PS_TIME_STAMP_INVALID; \
-       (dst)->barlf_stamp = PS_TIME_STAMP_INVALID; \
-       (dst)->penal_stamp = PS_TIME_STAMP_INVALID; \
+       (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; \
     } while (0)
-#define PS_BEGIN_TESTS(state, name) do { \
+#define PSC_BEGIN_TESTS(state, name) do { \
        (state)->test_name = (name); \
        GETTIMEOFDAY(&(state)->start_time); \
     } while (0)
-extern void ps_new_tests(PS_STATE *);
-extern void ps_parse_tests(PS_STATE *, const char *, time_t);
-extern char *ps_print_tests(VSTRING *, PS_STATE *);
-extern char *ps_print_grey_key(VSTRING *, const char *, const char *, const char *, const char *);
+extern void psc_new_tests(PSC_STATE *);
+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 *);
 
-#define PS_MIN(x, y) ((x) < (y) ? (x) : (y))
-#define PS_MAX(x, y) ((x) > (y) ? (x) : (y))
+#define PSC_MIN(x, y) ((x) < (y) ? (x) : (y))
+#define PSC_MAX(x, y) ((x) > (y) ? (x) : (y))
 
  /*
   * postscreen_early.c
   */
-extern void ps_early_tests(PS_STATE *);
-extern void ps_early_init(void);
+extern void psc_early_tests(PSC_STATE *);
+extern void psc_early_init(void);
 
  /*
   * postscreen_smtpd.c
   */
-extern void ps_smtpd_tests(PS_STATE *);
-extern void ps_smtpd_init(void);
+extern void psc_smtpd_tests(PSC_STATE *);
+extern void psc_smtpd_init(void);
+extern void psc_smtpd_pre_jail_init(void);
 
  /*
   * postscreen_misc.c
   */
-extern char *ps_format_delta_time(VSTRING *, struct timeval, DELTA_TIME *);
-extern void ps_conclude(PS_STATE *);
-extern void ps_hangup_event(PS_STATE *);
+extern char *psc_format_delta_time(VSTRING *, struct timeval, DELTA_TIME *);
+extern void psc_conclude(PSC_STATE *);
+extern void psc_hangup_event(PSC_STATE *);
 
  /*
   * postscreen_send.c
   */
-#define PS_SEND_REPLY(state, text) \
-    ps_send_reply(vstream_fileno((state)->smtp_client_stream), \
+#define PSC_SEND_REPLY(state, text) \
+    psc_send_reply(vstream_fileno((state)->smtp_client_stream), \
                  (state)->smtp_client_addr, \
                  (state)->smtp_client_port, \
                  (text))
-extern int ps_send_reply(int, const char *, const char *, const char *);
-extern void ps_send_socket(PS_STATE *);
+extern int psc_send_reply(int, const char *, const char *, const char *);
+extern void psc_send_socket(PSC_STATE *);
+
+ /*
+  * postscreen_starttls.c
+  */
+extern void psc_starttls_open(PSC_STATE *, EVENT_NOTIFY_FN);
 
 /* LICENSE
 /* .ad
index 03a92b7e2394af9df03473e0eca3d00986fd29eb..92c0ba450167e3e991234e68dfe158ddd218a0f3 100644 (file)
@@ -6,15 +6,15 @@
 /* SYNOPSIS
 /*     #include <postscreen.h>
 /*
-/*     int     ps_addr_match_list_match(match_list, client_addr)
+/*     int     psc_addr_match_list_match(match_list, client_addr)
 /*     ADDR_MATCH_LIST *match_list;
 /*     const char *client_addr;
 /*
-/*     const char *ps_cache_lookup(DICT_CACHE *cache, const char *key)
+/*     const char *psc_cache_lookup(DICT_CACHE *cache, const char *key)
 /*     DICT_CACHE *cache;
 /*     const char *key;
 /*
-/*     void    ps_cache_update(cache, key, value)
+/*     void    psc_cache_update(cache, key, value)
 /*     DICT_CACHE *cache;
 /*     const char *key;
 /*     const char *value;
 /*     access functions.  The functions log a warning when table
 /*     access takes a non-trivial amount of time.
 /*
-/*     ps_addr_match_list_match() is a wrapper around
+/*     psc_addr_match_list_match() is a wrapper around
 /*     addr_match_list_match().
 /*
-/*     ps_cache_lookup() and ps_cache_update() are wrappers around
+/*     psc_cache_lookup() and psc_cache_update() are wrappers around
 /*     the corresponding dict_cache() methods.
 /* LICENSE
 /* .ad
  /*
   * Monitor time-critical operations.
   */
-#define PS_GET_TIME_BEFORE_LOOKUP \
+#define PSC_GET_TIME_BEFORE_LOOKUP \
     struct timeval _before, _after; \
     DELTA_TIME _delta; \
     GETTIMEOFDAY(&_before);
 
-#define PS_DELTA_MS(d) ((d).dt_sec * 1000 + (d).dt_usec / 1000)
+#define PSC_DELTA_MS(d) ((d).dt_sec * 1000 + (d).dt_usec / 1000)
 
-#define PS_CHECK_TIME_AFTER_LOOKUP(table, action) \
+#define PSC_CHECK_TIME_AFTER_LOOKUP(table, action) \
     GETTIMEOFDAY(&_after); \
-    PS_CALC_DELTA(_delta, _after, _before); \
+    PSC_CALC_DELTA(_delta, _after, _before); \
     if (_delta.dt_sec > 1 || _delta.dt_usec > 100000) \
         msg_warn("%s: %s %s took %d ms", \
-                 myname, (table), (action), PS_DELTA_MS(_delta));
+                 myname, (table), (action), PSC_DELTA_MS(_delta));
 
-/* ps_addr_match_list_match - time-critical address list lookup */
+/* psc_addr_match_list_match - time-critical address list lookup */
 
-int     ps_addr_match_list_match(ADDR_MATCH_LIST *addr_list,
-                                        const char *addr_str)
+int     psc_addr_match_list_match(ADDR_MATCH_LIST *addr_list,
+                                         const char *addr_str)
 {
-    const char *myname = "ps_addr_match_list_match";
+    const char *myname = "psc_addr_match_list_match";
     int     result;
 
-    PS_GET_TIME_BEFORE_LOOKUP;
+    PSC_GET_TIME_BEFORE_LOOKUP;
     result = addr_match_list_match(addr_list, addr_str);
-    PS_CHECK_TIME_AFTER_LOOKUP("address list", "lookup");
+    PSC_CHECK_TIME_AFTER_LOOKUP("address list", "lookup");
     return (result);
 }
 
-/* ps_cache_lookup - time-critical cache lookup */
+/* psc_cache_lookup - time-critical cache lookup */
 
-const char *ps_cache_lookup(DICT_CACHE *cache, const char *key)
+const char *psc_cache_lookup(DICT_CACHE *cache, const char *key)
 {
-    const char *myname = "ps_cache_lookup";
+    const char *myname = "psc_cache_lookup";
     const char *result;
 
-    PS_GET_TIME_BEFORE_LOOKUP;
+    PSC_GET_TIME_BEFORE_LOOKUP;
     result = dict_cache_lookup(cache, key);
-    PS_CHECK_TIME_AFTER_LOOKUP(dict_cache_name(cache), "lookup");
+    PSC_CHECK_TIME_AFTER_LOOKUP(dict_cache_name(cache), "lookup");
     return (result);
 }
 
-/* ps_cache_update - time-critical cache update */
+/* psc_cache_update - time-critical cache update */
 
-void    ps_cache_update(DICT_CACHE *cache, const char *key, const char *value)
+void    psc_cache_update(DICT_CACHE *cache, const char *key, const char *value)
 {
-    const char *myname = "ps_cache_update";
+    const char *myname = "psc_cache_update";
 
-    PS_GET_TIME_BEFORE_LOOKUP;
+    PSC_GET_TIME_BEFORE_LOOKUP;
     dict_cache_update(cache, key, value);
-    PS_CHECK_TIME_AFTER_LOOKUP(dict_cache_name(cache), "update");
+    PSC_CHECK_TIME_AFTER_LOOKUP(dict_cache_name(cache), "update");
 }
index 2b68b00972d15053e12a67156c472bfbec93b3d5..81085892db70076037a1132782a4d4ca11de07cb 100644 (file)
@@ -6,14 +6,14 @@
 /* SYNOPSIS
 /*     #include <postscreen.h>
 /*
-/*     void    ps_dnsbl_init(void)
+/*     void    psc_dnsbl_init(void)
 /*
-/*     int     ps_dnsbl_request(client_addr, callback, context)
+/*     int     psc_dnsbl_request(client_addr, callback, context)
 /*     char    *client_addr;
 /*     void    (*callback)(int, char *);
 /*     char    *context;
 /*
-/*     int     ps_dnsbl_retrieve(client_addr, dnsbl_name, dnsbl_index)
+/*     int     psc_dnsbl_retrieve(client_addr, dnsbl_name, dnsbl_index)
 /*     char    *client_addr;
 /*     const char **dnsbl_name;
 /*     int     dnsbl_index;
 /*     Multiple requests for the same information are handled with
 /*     reference counts.
 /*
-/*     ps_dnsbl_init() initializes this module, and must be called
+/*     psc_dnsbl_init() initializes this module, and must be called
 /*     once before any of the other functions in this module.
 /*
-/*     ps_dnsbl_request() requests a blocklist score for the
+/*     psc_dnsbl_request() requests a blocklist score for the
 /*     specified client IP address and increments the reference
 /*     count.  The request completes in the background. The client
 /*     IP address must be in inet_ntop(3) output format.  The
 /*     on to the callback function. The callback should ignore its
 /*     first argument (it exists for compatibility with Postfix
 /*     generic event infrastructure).
-/*     The result value is the index for the ps_dnsbl_retrieve()
+/*     The result value is the index for the psc_dnsbl_retrieve()
 /*     call.
 /*
-/*     ps_dnsbl_retrieve() retrieves the result score requested with
-/*     ps_dnsbl_request() and decrements the reference count. It
+/*     psc_dnsbl_retrieve() retrieves the result score requested with
+/*     psc_dnsbl_request() and decrements the reference count. It
 /*     is an error to retrieve a score without requesting it first.
 /* LICENSE
 /* .ad
@@ -103,15 +103,15 @@ static HTABLE_INFO **dnsbl_site_list;     /* flattened cache */
 
 typedef struct {
     const char *safe_dnsbl;            /* from postscreen_dnsbl_reply_map */
-    struct PS_DNSBL_SITE *first;       /* list of (filter, weight) tuples */
-} PS_DNSBL_HEAD;
+    struct PSC_DNSBL_SITE *first;      /* list of (filter, weight) tuples */
+} PSC_DNSBL_HEAD;
 
-typedef struct PS_DNSBL_SITE {
+typedef struct PSC_DNSBL_SITE {
     char   *filter;                    /* printable filter (default: null) */
     char   *byte_codes;                        /* encoded filter (default: null) */
     int     weight;                    /* reply weight (default: 1) */
-    struct PS_DNSBL_SITE *next;                /* linked list */
-} PS_DNSBL_SITE;
+    struct PSC_DNSBL_SITE *next;       /* linked list */
+} PSC_DNSBL_SITE;
 
  /*
   * Per-client DNSBL scores.
@@ -132,7 +132,7 @@ static HTABLE *dnsbl_score_cache;   /* indexed by client address */
 typedef struct {
     void    (*callback) (int, char *); /* generic call-back routine */
     char   *context;                   /* generic call-back argument */
-} PS_CALL_BACK_ENTRY;
+} PSC_CALL_BACK_ENTRY;
 
 typedef struct {
     const char *dnsbl;                 /* one contributing DNSBL */
@@ -142,18 +142,18 @@ typedef struct {
     /* Call-back table support. */
     int     index;                     /* next table index */
     int     limit;                     /* last valid index */
-    PS_CALL_BACK_ENTRY table[1];       /* actually a bunch */
-} PS_DNSBL_SCORE;
+    PSC_CALL_BACK_ENTRY table[1];      /* actually a bunch */
+} PSC_DNSBL_SCORE;
 
-#define PS_CALL_BACK_INIT(sp) do { \
+#define PSC_CALL_BACK_INIT(sp) do { \
        (sp)->limit = 0; \
        (sp)->index = 0; \
     } while (0)
 
-#define PS_CALL_BACK_INDEX_OF_LAST(sp) ((sp)->index - 1)
+#define PSC_CALL_BACK_INDEX_OF_LAST(sp) ((sp)->index - 1)
 
-#define PS_CALL_BACK_CANCEL(sp, idx) do { \
-       PS_CALL_BACK_ENTRY *_cb_; \
+#define PSC_CALL_BACK_CANCEL(sp, idx) do { \
+       PSC_CALL_BACK_ENTRY *_cb_; \
        if ((idx) < 0 || (idx) >= (sp)->index) \
            msg_panic("%s: index %d must be >= 0 and < %d", \
                      myname, (idx), (sp)->index); \
@@ -163,30 +163,30 @@ typedef struct {
        _cb_->context = 0; \
     } while (0)
 
-#define PS_CALL_BACK_EXTEND(hp, sp) do { \
+#define PSC_CALL_BACK_EXTEND(hp, sp) do { \
        if ((sp)->index >= (sp)->limit) { \
            int _count_ = ((sp)->limit ? (sp)->limit * 2 : 5); \
            (hp)->value = myrealloc((char *) (sp), sizeof(*(sp)) + \
                                    _count_ * sizeof((sp)->table)); \
-           (sp) = (PS_DNSBL_SCORE *) (hp)->value; \
+           (sp) = (PSC_DNSBL_SCORE *) (hp)->value; \
            (sp)->limit = _count_; \
        } \
     } while (0)
 
-#define PS_CALL_BACK_ENTER(sp, fn, ctx) do { \
-       PS_CALL_BACK_ENTRY *_cb_ = (sp)->table + (sp)->index++; \
+#define PSC_CALL_BACK_ENTER(sp, fn, ctx) do { \
+       PSC_CALL_BACK_ENTRY *_cb_ = (sp)->table + (sp)->index++; \
        _cb_->callback = (fn); \
        _cb_->context = (ctx); \
     } while (0)
 
-#define PS_CALL_BACK_NOTIFY(sp, ev) do { \
-       PS_CALL_BACK_ENTRY *_cb_; \
+#define PSC_CALL_BACK_NOTIFY(sp, ev) do { \
+       PSC_CALL_BACK_ENTRY *_cb_; \
        for (_cb_ = (sp)->table; _cb_ < (sp)->table + (sp)->index; _cb_++) \
            if (_cb_->callback != 0) \
                _cb_->callback((ev), _cb_->context); \
     } while (0)
 
-#define PS_NULL_EVENT  (0)
+#define PSC_NULL_EVENT (0)
 
  /*
   * Per-request state.
@@ -199,15 +199,15 @@ static VSTRING *reply_client;             /* client address in DNSBLOG reply */
 static VSTRING *reply_dnsbl;           /* domain in DNSBLOG reply */
 static VSTRING *reply_addr;            /* adress list in DNSBLOG reply */
 
-/* ps_dnsbl_add_site - add DNSBL site information */
+/* psc_dnsbl_add_site - add DNSBL site information */
 
-static void ps_dnsbl_add_site(const char *site)
+static void psc_dnsbl_add_site(const char *site)
 {
-    const char *myname = "ps_dnsbl_add_site";
+    const char *myname = "psc_dnsbl_add_site";
     char   *saved_site = mystrdup(site);
     VSTRING *byte_codes = 0;
-    PS_DNSBL_HEAD *head;
-    PS_DNSBL_SITE *new_site;
+    PSC_DNSBL_HEAD *head;
+    PSC_DNSBL_SITE *new_site;
     char    junk;
     const char *weight_text;
     char   *pattern_text;
@@ -248,13 +248,13 @@ static void ps_dnsbl_add_site(const char *site)
      * Look up or create the (filter, weight) list head for this DNSBL domain
      * name.
      */
-    if ((head = (PS_DNSBL_HEAD *)
+    if ((head = (PSC_DNSBL_HEAD *)
         htable_find(dnsbl_site_cache, saved_site)) == 0) {
-       head = (PS_DNSBL_HEAD *) mymalloc(sizeof(*head));
+       head = (PSC_DNSBL_HEAD *) mymalloc(sizeof(*head));
        ht = htable_enter(dnsbl_site_cache, saved_site, (char *) head);
        /* Translate the DNSBL name into a safe name if available. */
-       if (ps_dnsbl_reply == 0
-         || (head->safe_dnsbl = dict_get(ps_dnsbl_reply, saved_site)) == 0)
+       if (psc_dnsbl_reply == 0
+        || (head->safe_dnsbl = dict_get(psc_dnsbl_reply, saved_site)) == 0)
            head->safe_dnsbl = ht->key;
        head->first = 0;
     }
@@ -263,7 +263,7 @@ static void ps_dnsbl_add_site(const char *site)
      * Append the new (filter, weight) node to the list for this DNSBL domain
      * name.
      */
-    new_site = (PS_DNSBL_SITE *) mymalloc(sizeof(*new_site));
+    new_site = (PSC_DNSBL_SITE *) mymalloc(sizeof(*new_site));
     new_site->filter = (pattern_text ? mystrdup(pattern_text) : 0);
     new_site->byte_codes = (byte_codes ? ip_match_save(byte_codes) : 0);
     new_site->weight = weight;
@@ -275,9 +275,9 @@ static void ps_dnsbl_add_site(const char *site)
        vstring_free(byte_codes);
 }
 
-/* ps_dnsbl_match - match DNSBL reply filter */
+/* psc_dnsbl_match - match DNSBL reply filter */
 
-static int ps_dnsbl_match(const char *filter, ARGV *reply)
+static int psc_dnsbl_match(const char *filter, ARGV *reply)
 {
     char    addr_buf[MAI_HOSTADDR_STRSIZE];
     char  **cpp;
@@ -295,26 +295,26 @@ static int ps_dnsbl_match(const char *filter, ARGV *reply)
     return (0);
 }
 
-/* ps_dnsbl_retrieve - retrieve blocklist score, decrement reference count */
+/* psc_dnsbl_retrieve - retrieve blocklist score, decrement reference count */
 
-int     ps_dnsbl_retrieve(const char *client_addr, const char **dnsbl_name,
-                                 int dnsbl_index)
+int     psc_dnsbl_retrieve(const char *client_addr, const char **dnsbl_name,
+                                  int dnsbl_index)
 {
-    const char *myname = "ps_dnsbl_retrieve";
-    PS_DNSBL_SCORE *score;
+    const char *myname = "psc_dnsbl_retrieve";
+    PSC_DNSBL_SCORE *score;
     int     result_score;
 
     /*
      * Sanity check.
      */
-    if ((score = (PS_DNSBL_SCORE *)
+    if ((score = (PSC_DNSBL_SCORE *)
         htable_find(dnsbl_score_cache, client_addr)) == 0)
        msg_panic("%s: no blocklist score for %s", myname, client_addr);
 
     /*
      * Disable callbacks.
      */
-    PS_CALL_BACK_CANCEL(score, dnsbl_index);
+    PSC_CALL_BACK_CANCEL(score, dnsbl_index);
 
     /*
      * Reads are destructive.
@@ -330,18 +330,18 @@ int     ps_dnsbl_retrieve(const char *client_addr, const char **dnsbl_name,
     return (result_score);
 }
 
-/* ps_dnsbl_receive - receive DNSBL reply, update blocklist score */
+/* psc_dnsbl_receive - receive DNSBL reply, update blocklist score */
 
-static void ps_dnsbl_receive(int event, char *context)
+static void psc_dnsbl_receive(int event, char *context)
 {
-    const char *myname = "ps_dnsbl_receive";
+    const char *myname = "psc_dnsbl_receive";
     VSTREAM *stream = (VSTREAM *) context;
-    PS_DNSBL_SCORE *score;
-    PS_DNSBL_HEAD *head;
-    PS_DNSBL_SITE *site;
+    PSC_DNSBL_SCORE *score;
+    PSC_DNSBL_HEAD *head;
+    PSC_DNSBL_SITE *site;
     ARGV   *reply_argv;
 
-    PS_CLEAR_EVENT_REQUEST(vstream_fileno(stream), ps_dnsbl_receive, context);
+    PSC_CLEAR_EVENT_REQUEST(vstream_fileno(stream), psc_dnsbl_receive, context);
 
     /*
      * Receive the DNSBL lookup result.
@@ -360,12 +360,12 @@ static void ps_dnsbl_receive(int event, char *context)
      */
     if (event == EVENT_READ
        && attr_scan(stream,
-                    ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
+                    ATTR_FLAG_STRICT,
                     ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, reply_dnsbl,
                     ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_ADDR, reply_client,
                     ATTR_TYPE_STR, MAIL_ATTR_RBL_ADDR, reply_addr,
                     ATTR_TYPE_END) == 3
-       && (score = (PS_DNSBL_SCORE *)
+       && (score = (PSC_DNSBL_SCORE *)
            htable_find(dnsbl_score_cache, STR(reply_client))) != 0) {
 
        /*
@@ -380,12 +380,12 @@ static void ps_dnsbl_receive(int event, char *context)
                     myname, STR(reply_client), score->total,
                     STR(reply_dnsbl), STR(reply_addr));
        if (*STR(reply_addr) != 0) {
-           head = (PS_DNSBL_HEAD *)
+           head = (PSC_DNSBL_HEAD *)
                htable_find(dnsbl_site_cache, STR(reply_dnsbl));
-           site = (head ? head->first : (PS_DNSBL_SITE *) 0);
+           site = (head ? head->first : (PSC_DNSBL_SITE *) 0);
            for (reply_argv = 0; site != 0; site = site->next) {
                if (site->byte_codes == 0
-               || ps_dnsbl_match(site->byte_codes, reply_argv ? reply_argv :
+                   || psc_dnsbl_match(site->byte_codes, reply_argv ? reply_argv :
                         (reply_argv = argv_split(STR(reply_addr), " ")))) {
                    if (score->dnsbl == 0)
                        score->dnsbl = head->safe_dnsbl;
@@ -407,23 +407,23 @@ static void ps_dnsbl_receive(int event, char *context)
         */
        score->pending_lookups -= 1;
        if (score->pending_lookups == 0)
-           PS_CALL_BACK_NOTIFY(score, PS_NULL_EVENT);
+           PSC_CALL_BACK_NOTIFY(score, PSC_NULL_EVENT);
     }
     /* Here, score may be a null pointer. */
     vstream_fclose(stream);
 }
 
-/* ps_dnsbl_request  - send dnsbl query, increment reference count */
+/* psc_dnsbl_request  - send dnsbl query, increment reference count */
 
-int     ps_dnsbl_request(const char *client_addr,
-                                void (*callback) (int, char *),
-                                char *context)
+int     psc_dnsbl_request(const char *client_addr,
+                                 void (*callback) (int, char *),
+                                 char *context)
 {
-    const char *myname = "ps_dnsbl_request";
+    const char *myname = "psc_dnsbl_request";
     int     fd;
     VSTREAM *stream;
     HTABLE_INFO **ht;
-    PS_DNSBL_SCORE *score;
+    PSC_DNSBL_SCORE *score;
     HTABLE_INFO *hash_node;
 
     /*
@@ -441,35 +441,35 @@ int     ps_dnsbl_request(const char *client_addr,
      * a zero-delay timer request and call the notification function from
      * there.
      * 
-     * ps_dnsbl_request() could instead return a result value to indicate that
+     * psc_dnsbl_request() could instead return a result value to indicate that
      * the DNSBL score is already available, but that would complicate the
      * caller with two different notification code paths: one asynchronous
      * code path via the callback invocation, and one synchronous code path
-     * via the ps_dnsbl_request() result value. That would be a source of
+     * via the psc_dnsbl_request() result value. That would be a source of
      * future bugs.
      */
     if ((hash_node = htable_locate(dnsbl_score_cache, client_addr)) != 0) {
-       score = (PS_DNSBL_SCORE *) hash_node->value;
+       score = (PSC_DNSBL_SCORE *) hash_node->value;
        score->refcount += 1;
-       PS_CALL_BACK_EXTEND(hash_node, score);
-       PS_CALL_BACK_ENTER(score, callback, context);
+       PSC_CALL_BACK_EXTEND(hash_node, score);
+       PSC_CALL_BACK_ENTER(score, callback, context);
        if (msg_verbose > 1)
            msg_info("%s: reuse blocklist score for %s refcount=%d pending=%d",
                     myname, client_addr, score->refcount,
                     score->pending_lookups);
        if (score->pending_lookups == 0)
            event_request_timer(callback, context, EVENT_NULL_DELAY);
-       return (PS_CALL_BACK_INDEX_OF_LAST(score));
+       return (PSC_CALL_BACK_INDEX_OF_LAST(score));
     }
     if (msg_verbose > 1)
        msg_info("%s: create blocklist score for %s", myname, client_addr);
-    score = (PS_DNSBL_SCORE *) mymalloc(sizeof(*score));
+    score = (PSC_DNSBL_SCORE *) mymalloc(sizeof(*score));
     score->dnsbl = 0;
     score->total = 0;
     score->refcount = 1;
     score->pending_lookups = 0;
-    PS_CALL_BACK_INIT(score);
-    PS_CALL_BACK_ENTER(score, callback, context);
+    PSC_CALL_BACK_INIT(score);
+    PSC_CALL_BACK_ENTER(score, callback, context);
     (void) htable_enter(dnsbl_score_cache, client_addr, (char *) score);
 
     /*
@@ -493,19 +493,19 @@ int     ps_dnsbl_request(const char *client_addr,
            vstream_fclose(stream);
            continue;
        }
-       PS_READ_EVENT_REQUEST(vstream_fileno(stream), ps_dnsbl_receive,
-                             (char *) stream, DNSBLOG_TIMEOUT);
+       PSC_READ_EVENT_REQUEST(vstream_fileno(stream), psc_dnsbl_receive,
+                              (char *) stream, DNSBLOG_TIMEOUT);
        score->pending_lookups += 1;
     }
-    return (PS_CALL_BACK_INDEX_OF_LAST(score));
+    return (PSC_CALL_BACK_INDEX_OF_LAST(score));
 }
 
-/* ps_dnsbl_init - initialize */
+/* psc_dnsbl_init - initialize */
 
-void    ps_dnsbl_init(void)
+void    psc_dnsbl_init(void)
 {
-    const char *myname = "ps_dnsbl_init";
-    ARGV   *dnsbl_site = argv_split(var_ps_dnsbl_sites, ", \t\r\n");
+    const char *myname = "psc_dnsbl_init";
+    ARGV   *dnsbl_site = argv_split(var_psc_dnsbl_sites, ", \t\r\n");
     char  **cpp;
 
     /*
@@ -521,7 +521,7 @@ void    ps_dnsbl_init(void)
      */
     dnsbl_site_cache = htable_create(13);
     for (cpp = dnsbl_site->argv; *cpp; cpp++)
-       ps_dnsbl_add_site(*cpp);
+       psc_dnsbl_add_site(*cpp);
     argv_free(dnsbl_site);
     dnsbl_site_list = htable_list(dnsbl_site_cache);
 
index 56844b91db5e286aa2a27dccc53f8702f3123964..807a0c9d506e63d2cce39e49073777bd9517b5de 100644 (file)
@@ -6,16 +6,16 @@
 /* SYNOPSIS
 /*     #include <postscreen.h>
 /*
-/*     void    ps_early_init(void)
+/*     void    psc_early_init(void)
 /*
-/*     void    ps_early_tests(state)
-/*     PS_STATE *state;
+/*     void    psc_early_tests(state)
+/*     PSC_STATE *state;
 /* DESCRIPTION
-/*     ps_early_tests() performs protocol tests before the SMTP
+/*     psc_early_tests() performs protocol tests before the SMTP
 /*     handshake: the pregreet test and the DNSBL test. Control
-/*     is passed to the ps_smtpd_tests() routine as appropriate.
+/*     is passed to the psc_smtpd_tests() routine as appropriate.
 /*
-/*     ps_early_init() performs one-time initialization.
+/*     psc_early_init() performs one-time initialization.
 /* LICENSE
 /* .ad
 /* .fi
 
 #include <postscreen.h>
 
-static char *ps_teaser_greeting;
+static char *psc_teaser_greeting;
 
-/* ps_early_event - handle pre-greet, EOF, and DNSBL results. */
+/* psc_early_event - handle pre-greet, EOF, and DNSBL results. */
 
-static void ps_early_event(int event, char *context)
+static void psc_early_event(int event, char *context)
 {
-    const char *myname = "ps_early_event";
-    PS_STATE *state = (PS_STATE *) context;
-    char    read_buf[PS_READ_BUF_SIZE];
+    const char *myname = "psc_early_event";
+    PSC_STATE *state = (PSC_STATE *) context;
+    char    read_buf[PSC_READ_BUF_SIZE];
     int     read_count;
     int     dnsbl_score;
     DELTA_TIME elapsed;
@@ -63,20 +63,20 @@ static void ps_early_event(int event, char *context)
 
     if (msg_verbose > 1)
        msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s",
-                myname, ps_post_queue_length, ps_check_queue_length,
+                myname, psc_post_queue_length, psc_check_queue_length,
                 event, vstream_fileno(state->smtp_client_stream),
                 state->smtp_client_addr, state->smtp_client_port,
-                ps_print_state_flags(state->flags, myname));
+                psc_print_state_flags(state->flags, myname));
 
-    PS_CLEAR_EVENT_REQUEST(vstream_fileno(state->smtp_client_stream),
-                          ps_early_event, context);
+    PSC_CLEAR_EVENT_REQUEST(vstream_fileno(state->smtp_client_stream),
+                           psc_early_event, context);
 
     /*
      * XXX Be sure to empty the DNSBL lookup buffer otherwise we have a
      * memory leak.
      * 
      * XXX We can avoid "forgetting" to do this by keeping a pointer to the
-     * DNSBL lookup buffer in the PS_STATE structure. This also allows us to
+     * DNSBL lookup buffer in the PSC_STATE structure. This also allows us to
      * shave off a hash table lookup when retrieving the DNSBL result.
      */
     switch (event) {
@@ -89,57 +89,57 @@ static void ps_early_event(int event, char *context)
        /*
         * Check if the SMTP client spoke before its turn.
         */
-       if ((state->flags & PS_STATE_MASK_PREGR_TODO_FAIL)
-           == PS_STATE_FLAG_PREGR_TODO) {
-           state->pregr_stamp = event_time() + var_ps_pregr_ttl;
-           PS_PASS_SESSION_STATE(state, "pregreet test",
-                                 PS_STATE_FLAG_PREGR_PASS);
+       if ((state->flags & PSC_STATE_MASK_PREGR_TODO_FAIL)
+           == PSC_STATE_FLAG_PREGR_TODO) {
+           state->pregr_stamp = event_time() + var_psc_pregr_ttl;
+           PSC_PASS_SESSION_STATE(state, "pregreet test",
+                                  PSC_STATE_FLAG_PREGR_PASS);
        }
-       if ((state->flags & PS_STATE_FLAG_PREGR_FAIL)
-           && ps_pregr_action == PS_ACT_IGNORE) {
-           PS_UNFAIL_SESSION_STATE(state, PS_STATE_FLAG_PREGR_FAIL);
-           /* Not: PS_PASS_SESSION_STATE. Repeat this test the next time. */
+       if ((state->flags & PSC_STATE_FLAG_PREGR_FAIL)
+           && psc_pregr_action == PSC_ACT_IGNORE) {
+           PSC_UNFAIL_SESSION_STATE(state, PSC_STATE_FLAG_PREGR_FAIL);
+           /* Not: PSC_PASS_SESSION_STATE. Repeat this test the next time. */
        }
 
        /*
         * If the client is DNS blocklisted, drop the connection, send the
         * client to a dummy protocol engine, or continue to the next test.
         */
-#define PS_DNSBL_FORMAT \
+#define PSC_DNSBL_FORMAT \
        "%s 5.7.1 Service unavailable; client [%s] blocked using %s\r\n"
 
-       if (state->flags & PS_STATE_FLAG_DNSBL_TODO) {
+       if (state->flags & PSC_STATE_FLAG_DNSBL_TODO) {
            dnsbl_score =
-               ps_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
-                                 state->dnsbl_index);
-           if (dnsbl_score < var_ps_dnsbl_thresh) {
-               state->dnsbl_stamp = event_time() + var_ps_dnsbl_ttl;
-               PS_PASS_SESSION_STATE(state, "dnsbl test",
-                                     PS_STATE_FLAG_DNSBL_PASS);
+               psc_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
+                                  state->dnsbl_index);
+           if (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, PS_CLIENT_ADDR_PORT(state));
-               PS_FAIL_SESSION_STATE(state, PS_STATE_FLAG_DNSBL_FAIL);
-               switch (ps_dnsbl_action) {
-               case PS_ACT_DROP:
+                        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),
-                                                    PS_DNSBL_FORMAT, "521",
+                                                   PSC_DNSBL_FORMAT, "521",
                                       state->smtp_client_addr, dnsbl_name);
-                   PS_DROP_SESSION_STATE(state, STR(state->dnsbl_reply));
+                   PSC_DROP_SESSION_STATE(state, STR(state->dnsbl_reply));
                    return;
-               case PS_ACT_ENFORCE:
+               case PSC_ACT_ENFORCE:
                    state->dnsbl_reply = vstring_sprintf(vstring_alloc(100),
-                                                    PS_DNSBL_FORMAT, "550",
+                                                   PSC_DNSBL_FORMAT, "550",
                                       state->smtp_client_addr, dnsbl_name);
-                   PS_ENFORCE_SESSION_STATE(state, STR(state->dnsbl_reply));
+                   PSC_ENFORCE_SESSION_STATE(state, STR(state->dnsbl_reply));
                    break;
-               case PS_ACT_IGNORE:
-                   PS_UNFAIL_SESSION_STATE(state, PS_STATE_FLAG_DNSBL_FAIL);
-                   /* Not: PS_PASS_SESSION_STATE. Repeat this test. */
+               case PSC_ACT_IGNORE:
+                   PSC_UNFAIL_SESSION_STATE(state, PSC_STATE_FLAG_DNSBL_FAIL);
+                   /* Not: PSC_PASS_SESSION_STATE. Repeat this test. */
                    break;
                default:
                    msg_panic("%s: unknown dnsbl action value %d",
-                             myname, ps_dnsbl_action);
+                             myname, psc_dnsbl_action);
 
                }
            }
@@ -149,146 +149,144 @@ static void ps_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 & (PS_STATE_FLAG_NOFORWARD | PS_STATE_MASK_SMTPD_TODO))
-           ps_smtpd_tests(state);
+       if (state->flags & (PSC_STATE_FLAG_NOFORWARD | PSC_STATE_MASK_SMTPD_TODO))
+           psc_smtpd_tests(state);
        else
-           ps_conclude(state);
+           psc_conclude(state);
        return;
 
        /*
         * EOF, or the client spoke before its turn. We simply drop the
         * connection, or we continue waiting and allow DNS replies to
         * trickle in.
-        * 
-        * XXX Reset the pregreet timer when the DNS results are complete.
         */
     default:
        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 & PS_STATE_FLAG_DNSBL_TODO)
-               (void) ps_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
-                                        state->dnsbl_index);
+           if (state->flags & PSC_STATE_FLAG_DNSBL_TODO)
+               (void) psc_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
+                                         state->dnsbl_index);
            /* XXX Wait for DNS replies to come in. */
-           ps_hangup_event(state);
+           psc_hangup_event(state);
            return;
        }
        read_buf[read_count] = 0;
        msg_info("PREGREET %d after %s from [%s]:%s: %.100s", read_count,
-                ps_format_delta_time(ps_temp, state->start_time, &elapsed),
-                PS_CLIENT_ADDR_PORT(state), printable(read_buf, '?'));
-       PS_FAIL_SESSION_STATE(state, PS_STATE_FLAG_PREGR_FAIL);
-       switch (ps_pregr_action) {
-       case PS_ACT_DROP:
+              psc_format_delta_time(psc_temp, state->start_time, &elapsed),
+                PSC_CLIENT_ADDR_PORT(state), printable(read_buf, '?'));
+       PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_PREGR_FAIL);
+       switch (psc_pregr_action) {
+       case PSC_ACT_DROP:
            /* Avoid memory leak. */
-           if (state->flags & PS_STATE_FLAG_DNSBL_TODO)
-               (void) ps_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
-                                        state->dnsbl_index);
-           PS_DROP_SESSION_STATE(state, "521 5.5.1 Protocol error\r\n");
+           if (state->flags & PSC_STATE_FLAG_DNSBL_TODO)
+               (void) psc_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
+                                         state->dnsbl_index);
+           PSC_DROP_SESSION_STATE(state, "521 5.5.1 Protocol error\r\n");
            return;
-       case PS_ACT_ENFORCE:
-           /* We call ps_dnsbl_retrieve() when the timer expires. */
-           PS_ENFORCE_SESSION_STATE(state, "550 5.5.1 Protocol error\r\n");
+       case PSC_ACT_ENFORCE:
+           /* We call psc_dnsbl_retrieve() when the timer expires. */
+           PSC_ENFORCE_SESSION_STATE(state, "550 5.5.1 Protocol error\r\n");
            break;
-       case PS_ACT_IGNORE:
-           /* We call ps_dnsbl_retrieve() when the timer expires. */
+       case PSC_ACT_IGNORE:
+           /* We call psc_dnsbl_retrieve() when the timer expires. */
            /* We must handle this case after the timer expires. */
            break;
        default:
            msg_panic("%s: unknown pregreet action value %d",
-                     myname, ps_pregr_action);
+                     myname, psc_pregr_action);
        }
 
        /*
         * Terminate the greet delay if we're just waiting for the pregreet
-        * test to complete. It is safe to call ps_early_event directly,
+        * test to complete. It is safe to call psc_early_event directly,
         * since we are already in that function.
         * 
         * XXX After this code passes all tests, swap around the two blocks in
         * this switch statement and fall through from EVENT_READ into
-        * EVENT_TIME, instead of calling ps_early_event recursively.
+        * EVENT_TIME, instead of calling psc_early_event recursively.
         */
-       state->flags |= PS_STATE_FLAG_PREGR_DONE;
-       if (elapsed.dt_sec >= PS_EFF_GREET_WAIT
-           || ((state->flags & PS_STATE_MASK_EARLY_DONE)
-               == PS_STATE_FLAGS_TODO_TO_DONE(state->flags & PS_STATE_MASK_EARLY_TODO)))
-           ps_early_event(EVENT_TIME, context);
+       state->flags |= PSC_STATE_FLAG_PREGR_DONE;
+       if (elapsed.dt_sec >= PSC_EFF_GREET_WAIT
+           || ((state->flags & PSC_STATE_MASK_EARLY_DONE)
+               == PSC_STATE_FLAGS_TODO_TO_DONE(state->flags & PSC_STATE_MASK_EARLY_TODO)))
+           psc_early_event(EVENT_TIME, context);
        else
-           event_request_timer(ps_early_event, context,
-                               PS_EFF_GREET_WAIT - elapsed.dt_sec);
+           event_request_timer(psc_early_event, context,
+                               PSC_EFF_GREET_WAIT - elapsed.dt_sec);
        return;
     }
 }
 
-/* ps_early_dnsbl_event - cancel pregreet timer if waiting for DNS only */
+/* psc_early_dnsbl_event - cancel pregreet timer if waiting for DNS only */
 
-static void ps_early_dnsbl_event(int unused_event, char *context)
+static void psc_early_dnsbl_event(int unused_event, char *context)
 {
-    const char *myname = "ps_early_dnsbl_event";
-    PS_STATE *state = (PS_STATE *) context;
+    const char *myname = "psc_early_dnsbl_event";
+    PSC_STATE *state = (PSC_STATE *) context;
 
     if (msg_verbose)
-       msg_info("%s: notify [%s]:%s", myname, PS_CLIENT_ADDR_PORT(state));
+       msg_info("%s: notify [%s]:%s", myname, PSC_CLIENT_ADDR_PORT(state));
 
     /*
      * Terminate the greet delay if we're just waiting for DNSBL lookup to
-     * complete. Don't call ps_early_event directly, that would result in a
+     * complete. Don't call psc_early_event directly, that would result in a
      * dangling pointer.
      */
-    state->flags |= PS_STATE_FLAG_DNSBL_DONE;
-    if ((state->flags & PS_STATE_MASK_EARLY_DONE)
-    == PS_STATE_FLAGS_TODO_TO_DONE(state->flags & PS_STATE_MASK_EARLY_TODO))
-       event_request_timer(ps_early_event, context, EVENT_NULL_DELAY);
+    state->flags |= PSC_STATE_FLAG_DNSBL_DONE;
+    if ((state->flags & PSC_STATE_MASK_EARLY_DONE)
+       == PSC_STATE_FLAGS_TODO_TO_DONE(state->flags & PSC_STATE_MASK_EARLY_TODO))
+       event_request_timer(psc_early_event, context, EVENT_NULL_DELAY);
 }
 
-/* ps_early_tests - start the early (before protocol) tests */
+/* psc_early_tests - start the early (before protocol) tests */
 
-void    ps_early_tests(PS_STATE *state)
+void    psc_early_tests(PSC_STATE *state)
 {
-    const char *myname = "ps_early_tests";
+    const char *myname = "psc_early_tests";
 
     /*
      * Report errors and progress in the context of this test.
      */
-    PS_BEGIN_TESTS(state, "tests before SMTP handshake");
+    PSC_BEGIN_TESTS(state, "tests before SMTP handshake");
 
     /*
      * Run a PREGREET test. Send half the greeting banner, by way of teaser,
      * then wait briefly to see if the client speaks before its turn.
      */
-    if ((state->flags & PS_STATE_FLAG_PREGR_TODO) != 0
-       && ps_teaser_greeting != 0
-       && PS_SEND_REPLY(state, ps_teaser_greeting) != 0) {
-       ps_hangup_event(state);
+    if ((state->flags & PSC_STATE_FLAG_PREGR_TODO) != 0
+       && psc_teaser_greeting != 0
+       && PSC_SEND_REPLY(state, psc_teaser_greeting) != 0) {
+       psc_hangup_event(state);
        return;
     }
 
     /*
      * Run a DNS blocklist query.
      */
-    if ((state->flags & PS_STATE_FLAG_DNSBL_TODO) != 0)
+    if ((state->flags & PSC_STATE_FLAG_DNSBL_TODO) != 0)
        state->dnsbl_index =
-           ps_dnsbl_request(state->smtp_client_addr, ps_early_dnsbl_event,
-                            (char *) state);
+           psc_dnsbl_request(state->smtp_client_addr, psc_early_dnsbl_event,
+                             (char *) state);
     else
        state->dnsbl_index = -1;
 
     /*
      * Wait for the client to respond or for DNS lookup to complete.
      */
-    if ((state->flags & PS_STATE_FLAG_PREGR_TODO) != 0)
-       PS_READ_EVENT_REQUEST(vstream_fileno(state->smtp_client_stream),
-                        ps_early_event, (char *) state, PS_EFF_GREET_WAIT);
+    if ((state->flags & PSC_STATE_FLAG_PREGR_TODO) != 0)
+       PSC_READ_EVENT_REQUEST(vstream_fileno(state->smtp_client_stream),
+                      psc_early_event, (char *) state, PSC_EFF_GREET_WAIT);
     else
-       event_request_timer(ps_early_event, (char *) state, PS_EFF_GREET_WAIT);
+       event_request_timer(psc_early_event, (char *) state, PSC_EFF_GREET_WAIT);
 }
 
-/* ps_early_init - initialize early tests */
+/* psc_early_init - initialize early tests */
 
-void    ps_early_init(void)
+void    psc_early_init(void)
 {
-    if (*var_ps_pregr_banner) {
-       vstring_sprintf(ps_temp, "220-%s\r\n", var_ps_pregr_banner);
-       ps_teaser_greeting = mystrdup(STR(ps_temp));
+    if (*var_psc_pregr_banner) {
+       vstring_sprintf(psc_temp, "220-%s\r\n", var_psc_pregr_banner);
+       psc_teaser_greeting = mystrdup(STR(psc_temp));
     }
 }
index 075b0d203668181d6ca8c4e017c2f9102099c07f..57a1bb67ddcf82adce9c1971c4bc6bc6c443856f 100644 (file)
@@ -6,31 +6,31 @@
 /* SYNOPSIS
 /*     #include <postscreen.h>
 /*
-/*     char    *ps_format_delta_time(buf, tv, delta)
+/*     char    *psc_format_delta_time(buf, tv, delta)
 /*     VSTRING *buf;
 /*     struct timeval tv;
 /*     DELTA_TIME *delta;
 /*
-/*     void    ps_conclude(state)
-/*     PS_STATE *state;
+/*     void    psc_conclude(state)
+/*     PSC_STATE *state;
 /*
-/*     void    ps_hangup_event(state)
-/*     PS_STATE *state;
+/*     void    psc_hangup_event(state)
+/*     PSC_STATE *state;
 /* DESCRIPTION
-/*     ps_format_delta_time() computes the time difference between
+/*     psc_format_delta_time() computes the time difference between
 /*     tv (past) and the present, formats the time difference with
 /*     sub-second resolution in a human-readable way, and returns
 /*     the integer time difference in seconds through the delta
 /*     argument.
 /*
-/*     ps_conclude() logs when a client passes all necessary tests,
+/*     psc_conclude() logs when a client passes all necessary tests,
 /*     updates the postscreen cache for any testes that were passed,
 /*     and either forwards the connection to a real SMTP server or
 /*     replies with the text in state->error_reply and hangs up the
 /*     connection (by default, state->error_reply is set to a
 /*     default 421 reply).
 /*
-/*     ps_hangup_event() cleans up after a client connection breaks
+/*     psc_hangup_event() cleans up after a client connection breaks
 /*     unexpectedly. If logs the test where the break happened,
 /*     and how much time as spent in that test before the connection
 /*     broke.
 
 #include <postscreen.h>
 
-/* ps_format_delta_time - pretty-formatted delta time */
+/* psc_format_delta_time - pretty-formatted delta time */
 
-char   *ps_format_delta_time(VSTRING *buf, struct timeval tv, DELTA_TIME *delta)
+char   *psc_format_delta_time(VSTRING *buf, struct timeval tv,
+                                     DELTA_TIME *delta)
 {
     DELTA_TIME pdelay;
     struct timeval now;
 
     GETTIMEOFDAY(&now);
-    PS_CALC_DELTA(pdelay, now, tv);
+    PSC_CALC_DELTA(pdelay, now, tv);
     VSTRING_RESET(buf);
     format_tv(buf, pdelay.dt_sec, pdelay.dt_usec, SIG_DIGS, var_delay_max_res);
     *delta = pdelay;
     return (STR(buf));
 }
 
-/* ps_conclude - bring this session to a conclusion */
+/* psc_conclude - bring this session to a conclusion */
 
-void    ps_conclude(PS_STATE *state)
+void    psc_conclude(PSC_STATE *state)
 {
-    const char *myname = "ps_conclude";
+    const char *myname = "psc_conclude";
 
     if (msg_verbose)
        msg_info("flags for %s: %s",
-                myname, ps_print_state_flags(state->flags, myname));
+                myname, psc_print_state_flags(state->flags, myname));
 
     /*
      * Handle clients that passed at least one test other than permanent
@@ -95,45 +96,45 @@ void    ps_conclude(PS_STATE *state)
      * blacklisting. There may still be unfinished tests; those tests will
      * need to be completed when the client returns in a later session.
      */
-    if (state->flags & PS_STATE_MASK_ANY_FAIL)
-       state->flags &= ~PS_STATE_MASK_ANY_PASS;
+    if (state->flags & PSC_STATE_MASK_ANY_FAIL)
+       state->flags &= ~PSC_STATE_MASK_ANY_PASS;
 
     /*
      * Log our final blessing when all unfinished tests were completed.
      */
-    if ((state->flags & PS_STATE_MASK_ANY_PASS) != 0
-       && (state->flags & PS_STATE_MASK_ANY_PASS) ==
-       PS_STATE_FLAGS_TODO_TO_PASS(state->flags & PS_STATE_MASK_ANY_TODO))
-       msg_info("PASS %s [%s]:%s", (state->flags & PS_STATE_FLAG_NEW) == 0 ?
-                "OLD" : "NEW", PS_CLIENT_ADDR_PORT(state));
+    if ((state->flags & PSC_STATE_MASK_ANY_PASS) != 0
+       && (state->flags & PSC_STATE_MASK_ANY_PASS) ==
+       PSC_STATE_FLAGS_TODO_TO_PASS(state->flags & PSC_STATE_MASK_ANY_TODO))
+       msg_info("PASS %s [%s]:%s", (state->flags & PSC_STATE_FLAG_NEW) == 0 ?
+                "OLD" : "NEW", PSC_CLIENT_ADDR_PORT(state));
 
     /*
      * Update the postscreen cache. This still supports a scenario where a
      * client gets whitelisted in the course of multiple sessions, as long as
      * that client does not "fail" any test.
      */
-    if ((state->flags & PS_STATE_MASK_ANY_UPDATE) != 0
-       && ps_cache_map != 0) {
-       ps_print_tests(ps_temp, state);
-       ps_cache_update(ps_cache_map, state->smtp_client_addr, STR(ps_temp));
+    if ((state->flags & PSC_STATE_MASK_ANY_UPDATE) != 0
+       && psc_cache_map != 0) {
+       psc_print_tests(psc_temp, state);
+       psc_cache_update(psc_cache_map, state->smtp_client_addr, STR(psc_temp));
     }
 
     /*
      * Either hand off the socket to a real SMTP engine, or say bye-bye.
      */
-    if ((state->flags & PS_STATE_FLAG_NOFORWARD) == 0) {
-       ps_send_socket(state);
+    if ((state->flags & PSC_STATE_FLAG_NOFORWARD) == 0) {
+       psc_send_socket(state);
     } else {
-       if ((state->flags & PS_STATE_FLAG_HANGUP) == 0)
-           (void) PS_SEND_REPLY(state, state->final_reply);
-       msg_info("DISCONNECT [%s]:%s", PS_CLIENT_ADDR_PORT(state));
-       ps_free_session_state(state);
+       if ((state->flags & PSC_STATE_FLAG_HANGUP) == 0)
+           (void) PSC_SEND_REPLY(state, state->final_reply);
+       msg_info("DISCONNECT [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
+       psc_free_session_state(state);
     }
 }
 
-/* ps_hangup_event - handle unexpected disconnect */
+/* psc_hangup_event - handle unexpected disconnect */
 
-void    ps_hangup_event(PS_STATE *state)
+void    psc_hangup_event(PSC_STATE *state)
 {
     DELTA_TIME elapsed;
 
@@ -145,10 +146,10 @@ void    ps_hangup_event(PS_STATE *state)
      * Log the current test phase, and the elapsed time after the start of that
      * phase.
      */
-    state->flags |= PS_STATE_FLAG_HANGUP;
+    state->flags |= PSC_STATE_FLAG_HANGUP;
     msg_info("HANGUP after %s from [%s]:%s in %s",
-            ps_format_delta_time(ps_temp, state->start_time, &elapsed),
-            PS_CLIENT_ADDR_PORT(state), state->test_name);
-    state->flags |= PS_STATE_FLAG_NOFORWARD;
-    ps_conclude(state);
+            psc_format_delta_time(psc_temp, state->start_time, &elapsed),
+            PSC_CLIENT_ADDR_PORT(state), state->test_name);
+    state->flags |= PSC_STATE_FLAG_NOFORWARD;
+    psc_conclude(state);
 }
index 0974537b065f00161a801a4d6c9a243492876fb7..7b7edc35004af2e08f45fcf6851511828f732449 100644 (file)
@@ -6,33 +6,33 @@
 /* SYNOPSIS
 /*     #include <postscreen.h>
 /*
-/*     int     ps_send_reply(client_fd, client_addr, client_port, text)
+/*     int     psc_send_reply(client_fd, client_addr, client_port, text)
 /*     int     client_fd;
 /*     const char *client_addr;
 /*     const char *client_port;
 /*     const char *text;
 /*
-/*     int     PS_SEND_REPLY(state, text)
+/*     int     PSC_SEND_REPLY(state, text)
 /*     const char *text;
 /*
-/*     void    ps_send_socket(state)
-/*     PS_STATE *state;
+/*     void    psc_send_socket(state)
+/*     PSC_STATE *state;
 /* DESCRIPTION
-/*     ps_send_reply() sends the specified text to the specified
+/*     psc_send_reply() sends the specified text to the specified
 /*     remote SMTP client.  In case of an immediate error, it logs
 /*     a warning (except EPIPE) with the client address and port,
 /*     and returns a non-zero result (all errors including EPIPE).
 /*
-/*     PS_SEND_REPLY() is a convenience wrapper for ps_send_reply().
+/*     PSC_SEND_REPLY() is a convenience wrapper for psc_send_reply().
 /*     It is an unsafe macro that evaluates its arguments multiple
 /*     times.
 /*
-/*     ps_send_socket() sends the specified socket to the real
+/*     psc_send_socket() sends the specified socket to the real
 /*     Postfix SMTP server. The socket is delivered in the background.
 /*     This function must be called after all other session-related
 /*     work is finished including postscreen cache updates.
 /*
-/*     In case of an immediate error, ps_send_socket() sends a 421
+/*     In case of an immediate error, psc_send_socket() sends a 421
 /*     reply to the remote SMTP client and closes the connection.
 /* LICENSE
 /* .ad
   * This program screens all inbound SMTP connections, so it better not waste
   * time.
   */
-#define PS_SEND_SOCK_CONNECT_TIMEOUT   1
-#define PS_SEND_SOCK_NOTIFY_TIMEOUT    100
-#define PS_SEND_TEXT_TIMEOUT           1
+#define PSC_SEND_SOCK_CONNECT_TIMEOUT  1
+#define PSC_SEND_SOCK_NOTIFY_TIMEOUT   100
+#define PSC_SEND_TEXT_TIMEOUT          1
 
-/* ps_send_reply - send reply to remote SMTP client */
+/* psc_send_reply - send reply to remote SMTP client */
 
-int     ps_send_reply(int smtp_client_fd, const char *smtp_client_addr,
-                             const char *smtp_client_port, const char *text)
+int     psc_send_reply(int smtp_client_fd, const char *smtp_client_addr,
+                            const char *smtp_client_port, const char *text)
 {
     int     ret;
 
@@ -85,22 +85,22 @@ int     ps_send_reply(int smtp_client_fd, const char *smtp_client_addr,
      * response, so that a nasty client can't cause this process to block.
      */
     ret = (write_buf(smtp_client_fd, text, strlen(text),
-                    PS_SEND_TEXT_TIMEOUT) < 0);
+                    PSC_SEND_TEXT_TIMEOUT) < 0);
     if (ret != 0 && errno != EPIPE)
        msg_warn("write [%s]:%s: %m", smtp_client_addr, smtp_client_port);
     return (ret);
 }
 
-/* ps_send_socket_close_event - file descriptor has arrived or timeout */
+/* psc_send_socket_close_event - file descriptor has arrived or timeout */
 
-static void ps_send_socket_close_event(int event, char *context)
+static void psc_send_socket_close_event(int event, char *context)
 {
-    const char *myname = "ps_send_socket_close_event";
-    PS_STATE *state = (PS_STATE *) context;
+    const char *myname = "psc_send_socket_close_event";
+    PSC_STATE *state = (PSC_STATE *) context;
 
     if (msg_verbose > 1)
        msg_info("%s: sq=%d cq=%d event %d on send socket %d from [%s]:%s",
-                myname, ps_post_queue_length, ps_check_queue_length,
+                myname, psc_post_queue_length, psc_check_queue_length,
                 event, state->smtp_server_fd, state->smtp_client_addr,
                 state->smtp_client_port);
 
@@ -110,25 +110,25 @@ static void ps_send_socket_close_event(int event, char *context)
      * possible that the real SMTP server will receive the socket so we
      * should not interfere.
      */
-    PS_CLEAR_EVENT_REQUEST(state->smtp_server_fd, ps_send_socket_close_event,
-                          context);
+    PSC_CLEAR_EVENT_REQUEST(state->smtp_server_fd, psc_send_socket_close_event,
+                           context);
     if (event == EVENT_TIME)
        msg_warn("timeout sending connection to service %s",
-                ps_smtpd_service_name);
-    ps_free_session_state(state);
+                psc_smtpd_service_name);
+    psc_free_session_state(state);
 }
 
-/* ps_send_socket - send socket to real SMTP server process */
+/* psc_send_socket - send socket to real SMTP server process */
 
-void    ps_send_socket(PS_STATE *state)
+void    psc_send_socket(PSC_STATE *state)
 {
-    const char *myname = "ps_send_socket";
+    const char *myname = "psc_send_socket";
     int     server_fd;
     int     window_size;
 
     if (msg_verbose > 1)
        msg_info("%s: sq=%d cq=%d send socket %d from [%s]:%s",
-                myname, ps_post_queue_length, ps_check_queue_length,
+                myname, psc_post_queue_length, psc_check_queue_length,
                 vstream_fileno(state->smtp_client_stream),
                 state->smtp_client_addr, state->smtp_client_port);
 
@@ -160,20 +160,20 @@ void    ps_send_socket(PS_STATE *state)
      * Postfix-specific.
      */
     if ((server_fd =
-        LOCAL_CONNECT(ps_smtpd_service_name, NON_BLOCKING,
-                      PS_SEND_SOCK_CONNECT_TIMEOUT)) < 0) {
-       msg_warn("cannot connect to service %s: %m", ps_smtpd_service_name);
-       PS_SEND_REPLY(state, "421 4.3.2 All server ports are busy\r\n");
-       ps_free_session_state(state);
+        LOCAL_CONNECT(psc_smtpd_service_name, NON_BLOCKING,
+                      PSC_SEND_SOCK_CONNECT_TIMEOUT)) < 0) {
+       msg_warn("cannot connect to service %s: %m", psc_smtpd_service_name);
+       PSC_SEND_REPLY(state, "421 4.3.2 All server ports are busy\r\n");
+       psc_free_session_state(state);
        return;
     }
-    PS_ADD_SERVER_STATE(state, server_fd);
+    PSC_ADD_SERVER_STATE(state, server_fd);
     if (LOCAL_SEND_FD(state->smtp_server_fd,
                      vstream_fileno(state->smtp_client_stream)) < 0) {
        msg_warn("cannot pass connection to service %s: %m",
-                ps_smtpd_service_name);
-       PS_SEND_REPLY(state, "421 4.3.2 No system resources\r\n");
-       ps_free_session_state(state);
+                psc_smtpd_service_name);
+       PSC_SEND_REPLY(state, "421 4.3.2 No system resources\r\n");
+       psc_free_session_state(state);
        return;
     } else {
 
@@ -183,10 +183,10 @@ void    ps_send_socket(PS_STATE *state)
         * it has already received the real SMTP server's 220 greeting!
         */
 #if 0
-       PS_DEL_CLIENT_STATE(state);
+       PSC_DEL_CLIENT_STATE(state);
 #endif
-       PS_READ_EVENT_REQUEST(state->smtp_server_fd, ps_send_socket_close_event,
-                             (char *) state, PS_SEND_SOCK_NOTIFY_TIMEOUT);
+       PSC_READ_EVENT_REQUEST(state->smtp_server_fd, psc_send_socket_close_event,
+                              (char *) state, PSC_SEND_SOCK_NOTIFY_TIMEOUT);
        return;
     }
 }
index 5e9e19e21d2744638b2bf5c2823a721ad0171c17..8b529bc773742bd5f966b4118a560f2c27f5c1f1 100644 (file)
@@ -6,14 +6,19 @@
 /* SYNOPSIS
 /*     #include <postscreen.h>
 /*
-/*     void    ps_smtpd_init(void)
+/*     void    psc_smtpd_pre_jail_init(void)
 /*
-/*     void    ps_smtpd_tests(state)
-/*     PS_STATE *state;
+/*     void    psc_smtpd_init(void)
+/*
+/*     void    psc_smtpd_tests(state)
+/*     PSC_STATE *state;
 /* DESCRIPTION
-/*     ps_smtpd_init() performs one-time per-process initialization.
+/*     psc_smtpd_pre_jail_init() performs one-time per-process
+/*     initialization during the "before chroot" execution phase.
+/*
+/*     psc_smtpd_init() performs one-time per-process initialization.
 /*
-/*     ps_smtpd_tests() starts up an SMTP server engine for deep
+/*     psc_smtpd_tests() starts up an SMTP server engine for deep
 /*     protocol tests and for collecting helo/sender/recipient
 /*     information.
 /*
 /*     their commands anyway. To pass this test, the client has
 /*     to speak SMTP all the way to the RCPT TO command.
 /*
-/*     No support is announced for AUTH, STARTTLS, XCLIENT or
-/*     XFORWARD. Clients that need this should be whitelisted or
-/*     should talk directly to the submission service.  Support
-/*     for STARTTLS may be added later.
+/*     No support is announced for AUTH, XCLIENT or XFORWARD.
+/*     Clients that need this should be whitelisted or should talk
+/*     directly to the submission service.
 /*
 /*     The engine rejects RCPT TO and VRFY commands with the
 /*     state->rcpt_reply response which depends on program history,
 #include <mail_proto.h>
 #include <is_header.h>
 #include <string_list.h>
+#include <maps.h>
+#include <ehlo_mask.h>
+
+/* TLS library. */
+
+#include <tls.h>
 
 /* Application-specific. */
 
   * per-session push-back except for the single-character push-back that
   * VSTREAM guarantees after we read one character.
   */
-#define PS_SMTPD_HAVE_PUSH_BACK(state) (0)
-#define PS_SMTPD_PUSH_BACK_CHAR(state, ch) \
+#define PSC_SMTPD_HAVE_PUSH_BACK(state)        (0)
+#define PSC_SMTPD_PUSH_BACK_CHAR(state, ch) \
        vstream_ungetc((state)->smtp_client_stream, (ch))
-#define PS_SMTPD_NEXT_CHAR(state) \
+#define PSC_SMTPD_NEXT_CHAR(state) \
        VSTREAM_GETC((state)->smtp_client_stream)
 
  /*
   * Dynamic reply strings. To minimize overhead we format these once.
   */
-static char *ps_smtpd_greeting;                /* smtp banner */
-static char *ps_smtpd_helo_reply;      /* helo reply */
-static char *ps_smtpd_ehlo_reply;      /* multi-line ehlo reply */
-static char *ps_smtpd_timeout_reply;   /* timeout reply */
-static char *ps_smtpd_421_reply;       /* generic final_reply value */
+static char *psc_smtpd_greeting;       /* smtp banner */
+static char *psc_smtpd_helo_reply;     /* helo reply */
+static char *psc_smtpd_ehlo_reply_plain;/* multi-line ehlo reply, non-TLS */
+static char *psc_smtpd_ehlo_reply_tls; /* multi-line ehlo reply, with TLS */
+static char *psc_smtpd_timeout_reply;  /* timeout reply */
+static char *psc_smtpd_421_reply;      /* generic final_reply value */
 
  /*
-  * Forward declaration, needed by PS_CLEAR_EVENT_REQUEST.
+  * Forward declaration, needed by PSC_CLEAR_EVENT_REQUEST.
   */
-static void ps_smtpd_time_event(int, char *);
+static void psc_smtpd_time_event(int, char *);
+static void psc_smtpd_read_event(int, char *);
+
+ /*
+  * Encapsulation. The STARTTLS, EHLO and AUTH command handlers temporarily
+  * suspend SMTP command events, send an asynchronous proxy request, and
+  * resume SMTP command events after receiving the asynchrounous proxy
+  * response.
+  */
+#define PSC_RESUME_SMTP_CMD_EVENTS(state) \
+    PSC_READ_EVENT_REQUEST2(vstream_fileno((state)->smtp_client_stream), \
+                          psc_smtpd_read_event, psc_smtpd_time_event, \
+                          (char *) (state), PSC_EFF_CMD_TIME_LIMIT)
+
+#define PSC_SUSPEND_SMTP_CMD_EVENTS(state) \
+    PSC_CLEAR_EVENT_REQUEST(vstream_fileno((state)->smtp_client_stream), \
+                          psc_smtpd_time_event, (char *) (state));
 
  /*
   * Command parser support.
   */
-#define PS_SMTPD_NEXT_TOKEN(ptr) mystrtok(&(ptr), " ")
+#define PSC_SMTPD_NEXT_TOKEN(ptr) mystrtok(&(ptr), " ")
+
+ /*
+  * EHLO keyword filter
+  */
+static MAPS *psc_ehlo_discard_maps;
+static int psc_ehlo_discard_mask;
+
+ /*
+  * STARTTLS support. Note the complete absence of #ifdef USE_TLS throughout
+  * the postscreen(8) source code. If Postfix is built without TLS support,
+  * then the TLS proxy will simply report that TLS is not available, and
+  * conventional error handling will take care of the issue.
+  */
+static int psc_tls_use_tls;
+static int psc_tls_enforce_tls;
+
+#ifdef TODO_USE_SASL_AUTH
+static int psc_tls_auth_only;
+
+#endif
 
  /*
   * Encapsulation. We must not forget turn off input/timer events when we
@@ -181,57 +228,185 @@ static void ps_smtpd_time_event(int, char *);
   * with the Postfix smtp-source and smtp-sink tools shows that this would
   * noticeably increase the run-time cost.
   */
-#define PS_CLEAR_EVENT_DROP_SESSION_STATE(state, event, reply) do { \
-       PS_CLEAR_EVENT_REQUEST(vstream_fileno((state)->smtp_client_stream), \
+#define PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, event, reply) do { \
+       PSC_CLEAR_EVENT_REQUEST(vstream_fileno((state)->smtp_client_stream), \
                                   (event), (char *) (state)); \
-       PS_DROP_SESSION_STATE((state), (reply)); \
+       PSC_DROP_SESSION_STATE((state), (reply)); \
     } while (0);
 
-#define PS_CLEAR_EVENT_HANGUP(state, event) do { \
-       PS_CLEAR_EVENT_REQUEST(vstream_fileno((state)->smtp_client_stream), \
+#define PSC_CLEAR_EVENT_HANGUP(state, event) do { \
+       PSC_CLEAR_EVENT_REQUEST(vstream_fileno((state)->smtp_client_stream), \
                                   (event), (char *) (state)); \
-       ps_hangup_event(state); \
+       psc_hangup_event(state); \
     } while (0);
 
-/* ps_helo_cmd - record HELO and respond */
+/* psc_helo_cmd - record HELO and respond */
 
-static int ps_helo_cmd(PS_STATE *state, char *args)
+static int psc_helo_cmd(PSC_STATE *state, char *args)
 {
-    char   *helo_name = PS_SMTPD_NEXT_TOKEN(args);
+    char   *helo_name = PSC_SMTPD_NEXT_TOKEN(args);
 
     /*
      * smtpd(8) incompatibility: we ignore extra words; smtpd(8) saves them.
      */
     if (helo_name == 0)
-       return (PS_SEND_REPLY(state, "501 Syntax: HELO hostname\r\n"));
+       return (PSC_SEND_REPLY(state, "501 Syntax: HELO hostname\r\n"));
 
-    PS_STRING_UPDATE(state->helo_name, helo_name);
-    PS_STRING_RESET(state->sender);
+    PSC_STRING_UPDATE(state->helo_name, helo_name);
+    PSC_STRING_RESET(state->sender);
     /* Don't downgrade state->protocol, in case some test depends on this. */
-    return (PS_SEND_REPLY(state, ps_smtpd_helo_reply));
+    return (PSC_SEND_REPLY(state, psc_smtpd_helo_reply));
+}
+
+/* psc_smtpd_format_ehlo_reply - format EHLO response */
+
+static void psc_smtpd_format_ehlo_reply(VSTRING *buf, int discard_mask)
+{
+    const char *myname = "psc_smtpd_format_ehlo_reply";
+    int     saved_len = 0;
+
+    if (msg_verbose)
+       msg_info("%s: discard_mask %s", myname, str_ehlo_mask(discard_mask));
+
+#define PSC_EHLO_APPEND(save, buf, fmt) do { \
+       (save) = LEN(buf); \
+       vstring_sprintf_append((buf), (fmt)); \
+    } while (0)
+
+#define PSC_EHLO_APPEND1(save, buf, fmt, arg1) do { \
+       (save) = LEN(buf); \
+       vstring_sprintf_append((buf), (fmt), (arg1)); \
+    } while (0)
+
+    vstring_sprintf(psc_temp, "250-%s\r\n", var_myhostname);
+    if ((discard_mask & EHLO_MASK_SIZE) == 0) {
+       if (var_message_limit)
+           PSC_EHLO_APPEND1(saved_len, psc_temp, "250-SIZE %lu\r\n",
+                            (unsigned long) var_message_limit);
+       else
+           PSC_EHLO_APPEND(saved_len, psc_temp, "250-SIZE\r\n");
+    }
+    if ((discard_mask & EHLO_MASK_VRFY) == 0 && var_disable_vrfy_cmd == 0)
+       PSC_EHLO_APPEND(saved_len, psc_temp, "250-VRFY\r\n");
+    if ((discard_mask & EHLO_MASK_ETRN) == 0)
+       PSC_EHLO_APPEND(saved_len, psc_temp, "250-ETRN\r\n");
+    if ((discard_mask & EHLO_MASK_STARTTLS) == 0
+       && (psc_tls_use_tls || psc_tls_enforce_tls))
+       PSC_EHLO_APPEND(saved_len, psc_temp, "250-STARTTLS\r\n");
+#ifdef TODO_SASL_AUTH
+    if ((discard_mask & EHLO_MASK_AUTH) == 0 && sasl_mechanism_list
+       && (psc_tls_auth_only == 0 || (discard_mask & EHLO_MASK_STARTTLS))) {
+       PSC_EHLO_APPEND1(saved_len, psc_temp, "AUTH %s", sasl_mechanism_list);
+       if (var_broken_auth_clients)
+           PSC_EHLO_APPEND1(saved_len, psc_temp, "AUTH=%s", sasl_mechanism_list);
+    }
+#endif
+    if ((discard_mask & EHLO_MASK_ENHANCEDSTATUSCODES) == 0)
+       PSC_EHLO_APPEND(saved_len, psc_temp, "250-ENHANCEDSTATUSCODES\r\n");
+    if ((discard_mask & EHLO_MASK_8BITMIME) == 0)
+       PSC_EHLO_APPEND(saved_len, psc_temp, "250-8BITMIME\r\n");
+    if ((discard_mask & EHLO_MASK_DSN) == 0)
+       PSC_EHLO_APPEND(saved_len, psc_temp, "250-DSN\r\n");
+    STR(psc_temp)[saved_len + 3] = ' ';
 }
 
-/* ps_ehlo_cmd - record EHLO and respond */
+/* psc_ehlo_cmd - record EHLO and respond */
 
-static int ps_ehlo_cmd(PS_STATE *state, char *args)
+static int psc_ehlo_cmd(PSC_STATE *state, char *args)
 {
-    char   *helo_name = PS_SMTPD_NEXT_TOKEN(args);
+    char   *helo_name = PSC_SMTPD_NEXT_TOKEN(args);
+    const char *ehlo_words;
+    int     discard_mask;
+    char   *reply;
 
     /*
      * smtpd(8) incompatibility: we ignore extra words; smtpd(8) saves them.
      */
     if (helo_name == 0)
-       return (PS_SEND_REPLY(state, "501 Syntax: EHLO hostname\r\n"));
+       return (PSC_SEND_REPLY(state, "501 Syntax: EHLO hostname\r\n"));
 
-    PS_STRING_UPDATE(state->helo_name, helo_name);
-    PS_STRING_RESET(state->sender);
+    PSC_STRING_UPDATE(state->helo_name, helo_name);
+    PSC_STRING_RESET(state->sender);
     state->protocol = MAIL_PROTO_ESMTP;
-    return (PS_SEND_REPLY(state, ps_smtpd_ehlo_reply));
+
+    /*
+     * smtpd(8) compatibility: dynamic reply filtering.
+     */
+    if (psc_ehlo_discard_maps != 0
+       && (ehlo_words = maps_find(psc_ehlo_discard_maps,
+                                  state->smtp_client_addr, 0)) != 0
+       && (discard_mask = ehlo_mask(ehlo_words)) != psc_ehlo_discard_mask) {
+       if (discard_mask && !(discard_mask & EHLO_MASK_SILENT))
+           msg_info("[%s]%s: discarding EHLO keywords: %s",
+                 PSC_CLIENT_ADDR_PORT(state), str_ehlo_mask(discard_mask));
+       if (state->flags & PSC_STATE_FLAG_USING_TLS)
+           discard_mask |= EHLO_MASK_STARTTLS;
+       psc_smtpd_format_ehlo_reply(psc_temp, discard_mask);
+       reply = STR(psc_temp);
+       state->ehlo_discard_mask = discard_mask;
+    } else if (state->flags & PSC_STATE_FLAG_USING_TLS) {
+       reply = psc_smtpd_ehlo_reply_tls;
+       state->ehlo_discard_mask = psc_ehlo_discard_mask | EHLO_MASK_STARTTLS;
+    } else {
+       reply = psc_smtpd_ehlo_reply_plain;
+       state->ehlo_discard_mask = psc_ehlo_discard_mask;
+    }
+    return (PSC_SEND_REPLY(state, reply));
+}
+
+/* psc_starttls_resume - resume the SMTP protocol after tlsproxy activation */
+
+static void psc_starttls_resume(int unused_event, char *context)
+{
+    const char *myname = "psc_starttls_resume";
+    PSC_STATE *state = (PSC_STATE *) context;
+
+    /*
+     * Reset SMTP server state if STARTTLS was successful. Todo: reset SASL
+     * AUTH state. Dovecot responses may change when it knows that a
+     * connection is encrypted.
+     */
+    if (state->flags & PSC_STATE_FLAG_USING_TLS) {
+       PSC_STRING_RESET(state->helo_name);
+       PSC_STRING_RESET(state->sender);
+    }
+
+    /*
+     * Wait for the client to respond.
+     */
+    PSC_RESUME_SMTP_CMD_EVENTS(state);
+}
+
+/* psc_starttls_cmd - activate the tlsproxy server */
+
+static int psc_starttls_cmd(PSC_STATE *state, char *args)
+{
+    const char *myname = "psc_starttls_cmd";
+
+    /*
+     * smtpd(8) incompatibility: we can't send a 4XX reply that TLS is
+     * unavailable when tlsproxy(8) detects the problem too late.
+     */
+    if (PSC_SMTPD_NEXT_TOKEN(args) != 0)
+       return (PSC_SEND_REPLY(state, "501 Syntax: EHLO hostname\r\n"));
+    if (state->flags & PSC_STATE_FLAG_USING_TLS)
+       return (PSC_SEND_REPLY(state,
+                              "554 5.5.1 Error: TLS already active\r\n"));
+    if (psc_tls_use_tls == 0 || (state->ehlo_discard_mask & EHLO_MASK_STARTTLS))
+       return (PSC_SEND_REPLY(state,
+                          "502 5.5.1 Error: command not implemented\r\n"));
+
+    /*
+     * Suspend the SMTP protocol until psc_starttls_resume() is called.
+     */
+    PSC_SUSPEND_SMTP_CMD_EVENTS(state);
+    psc_starttls_open(state, psc_starttls_resume);
+    return (0);
 }
 
-/* ps_extract_addr - extract MAIL/RCPT address, unquoted form */
+/* psc_extract_addr - extract MAIL/RCPT address, unquoted form */
 
-static char *ps_extract_addr(VSTRING *result, const char *string)
+static char *psc_extract_addr(VSTRING *result, const char *string)
 {
     const unsigned char *cp = (const unsigned char *) string;
     int     stop_at;
@@ -274,9 +449,9 @@ static char *ps_extract_addr(VSTRING *result, const char *string)
     return (STR(result));
 }
 
-/* ps_mail_cmd - record MAIL and respond */
+/* psc_mail_cmd - record MAIL and respond */
 
-static int ps_mail_cmd(PS_STATE *state, char *args)
+static int psc_mail_cmd(PSC_STATE *state, char *args)
 {
     char   *colon;
     char   *addr;
@@ -285,25 +460,25 @@ static int ps_mail_cmd(PS_STATE *state, char *args)
      * smtpd(8) incompatibility: we never reject the sender, and we ignore
      * additional arguments.
      */
-    if (var_ps_helo_required && state->helo_name == 0)
-       return (PS_SEND_REPLY(state,
-                             "503 5.5.1 Error: send HELO/EHLO first\r\n"));
+    if (var_psc_helo_required && state->helo_name == 0)
+       return (PSC_SEND_REPLY(state,
+                              "503 5.5.1 Error: send HELO/EHLO first\r\n"));
     if (state->sender != 0)
-       return (PS_SEND_REPLY(state,
-                             "503 5.5.1 Error: nested MAIL command\r\n"));
+       return (PSC_SEND_REPLY(state,
+                              "503 5.5.1 Error: nested MAIL command\r\n"));
     if (args == 0 || (colon = strchr(args, ':')) == 0)
-       return (PS_SEND_REPLY(state,
-                             "501 5.5.4 Syntax: MAIL FROM:<address>\r\n"));
-    if ((addr = ps_extract_addr(ps_temp, colon + 1)) == 0)
-       return (PS_SEND_REPLY(state,
-                             "501 5.1.7 Bad sender address syntax\r\n"));
-    PS_STRING_UPDATE(state->sender, addr);
-    return (PS_SEND_REPLY(state, "250 2.1.0 Ok\r\n"));
+       return (PSC_SEND_REPLY(state,
+                              "501 5.5.4 Syntax: MAIL FROM:<address>\r\n"));
+    if ((addr = psc_extract_addr(psc_temp, colon + 1)) == 0)
+       return (PSC_SEND_REPLY(state,
+                              "501 5.1.7 Bad sender address syntax\r\n"));
+    PSC_STRING_UPDATE(state->sender, addr);
+    return (PSC_SEND_REPLY(state, "250 2.1.0 Ok\r\n"));
 }
 
-/* ps_rcpt_cmd record RCPT and respond */
+/* psc_rcpt_cmd record RCPT and respond */
 
-static int ps_rcpt_cmd(PS_STATE *state, char *args)
+static int psc_rcpt_cmd(PSC_STATE *state, char *args)
 {
     char   *colon;
     char   *addr;
@@ -313,37 +488,37 @@ static int ps_rcpt_cmd(PS_STATE *state, char *args)
      * additional arguments.
      */
     if (state->sender == 0)
-       return (PS_SEND_REPLY(state,
-                             "503 5.5.1 Error: need MAIL command\r\n"));
+       return (PSC_SEND_REPLY(state,
+                              "503 5.5.1 Error: need MAIL command\r\n"));
     if (args == 0 || (colon = strchr(args, ':')) == 0)
-       return (PS_SEND_REPLY(state,
-                             "501 5.5.4 Syntax: RCPT TO:<address>\r\n"));
-    if ((addr = ps_extract_addr(ps_temp, colon + 1)) == 0)
-       return (PS_SEND_REPLY(state,
-                             "501 5.1.3 Bad recipient address syntax\r\n"));
+       return (PSC_SEND_REPLY(state,
+                              "501 5.5.4 Syntax: RCPT TO:<address>\r\n"));
+    if ((addr = psc_extract_addr(psc_temp, colon + 1)) == 0)
+       return (PSC_SEND_REPLY(state,
+                            "501 5.1.3 Bad recipient address syntax\r\n"));
     msg_info("NOQUEUE: reject: RCPT from [%s]:%s: %.*s; "
             "from=<%s>, to=<%s>, proto=%s, helo=<%s>",
-            PS_CLIENT_ADDR_PORT(state),
+            PSC_CLIENT_ADDR_PORT(state),
             (int) strlen(state->rcpt_reply) - 2, state->rcpt_reply,
             state->sender, addr, state->protocol,
             state->helo_name ? state->helo_name : "");
-    return (PS_SEND_REPLY(state, state->rcpt_reply));
+    return (PSC_SEND_REPLY(state, state->rcpt_reply));
 }
 
-/* ps_data_cmd - respond to DATA and disconnect */
+/* psc_data_cmd - respond to DATA and disconnect */
 
-static int ps_data_cmd(PS_STATE *state, char *args)
+static int psc_data_cmd(PSC_STATE *state, char *args)
 {
 
     /*
      * smtpd(8) incompatibility: we reject all requests.
      */
-    if (PS_SMTPD_NEXT_TOKEN(args) != 0)
-       return (PS_SEND_REPLY(state,
-                             "501 5.5.4 Syntax: DATA\r\n"));
+    if (PSC_SMTPD_NEXT_TOKEN(args) != 0)
+       return (PSC_SEND_REPLY(state,
+                              "501 5.5.4 Syntax: DATA\r\n"));
     if (state->sender == 0)
-       return (PS_SEND_REPLY(state,
-                             "503 5.5.1 Error: need RCPT command\r\n"));
+       return (PSC_SEND_REPLY(state,
+                              "503 5.5.1 Error: need RCPT command\r\n"));
 
     /*
      * We really would like to hang up the connection as early as possible,
@@ -353,90 +528,90 @@ static int ps_data_cmd(PS_STATE *state, char *args)
      * 
      * If we proceed into the data phase, enforce over-all DATA time limit.
      */
-    return (PS_SEND_REPLY(state,
-                         "554 5.5.1 Error: no valid recipients\r\n"));
+    return (PSC_SEND_REPLY(state,
+                          "554 5.5.1 Error: no valid recipients\r\n"));
 }
 
-/* ps_rset_cmd - reset, send 250 OK */
+/* psc_rset_cmd - reset, send 250 OK */
 
-static int ps_rset_cmd(PS_STATE *state, char *unused_args)
+static int psc_rset_cmd(PSC_STATE *state, char *unused_args)
 {
-    PS_STRING_RESET(state->sender);
-    return (PS_SEND_REPLY(state, "250 2.0.0 Ok\r\n"));
+    PSC_STRING_RESET(state->sender);
+    return (PSC_SEND_REPLY(state, "250 2.0.0 Ok\r\n"));
 }
 
-/* ps_noop_cmd - respond to something */
+/* psc_noop_cmd - respond to something */
 
-static int ps_noop_cmd(PS_STATE *state, char *unused_args)
+static int psc_noop_cmd(PSC_STATE *state, char *unused_args)
 {
-    return (PS_SEND_REPLY(state, "250 2.0.0 Ok\r\n"));
+    return (PSC_SEND_REPLY(state, "250 2.0.0 Ok\r\n"));
 }
 
-/* ps_vrfy_cmd - respond to VRFY */
+/* psc_vrfy_cmd - respond to VRFY */
 
-static int ps_vrfy_cmd(PS_STATE *state, char *args)
+static int psc_vrfy_cmd(PSC_STATE *state, char *args)
 {
 
     /*
      * smtpd(8) incompatibility: we reject all requests, and ignore
      * additional arguments.
      */
-    if (PS_SMTPD_NEXT_TOKEN(args) == 0)
-       return (PS_SEND_REPLY(state,
-                             "501 5.5.4 Syntax: VRFY address\r\n"));
-    if (var_ps_disable_vrfy)
-       return (PS_SEND_REPLY(state,
-                             "502 5.5.1 VRFY command is disabled\r\n"));
-    return (PS_SEND_REPLY(state, state->rcpt_reply));
+    if (PSC_SMTPD_NEXT_TOKEN(args) == 0)
+       return (PSC_SEND_REPLY(state,
+                              "501 5.5.4 Syntax: VRFY address\r\n"));
+    if (var_psc_disable_vrfy)
+       return (PSC_SEND_REPLY(state,
+                              "502 5.5.1 VRFY command is disabled\r\n"));
+    return (PSC_SEND_REPLY(state, state->rcpt_reply));
 }
 
-/* ps_etrn_cmd - reset, send 250 OK */
+/* psc_etrn_cmd - reset, send 250 OK */
 
-static int ps_etrn_cmd(PS_STATE *state, char *args)
+static int psc_etrn_cmd(PSC_STATE *state, char *args)
 {
 
     /*
      * smtpd(8) incompatibility: we reject all requests, and ignore
      * additional arguments.
      */
-    if (var_ps_helo_required && state->helo_name == 0)
-       return (PS_SEND_REPLY(state,
-                             "503 5.5.1 Error: send HELO/EHLO first\r\n"));
-    if (PS_SMTPD_NEXT_TOKEN(args) == 0)
-       return (PS_SEND_REPLY(state,
-                             "500 Syntax: ETRN domain\r\n"));
-    return (PS_SEND_REPLY(state, "458 Unable to queue messages\r\n"));
+    if (var_psc_helo_required && state->helo_name == 0)
+       return (PSC_SEND_REPLY(state,
+                              "503 5.5.1 Error: send HELO/EHLO first\r\n"));
+    if (PSC_SMTPD_NEXT_TOKEN(args) == 0)
+       return (PSC_SEND_REPLY(state,
+                              "500 Syntax: ETRN domain\r\n"));
+    return (PSC_SEND_REPLY(state, "458 Unable to queue messages\r\n"));
 }
 
-/* ps_quit_cmd - respond to QUIT and disconnect */
+/* psc_quit_cmd - respond to QUIT and disconnect */
 
-static int ps_quit_cmd(PS_STATE *state, char *unused_args)
+static int psc_quit_cmd(PSC_STATE *state, char *unused_args)
 {
-    const char *myname = "ps_quit_cmd";
+    const char *myname = "psc_quit_cmd";
 
-    PS_CLEAR_EVENT_DROP_SESSION_STATE(state, ps_smtpd_time_event,
-                                     "221 2.0.0 Bye\r\n");
+    PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event,
+                                      "221 2.0.0 Bye\r\n");
     /* Caution: state is now a dangling pointer. */
     return (0);
 }
 
-/* ps_smtpd_time_event - handle per-session time limit */
+/* psc_smtpd_time_event - handle per-session time limit */
 
-static void ps_smtpd_time_event(int event, char *context)
+static void psc_smtpd_time_event(int event, char *context)
 {
-    const char *myname = "ps_smtpd_time_event";
-    PS_STATE *state = (PS_STATE *) context;
+    const char *myname = "psc_smtpd_time_event";
+    PSC_STATE *state = (PSC_STATE *) context;
 
     if (msg_verbose > 1)
        msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s",
-                myname, ps_post_queue_length, ps_check_queue_length,
+                myname, psc_post_queue_length, psc_check_queue_length,
                 event, vstream_fileno(state->smtp_client_stream),
                 state->smtp_client_addr, state->smtp_client_port,
-                ps_print_state_flags(state->flags, myname));
+                psc_print_state_flags(state->flags, myname));
 
-    msg_info("COMMAND TIME LIMIT from [%s]:%s", PS_CLIENT_ADDR_PORT(state));
-    PS_CLEAR_EVENT_DROP_SESSION_STATE(state, ps_smtpd_time_event,
-                                     ps_smtpd_timeout_reply);
+    msg_info("COMMAND TIME LIMIT from [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
+    PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event,
+                                      psc_smtpd_timeout_reply);
 }
 
  /*
@@ -444,38 +619,40 @@ static void ps_smtpd_time_event(int event, char *context)
   */
 typedef struct {
     const char *name;
-    int     (*action) (PS_STATE *, char *);
+    int     (*action) (PSC_STATE *, char *);
     int     flags;                     /* see below */
-} PS_SMTPD_COMMAND;
-
-#define PS_SMTPD_CMD_FLAG_NONE         (0)     /* no flags (i.e. disabled) */
-#define PS_SMTPD_CMD_FLAG_ENABLE       (1<<0)  /* command is enabled */
-#define PS_SMTPD_CMD_FLAG_DESTROY      (1<<1)  /* dangling pointer alert */
-
-static const PS_SMTPD_COMMAND command_table[] = {
-    "HELO", ps_helo_cmd, PS_SMTPD_CMD_FLAG_ENABLE,
-    "EHLO", ps_ehlo_cmd, PS_SMTPD_CMD_FLAG_ENABLE,
-    "XCLIENT", ps_noop_cmd, PS_SMTPD_CMD_FLAG_NONE,
-    "XFORWARD", ps_noop_cmd, PS_SMTPD_CMD_FLAG_NONE,
-    "AUTH", ps_noop_cmd, PS_SMTPD_CMD_FLAG_NONE,
-    "MAIL", ps_mail_cmd, PS_SMTPD_CMD_FLAG_ENABLE,
-    "RCPT", ps_rcpt_cmd, PS_SMTPD_CMD_FLAG_ENABLE,
-    "DATA", ps_data_cmd, PS_SMTPD_CMD_FLAG_ENABLE,
-    /* ".", ps_dot_cmd, PS_SMTPD_CMD_FLAG_NONE, */
-    "RSET", ps_rset_cmd, PS_SMTPD_CMD_FLAG_ENABLE,
-    "NOOP", ps_noop_cmd, PS_SMTPD_CMD_FLAG_ENABLE,
-    "VRFY", ps_vrfy_cmd, PS_SMTPD_CMD_FLAG_ENABLE,
-    "ETRN", ps_etrn_cmd, PS_SMTPD_CMD_FLAG_ENABLE,
-    "QUIT", ps_quit_cmd, PS_SMTPD_CMD_FLAG_ENABLE | PS_SMTPD_CMD_FLAG_DESTROY,
+} PSC_SMTPD_COMMAND;
+
+#define PSC_SMTPD_CMD_FLAG_NONE                (0)     /* no flags (i.e. disabled) */
+#define PSC_SMTPD_CMD_FLAG_ENABLE      (1<<0)  /* command is enabled */
+#define PSC_SMTPD_CMD_FLAG_DESTROY     (1<<1)  /* dangling pointer alert */
+#define PSC_SMTPD_CMD_FLAG_PRE_TLS     (1<<2)  /* allowed with mandatory TLS */
+
+static const PSC_SMTPD_COMMAND command_table[] = {
+    "HELO", psc_helo_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_PRE_TLS,
+    "EHLO", psc_ehlo_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_PRE_TLS,
+    "STARTTLS", psc_starttls_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_PRE_TLS,
+    "XCLIENT", psc_noop_cmd, PSC_SMTPD_CMD_FLAG_NONE,
+    "XFORWARD", psc_noop_cmd, PSC_SMTPD_CMD_FLAG_NONE,
+    "AUTH", psc_noop_cmd, PSC_SMTPD_CMD_FLAG_NONE,
+    "MAIL", psc_mail_cmd, PSC_SMTPD_CMD_FLAG_ENABLE,
+    "RCPT", psc_rcpt_cmd, PSC_SMTPD_CMD_FLAG_ENABLE,
+    "DATA", psc_data_cmd, PSC_SMTPD_CMD_FLAG_ENABLE,
+    /* ".", psc_dot_cmd, PSC_SMTPD_CMD_FLAG_NONE, */
+    "RSET", psc_rset_cmd, PSC_SMTPD_CMD_FLAG_ENABLE,
+    "NOOP", psc_noop_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_PRE_TLS,
+    "VRFY", psc_vrfy_cmd, PSC_SMTPD_CMD_FLAG_ENABLE,
+    "ETRN", psc_etrn_cmd, PSC_SMTPD_CMD_FLAG_ENABLE,
+    "QUIT", psc_quit_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_DESTROY | PSC_SMTPD_CMD_FLAG_PRE_TLS,
     0,
 };
 
-/* ps_smtpd_read_event - pseudo responder */
+/* psc_smtpd_read_event - pseudo responder */
 
-static void ps_smtpd_read_event(int event, char *context)
+static void psc_smtpd_read_event(int event, char *context)
 {
-    const char *myname = "ps_smtpd_read_event";
-    PS_STATE *state = (PS_STATE *) context;
+    const char *myname = "psc_smtpd_read_event";
+    PSC_STATE *state = (PSC_STATE *) context;
     int     ch;
     struct cmd_trans {
        int     state;
@@ -483,27 +660,27 @@ static void ps_smtpd_read_event(int event, char *context)
        int     next_state;
     };
 
-#define PS_SMTPD_CMD_ST_ANY            0
-#define PS_SMTPD_CMD_ST_CR             1
-#define PS_SMTPD_CMD_ST_CR_LF          2
+#define PSC_SMTPD_CMD_ST_ANY           0
+#define PSC_SMTPD_CMD_ST_CR            1
+#define PSC_SMTPD_CMD_ST_CR_LF         2
 
     static const struct cmd_trans cmd_trans[] = {
-       PS_SMTPD_CMD_ST_ANY, '\r', PS_SMTPD_CMD_ST_CR,
-       PS_SMTPD_CMD_ST_CR, '\n', PS_SMTPD_CMD_ST_CR_LF,
+       PSC_SMTPD_CMD_ST_ANY, '\r', PSC_SMTPD_CMD_ST_CR,
+       PSC_SMTPD_CMD_ST_CR, '\n', PSC_SMTPD_CMD_ST_CR_LF,
        0, 0, 0,
     };
     const struct cmd_trans *transp;
     char   *cmd_buffer_ptr;
     char   *command;
-    const PS_SMTPD_COMMAND *cmdp;
+    const PSC_SMTPD_COMMAND *cmdp;
     int     write_stat;
 
     if (msg_verbose > 1)
        msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s",
-                myname, ps_post_queue_length, ps_check_queue_length,
+                myname, psc_post_queue_length, psc_check_queue_length,
                 event, vstream_fileno(state->smtp_client_stream),
                 state->smtp_client_addr, state->smtp_client_port,
-                ps_print_state_flags(state->flags, myname));
+                psc_print_state_flags(state->flags, myname));
 
     /*
      * Basic liveness requirements.
@@ -514,12 +691,12 @@ static void ps_smtpd_read_event(int event, char *context)
      * Don't try to read input before it has arrived, otherwise we would starve
      * the pseudo threads of other sessions. Get out of here as soon as the
      * VSTREAM read buffer dries up. Do not look for more input in kernel
-     * buffers. That input wasn't likely there when ps_smtpd_read_event() was
-     * called. Also, yielding the pseudo thread will improve fairness for
+     * buffers. That input wasn't likely there when psc_smtpd_read_event()
+     * was called. Also, yielding the pseudo thread will improve fairness for
      * other pseudo threads.
      */
-#define PS_SMTPD_BUFFER_EMPTY(state) \
-       (!PS_SMTPD_HAVE_PUSH_BACK(state) \
+#define PSC_SMTPD_BUFFER_EMPTY(state) \
+       (!PSC_SMTPD_HAVE_PUSH_BACK(state) \
        && vstream_peek(state->smtp_client_stream) <= 0)
 
     /*
@@ -533,20 +710,20 @@ static void ps_smtpd_read_event(int event, char *context)
         */
        for (;;) {
 
-           if ((ch = PS_SMTPD_NEXT_CHAR(state)) == VSTREAM_EOF) {
-               PS_CLEAR_EVENT_HANGUP(state, ps_smtpd_time_event);
+           if ((ch = PSC_SMTPD_NEXT_CHAR(state)) == VSTREAM_EOF) {
+               PSC_CLEAR_EVENT_HANGUP(state, psc_smtpd_time_event);
                return;
            }
 
            /*
             * Sanity check. We don't want to store infinitely long commands.
             */
-           if (state->read_state == PS_SMTPD_CMD_ST_ANY
+           if (state->read_state == PSC_SMTPD_CMD_ST_ANY
                && VSTRING_LEN(state->cmd_buffer) >= var_line_limit) {
                msg_info("COMMAND LENGTH LIMIT from [%s]:%s",
-                        PS_CLIENT_ADDR_PORT(state));
-               PS_CLEAR_EVENT_DROP_SESSION_STATE(state, ps_smtpd_time_event,
-                                                 ps_smtpd_421_reply);
+                        PSC_CLIENT_ADDR_PORT(state));
+               PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event,
+                                                  psc_smtpd_421_reply);
                return;
            }
            VSTRING_ADDCH(state->cmd_buffer, ch);
@@ -567,8 +744,8 @@ static void ps_smtpd_read_event(int event, char *context)
            else if (ch == cmd_trans[0].want)
                state->read_state = cmd_trans[0].next_state;
            else
-               state->read_state = PS_SMTPD_CMD_ST_ANY;
-           if (state->read_state == PS_SMTPD_CMD_ST_CR_LF) {
+               state->read_state = PSC_SMTPD_CMD_ST_ANY;
+           if (state->read_state == PSC_SMTPD_CMD_ST_CR_LF) {
                vstring_truncate(state->cmd_buffer,
                                 VSTRING_LEN(state->cmd_buffer) - 2);
                break;
@@ -578,37 +755,37 @@ static void ps_smtpd_read_event(int event, char *context)
             * Bare newline test.
             */
            if (ch == '\n') {
-               if ((state->flags & PS_STATE_MASK_BARLF_TODO_SKIP)
-                   == PS_STATE_FLAG_BARLF_TODO) {
+               if ((state->flags & PSC_STATE_MASK_BARLF_TODO_SKIP)
+                   == PSC_STATE_FLAG_BARLF_TODO) {
                    msg_info("BARE NEWLINE from [%s]:%s",
-                            PS_CLIENT_ADDR_PORT(state));
-                   PS_FAIL_SESSION_STATE(state, PS_STATE_FLAG_BARLF_FAIL);
-                   PS_UNPASS_SESSION_STATE(state, PS_STATE_FLAG_BARLF_PASS);
-                   state->barlf_stamp = PS_TIME_STAMP_DISABLED;        /* XXX */
+                            PSC_CLIENT_ADDR_PORT(state));
+                   PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_BARLF_FAIL);
+                   PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_BARLF_PASS);
+                   state->barlf_stamp = PSC_TIME_STAMP_DISABLED;       /* XXX */
                    /* Skip this test for the remainder of this session. */
-                   PS_SKIP_SESSION_STATE(state, "bare newline test",
-                                         PS_STATE_FLAG_BARLF_SKIP);
-                   switch (ps_barlf_action) {
-                   case PS_ACT_DROP:
-                       PS_CLEAR_EVENT_DROP_SESSION_STATE(state,
-                                                       ps_smtpd_time_event,
+                   PSC_SKIP_SESSION_STATE(state, "bare newline test",
+                                          PSC_STATE_FLAG_BARLF_SKIP);
+                   switch (psc_barlf_action) {
+                   case PSC_ACT_DROP:
+                       PSC_CLEAR_EVENT_DROP_SESSION_STATE(state,
+                                                      psc_smtpd_time_event,
                                            "521 5.5.1 Protocol error\r\n");
                        return;
-                   case PS_ACT_ENFORCE:
-                       PS_ENFORCE_SESSION_STATE(state,
+                   case PSC_ACT_ENFORCE:
+                       PSC_ENFORCE_SESSION_STATE(state,
                                            "550 5.5.1 Protocol error\r\n");
                        break;
-                   case PS_ACT_IGNORE:
-                       PS_UNFAIL_SESSION_STATE(state,
-                                               PS_STATE_FLAG_BARLF_FAIL);
+                   case PSC_ACT_IGNORE:
+                       PSC_UNFAIL_SESSION_STATE(state,
+                                                PSC_STATE_FLAG_BARLF_FAIL);
                        /* Temporarily whitelist until something expires. */
-                       PS_PASS_SESSION_STATE(state, "bare newline test",
-                                             PS_STATE_FLAG_BARLF_PASS);
-                       state->barlf_stamp = event_time() + ps_min_ttl;
+                       PSC_PASS_SESSION_STATE(state, "bare newline test",
+                                              PSC_STATE_FLAG_BARLF_PASS);
+                       state->barlf_stamp = event_time() + psc_min_ttl;
                        break;
                    default:
                        msg_panic("%s: unknown bare_newline action value %d",
-                                 myname, ps_barlf_action);
+                                 myname, psc_barlf_action);
                    }
                }
                vstring_truncate(state->cmd_buffer,
@@ -623,7 +800,7 @@ static void ps_smtpd_read_event(int event, char *context)
             * XXX Do not reset the read timeout. The entire command must be
             * received within the time limit.
             */
-           if (PS_SMTPD_BUFFER_EMPTY(state))
+           if (PSC_SMTPD_BUFFER_EMPTY(state))
                return;
        }
 
@@ -633,7 +810,7 @@ static void ps_smtpd_read_event(int event, char *context)
         * this to work as expected, VSTRING_RESET() must be non-destructive.
         */
        VSTRING_TERMINATE(state->cmd_buffer);
-       state->read_state = PS_SMTPD_CMD_ST_ANY;
+       state->read_state = PSC_SMTPD_CMD_ST_ANY;
        VSTRING_RESET(state->cmd_buffer);
 
        /*
@@ -649,7 +826,7 @@ static void ps_smtpd_read_event(int event, char *context)
                     state->smtp_client_port, cmd_buffer_ptr);
 
        /* Parse the command name. */
-       if ((command = PS_SMTPD_NEXT_TOKEN(cmd_buffer_ptr)) == 0)
+       if ((command = PSC_SMTPD_NEXT_TOKEN(cmd_buffer_ptr)) == 0)
            command = "";
 
        /*
@@ -663,76 +840,76 @@ static void ps_smtpd_read_event(int event, char *context)
                break;
 
        /* Non-SMTP command test. */
-       if ((state->flags & PS_STATE_MASK_NSMTP_TODO_SKIP)
-           == PS_STATE_FLAG_NSMTP_TODO && cmdp->name == 0
+       if ((state->flags & PSC_STATE_MASK_NSMTP_TODO_SKIP)
+           == PSC_STATE_FLAG_NSMTP_TODO && cmdp->name == 0
            && (is_header(command)
-               || (*var_ps_forbid_cmds
-                   && string_list_match(ps_forbid_cmds, command)))) {
+               || (*var_psc_forbid_cmds
+                   && string_list_match(psc_forbid_cmds, command)))) {
            printable(command, '?');
            msg_info("NON-SMTP COMMAND from [%s]:%s %.100s",
-                    PS_CLIENT_ADDR_PORT(state), command);
-           PS_FAIL_SESSION_STATE(state, PS_STATE_FLAG_NSMTP_FAIL);
-           PS_UNPASS_SESSION_STATE(state, PS_STATE_FLAG_NSMTP_PASS);
-           state->nsmtp_stamp = PS_TIME_STAMP_DISABLED;        /* XXX */
+                    PSC_CLIENT_ADDR_PORT(state), command);
+           PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_NSMTP_FAIL);
+           PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_NSMTP_PASS);
+           state->nsmtp_stamp = PSC_TIME_STAMP_DISABLED;       /* XXX */
            /* Skip this test for the remainder of this SMTP session. */
-           PS_SKIP_SESSION_STATE(state, "non-smtp test",
-                                 PS_STATE_FLAG_NSMTP_SKIP);
-           switch (ps_nsmtp_action) {
-           case PS_ACT_DROP:
-               PS_CLEAR_EVENT_DROP_SESSION_STATE(state,
-                                                 ps_smtpd_time_event,
+           PSC_SKIP_SESSION_STATE(state, "non-smtp test",
+                                  PSC_STATE_FLAG_NSMTP_SKIP);
+           switch (psc_nsmtp_action) {
+           case PSC_ACT_DROP:
+               PSC_CLEAR_EVENT_DROP_SESSION_STATE(state,
+                                                  psc_smtpd_time_event,
                   "521 5.7.0 Error: I can break rules, too. Goodbye.\r\n");
                return;
-           case PS_ACT_ENFORCE:
-               PS_ENFORCE_SESSION_STATE(state,
-                                        "550 5.5.1 Protocol error\r\n");
+           case PSC_ACT_ENFORCE:
+               PSC_ENFORCE_SESSION_STATE(state,
+                                         "550 5.5.1 Protocol error\r\n");
                break;
-           case PS_ACT_IGNORE:
-               PS_UNFAIL_SESSION_STATE(state,
-                                       PS_STATE_FLAG_NSMTP_FAIL);
+           case PSC_ACT_IGNORE:
+               PSC_UNFAIL_SESSION_STATE(state,
+                                        PSC_STATE_FLAG_NSMTP_FAIL);
                /* Temporarily whitelist until something else expires. */
-               PS_PASS_SESSION_STATE(state, "non-smtp test",
-                                     PS_STATE_FLAG_NSMTP_PASS);
-               state->nsmtp_stamp = event_time() + ps_min_ttl;
+               PSC_PASS_SESSION_STATE(state, "non-smtp test",
+                                      PSC_STATE_FLAG_NSMTP_PASS);
+               state->nsmtp_stamp = event_time() + psc_min_ttl;
                break;
            default:
                msg_panic("%s: unknown non_smtp_command action value %d",
-                         myname, ps_nsmtp_action);
+                         myname, psc_nsmtp_action);
            }
        }
        /* Command PIPELINING test. */
-       if ((state->flags & PS_STATE_MASK_PIPEL_TODO_SKIP)
-           == PS_STATE_FLAG_PIPEL_TODO && !PS_SMTPD_BUFFER_EMPTY(state)) {
+       if ((state->flags & PSC_STATE_MASK_PIPEL_TODO_SKIP)
+           == PSC_STATE_FLAG_PIPEL_TODO && !PSC_SMTPD_BUFFER_EMPTY(state)) {
            printable(command, '?');
            msg_info("COMMAND PIPELINING from [%s]:%s after %.100s",
-                    PS_CLIENT_ADDR_PORT(state), command);
-           PS_FAIL_SESSION_STATE(state, PS_STATE_FLAG_PIPEL_FAIL);
-           PS_UNPASS_SESSION_STATE(state, PS_STATE_FLAG_PIPEL_PASS);
-           state->pipel_stamp = PS_TIME_STAMP_DISABLED;        /* XXX */
+                    PSC_CLIENT_ADDR_PORT(state), command);
+           PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_PIPEL_FAIL);
+           PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_PIPEL_PASS);
+           state->pipel_stamp = PSC_TIME_STAMP_DISABLED;       /* XXX */
            /* Skip this test for the remainder of this SMTP session. */
-           PS_SKIP_SESSION_STATE(state, "pipelining test",
-                                 PS_STATE_FLAG_PIPEL_SKIP);
-           switch (ps_pipel_action) {
-           case PS_ACT_DROP:
-               PS_CLEAR_EVENT_DROP_SESSION_STATE(state,
-                                                 ps_smtpd_time_event,
+           PSC_SKIP_SESSION_STATE(state, "pipelining test",
+                                  PSC_STATE_FLAG_PIPEL_SKIP);
+           switch (psc_pipel_action) {
+           case PSC_ACT_DROP:
+               PSC_CLEAR_EVENT_DROP_SESSION_STATE(state,
+                                                  psc_smtpd_time_event,
                                            "521 5.5.1 Protocol error\r\n");
                return;
-           case PS_ACT_ENFORCE:
-               PS_ENFORCE_SESSION_STATE(state,
-                                        "550 5.5.1 Protocol error\r\n");
+           case PSC_ACT_ENFORCE:
+               PSC_ENFORCE_SESSION_STATE(state,
+                                         "550 5.5.1 Protocol error\r\n");
                break;
-           case PS_ACT_IGNORE:
-               PS_UNFAIL_SESSION_STATE(state,
-                                       PS_STATE_FLAG_PIPEL_FAIL);
+           case PSC_ACT_IGNORE:
+               PSC_UNFAIL_SESSION_STATE(state,
+                                        PSC_STATE_FLAG_PIPEL_FAIL);
                /* Temporarily whitelist until something else expires. */
-               PS_PASS_SESSION_STATE(state, "pipelining test",
-                                     PS_STATE_FLAG_PIPEL_PASS);
-               state->pipel_stamp = event_time() + ps_min_ttl;
+               PSC_PASS_SESSION_STATE(state, "pipelining test",
+                                      PSC_STATE_FLAG_PIPEL_PASS);
+               state->pipel_stamp = event_time() + psc_min_ttl;
                break;
            default:
                msg_panic("%s: unknown pipelining action value %d",
-                         myname, ps_pipel_action);
+                         myname, psc_pipel_action);
            }
        }
 
@@ -741,45 +918,50 @@ static void ps_smtpd_read_event(int event, char *context)
         * to the RCPT TO command. However, the client can still fail these
         * tests with some later command.
         */
-       if (cmdp->action == ps_rcpt_cmd) {
-           if ((state->flags & PS_STATE_MASK_BARLF_TODO_PASS_FAIL)
-               == PS_STATE_FLAG_BARLF_TODO) {
-               PS_PASS_SESSION_STATE(state, "bare newline test",
-                                     PS_STATE_FLAG_BARLF_PASS);
-               /* XXX Reset to PS_TIME_STAMP_DISABLED on failure. */
-               state->barlf_stamp = event_time() + var_ps_barlf_ttl;
+       if (cmdp->action == psc_rcpt_cmd) {
+           if ((state->flags & PSC_STATE_MASK_BARLF_TODO_PASS_FAIL)
+               == PSC_STATE_FLAG_BARLF_TODO) {
+               PSC_PASS_SESSION_STATE(state, "bare newline test",
+                                      PSC_STATE_FLAG_BARLF_PASS);
+               /* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */
+               state->barlf_stamp = event_time() + var_psc_barlf_ttl;
            }
-           if ((state->flags & PS_STATE_MASK_NSMTP_TODO_PASS_FAIL)
-               == PS_STATE_FLAG_NSMTP_TODO) {
-               PS_PASS_SESSION_STATE(state, "non-smtp test",
-                                     PS_STATE_FLAG_NSMTP_PASS);
-               /* XXX Reset to PS_TIME_STAMP_DISABLED on failure. */
-               state->nsmtp_stamp = event_time() + var_ps_nsmtp_ttl;
+           if ((state->flags & PSC_STATE_MASK_NSMTP_TODO_PASS_FAIL)
+               == PSC_STATE_FLAG_NSMTP_TODO) {
+               PSC_PASS_SESSION_STATE(state, "non-smtp test",
+                                      PSC_STATE_FLAG_NSMTP_PASS);
+               /* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */
+               state->nsmtp_stamp = event_time() + var_psc_nsmtp_ttl;
            }
-           if ((state->flags & PS_STATE_MASK_PIPEL_TODO_PASS_FAIL)
-               == PS_STATE_FLAG_PIPEL_TODO) {
-               PS_PASS_SESSION_STATE(state, "pipelining test",
-                                     PS_STATE_FLAG_PIPEL_PASS);
-               /* XXX Reset to PS_TIME_STAMP_DISABLED on failure. */
-               state->pipel_stamp = event_time() + var_ps_pipel_ttl;
+           if ((state->flags & PSC_STATE_MASK_PIPEL_TODO_PASS_FAIL)
+               == PSC_STATE_FLAG_PIPEL_TODO) {
+               PSC_PASS_SESSION_STATE(state, "pipelining test",
+                                      PSC_STATE_FLAG_PIPEL_PASS);
+               /* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */
+               state->pipel_stamp = event_time() + var_psc_pipel_ttl;
            }
        }
        /* Command COUNT limit test. */
-       if (++state->command_count > var_ps_cmd_count
-           && cmdp->action != ps_quit_cmd) {
+       if (++state->command_count > var_psc_cmd_count
+           && cmdp->action != psc_quit_cmd) {
            msg_info("COMMAND COUNT LIMIT from [%s]:%s",
-                    PS_CLIENT_ADDR_PORT(state));
-           PS_CLEAR_EVENT_DROP_SESSION_STATE(state, ps_smtpd_time_event,
-                                             ps_smtpd_421_reply);
+                    PSC_CLIENT_ADDR_PORT(state));
+           PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event,
+                                              psc_smtpd_421_reply);
            return;
        }
        /* Finally, execute the command. */
-       if (cmdp->name == 0 || (cmdp->flags & PS_SMTPD_CMD_FLAG_ENABLE) == 0) {
-           write_stat = PS_SEND_REPLY(state,
+       if (cmdp->name == 0 || (cmdp->flags & PSC_SMTPD_CMD_FLAG_ENABLE) == 0) {
+           write_stat = PSC_SEND_REPLY(state,
                             "502 5.5.2 Error: command not recognized\r\n");
+       } else if (psc_tls_enforce_tls
+                  && (state->flags & PSC_STATE_FLAG_USING_TLS) == 0
+                  && (cmdp->flags & PSC_SMTPD_CMD_FLAG_PRE_TLS) == 0) {
+           write_stat = PSC_SEND_REPLY(state,
+                      "530 5.7.0 Must issue a STARTTLS command first\r\n");
        } else {
            write_stat = cmdp->action(state, cmd_buffer_ptr);
-           if (cmdp->flags & PS_SMTPD_CMD_FLAG_DESTROY)
+           if (cmdp->flags & PSC_SMTPD_CMD_FLAG_DESTROY)
                return;
        }
 
@@ -787,41 +969,41 @@ static void ps_smtpd_read_event(int event, char *context)
         * Terminate the session after a write error.
         */
        if (write_stat < 0) {
-           PS_CLEAR_EVENT_HANGUP(state, ps_smtpd_time_event);
+           PSC_CLEAR_EVENT_HANGUP(state, psc_smtpd_time_event);
            return;
        }
 
        /*
         * Reset the command read timeout before reading the next command.
         */
-       event_request_timer(ps_smtpd_time_event, (char *) state,
-                           PS_EFF_CMD_TIME_LIMIT);
+       event_request_timer(psc_smtpd_time_event, (char *) state,
+                           PSC_EFF_CMD_TIME_LIMIT);
 
        /*
         * Yield this pseudo thread when the VSTREAM buffer is empty.
         */
-       if (PS_SMTPD_BUFFER_EMPTY(state))
+       if (PSC_SMTPD_BUFFER_EMPTY(state))
            return;
     }
 }
 
-/* ps_smtpd_tests - per-session deep protocol test initialization */
+/* psc_smtpd_tests - per-session deep protocol test initialization */
 
-void    ps_smtpd_tests(PS_STATE *state)
+void    psc_smtpd_tests(PSC_STATE *state)
 {
-    static char *myname = "ps_smtpd_tests";
+    static char *myname = "psc_smtpd_tests";
 
     /*
      * Report errors and progress in the context of this test.
      */
-    PS_BEGIN_TESTS(state, "tests after SMTP handshake");
+    PSC_BEGIN_TESTS(state, "tests after SMTP handshake");
 
     /*
      * Initialize per-session state that is used only by the dummy engine:
      * the command read buffer and the command read state machine.
      */
     state->cmd_buffer = vstring_alloc(100);
-    state->read_state = PS_SMTPD_CMD_ST_ANY;
+    state->read_state = PSC_SMTPD_CMD_ST_ANY;
 
     /*
      * Opportunistically make postscreen more useful by turning on the
@@ -830,78 +1012,116 @@ void    ps_smtpd_tests(PS_STATE *state)
      * 
      * XXX Make "opportunistically" configurable for each test.
      */
-    state->flags |= (PS_STATE_FLAG_PIPEL_TODO | PS_STATE_FLAG_NSMTP_TODO | \
-                    PS_STATE_FLAG_BARLF_TODO);
+    state->flags |= (PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_NSMTP_TODO | \
+                    PSC_STATE_FLAG_BARLF_TODO);
 
     /*
      * Send no SMTP banner to pregreeting clients. This eliminates a lot of
      * "NON-SMTP COMMAND" events, and improves sender/recipient logging.
      */
-    if ((state->flags & PS_STATE_FLAG_PREGR_FAIL) == 0
-       && PS_SEND_REPLY(state, ps_smtpd_greeting) != 0) {
-       ps_hangup_event(state);
+    if ((state->flags & PSC_STATE_FLAG_PREGR_FAIL) == 0
+       && PSC_SEND_REPLY(state, psc_smtpd_greeting) != 0) {
+       psc_hangup_event(state);
        return;
     }
 
     /*
      * Wait for the client to respond.
      */
-    PS_READ_EVENT_REQUEST2(vstream_fileno(state->smtp_client_stream),
-                          ps_smtpd_read_event, ps_smtpd_time_event,
-                          (char *) state, PS_EFF_CMD_TIME_LIMIT);
+    PSC_READ_EVENT_REQUEST2(vstream_fileno(state->smtp_client_stream),
+                           psc_smtpd_read_event, psc_smtpd_time_event,
+                           (char *) state, PSC_EFF_CMD_TIME_LIMIT);
 }
 
-/* ps_smtpd_init - per-process deep protocol test initialization */
+/* psc_smtpd_init - per-process deep protocol test initialization */
 
-void    ps_smtpd_init(void)
+void    psc_smtpd_init(void)
 {
 
     /*
      * Initialize the server banner.
      */
-    vstring_sprintf(ps_temp, "220 %s\r\n", var_smtpd_banner);
-    ps_smtpd_greeting = mystrdup(STR(ps_temp));
+    vstring_sprintf(psc_temp, "220 %s\r\n", var_smtpd_banner);
+    psc_smtpd_greeting = mystrdup(STR(psc_temp));
 
     /*
      * Initialize the HELO reply.
      */
-    vstring_sprintf(ps_temp, "250 %s\r\n", var_myhostname);
-    ps_smtpd_helo_reply = mystrdup(STR(ps_temp));
+    vstring_sprintf(psc_temp, "250 %s\r\n", var_myhostname);
+    psc_smtpd_helo_reply = mystrdup(STR(psc_temp));
 
     /*
-     * Initialize the EHLO reply.
+     * Legacy code copied from smtpd(8). The pre-fabricated EHLO reply
+     * depends on this.
      */
-    vstring_sprintf(ps_temp,
-                   "250-%s\r\n",               /* NOT: PIPELINING */
-                   var_myhostname);
-    if (var_message_limit)
-       vstring_sprintf_append(ps_temp,
-                              "250-SIZE %lu\r\n",
-                              (unsigned long) var_message_limit);
-    else
-       vstring_sprintf_append(ps_temp,
-                              "250-SIZE\r\n");
-    if (var_disable_vrfy_cmd == 0)
-       vstring_sprintf_append(ps_temp,
-                              "250-VRFY\r\n");
-    vstring_sprintf_append(ps_temp,
-                          "250-ETRN\r\n"
-                          "250-ENHANCEDSTATUSCODES\r\n"
-                          "250-8BITMIME\r\n"
-                          "250 DSN\r\n");
-    ps_smtpd_ehlo_reply = mystrdup(STR(ps_temp));
+    if (*var_psc_tls_level) {
+       switch (tls_level_lookup(var_psc_tls_level)) {
+       default:
+           msg_fatal("Invalid TLS level \"%s\"", var_psc_tls_level);
+           /* NOTREACHED */
+           break;
+       case TLS_LEV_SECURE:
+       case TLS_LEV_VERIFY:
+       case TLS_LEV_FPRINT:
+       case TLS_LEV_ENCRYPT:
+           var_psc_enforce_tls = var_psc_use_tls = 1;
+           break;
+       case TLS_LEV_MAY:
+           var_psc_enforce_tls = 0;
+           var_psc_use_tls = 1;
+           break;
+       case TLS_LEV_NONE:
+           var_psc_enforce_tls = var_psc_use_tls = 0;
+           break;
+       }
+    }
+    psc_tls_enforce_tls = var_psc_enforce_tls;
+    psc_tls_use_tls = var_psc_use_tls || var_psc_enforce_tls;
+#ifdef TODO_SASL_AUTH
+    if (var_psc_tls_auth_only || psc_tls_enforce_tls)
+       psc_tls_auth_only = 1;
+#endif
+
+    /*
+     * Initialize the EHLO reply. Once for plaintext sessions, and once for
+     * TLS sessions.
+     */
+    psc_smtpd_format_ehlo_reply(psc_temp, psc_ehlo_discard_mask);
+    psc_smtpd_ehlo_reply_plain = mystrdup(STR(psc_temp));
+
+    psc_smtpd_format_ehlo_reply(psc_temp,
+                               psc_ehlo_discard_mask | EHLO_MASK_STARTTLS);
+    psc_smtpd_ehlo_reply_tls = mystrdup(STR(psc_temp));
 
     /*
      * Initialize the 421 timeout reply.
      */
-    vstring_sprintf(ps_temp, "421 4.4.2 %s Error: timeout exceeded\r\n",
+    vstring_sprintf(psc_temp, "421 4.4.2 %s Error: timeout exceeded\r\n",
                    var_myhostname);
-    ps_smtpd_timeout_reply = mystrdup(STR(ps_temp));
+    psc_smtpd_timeout_reply = mystrdup(STR(psc_temp));
 
     /*
      * Initialize the generic 421 reply.
      */
-    vstring_sprintf(ps_temp, "421 %s Service unavailable - try again later\r\n",
+    vstring_sprintf(psc_temp, "421 %s Service unavailable - try again later\r\n",
                    var_myhostname);
-    ps_smtpd_421_reply = mystrdup(STR(ps_temp));
+    psc_smtpd_421_reply = mystrdup(STR(psc_temp));
+}
+
+/* psc_smtpd_pre_jail_init - per-process deep protocol test initialization */
+
+void    psc_smtpd_pre_jail_init(void)
+{
+
+    /*
+     * Determine what server ESMTP features to suppress, typically to avoid
+     * inter-operability problems. We do the default filter here, and
+     * determine client-dependent filtering on the fly.
+     * 
+     * XXX Bugger. This means we have to restart when the table changes!
+     */
+    psc_ehlo_discard_maps = maps_create(VAR_PSC_EHLO_DIS_MAPS,
+                                       var_psc_ehlo_dis_maps,
+                                       DICT_FLAG_LOCK);
+    psc_ehlo_discard_mask = ehlo_mask(var_psc_ehlo_dis_words);
 }
diff --git a/postfix/src/postscreen/postscreen_starttls.c b/postfix/src/postscreen/postscreen_starttls.c
new file mode 100644 (file)
index 0000000..f43b53e
--- /dev/null
@@ -0,0 +1,235 @@
+/*++
+/* NAME
+/*     postscreen_starttls 3
+/* SUMMARY
+/*     postscreen TLS proxy support
+/* SYNOPSIS
+/*     #include <postscreen.h>
+/*
+/*     int     psc_starttls_open(state, resume_event)
+/*     PSC_STATE *state;
+/*     void    (*resume_event)(int unused_event, char *context);
+/* DESCRIPTION
+/*     This module inserts the tlsproxy(8) proxy between the
+/*     postscreen(8) server and the remote SMTP client. The entire
+/*     process happens in the background, including notification
+/*     of completion to the remote SMTP client and to the calling
+/*     application.
+/*
+/*     Before calling psc_starttls_open() the caller must turn off
+/*     all pending timer and I/O event requests on the SMTP client
+/*     stream.
+/*
+/*     psc_starttls_open() starts the first transaction in the
+/*     tlsproxy(8) hand-off protocol, and sets up event handlers
+/*     for the successive protocol stages.
+/*
+/*     Upon completion, the event handlers call resume_event()
+/*     which must reset the SMTP helo/sender/etc. state when the
+/*     PSC_STATE_FLAG_USING_TLS is set, and set up timer and read
+/*     event requests to receive the next SMTP command.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <connect.h>
+#include <stringops.h>                 /* concatenate() */
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <mail_proto.h>
+
+/* Application-specific. */
+
+#include <postscreen.h>
+
+ /*
+  * For now, this code is built into the postscreen(8) daemon. In the future
+  * it may be abstracted into a reusable library module for use by other
+  * event-driven programs (perhaps smtp-source and smtp-sink).
+  */
+
+ /*
+  * Transient state for the portscreen(8)-to-tlsproxy(8) hand-off protocol.
+  */
+typedef struct {
+    VSTREAM *tlsproxy_stream;          /* hand-off negotiation */
+    EVENT_NOTIFY_FN resume_event;      /* call-back handler */
+    PSC_STATE *smtp_state;             /* SMTP session state */
+} PSC_STARTTLS;
+
+#define TLSPROXY_SERVICE               "tlsproxy"
+#define TLSPROXY_INIT_TIMEOUT          10
+
+/* psc_starttls_finish - complete negotiation with TLS proxy */
+
+static void psc_starttls_finish(int event, char *context)
+{
+    const char *myname = "psc_starttls_finish";
+    PSC_STARTTLS *starttls_state = (PSC_STARTTLS *) context;
+    PSC_STATE *smtp_state = starttls_state->smtp_state;
+    VSTREAM *tlsproxy_stream = starttls_state->tlsproxy_stream;
+    int     status;
+
+    if (msg_verbose)
+       msg_info("%s: send client handle on proxy socket %d"
+                " for smtp socket %d from [%s]:%s flags=%s",
+                myname, vstream_fileno(tlsproxy_stream),
+                vstream_fileno(smtp_state->smtp_client_stream),
+                smtp_state->smtp_client_addr, smtp_state->smtp_client_port,
+                psc_print_state_flags(smtp_state->flags, myname));
+
+    /*
+     * We leave read-event notification enabled on the postscreen to TLS
+     * proxy stream, to avoid two kqueue/epoll/etc. system calls: one here,
+     * and one when resuming the dummy SMTP engine.
+     */
+    if (event != EVENT_TIME)
+       event_cancel_timer(psc_starttls_finish, (char *) starttls_state);
+
+    /*
+     * Receive the "TLS is available" indication.
+     * 
+     * This may seem out of order, but we must have a read transaction between
+     * sending the request attributes and sending the SMTP client file
+     * descriptor. We can't assume UNIX-domain socket semantics here.
+     */
+    if (event != EVENT_READ
+       || attr_scan(tlsproxy_stream, ATTR_FLAG_STRICT,
+                    ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
+                    ATTR_TYPE_END) != 1 || status == 0) {
+
+       /*
+        * The TLS proxy reports that the TLS engine is not available (due to
+        * configuration error, or other causes).
+        */
+       event_disable_readwrite(vstream_fileno(tlsproxy_stream));
+       vstream_fclose(tlsproxy_stream);
+       PSC_SEND_REPLY(smtp_state,
+                   "454 4.7.0 TLS not available due to local problem\r\n");
+    }
+
+    /*
+     * Send the remote SMTP client file descriptor.
+     */
+    else if (LOCAL_SEND_FD(vstream_fileno(tlsproxy_stream),
+                     vstream_fileno(smtp_state->smtp_client_stream)) < 0) {
+
+       /*
+        * Some error: drop the TLS proxy stream.
+        */
+       msg_warn("%s sending file handle to %s service",
+                event == EVENT_TIME ? "timeout" : "problem",
+                TLSPROXY_SERVICE);
+       event_disable_readwrite(vstream_fileno(tlsproxy_stream));
+       vstream_fclose(tlsproxy_stream);
+       PSC_SEND_REPLY(smtp_state,
+                   "454 4.7.0 TLS not available due to local problem\r\n");
+    }
+
+    /*
+     * After we send the plaintext 220 greeting, the client-side TLS engine
+     * is supposed to talk first, then the server-side TLS engine. However,
+     * postscreen(8) will not participate in that conversation.
+     */
+    else {
+       PSC_SEND_REPLY(smtp_state, "220 2.0.0 Ready to start TLS\r\n");
+
+       /*
+        * Replace our SMTP client stream by the TLS proxy stream.  Once the
+        * TLS handshake is done, the TLS proxy will deliver plaintext SMTP
+        * commands to postscreen(8).
+        */
+       vstream_fclose(smtp_state->smtp_client_stream);
+       smtp_state->smtp_client_stream = tlsproxy_stream;
+       smtp_state->flags |= PSC_STATE_FLAG_USING_TLS;
+    }
+
+    /*
+     * Resume the postscreen(8) dummy SMTP engine and clean up.
+     */
+    starttls_state->resume_event(event, (char *) smtp_state);
+    myfree((char *) starttls_state);
+}
+
+/* psc_starttls_open - open negotiations with TLS proxy */
+
+void    psc_starttls_open(PSC_STATE *smtp_state, EVENT_NOTIFY_FN resume_event)
+{
+    const char *myname = "psc_starttls_open";
+    PSC_STARTTLS *starttls_state;
+    VSTREAM *tlsproxy_stream;
+    char   *remote_endpt;
+    int     fd;
+
+    /*
+     * Connect to the tlsproxy(8) daemon. We report all errors
+     * asynchronously, to avoid having to maintain multiple delivery paths.
+     */
+    if ((fd = LOCAL_CONNECT("private/" TLSPROXY_SERVICE,
+                           NON_BLOCKING, 1)) < 0) {
+       msg_warn("connect to %s service: %m", TLSPROXY_SERVICE);
+       PSC_SEND_REPLY(smtp_state,
+                   "454 4.7.0 TLS not available due to local problem\r\n");
+       event_request_timer(resume_event, (char *) smtp_state, 0);
+       return;
+    }
+    if (msg_verbose)
+       msg_info("%s: send client name/address on proxy socket %d"
+                " for smtp socket %d from [%s]:%s flags=%s",
+                myname, fd, vstream_fileno(smtp_state->smtp_client_stream),
+                smtp_state->smtp_client_addr, smtp_state->smtp_client_port,
+                psc_print_state_flags(smtp_state->flags, myname));
+
+    /*
+     * Initial handshake. Send the data attributes now, and send the client
+     * file descriptor in a later transaction. We report all errors
+     * asynchronously, to avoid having to maintain multiple delivery paths.
+     * 
+     * XXX The formatted endpoint should be a state member. Then, we can
+     * simplify all the format strings throughout the program.
+     */
+    tlsproxy_stream = vstream_fdopen(fd, O_RDWR);
+    remote_endpt = concatenate("[", smtp_state->smtp_client_addr, "]:",
+                              smtp_state->smtp_client_port, (char *) 0);
+    attr_print(tlsproxy_stream, ATTR_FLAG_NONE,
+              ATTR_TYPE_STR, MAIL_ATTR_REMOTE_ENDPT, remote_endpt,
+              ATTR_TYPE_STR, MAIL_ATTR_ROLE, MAIL_ATTR_ROLE_SERVER,
+              ATTR_TYPE_INT, MAIL_ATTR_TIMEOUT, psc_normal_cmd_time_limit,
+              ATTR_TYPE_END);
+    myfree(remote_endpt);
+    if (vstream_fflush(tlsproxy_stream) != 0) {
+       msg_warn("error sending request to %s service: %m", TLSPROXY_SERVICE);
+       vstream_fclose(tlsproxy_stream);
+       PSC_SEND_REPLY(smtp_state,
+                   "454 4.7.0 TLS not available due to local problem\r\n");
+       event_request_timer(resume_event, (char *) smtp_state, 0);
+       return;
+    }
+
+    /*
+     * Set up a read event for the next phase of the TLS proxy handshake.
+     */
+    starttls_state = (PSC_STARTTLS *) mymalloc(sizeof(*starttls_state));
+    starttls_state->tlsproxy_stream = tlsproxy_stream;
+    starttls_state->resume_event = resume_event;
+    starttls_state->smtp_state = smtp_state;
+    PSC_READ_EVENT_REQUEST(vstream_fileno(tlsproxy_stream), psc_starttls_finish,
+                          (char *) starttls_state, TLSPROXY_INIT_TIMEOUT);
+}
index 9e092d80052dcee59c967e745e7fdc71c19479e9..42e2f0aed787abeadca6fde138252332e16705a1 100644 (file)
 /* SYNOPSIS
 /*     #include <postscreen.h>
 /*
-/*     PS_STATE *ps_new_session_state(stream, addr, port)
+/*     PSC_STATE *psc_new_session_state(stream, addr, port)
 /*     VSTREAM *stream;
 /*     const char *addr;
 /*     const char *port;
 /*
-/*     void    ps_free_session_state(state)
-/*     PS_STATE *state;
+/*     void    psc_free_session_state(state)
+/*     PSC_STATE *state;
 /*
-/*     char    *ps_print_state_flags(flags, context)
+/*     char    *psc_print_state_flags(flags, context)
 /*     int     flags;
 /*     const char *context;
 /*
-/*     void    PS_ADD_SERVER_STATE(state, server_fd)
-/*     PS_STATE *state;
+/*     void    PSC_ADD_SERVER_STATE(state, server_fd)
+/*     PSC_STATE *state;
 /*     int     server_fd;
 /*
-/*     void    PS_DEL_CLIENT_STATE(state)
-/*     PS_STATE *state;
+/*     void    PSC_DEL_CLIENT_STATE(state)
+/*     PSC_STATE *state;
 /*
-/*     void    PS_DROP_SESSION_STATE(state, final_reply)
-/*     PS_STATE *state;
+/*     void    PSC_DROP_SESSION_STATE(state, final_reply)
+/*     PSC_STATE *state;
 /*     const char *final_reply;
 /*
-/*     void    PS_ENFORCE_SESSION_STATE(state, rcpt_reply)
-/*     PS_STATE *state;
+/*     void    PSC_ENFORCE_SESSION_STATE(state, rcpt_reply)
+/*     PSC_STATE *state;
 /*     const char *rcpt_reply;
 /*
-/*     void    PS_PASS_SESSION_STATE(state, testname, pass_flag)
-/*     PS_STATE *state;
+/*     void    PSC_PASS_SESSION_STATE(state, testname, pass_flag)
+/*     PSC_STATE *state;
 /*     const char *testname;
 /*     int     pass_flag;
 /*
-/*     void    PS_FAIL_SESSION_STATE(state, fail_flag)
-/*     PS_STATE *state;
+/*     void    PSC_FAIL_SESSION_STATE(state, fail_flag)
+/*     PSC_STATE *state;
 /*     int     fail_flag;
 /*
-/*     void    PS_UNFAIL_SESSION_STATE(state, fail_flag)
-/*     PS_STATE *state;
+/*     void    PSC_UNFAIL_SESSION_STATE(state, fail_flag)
+/*     PSC_STATE *state;
 /*     int     fail_flag;
 /* DESCRIPTION
 /*     This module maintains per-client session state, and two
 /*     global file descriptor counters:
-/* .IP ps_check_queue_length
+/* .IP psc_check_queue_length
 /*     The total number of remote SMTP client sockets.
-/* .IP ps_post_queue_length
+/* .IP psc_post_queue_length
 /*     The total number of server file descriptors that are currently
 /*     in use for client file descriptor passing. This number
 /*     equals the number of client file descriptors in transit.
 /* .PP
-/*     ps_new_session_state() creates a new session state object
+/*     psc_new_session_state() creates a new session state object
 /*     for the specified client stream, and increments the
-/*     ps_check_queue_length counter.  The flags and per-test time
-/*     stamps are initialized with PS_INIT_TESTS().  The addr and
+/*     psc_check_queue_length counter.  The flags and per-test time
+/*     stamps are initialized with PSC_INIT_TESTS().  The addr and
 /*     port arguments are null-terminated strings with the remote
 /*     SMTP client endpoint. The _reply members are set to
 /*     polite "try again" SMTP replies. The protocol member is set
 /*     to "SMTP".
 /*
-/*     The ps_stress variable is set to non-zero when
-/*     ps_check_queue_length passes over a high-water mark.
+/*     The psc_stress variable is set to non-zero when
+/*     psc_check_queue_length passes over a high-water mark.
 /*
-/*     ps_free_session_state() destroys the specified session state
+/*     psc_free_session_state() destroys the specified session state
 /*     object, closes the applicable I/O channels, and decrements
-/*     the applicable file descriptor counters: ps_check_queue_length
-/*     and ps_post_queue_length.
+/*     the applicable file descriptor counters: psc_check_queue_length
+/*     and psc_post_queue_length.
 /*
-/*     The ps_stress variable is reset to zero when ps_check_queue_length
+/*     The psc_stress variable is reset to zero when psc_check_queue_length
 /*     passes under a low-water mark.
 /*
-/*     ps_print_state_flags() converts per-session flags into
+/*     psc_print_state_flags() converts per-session flags into
 /*     human-readable form. The context is for error reporting.
 /*     The result is overwritten upon each call.
 /*
-/*     PS_ADD_SERVER_STATE() updates the specified session state
+/*     PSC_ADD_SERVER_STATE() updates the specified session state
 /*     object with the specified server file descriptor, and
-/*     increments the global ps_post_queue_length file descriptor
+/*     increments the global psc_post_queue_length file descriptor
 /*     counter.
 /*
-/*     PS_DEL_CLIENT_STATE() updates the specified session state
+/*     PSC_DEL_CLIENT_STATE() updates the specified session state
 /*     object, closes the client stream, and decrements the global
-/*     ps_check_queue_length file descriptor counter.
+/*     psc_check_queue_length file descriptor counter.
 /*
-/*     PS_DROP_SESSION_STATE() updates the specified session state
+/*     PSC_DROP_SESSION_STATE() updates the specified session state
 /*     object and closes the client stream after sending the
 /*     specified SMTP reply.
 /*
-/*     PS_ENFORCE_SESSION_STATE() updates the specified session
+/*     PSC_ENFORCE_SESSION_STATE() updates the specified session
 /*     state object. It arranges that the built-in SMTP engine
 /*     logs sender/recipient information and rejects all RCPT TO
 /*     commands with the specified SMTP reply.
 /*
-/*     PS_PASS_SESSION_STATE() sets the specified "pass" flag.
+/*     PSC_PASS_SESSION_STATE() sets the specified "pass" flag.
 /*     The testname is used for debug logging.
 /*
-/*     PS_FAIL_SESSION_STATE() sets the specified "fail" flag.
+/*     PSC_FAIL_SESSION_STATE() sets the specified "fail" flag.
 /*
-/*     PS_UNFAIL_SESSION_STATE() unsets the specified "fail" flag.
+/*     PSC_UNFAIL_SESSION_STATE() unsets the specified "fail" flag.
 /* LICENSE
 /* .ad
 /* .fi
 
 #include <postscreen.h>
 
-/* ps_new_session_state - fill in connection state for event processing */
+/* psc_new_session_state - fill in connection state for event processing */
 
-PS_STATE *ps_new_session_state(VSTREAM *stream,
-                                      const char *addr,
-                                      const char *port)
+PSC_STATE *psc_new_session_state(VSTREAM *stream,
+                                        const char *addr,
+                                        const char *port)
 {
-    PS_STATE *state;
+    PSC_STATE *state;
     HTABLE_INFO *ht;
 
-    state = (PS_STATE *) mymalloc(sizeof(*state));
-    PS_INIT_TESTS(state);
+    state = (PSC_STATE *) mymalloc(sizeof(*state));
+    PSC_INIT_TESTS(state);
     if ((state->smtp_client_stream = stream) != 0)
-       ps_check_queue_length++;
+       psc_check_queue_length++;
     state->smtp_server_fd = (-1);
     state->smtp_client_addr = mystrdup(addr);
     state->smtp_client_port = mystrdup(port);
@@ -163,51 +163,54 @@ PS_STATE *ps_new_session_state(VSTREAM *stream,
     state->sender = 0;
     state->cmd_buffer = 0;
     state->read_state = 0;
+    state->ehlo_discard_mask = 0;              /* XXX Should be ~0 */
 
     /*
      * Update the stress level.
      */
-    if (ps_stress == 0
-       && ps_check_queue_length >= ps_check_queue_length_hiwat) {
-       ps_stress = 1;
+    if (psc_stress == 0
+       && psc_check_queue_length >= psc_check_queue_length_hiwat) {
+       psc_stress = 1;
        msg_info("entering STRESS mode with %d connections",
-                ps_check_queue_length);
+                psc_check_queue_length);
     }
 
     /*
      * Update the per-client session count.
      */
-    if ((ht = htable_locate(ps_client_concurrency, addr)) == 0)
-       ht = htable_enter(ps_client_concurrency, addr, (char *) 0);
+    if ((ht = htable_locate(psc_client_concurrency, addr)) == 0)
+       ht = htable_enter(psc_client_concurrency, addr, (char *) 0);
     ht->value += 1;
     state->client_concurrency = CAST_CHAR_PTR_TO_INT(ht->value);
 
     return (state);
 }
 
-/* ps_free_session_state - destroy connection state including connections */
+/* psc_free_session_state - destroy connection state including connections */
 
-void    ps_free_session_state(PS_STATE *state)
+void    psc_free_session_state(PSC_STATE *state)
 {
-    const char *myname = "ps_free_session_state";
+    const char *myname = "psc_free_session_state";
     HTABLE_INFO *ht;
 
     /*
      * Update the per-client session count.
      */
-    if ((ht = htable_locate(ps_client_concurrency, state->smtp_client_addr)) == 0)
-       msg_panic("%s: unknown client address: %s", 
+    if ((ht = htable_locate(psc_client_concurrency,
+                           state->smtp_client_addr)) == 0)
+       msg_panic("%s: unknown client address: %s",
                  myname, state->smtp_client_addr);
     if (--(ht->value) == 0)
-       htable_delete(ps_client_concurrency, state->smtp_client_addr, (void (*) (char *)) 0);
+       htable_delete(psc_client_concurrency, state->smtp_client_addr,
+                     (void (*) (char *)) 0);
 
     if (state->smtp_client_stream != 0) {
        event_server_disconnect(state->smtp_client_stream);
-       ps_check_queue_length--;
+       psc_check_queue_length--;
     }
     if (state->smtp_server_fd >= 0) {
        close(state->smtp_server_fd);
-       ps_post_queue_length--;
+       psc_post_queue_length--;
     }
     myfree(state->smtp_client_addr);
     myfree(state->smtp_client_port);
@@ -221,59 +224,60 @@ void    ps_free_session_state(PS_STATE *state)
        vstring_free(state->cmd_buffer);
     myfree((char *) state);
 
-    if (ps_check_queue_length < 0 || ps_post_queue_length < 0)
+    if (psc_check_queue_length < 0 || psc_post_queue_length < 0)
        msg_panic("bad queue length: check_queue=%d, post_queue=%d",
-                 ps_check_queue_length, ps_post_queue_length);
+                 psc_check_queue_length, psc_post_queue_length);
 
     /*
      * Update the stress level.
      */
-    if (ps_stress != 0
-       && ps_check_queue_length <= ps_check_queue_length_lowat) {
-       ps_stress = 0;
+    if (psc_stress != 0
+       && psc_check_queue_length <= psc_check_queue_length_lowat) {
+       psc_stress = 0;
        msg_info("leaving STRESS mode with %d connections",
-                ps_check_queue_length);
+                psc_check_queue_length);
     }
 }
 
-/* ps_print_state_flags - format state flags */
+/* psc_print_state_flags - format state flags */
 
-const char *ps_print_state_flags(int flags, const char *context)
+const char *psc_print_state_flags(int flags, const char *context)
 {
     static const NAME_MASK flags_mask[] = {
-       "NOFORWARD", PS_STATE_FLAG_NOFORWARD,
-       "NEW", PS_STATE_FLAG_NEW,
-       "BLIST_FAIL", PS_STATE_FLAG_BLIST_FAIL,
-       "HANGUP", PS_STATE_FLAG_HANGUP,
-       "CACHE_EXPIRED", PS_STATE_FLAG_CACHE_EXPIRED,
+       "NOFORWARD", PSC_STATE_FLAG_NOFORWARD,
+       "USING_TLS", PSC_STATE_FLAG_USING_TLS,
+       "NEW", PSC_STATE_FLAG_NEW,
+       "BLIST_FAIL", PSC_STATE_FLAG_BLIST_FAIL,
+       "HANGUP", PSC_STATE_FLAG_HANGUP,
+       "CACHE_EXPIRED", PSC_STATE_FLAG_CACHE_EXPIRED,
 
-       "PENAL_UPDATE", PS_STATE_FLAG_PENAL_UPDATE,
-       "PENAL_FAIL", PS_STATE_FLAG_PENAL_FAIL,
+       "PENAL_UPDATE", PSC_STATE_FLAG_PENAL_UPDATE,
+       "PENAL_FAIL", PSC_STATE_FLAG_PENAL_FAIL,
 
-       "PREGR_FAIL", PS_STATE_FLAG_PREGR_FAIL,
-       "PREGR_PASS", PS_STATE_FLAG_PREGR_PASS,
-       "PREGR_TODO", PS_STATE_FLAG_PREGR_TODO,
-       "PREGR_DONE", PS_STATE_FLAG_PREGR_DONE,
+       "PREGR_FAIL", PSC_STATE_FLAG_PREGR_FAIL,
+       "PREGR_PASS", PSC_STATE_FLAG_PREGR_PASS,
+       "PREGR_TODO", PSC_STATE_FLAG_PREGR_TODO,
+       "PREGR_DONE", PSC_STATE_FLAG_PREGR_DONE,
 
-       "DNSBL_FAIL", PS_STATE_FLAG_DNSBL_FAIL,
-       "DNSBL_PASS", PS_STATE_FLAG_DNSBL_PASS,
-       "DNSBL_TODO", PS_STATE_FLAG_DNSBL_TODO,
-       "DNSBL_DONE", PS_STATE_FLAG_DNSBL_DONE,
+       "DNSBL_FAIL", PSC_STATE_FLAG_DNSBL_FAIL,
+       "DNSBL_PASS", PSC_STATE_FLAG_DNSBL_PASS,
+       "DNSBL_TODO", PSC_STATE_FLAG_DNSBL_TODO,
+       "DNSBL_DONE", PSC_STATE_FLAG_DNSBL_DONE,
 
-       "PIPEL_FAIL", PS_STATE_FLAG_PIPEL_FAIL,
-       "PIPEL_PASS", PS_STATE_FLAG_PIPEL_PASS,
-       "PIPEL_TODO", PS_STATE_FLAG_PIPEL_TODO,
-       "PIPEL_SKIP", PS_STATE_FLAG_PIPEL_SKIP,
+       "PIPEL_FAIL", PSC_STATE_FLAG_PIPEL_FAIL,
+       "PIPEL_PASS", PSC_STATE_FLAG_PIPEL_PASS,
+       "PIPEL_TODO", PSC_STATE_FLAG_PIPEL_TODO,
+       "PIPEL_SKIP", PSC_STATE_FLAG_PIPEL_SKIP,
 
-       "NSMTP_FAIL", PS_STATE_FLAG_NSMTP_FAIL,
-       "NSMTP_PASS", PS_STATE_FLAG_NSMTP_PASS,
-       "NSMTP_TODO", PS_STATE_FLAG_NSMTP_TODO,
-       "NSMTP_SKIP", PS_STATE_FLAG_NSMTP_SKIP,
+       "NSMTP_FAIL", PSC_STATE_FLAG_NSMTP_FAIL,
+       "NSMTP_PASS", PSC_STATE_FLAG_NSMTP_PASS,
+       "NSMTP_TODO", PSC_STATE_FLAG_NSMTP_TODO,
+       "NSMTP_SKIP", PSC_STATE_FLAG_NSMTP_SKIP,
 
-       "BARLF_FAIL", PS_STATE_FLAG_BARLF_FAIL,
-       "BARLF_PASS", PS_STATE_FLAG_BARLF_PASS,
-       "BARLF_TODO", PS_STATE_FLAG_BARLF_TODO,
-       "BARLF_SKIP", PS_STATE_FLAG_BARLF_SKIP,
+       "BARLF_FAIL", PSC_STATE_FLAG_BARLF_FAIL,
+       "BARLF_PASS", PSC_STATE_FLAG_BARLF_PASS,
+       "BARLF_TODO", PSC_STATE_FLAG_BARLF_TODO,
+       "BARLF_SKIP", PSC_STATE_FLAG_BARLF_SKIP,
        0,
     };
 
index 3ba7adc7637c4287f510d2cf637653e56016617a..e166617d381ddd93881864ca06e22894491505ec 100644 (file)
@@ -6,22 +6,22 @@
 /* SYNOPSIS
 /*     #include <postscreen.h>
 /*
-/*     void    PS_INIT_TESTS(state)
-/*     PS_STATE *state;
+/*     void    PSC_INIT_TESTS(state)
+/*     PSC_STATE *state;
 /*
-/*     void    ps_new_tests(state)
-/*     PS_STATE *state;
+/*     void    psc_new_tests(state)
+/*     PSC_STATE *state;
 /*
-/*     void    ps_parse_tests(state, stamp_text, time_value)
-/*     PS_STATE *state;
+/*     void    psc_parse_tests(state, stamp_text, time_value)
+/*     PSC_STATE *state;
 /*     const char *stamp_text;
 /*     time_t time_value;
 /*
-/*     char    *ps_print_tests(buffer, state)
+/*     char    *psc_print_tests(buffer, state)
 /*     VSTRING *buffer;
-/*     PS_STATE *state;
+/*     PSC_STATE *state;
 /*
-/*     char    *ps_print_grey_key(buffer, client, helo, sender, rcpt)
+/*     char    *psc_print_grey_key(buffer, client, helo, sender, rcpt)
 /*     VSTRING *buffer;
 /*     const char *client;
 /*     const char *helo;
 /*     as unsafe macros, meaning they evaluate one or more arguments
 /*     multiple times.
 /*
-/*     PS_INIT_TESTS() is an unsafe macro that sets the per-test
-/*     expiration time stamps to PS_TIME_STAMP_INVALID, and that
+/*     PSC_INIT_TESTS() is an unsafe macro that sets the per-test
+/*     expiration time stamps to PSC_TIME_STAMP_INVALID, and that
 /*     zeroes all the flags bits. These values are not meant to
 /*     be stored into the postscreen(8) cache.
 /*
-/*     ps_new_tests() sets all test expiration time stamps to
-/*     PS_TIME_STAMP_NEW, and overwrites all flags bits. Only
-/*     enabled tests are flagged with PS_STATE_FLAG_TODO; the
-/*     object is flagged with PS_STATE_FLAG_NEW.
+/*     psc_new_tests() sets all test expiration time stamps to
+/*     PSC_TIME_STAMP_NEW, and overwrites all flags bits. Only
+/*     enabled tests are flagged with PSC_STATE_FLAG_TODO; the
+/*     object is flagged with PSC_STATE_FLAG_NEW.
 /*
-/*     ps_parse_tests() parses a cache file record and overwrites
+/*     psc_parse_tests() parses a cache file record and overwrites
 /*     all flags bits. Tests are considered "expired" when they
 /*     would be expired at the specified time value. Only enabled
 /*     tests are flagged as "expired"; the object is flagged as
 /*     "new" if some enabled tests have "new" time stamps.
 /*
-/*     ps_print_tests() creates a cache file record for the
+/*     psc_print_tests() creates a cache file record for the
 /*     specified flags and per-test expiration time stamps.
 /*     This may modify the time stamps for disabled tests.
 /*
-/*     ps_print_grey_key() prints a greylist lookup key.
+/*     psc_print_grey_key() prints a greylist lookup key.
 /* LICENSE
 /* .ad
 /* .fi
@@ -85,8 +85,8 @@
  /*
   * Kludge to detect if some test is enabled.
   */
-#define PS_PREGR_TEST_ENABLE() (*var_ps_pregr_banner != 0)
-#define PS_DNSBL_TEST_ENABLE() (*var_ps_dnsbl_sites != 0)
+#define PSC_PREGR_TEST_ENABLE()        (*var_psc_pregr_banner != 0)
+#define PSC_DNSBL_TEST_ENABLE()        (*var_psc_dnsbl_sites != 0)
 
  /*
   * Format of a persistent cache entry (which is almost but not quite the
   * 
   * Each cache entry has one time stamp for each test.
   * 
-  * - A time stamp of PS_TIME_STAMP_INVALID must never appear in the cache. It
+  * - A time stamp of PSC_TIME_STAMP_INVALID must never appear in the cache. It
   * is reserved for in-memory objects that are still being initialized.
   * 
-  * - A time stamp of PS_TIME_STAMP_NEW indicates that the test never passed.
+  * - A time stamp of PSC_TIME_STAMP_NEW indicates that the test never passed.
   * Postscreen will log the client with "pass new" when it passes the final
   * test.
   * 
-  * - A time stamp of PS_TIME_STAMP_DISABLED indicates that the test never
+  * - A time stamp of PSC_TIME_STAMP_DISABLED indicates that the test never
   * passed, and that the test was disabled when the cache entry was written.
   * 
   * - Otherwise, the test was passed, and the time stamp indicates when that
   * expired.
   */
 
-/* ps_new_tests - initialize new test results from scratch */
+/* psc_new_tests - initialize new test results from scratch */
 
-void    ps_new_tests(PS_STATE *state)
+void    psc_new_tests(PSC_STATE *state)
 {
 
     /*
      * We know this client is brand new.
      */
-    state->flags = PS_STATE_FLAG_NEW;
+    state->flags = PSC_STATE_FLAG_NEW;
 
     /*
-     * Give all tests a PS_TIME_STAMP_NEW time stamp, so that we can later
+     * Give all tests a PSC_TIME_STAMP_NEW time stamp, so that we can later
      * recognize cache entries that haven't passed all enabled tests. When we
      * write a cache entry to the database, any new-but-disabled tests will
-     * get a PS_TIME_STAMP_DISABLED time stamp.
+     * get a PSC_TIME_STAMP_DISABLED time stamp.
      */
-    state->pregr_stamp = PS_TIME_STAMP_NEW;
-    state->dnsbl_stamp = PS_TIME_STAMP_NEW;
-    state->pipel_stamp = PS_TIME_STAMP_NEW;
-    state->nsmtp_stamp = PS_TIME_STAMP_NEW;
-    state->barlf_stamp = PS_TIME_STAMP_NEW;
-    state->penal_stamp = PS_TIME_STAMP_NEW;
+    state->pregr_stamp = PSC_TIME_STAMP_NEW;
+    state->dnsbl_stamp = PSC_TIME_STAMP_NEW;
+    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
      * make those bits go away.
      */
-    if (PS_PREGR_TEST_ENABLE())
-       state->flags |= PS_STATE_FLAG_PREGR_TODO;
-    if (PS_DNSBL_TEST_ENABLE())
-       state->flags |= PS_STATE_FLAG_DNSBL_TODO;
-    if (var_ps_pipel_enable)
-       state->flags |= PS_STATE_FLAG_PIPEL_TODO;
-    if (var_ps_nsmtp_enable)
-       state->flags |= PS_STATE_FLAG_NSMTP_TODO;
-    if (var_ps_barlf_enable)
-       state->flags |= PS_STATE_FLAG_BARLF_TODO;
+    if (PSC_PREGR_TEST_ENABLE())
+       state->flags |= PSC_STATE_FLAG_PREGR_TODO;
+    if (PSC_DNSBL_TEST_ENABLE())
+       state->flags |= PSC_STATE_FLAG_DNSBL_TODO;
+    if (var_psc_pipel_enable)
+       state->flags |= PSC_STATE_FLAG_PIPEL_TODO;
+    if (var_psc_nsmtp_enable)
+       state->flags |= PSC_STATE_FLAG_NSMTP_TODO;
+    if (var_psc_barlf_enable)
+       state->flags |= PSC_STATE_FLAG_BARLF_TODO;
 }
 
-/* ps_parse_tests - parse test results from cache */
+/* psc_parse_tests - parse test results from cache */
 
-void    ps_parse_tests(PS_STATE *state,
-                              const char *stamp_str,
-                              time_t time_value)
+void    psc_parse_tests(PSC_STATE *state,
+                               const char *stamp_str,
+                               time_t time_value)
 {
     unsigned long pregr_stamp;
     unsigned long dnsbl_stamp;
@@ -186,17 +186,17 @@ void    ps_parse_tests(PS_STATE *state,
                   &pregr_stamp, &dnsbl_stamp, &pipel_stamp, &nsmtp_stamp,
                   &barlf_stamp, &penal_stamp)) {
     case 0:
-       pregr_stamp = PS_TIME_STAMP_DISABLED;
+       pregr_stamp = PSC_TIME_STAMP_DISABLED;
     case 1:
-       dnsbl_stamp = PS_TIME_STAMP_DISABLED;
+       dnsbl_stamp = PSC_TIME_STAMP_DISABLED;
     case 2:
-       pipel_stamp = PS_TIME_STAMP_DISABLED;
+       pipel_stamp = PSC_TIME_STAMP_DISABLED;
     case 3:
-       nsmtp_stamp = PS_TIME_STAMP_DISABLED;
+       nsmtp_stamp = PSC_TIME_STAMP_DISABLED;
     case 4:
-       barlf_stamp = PS_TIME_STAMP_DISABLED;
+       barlf_stamp = PSC_TIME_STAMP_DISABLED;
     case 5:
-       penal_stamp = PS_TIME_STAMP_DISABLED;
+       penal_stamp = PSC_TIME_STAMP_DISABLED;
     default:
        break;
     }
@@ -207,12 +207,12 @@ void    ps_parse_tests(PS_STATE *state,
     state->barlf_stamp = barlf_stamp;
     state->penal_stamp = penal_stamp;
 
-    if (pregr_stamp == PS_TIME_STAMP_NEW
-       || dnsbl_stamp == PS_TIME_STAMP_NEW
-       || pipel_stamp == PS_TIME_STAMP_NEW
-       || nsmtp_stamp == PS_TIME_STAMP_NEW
-       || barlf_stamp == PS_TIME_STAMP_NEW)
-       state->flags |= PS_STATE_FLAG_NEW;
+    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 a cache entry as expired just because some test was never
@@ -221,30 +221,30 @@ void    ps_parse_tests(PS_STATE *state,
      * Don't flag disabled tests as "todo", because there would be no way to
      * make those bits go away.
      */
-    if (PS_PREGR_TEST_ENABLE() && time_value > state->pregr_stamp) {
-       state->flags |= PS_STATE_FLAG_PREGR_TODO;
-       if (state->pregr_stamp > PS_TIME_STAMP_DISABLED)
-           state->flags |= PS_STATE_FLAG_CACHE_EXPIRED;
+    if (PSC_PREGR_TEST_ENABLE() && time_value > state->pregr_stamp) {
+       state->flags |= PSC_STATE_FLAG_PREGR_TODO;
+       if (state->pregr_stamp > PSC_TIME_STAMP_DISABLED)
+           state->flags |= PSC_STATE_FLAG_CACHE_EXPIRED;
     }
-    if (PS_DNSBL_TEST_ENABLE() && time_value > state->dnsbl_stamp) {
-       state->flags |= PS_STATE_FLAG_DNSBL_TODO;
-       if (state->dnsbl_stamp > PS_TIME_STAMP_DISABLED)
-           state->flags |= PS_STATE_FLAG_CACHE_EXPIRED;
+    if (PSC_DNSBL_TEST_ENABLE() && time_value > state->dnsbl_stamp) {
+       state->flags |= PSC_STATE_FLAG_DNSBL_TODO;
+       if (state->dnsbl_stamp > PSC_TIME_STAMP_DISABLED)
+           state->flags |= PSC_STATE_FLAG_CACHE_EXPIRED;
     }
-    if (var_ps_pipel_enable && time_value > state->pipel_stamp) {
-       state->flags |= PS_STATE_FLAG_PIPEL_TODO;
-       if (state->pipel_stamp > PS_TIME_STAMP_DISABLED)
-           state->flags |= PS_STATE_FLAG_CACHE_EXPIRED;
+    if (var_psc_pipel_enable && time_value > state->pipel_stamp) {
+       state->flags |= PSC_STATE_FLAG_PIPEL_TODO;
+       if (state->pipel_stamp > PSC_TIME_STAMP_DISABLED)
+           state->flags |= PSC_STATE_FLAG_CACHE_EXPIRED;
     }
-    if (var_ps_nsmtp_enable && time_value > state->nsmtp_stamp) {
-       state->flags |= PS_STATE_FLAG_NSMTP_TODO;
-       if (state->nsmtp_stamp > PS_TIME_STAMP_DISABLED)
-           state->flags |= PS_STATE_FLAG_CACHE_EXPIRED;
+    if (var_psc_nsmtp_enable && time_value > state->nsmtp_stamp) {
+       state->flags |= PSC_STATE_FLAG_NSMTP_TODO;
+       if (state->nsmtp_stamp > PSC_TIME_STAMP_DISABLED)
+           state->flags |= PSC_STATE_FLAG_CACHE_EXPIRED;
     }
-    if (var_ps_barlf_enable && time_value > state->barlf_stamp) {
-       state->flags |= PS_STATE_FLAG_BARLF_TODO;
-       if (state->barlf_stamp > PS_TIME_STAMP_DISABLED)
-           state->flags |= PS_STATE_FLAG_CACHE_EXPIRED;
+    if (var_psc_barlf_enable && time_value > state->barlf_stamp) {
+       state->flags |= PSC_STATE_FLAG_BARLF_TODO;
+       if (state->barlf_stamp > PSC_TIME_STAMP_DISABLED)
+           state->flags |= PSC_STATE_FLAG_CACHE_EXPIRED;
     }
 
     /*
@@ -256,11 +256,11 @@ void    ps_parse_tests(PS_STATE *state,
      * full postscreen_greet_wait too frequently.
      */
 #if 0
-    if (state->flags & PS_STATE_MASK_EARLY_TODO) {
-       if (PS_PREGR_TEST_ENABLE())
-           state->flags |= PS_STATE_FLAG_PREGR_TODO;
-       if (PS_DNSBL_TEST_ENABLE())
-           state->flags |= PS_STATE_FLAG_DNSBL_TODO;
+    if (state->flags & PSC_STATE_MASK_EARLY_TODO) {
+       if (PSC_PREGR_TEST_ENABLE())
+           state->flags |= PSC_STATE_FLAG_PREGR_TODO;
+       if (PSC_DNSBL_TEST_ENABLE())
+           state->flags |= PSC_STATE_FLAG_DNSBL_TODO;
     }
 #endif
 
@@ -275,41 +275,41 @@ void    ps_parse_tests(PS_STATE *state,
     if ((penalty_left = state->penal_stamp - event_time()) > 0) {
        msg_info("PENALTY %ld for %s",
                 (long) penalty_left, state->smtp_client_addr);
-       PS_FAIL_SESSION_STATE(state, PS_STATE_FLAG_PENAL_FAIL);
+       PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_PENAL_FAIL);
 #if 0
-       switch (ps_penal_action) {
-       case PS_ACT_DROP:
-           PS_DROP_SESSION_STATE(state,
+       switch (psc_penal_action) {
+       case PSC_ACT_DROP:
+           PSC_DROP_SESSION_STATE(state,
                             "421 4.3.2 Service currently unavailable\r\n");
            break;
-       case PS_ACT_ENFORCE:
+       case PSC_ACT_ENFORCE:
 #endif
-           PS_ENFORCE_SESSION_STATE(state,
+           PSC_ENFORCE_SESSION_STATE(state,
                             "450 4.3.2 Service currently unavailable\r\n");
 #if 0
            break;
-       case PS_ACT_IGNORE:
-           PS_UNFAIL_SESSION_STATE(state, PS_STATE_FLAG_PENAL_FAIL);
+       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, ps_penal_action);
+                     myname, psc_penal_action);
        }
 #endif
     }
 #endif                                         /* NONPROD */
 }
 
-/* ps_print_tests - print postscreen cache record */
+/* psc_print_tests - print postscreen cache record */
 
-char   *ps_print_tests(VSTRING *buf, PS_STATE *state)
+char   *psc_print_tests(VSTRING *buf, PSC_STATE *state)
 {
-    const char *myname = "ps_print_tests";
+    const char *myname = "psc_print_tests";
 
     /*
      * Sanity check.
      */
-    if ((state->flags & PS_STATE_MASK_ANY_UPDATE) == 0)
+    if ((state->flags & PSC_STATE_MASK_ANY_UPDATE) == 0)
        msg_panic("%s: attempt to save a no-update record", myname);
 
     /*
@@ -323,11 +323,11 @@ char   *ps_print_tests(VSTRING *buf, PS_STATE *state)
      * time stamp only when the corresponding "pass" flag is raised.
      */
 #ifdef NONPROD
-    if (state->flags & PS_STATE_FLAG_PENAL_FAIL) {
+    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 & PS_STATE_FLAG_NEW) ?
-            PS_TIME_STAMP_NEW : PS_TIME_STAMP_DISABLED);
+           ((state->flags & PSC_STATE_FLAG_NEW) ?
+            PSC_TIME_STAMP_NEW : PSC_TIME_STAMP_DISABLED);
     }
 #endif
 
@@ -336,16 +336,16 @@ char   *ps_print_tests(VSTRING *buf, PS_STATE *state)
      * with "pass new" when some disabled test becomes enabled at some later
      * time.
      */
-    if (PS_PREGR_TEST_ENABLE() == 0 && state->pregr_stamp == PS_TIME_STAMP_NEW)
-       state->pregr_stamp = PS_TIME_STAMP_DISABLED;
-    if (PS_DNSBL_TEST_ENABLE() == 0 && state->dnsbl_stamp == PS_TIME_STAMP_NEW)
-       state->dnsbl_stamp = PS_TIME_STAMP_DISABLED;
-    if (var_ps_pipel_enable == 0 && state->pipel_stamp == PS_TIME_STAMP_NEW)
-       state->pipel_stamp = PS_TIME_STAMP_DISABLED;
-    if (var_ps_nsmtp_enable == 0 && state->nsmtp_stamp == PS_TIME_STAMP_NEW)
-       state->nsmtp_stamp = PS_TIME_STAMP_DISABLED;
-    if (var_ps_barlf_enable == 0 && state->barlf_stamp == PS_TIME_STAMP_NEW)
-       state->barlf_stamp = PS_TIME_STAMP_DISABLED;
+    if (PSC_PREGR_TEST_ENABLE() == 0 && state->pregr_stamp == PSC_TIME_STAMP_NEW)
+       state->pregr_stamp = PSC_TIME_STAMP_DISABLED;
+    if (PSC_DNSBL_TEST_ENABLE() == 0 && state->dnsbl_stamp == PSC_TIME_STAMP_NEW)
+       state->dnsbl_stamp = PSC_TIME_STAMP_DISABLED;
+    if (var_psc_pipel_enable == 0 && state->pipel_stamp == PSC_TIME_STAMP_NEW)
+       state->pipel_stamp = PSC_TIME_STAMP_DISABLED;
+    if (var_psc_nsmtp_enable == 0 && state->nsmtp_stamp == PSC_TIME_STAMP_NEW)
+       state->nsmtp_stamp = PSC_TIME_STAMP_DISABLED;
+    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",
                    (unsigned long) state->pregr_stamp,
@@ -357,11 +357,11 @@ char   *ps_print_tests(VSTRING *buf, PS_STATE *state)
     return (STR(buf));
 }
 
-/* ps_print_grey_key - print postscreen cache record */
+/* psc_print_grey_key - print postscreen cache record */
 
-char   *ps_print_grey_key(VSTRING *buf, const char *client,
-                                 const char *helo, const char *sender,
-                                 const char *rcpt)
+char   *psc_print_grey_key(VSTRING *buf, const char *client,
+                                  const char *helo, const char *sender,
+                                  const char *rcpt)
 {
     return (STR(vstring_sprintf(buf, "%s/%s/%s/%s",
                                client, helo, sender, rcpt)));
index c08a28a3e07d9a64a50a7c6ac0b766a97adc7d06..aad28af8f282a66ea52d0c3850c40d0e7f5ce973 100644 (file)
 /*     Try to detect a mail hijacking attack based on a TLS protocol
 /*     vulnerability (CVE-2009-3555), where an attacker prepends malicious
 /*     HELO, MAIL, RCPT, DATA commands to a Postfix SMTP client TLS session.
+/* .PP
+/*     Available in Postfix version 2.8 and later:
+/* .IP "\fBtls_disable_workarounds (see 'postconf -d' output)\fR"
+/*     List or bit-mask of OpenSSL bug work-arounds to disable.
 /* OBSOLETE STARTTLS CONTROLS
 /* .ad
 /* .fi
@@ -965,7 +969,7 @@ static void post_init(char *unused_name, char **unused_argv)
      * Select DNS query flags.
      */
     smtp_dns_res_opt = name_mask(VAR_SMTP_DNS_RES_OPT, dns_res_opt_masks,
-                               var_smtp_dns_res_opt);
+                                var_smtp_dns_res_opt);
 }
 
 /* pre_init - pre-jail initialization */
index f4e0d946bc8b379febc07a4cf1c046435de7b4de..c288a210cb985a31bbee6a787e7186f05f2f0c04 100644 (file)
@@ -274,8 +274,6 @@ int     smtp_helo(SMTP_STATE *state)
        XFORWARD_DOMAIN, SMTP_FEATURE_XFORWARD_DOMAIN,
        0, 0,
     };
-    SOCKOPT_SIZE optlen;
-    int     sndbufsize;
     const char *ehlo_words;
     int     discard_mask;
     static const NAME_MASK pix_bug_table[] = {
@@ -354,7 +352,8 @@ int     smtp_helo(SMTP_STATE *state)
            }
            if (*pix_bug_words) {
                pix_bug_mask = name_mask_opt(pix_bug_source, pix_bug_table,
-                                        pix_bug_words, NAME_MASK_ANY_CASE);
+                                            pix_bug_words,
+                                    NAME_MASK_ANY_CASE | NAME_MASK_IGNORE);
                msg_info("%s: enabling PIX workarounds: %s for %s",
                         request->queue_id,
                         str_name_mask("pix workaround bitmask",
@@ -560,27 +559,64 @@ int     smtp_helo(SMTP_STATE *state)
      * XXX No need to do this before and after STARTTLS, but it's not a big deal
      * if we do.
      * 
-     * XXX This critically depends on VSTREAM buffers to never be smaller than
-     * VSTREAM_BUFSIZE.
+     * XXX When TLS is turned on, the SMTP-level writes will be encapsulated as
+     * TLS messages. Thus, the TCP-level payload will be larger than the
+     * SMTP-level payload. This has implications for the PIPELINING engine.
+     * 
+     * To avoid deadlock, the PIPELINING engine needs to request a TCP send
+     * buffer size that can hold the unacknowledged commands plus the TLS
+     * encapsulation overhead.
+     * 
+     * The PIPELINING engine keeps the unacknowledged command size <= the
+     * default VSTREAM buffer size (to avoid small-write performance issues
+     * when the VSTREAM buffer size is at its default size). With a default
+     * VSTREAM buffer size of 4096 there is no reason to increase the
+     * unacknowledged command size as the TCP MSS increases. It's safer to
+     * spread the remote SMTP server's recipient processing load over time,
+     * than dumping a very large recipient list all at once.
+     * 
+     * For TLS encapsulation overhead we make a conservative guess: take the
+     * current protocol overhead of ~40 bytes, double the number for future
+     * proofing (~80 bytes), then round up the result to the nearest power of
+     * 2 (128 bytes). Plus, be prepared for worst-case compression that
+     * expands data by 1 kbyte, so that the worst-case SMTP payload per TLS
+     * message becomes 15 kbytes.
      */
+#define PIPELINING_BUFSIZE     VSTREAM_BUFSIZE
+#ifdef USE_TLS
+#define TLS_WORST_PAYLOAD      16384
+#define TLS_WORST_COMP_OVERHD  1024
+#define TLS_WORST_PROTO_OVERHD 128
+#define TLS_WORST_SMTP_PAYLOAD (TLS_WORST_PAYLOAD - TLS_WORST_COMP_OVERHD)
+#define TLS_WORST_TOTAL_OVERHD (TLS_WORST_COMP_OVERHD + TLS_WORST_PROTO_OVERHD)
+#endif
+
     if (session->features & SMTP_FEATURE_PIPELINING) {
-       optlen = sizeof(sndbufsize);
+       SOCKOPT_SIZE optlen;
+       int     tcp_bufsize;
+       int     enc_overhead = 0;
+
+       optlen = sizeof(tcp_bufsize);
        if (getsockopt(vstream_fileno(session->stream), SOL_SOCKET,
-                      SO_SNDBUF, (char *) &sndbufsize, &optlen) < 0)
+                      SO_SNDBUF, (char *) &tcp_bufsize, &optlen) < 0)
            msg_fatal("%s: getsockopt: %m", myname);
-       if (sndbufsize > VSTREAM_BUFSIZE)
-           sndbufsize = VSTREAM_BUFSIZE;
-       if (sndbufsize < VSTREAM_BUFSIZE) {
-           sndbufsize = VSTREAM_BUFSIZE;
+#ifdef USE_TLS
+       if (state->misc_flags & SMTP_MISC_FLAG_IN_STARTTLS)
+           enc_overhead +=
+               (1 + (PIPELINING_BUFSIZE - 1)
+                / TLS_WORST_SMTP_PAYLOAD) * TLS_WORST_TOTAL_OVERHD;
+#endif
+       if (tcp_bufsize < PIPELINING_BUFSIZE + enc_overhead) {
+           tcp_bufsize = PIPELINING_BUFSIZE + enc_overhead;
            if (setsockopt(vstream_fileno(session->stream), SOL_SOCKET,
-                          SO_SNDBUF, (char *) &sndbufsize, optlen) < 0)
+                          SO_SNDBUF, (char *) &tcp_bufsize, optlen) < 0)
                msg_fatal("%s: setsockopt: %m", myname);
        }
        if (msg_verbose)
-           msg_info("Using %s PIPELINING, TCP send buffer size is %d",
-                    (state->misc_flags &
-                     SMTP_MISC_FLAG_USE_LMTP) ? "LMTP" : "ESMTP",
-                    sndbufsize);
+           msg_info("Using %s PIPELINING, TCP send buffer size is %d, "
+                    "PIPELINING buffer size is %d", (state->misc_flags &
+                               SMTP_MISC_FLAG_USE_LMTP) ? "LMTP" : "ESMTP",
+                    tcp_bufsize, PIPELINING_BUFSIZE);
     }
 #ifdef USE_TLS
 
@@ -1470,13 +1506,32 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
         * Flush unsent output if command pipelining is off or if no I/O
         * happened for a while. This limits the accumulation of client-side
         * delays in pipelined sessions.
+        * 
+        * The PIPELINING engine will flush the VSTREAM buffer if the sender
+        * could otherwise produce more output than fits the PIPELINING
+        * buffer. This generally works because we know exactly how much
+        * output we produced since the last time that the sender and
+        * receiver synchronized the SMTP state. However this logic is not
+        * applicable after the sender enters the DATA phase, where it does
+        * not synchronize with the receiver until the <CR><LF>.<CR><LF>.
+        * Thus, the PIPELINING engine no longer knows how much data is
+        * pending in the TCP send buffer. For this reason, if PIPELINING is
+        * enabled, we always pipeline QUIT after <CR><LF>.<CR><LF>. This is
+        * safe because once the receiver reads <CR><LF>.<CR><LF>, its TCP
+        * stack either has already received the QUIT<CR><LF>, or else it
+        * acknowledges all bytes up to and including <CR><LF>.<CR><LF>,
+        * making room in the sender's TCP stack for QUIT<CR><LF>.
         */
+#define CHECK_PIPELINING_BUFSIZE \
+       (recv_state != SMTP_STATE_DOT || send_state != SMTP_STATE_QUIT)
+
        if (SENDER_IN_WAIT_STATE
            || (SENDER_IS_AHEAD
                && ((session->features & SMTP_FEATURE_PIPELINING) == 0
-                   || (VSTRING_LEN(next_command) + 2
+                   || (CHECK_PIPELINING_BUFSIZE
+                       && (VSTRING_LEN(next_command) + 2
                    + vstream_bufstat(session->stream, VSTREAM_BST_OUT_PEND)
-                       > VSTREAM_BUFSIZE)
+                           > PIPELINING_BUFSIZE))
                    || time((time_t *) 0)
                    - vstream_ftime(session->stream) > 10))) {
            while (SENDER_IS_AHEAD) {
index 8adc1f1a3ee087236970118d708a5c2a38f22a92..638cc95a00fc96eb3275cfc3afbecf11b825a91a 100644 (file)
 /* .IP "\fBtls_eecdh_ultra_curve (secp384r1)\fR"
 /*     The elliptic curve used by the SMTP server for maximally strong
 /*     ephemeral ECDH key exchange.
+/* .PP
+/*     Available in Postfix version 2.8 and later:
+/* .IP "\fBtls_preempt_cipherlist (no)\fR"
+/*     With SSLv3 and later, use the server's cipher preference order
+/*     instead of the client's cipher preference order.
+/* .IP "\fBtls_disable_workarounds (see 'postconf -d' output)\fR"
+/*     List or bit-mask of OpenSSL bug work-arounds to disable.
 /* OBSOLETE STARTTLS CONTROLS
 /* .ad
 /* .fi
@@ -4046,12 +4053,14 @@ static void smtpd_start_tls(SMTPD_STATE *state)
     /*
      * When TLS is turned on, we may offer AUTH methods that would not be
      * offered within a plain-text session.
+     * 
+     * XXX Always refresh SASL the mechanism list after STARTTLS. Dovecot
+     * responses may depend on whether the SMTP connection is encrypted.
      */
 #ifdef USE_SASL_AUTH
     if (var_smtpd_sasl_enable) {
        /* Non-wrappermode, presumably. */
-       if (smtpd_sasl_is_active(state)
-           && strcmp(var_smtpd_sasl_opts, var_smtpd_sasl_tls_opts) != 0) {
+       if (smtpd_sasl_is_active(state)) {
            smtpd_sasl_auth_reset(state);
            smtpd_sasl_deactivate(state);
        }
index b4be636e2e2f3a9aa964c706dbbdabd783460cef..6e18badbdb3179acfb3831063ca29e11c85efab2 100644 (file)
@@ -98,6 +98,9 @@ typedef struct {
     int     log_level;                 /* TLS library logging level */
     int     session_reused;            /* this session was reused */
     int     am_server;                 /* Are we an SSL server or client? */
+    /* Built-in vs external SSL_accept/read/write/shutdown support. */
+    char   *fpt_dgst;                  /* Certificate fingerprint digest */
+    VSTREAM *stream;                   /* Blocking-mode SMTP session */
 } TLS_SESS_STATE;
 
  /*
@@ -277,6 +280,7 @@ typedef struct {
 
 extern TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *);
 extern TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props);
+extern TLS_SESS_STATE *tls_server_post_accept(TLS_SESS_STATE *);
 
 #define tls_server_stop(ctx, stream, timeout, failure, TLScontext) \
        tls_session_stop(ctx, (stream), (timeout), (failure), (TLScontext))
index b9b2788c36a4872d39521626def04a259d66a704..79a7d44b5e4b091bcf220aa405ae0456f0d124f9 100644 (file)
@@ -865,7 +865,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
      * Connect the SSL connection with the network socket.
      */
     if (SSL_set_fd(TLScontext->con, vstream_fileno(props->stream)) != 1) {
-       msg_info("SSL_set_fd error to %s: %d", props->namaddr, sts);
+       msg_info("SSL_set_fd error to %s", props->namaddr);
        tls_print_errors();
        uncache_session(app_ctx->ssl_ctx, TLScontext);
        tls_free_context(TLScontext);
index 4f592c32a2645848686a331c08a3046fc32b0074..bc7b703820cdbfea8b7ce09750777f8a3ff17f47 100644 (file)
@@ -16,6 +16,7 @@
 /*     char    *var_tls_eecdh_ultra;
 /*     int     var_tls_daemon_rand_bytes;
 /*     bool    var_tls_append_def_CA;
+/*     bool    var_tls_preempt_clist;
 /*
 /*     TLS_APPL_STATE *tls_alloc_app_context(ssl_ctx)
 /*     SSL_CTX *ssl_ctx;
 #include <vstring.h>
 #include <stringops.h>
 #include <argv.h>
+#include <name_mask.h>
+#include <name_code.h>
 
  /*
   * Global library.
@@ -192,6 +195,12 @@ int     var_tls_daemon_rand_bytes;
 char   *var_tls_eecdh_strong;
 char   *var_tls_eecdh_ultra;
 bool    var_tls_append_def_CA;
+char   *var_tls_bug_tweaks;
+
+#ifdef VAR_TLS_PREEMPT_CLIST
+bool    var_tls_preempt_clist;
+
+#endif
 
  /*
   * Index to attach TLScontext pointers to SSL objects, so that they can be
@@ -209,6 +218,82 @@ static const NAME_CODE protocol_table[] = {
     0, TLS_PROTOCOL_INVALID,
 };
 
+ /*
+  * SSL_OP_MUMBLE bug work-around name <=> mask conversion. We expect the C
+  * preprocessor to be able to handle "long" #if operands
+  */
+#define NAMEBUG(x)     #x, SSL_OP_##x
+static const LONG_NAME_MASK ssl_bug_tweaks[] = {
+
+#if defined(SSL_OP_MICROSOFT_SESS_ID_BUG) && \
+           ((SSL_OP_MICROSOFT_SESS_ID_BUG & SSL_OP_ALL) != 0L)
+    NAMEBUG(MICROSOFT_SESS_ID_BUG),    /* 0x00000001L */
+#endif
+
+#if defined(SSL_OP_NETSCAPE_CHALLENGE_BUG) && \
+           ((SSL_OP_NETSCAPE_CHALLENGE_BUG & SSL_OP_ALL) != 0L)
+    NAMEBUG(NETSCAPE_CHALLENGE_BUG),   /* 0x00000002L */
+#endif
+
+#if defined(SSL_OP_LEGACY_SERVER_CONNECT) && \
+           ((SSL_OP_LEGACY_SERVER_CONNECT & SSL_OP_ALL) != 0L)
+    NAMEBUG(LEGACY_SERVER_CONNECT),    /* 0x00000004L */
+#endif
+
+#if defined(SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG) && \
+           ((SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG & SSL_OP_ALL) != 0L)
+    NAMEBUG(NETSCAPE_REUSE_CIPHER_CHANGE_BUG), /* 0x00000008L */
+    "CVE-2010-4180", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG,
+#endif
+
+#if defined(SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG) && \
+           ((SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG & SSL_OP_ALL) != 0L)
+    NAMEBUG(SSLREF2_REUSE_CERT_TYPE_BUG),      /* 0x00000010L */
+#endif
+
+#if defined(SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) && \
+           ((SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER & SSL_OP_ALL) != 0L)
+    NAMEBUG(MICROSOFT_BIG_SSLV3_BUFFER),/* 0x00000020L  */
+#endif
+
+#if defined(SSL_OP_MSIE_SSLV2_RSA_PADDING) && \
+           ((SSL_OP_MSIE_SSLV2_RSA_PADDING & SSL_OP_ALL) != 0L)
+    NAMEBUG(MSIE_SSLV2_RSA_PADDING),   /* 0x00000040L */
+    "CVE-2005-2969", SSL_OP_MSIE_SSLV2_RSA_PADDING,
+#endif
+
+#if defined(SSL_OP_SSLEAY_080_CLIENT_DH_BUG) && \
+           ((SSL_OP_SSLEAY_080_CLIENT_DH_BUG & SSL_OP_ALL) != 0L)
+    NAMEBUG(SSLEAY_080_CLIENT_DH_BUG), /* 0x00000080L */
+#endif
+
+#if defined(SSL_OP_TLS_D5_BUG) && \
+           ((SSL_OP_TLS_D5_BUG & SSL_OP_ALL) != 0L)
+    NAMEBUG(TLS_D5_BUG),               /* 0x00000100L   */
+#endif
+
+#if defined(SSL_OP_TLS_BLOCK_PADDING_BUG) && \
+           ((SSL_OP_TLS_BLOCK_PADDING_BUG & SSL_OP_ALL) != 0L)
+    NAMEBUG(TLS_BLOCK_PADDING_BUG),    /* 0x00000200L */
+#endif
+
+#if defined(SSL_OP_TLS_ROLLBACK_BUG) && \
+           ((SSL_OP_TLS_ROLLBACK_BUG & SSL_OP_ALL) != 0L)
+    NAMEBUG(TLS_ROLLBACK_BUG),         /* 0x00000400L */
+#endif
+
+#if defined(SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) && \
+           ((SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS & SSL_OP_ALL) != 0L)
+    NAMEBUG(DONT_INSERT_EMPTY_FRAGMENTS),      /* 0x00000800L */
+#endif
+
+#if defined(SSL_OP_CRYPTOPRO_TLSEXT_BUG) && \
+           ((SSL_OP_CRYPTOPRO_TLSEXT_BUG & SSL_OP_ALL) != 0L)
+    NAMEBUG(CRYPTOPRO_TLSEXT_BUG),     /* 0x80000000L */
+#endif
+    0, 0,
+};
+
  /*
   * Ciphersuite name <=> code conversion.
   */
@@ -403,6 +488,7 @@ void    tls_param_init(void)
        VAR_TLS_NULL_CLIST, DEF_TLS_NULL_CLIST, &var_tls_null_clist, 1, 0,
        VAR_TLS_EECDH_STRONG, DEF_TLS_EECDH_STRONG, &var_tls_eecdh_strong, 1, 0,
        VAR_TLS_EECDH_ULTRA, DEF_TLS_EECDH_ULTRA, &var_tls_eecdh_ultra, 1, 0,
+       VAR_TLS_BUG_TWEAKS, DEF_TLS_BUG_TWEAKS, &var_tls_bug_tweaks, 0, 0,
        0,
     };
     static const CONFIG_INT_TABLE int_table[] = {
@@ -411,6 +497,9 @@ void    tls_param_init(void)
     };
     static const CONFIG_BOOL_TABLE bool_table[] = {
        VAR_TLS_APPEND_DEF_CA, DEF_TLS_APPEND_DEF_CA, &var_tls_append_def_CA,
+#if OPENSSL_VERSION_NUMBER >= 0x0090700fL      /* OpenSSL 0.9.7 and later */
+       VAR_TLS_PREEMPT_CLIST, DEF_TLS_PREEMPT_CLIST, &var_tls_preempt_clist,
+#endif
        0,
     };
     static int init_done;
@@ -591,6 +680,7 @@ TLS_SESS_STATE *tls_alloc_sess_context(int log_level, const char *namaddr)
     TLScontext->cipher_name = 0;
     TLScontext->log_level = log_level;
     TLScontext->namaddr = lowercase(mystrdup(namaddr));
+    TLScontext->fpt_dgst = 0;
 
     return (TLScontext);
 }
@@ -619,6 +709,8 @@ void    tls_free_context(TLS_SESS_STATE *TLScontext)
        myfree(TLScontext->issuer_CN);
     if (TLScontext->peer_fingerprint)
        myfree(TLScontext->peer_fingerprint);
+    if (TLScontext->fpt_dgst)
+       myfree(TLScontext->fpt_dgst);
 
     myfree((char *) TLScontext);
 }
@@ -714,6 +806,7 @@ void    tls_check_version(void)
 long    tls_bug_bits(void)
 {
     long    bits = SSL_OP_ALL;         /* Work around all known bugs */
+    long    mask;
 
 #if OPENSSL_VERSION_NUMBER >= 0x00908000L
     long    lib_version = SSLeay();
@@ -732,6 +825,16 @@ long    tls_bug_bits(void)
            bits &= ~SSL_OP_TLS_BLOCK_PADDING_BUG;
     }
 #endif
+
+    /*
+     * Silently ignore any strings that don't appear in the tweaks table, or
+     * hex bits that are not in SSL_OP_ALL.
+     */
+    if (*var_tls_bug_tweaks) {
+       bits &= ~long_name_mask_opt(VAR_TLS_BUG_TWEAKS, ssl_bug_tweaks,
+                                   var_tls_bug_tweaks, NAME_MASK_ANY_CASE |
+                                   NAME_MASK_NUMBER | NAME_MASK_WARN);
+    }
     return (bits);
 }
 
index 4d78e1b24e9e5a7d86fbaac5c094ce479fe7a427..8792f7102522e9c0a6a7fbd5ea845ccef24b6fa9 100644 (file)
@@ -12,6 +12,9 @@
 /*     TLS_SESS_STATE *tls_server_start(props)
 /*     const TLS_SERVER_START_PROPS *props;
 /*
+/*     TLS_SESS_STATE *tls_server_post_accept(TLScontext)
+/*     TLS_SESS_STATE *TLScontext;
+/*
 /*     void    tls_server_stop(app_ctx, stream, failure, TLScontext)
 /*     TLS_APPL_STATE *app_ctx;
 /*     VSTREAM *stream;
@@ -21,6 +24,9 @@
 /*     This module is the interface between Postfix TLS servers,
 /*     the OpenSSL library, and the TLS entropy and cache manager.
 /*
+/*     See "EVENT_DRIVEN APPLICATIONS" below for using this code
+/*     in event-driven programs.
+/*
 /*     tls_server_init() is called once when the SMTP server
 /*     initializes.
 /*     Certificate details are also decided during this phase,
@@ -28,7 +34,7 @@
 /*
 /*     tls_server_start() activates the TLS feature for the VSTREAM
 /*     passed as argument. We assume that network buffers are flushed
-/*     and the TLS handshake can begin immediately.
+/*     and the TLS handshake can begin immediately. 
 /*
 /*     tls_server_stop() sends the "close notify" alert via
 /*     SSL_shutdown() to the peer and resets all connection specific
 /*     certificate is available.
 /* .PP
 /*     If no peer certificate is presented the peer_status is set to 0.
+/* EVENT_DRIVEN APPLICATIONS
+/* .ad
+/* .fi
+/*     Event-driven programs manage multiple I/O channels.  Such
+/*     programs cannot use the synchronous VSTREAM-over-TLS
+/*     implementation that the current TLS library provides,
+/*     including tls_server_stop() and the underlying tls_stream(3)
+/*     and tls_bio_ops(3) routines. 
+/*
+/*     With the current TLS library implementation, this means
+/*     that the application is responsible for calling and retrying
+/*     SSL_accept(), SSL_read(), SSL_write() and SSL_shutdown().
+/*
+/*     To maintain control over TLS I/O, an event-driven server
+/*     invokes tls_server_start() with a null VSTREAM argument.
+/*     Then, tls_server_start() performs all the necessary
+/*     preparations before the TLS handshake and returns a partially
+/*     populated TLS context. The event-driven application is then
+/*     responsible for invoking SSL_accept(), and if successful,
+/*     for invoking tls_server_post_accept() to finish the work
+/*     that was started by tls_server_start(). In case of unrecoverable
+/*     failure, tls_server_post_accept() destroys the TLS context
+/*     and returns a null pointer value.
 /* LICENSE
 /* .ad
 /* .fi
@@ -370,6 +399,21 @@ TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props)
                 | ((protomask & TLS_PROTOCOL_SSLv3) ? SSL_OP_NO_SSLv3 : 0L)
               | ((protomask & TLS_PROTOCOL_SSLv2) ? SSL_OP_NO_SSLv2 : 0L));
 
+#if OPENSSL_VERSION_NUMBER >= 0x0090700fL
+
+    /*
+     * Some sites may want to give the client less rope. On the other hand,
+     * this could trigger inter-operability issues, the client should not
+     * offer ciphers it implements poorly, but this hasn't stopped some
+     * vendors from getting it wrong.
+     * 
+     * XXX: Given OpenSSL's security history, nobody should still be using
+     * 0.9.7, let alone 0.9.6 or earlier. Warning added to TLS_README.html.
+     */
+    if (var_tls_preempt_clist)
+       SSL_CTX_set_options(server_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
+#endif
+
     /*
      * Set the call-back routine to debug handshake progress.
      */
@@ -555,9 +599,6 @@ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props)
 {
     int     sts;
     TLS_SESS_STATE *TLScontext;
-    const SSL_CIPHER *cipher;
-    X509   *peer;
-    char    buf[CCERT_BUFSIZ];
     const char *cipher_list;
     TLS_APPL_STATE *app_ctx = props->ctx;
 
@@ -585,6 +626,9 @@ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props)
     TLScontext->serverid = mystrdup(props->serverid);
     TLScontext->am_server = 1;
 
+    TLScontext->fpt_dgst = mystrdup(props->fpt_dgst);
+    TLScontext->stream = props->stream;
+
     ERR_clear_error();
     if ((TLScontext->con = (SSL *) SSL_new(app_ctx->ssl_ctx)) == 0) {
        msg_warn("Could not allocate 'TLScontext->con' with SSL_new()");
@@ -613,11 +657,29 @@ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props)
      */
     SSL_set_accept_state(TLScontext->con);
 
+    /*
+     * If the debug level selected is high enough, all of the data is dumped:
+     * 3 will dump the SSL negotiation, 4 will dump everything.
+     * 
+     * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called?
+     * Well there is a BIO below the SSL routines that is automatically
+     * created for us, so we can use it for debugging purposes.
+     */
+    if (props->log_level >= 3)
+       BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb);
+
+    /*
+     * If we don't trigger the handshake in the library, leave control over
+     * SSL_accept/read/write/etc with the application.
+     */
+    if (props->stream == 0)
+       return (TLScontext);
+
     /*
      * Connect the SSL connection with the network socket.
      */
     if (SSL_set_fd(TLScontext->con, vstream_fileno(props->stream)) != 1) {
-       msg_info("SSL_set_fd error to %s: %d", props->namaddr, sts);
+       msg_info("SSL_set_fd error to %s", props->namaddr);
        tls_print_errors();
        uncache_session(app_ctx->ssl_ctx, TLScontext);
        tls_free_context(TLScontext);
@@ -630,17 +692,6 @@ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props)
      */
     non_blocking(vstream_fileno(props->stream), NON_BLOCKING);
 
-    /*
-     * If the debug level selected is high enough, all of the data is dumped:
-     * 3 will dump the SSL negotiation, 4 will dump everything.
-     * 
-     * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called?
-     * Well there is a BIO below the SSL routines that is automatically
-     * created for us, so we can use it for debugging purposes.
-     */
-    if (props->log_level >= 3)
-       BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb);
-
     /*
      * Start TLS negotiations. This process is a black box that invokes our
      * call-backs for session caching and certificate verification.
@@ -656,8 +707,19 @@ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props)
        tls_free_context(TLScontext);
        return (0);
     }
+    return (tls_server_post_accept(TLScontext));
+}
+
+/* tls_server_post_accept - post-handshake processing */
+
+TLS_SESS_STATE *tls_server_post_accept(TLS_SESS_STATE *TLScontext)
+{
+    const SSL_CIPHER *cipher;
+    X509   *peer;
+    char    buf[CCERT_BUFSIZ];
+
     /* Only loglevel==4 dumps everything */
-    if (props->log_level < 4)
+    if (TLScontext->log_level < 4)
        BIO_set_callback(SSL_get_rbio(TLScontext->con), 0);
 
     /*
@@ -678,7 +740,7 @@ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props)
        if (SSL_get_verify_result(TLScontext->con) == X509_V_OK)
            TLScontext->peer_status |= TLS_CERT_FLAG_TRUSTED;
 
-       if (props->log_level >= 2) {
+       if (TLScontext->log_level >= 2) {
            X509_NAME_oneline(X509_get_subject_name(peer),
                              buf, sizeof(buf));
            msg_info("subject=%s", buf);
@@ -688,11 +750,12 @@ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props)
        }
        TLScontext->peer_CN = tls_peer_CN(peer, TLScontext);
        TLScontext->issuer_CN = tls_issuer_CN(peer, TLScontext);
-       TLScontext->peer_fingerprint = tls_fingerprint(peer, props->fpt_dgst);
+       TLScontext->peer_fingerprint =
+           tls_fingerprint(peer, TLScontext->fpt_dgst);
 
-       if (props->log_level >= 1) {
+       if (TLScontext->log_level >= 1) {
            msg_info("%s: %s: subject_CN=%s, issuer=%s, fingerprint=%s",
-                    props->namaddr,
+                    TLScontext->namaddr,
                  TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted",
                     TLScontext->peer_CN, TLScontext->issuer_CN,
                     TLScontext->peer_fingerprint);
@@ -714,19 +777,22 @@ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props)
                                             &(TLScontext->cipher_algbits));
 
     /*
-     * The TLS engine is active. Switch to the tls_timed_read/write()
-     * functions and make the TLScontext available to those functions.
+     * If the library triggered the SSL handshake, switch to the
+     * tls_timed_read/write() functions and make the TLScontext available to
+     * those functions. Otherwise, leave control over SSL_read/write/etc.
+     * with the application.
      */
-    tls_stream_start(props->stream, TLScontext);
+    if (TLScontext->stream != 0)
+       tls_stream_start(TLScontext->stream, TLScontext);
 
     /*
      * All the key facts in a single log entry.
      */
-    if (props->log_level >= 1)
+    if (TLScontext->log_level >= 1)
        msg_info("%s TLS connection established from %s: %s with cipher %s "
              "(%d/%d bits)", !TLS_CERT_IS_PRESENT(TLScontext) ? "Anonymous"
                 : TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted",
-             props->namaddr, TLScontext->protocol, TLScontext->cipher_name,
+        TLScontext->namaddr, TLScontext->protocol, TLScontext->cipher_name,
                 TLScontext->cipher_usebits, TLScontext->cipher_algbits);
 
     tls_int_seed();
diff --git a/postfix/src/tlsproxy/.indent.pro b/postfix/src/tlsproxy/.indent.pro
new file mode 120000 (symlink)
index 0000000..5c837ec
--- /dev/null
@@ -0,0 +1 @@
+../../.indent.pro
\ No newline at end of file
diff --git a/postfix/src/tlsproxy/Makefile.in b/postfix/src/tlsproxy/Makefile.in
new file mode 100644 (file)
index 0000000..9b21b01
--- /dev/null
@@ -0,0 +1,96 @@
+SHELL  = /bin/sh
+SRCS   = tlsproxy.c tlsproxy_state.c
+OBJS   = tlsproxy.o tlsproxy_state.o
+HDRS   = 
+TESTSRC        =
+DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
+CFLAGS = $(DEBUG) $(OPT) $(DEFS)
+TESTPROG= 
+PROG   = tlsproxy
+INC_DIR = ../../include
+LIBS   = ../../lib/libtls.a ../../lib/libmaster.a ../../lib/libglobal.a \
+       ../../lib/libutil.a
+
+.c.o:; $(CC) $(CFLAGS) -c $*.c
+
+$(PROG): $(OBJS) $(LIBS)
+       $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
+
+$(OBJS): ../../conf/makedefs.out
+
+Makefile: Makefile.in
+       cat ../../conf/makedefs.out $? >$@
+
+test:  $(TESTPROG)
+
+tests: test
+
+root_tests:
+
+update: ../../libexec/$(PROG)
+
+../../libexec/$(PROG): $(PROG)
+       cp $(PROG) ../../libexec
+
+printfck: $(OBJS) $(PROG)
+       rm -rf printfck
+       mkdir printfck
+       sed '1,/^# do not edit/!d' Makefile >printfck/Makefile
+       set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done
+       cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o`
+
+lint:
+       lint $(DEFS) $(SRCS) $(LINTFIX)
+
+clean:
+       rm -f *.o *core $(PROG) $(TESTPROG) junk 
+       rm -rf printfck
+
+tidy:  clean
+
+depend: $(MAKES)
+       (sed '1,/^# do not edit/!d' Makefile.in; \
+       set -e; for i in [a-z][a-z0-9]*.c; do \
+           $(CC) -E $(DEFS) $(INCL) $$i | grep -v '[<>]' | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
+           -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' \
+           -e 's/o: \.\//o: /' -e p -e '}' ; \
+       done | sort -u) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
+       @$(EXPORT) make -f Makefile.in Makefile 1>&2
+
+# do not edit below this line - it is generated by 'make depend'
+tlsproxy.o: ../../include/argv.h
+tlsproxy.o: ../../include/attr.h
+tlsproxy.o: ../../include/events.h
+tlsproxy.o: ../../include/iostuff.h
+tlsproxy.o: ../../include/mail_conf.h
+tlsproxy.o: ../../include/mail_params.h
+tlsproxy.o: ../../include/mail_proto.h
+tlsproxy.o: ../../include/mail_server.h
+tlsproxy.o: ../../include/mail_version.h
+tlsproxy.o: ../../include/msg.h
+tlsproxy.o: ../../include/mymalloc.h
+tlsproxy.o: ../../include/name_code.h
+tlsproxy.o: ../../include/name_mask.h
+tlsproxy.o: ../../include/nbbio.h
+tlsproxy.o: ../../include/sys_defs.h
+tlsproxy.o: ../../include/tls.h
+tlsproxy.o: ../../include/vbuf.h
+tlsproxy.o: ../../include/vstream.h
+tlsproxy.o: ../../include/vstring.h
+tlsproxy.o: tlsproxy.c
+tlsproxy.o: tlsproxy.h
+tlsproxy_state.o: ../../include/argv.h
+tlsproxy_state.o: ../../include/events.h
+tlsproxy_state.o: ../../include/mail_server.h
+tlsproxy_state.o: ../../include/msg.h
+tlsproxy_state.o: ../../include/mymalloc.h
+tlsproxy_state.o: ../../include/name_code.h
+tlsproxy_state.o: ../../include/name_mask.h
+tlsproxy_state.o: ../../include/nbbio.h
+tlsproxy_state.o: ../../include/sys_defs.h
+tlsproxy_state.o: ../../include/tls.h
+tlsproxy_state.o: ../../include/vbuf.h
+tlsproxy_state.o: ../../include/vstream.h
+tlsproxy_state.o: ../../include/vstring.h
+tlsproxy_state.o: tlsproxy.h
+tlsproxy_state.o: tlsproxy_state.c
diff --git a/postfix/src/tlsproxy/tlsproxy.c b/postfix/src/tlsproxy/tlsproxy.c
new file mode 100644 (file)
index 0000000..4e0b350
--- /dev/null
@@ -0,0 +1,1107 @@
+/*++
+/* NAME
+/*     tlsproxy 8
+/* SUMMARY
+/*     Postfix TLS proxy
+/* SYNOPSIS
+/*     \fBtlsproxy\fR [generic Postfix daemon options]
+/* DESCRIPTION
+/*     The \fBtlsproxy\fR(8) server implements a server-side TLS
+/*     proxy. Its primary use is to talk plaintext SMTP with
+/*     \fBpostscreen\fR(8), and to talk SMTP-over-TLS with remote
+/*     SMTP clients whose whitelist status has expired, but it
+/*     should also work for non-SMTP protocols.
+/*
+/*     Although one \fBtlsproxy\fR(8) process can serve multiple
+/*     sessions at the same time, it is a good idea to allow the
+/*     number of processes to increase with load, so that the
+/*     service remains available.
+/* PROTOCOL EXAMPLE
+/* .ad
+/* .fi
+/*     The example below involves \fBpostscreen\fR(8). However,
+/*     the \fBtlsproxy\fR(8) server is agnostic of the application
+/*     protocol, and the example is easily adapted to other
+/*     applications.
+/*
+/*     The \fBpostscreen\fR(8) server sends the remote SMTP client
+/*     endpoint string, the requested role (server), and the
+/*     requested timeout to \fBtlsproxy\fR(8).  \fBpostscreen\fR(8)
+/*     then receives a "TLS available" indication from \fBtlsproxy\fR(8).
+/*     If the TLS service is available, \fBpostscreen\fR(8) sends
+/*     the remote SMTP client file descriptor to \fBtlsproxy\fR(8),
+/*     and sends the plaintext 220 greeting to the remote SMTP
+/*     client.  This triggers TLS negotiations between the remote
+/*     SMTP client and \fBtlsproxy\fR(8).  Upon completion of the
+/*     TLS-level handshake, \fBtlsproxy\fR(8) translates between
+/*     plaintext from/to \fBpostscreen\fR(8) and ciphertext to/from
+/*     the remote SMTP client.
+/* SECURITY
+/* .ad
+/* .fi
+/*     The \fBtlsproxy\fR(8) server is moderately security-sensitive.
+/*     It talks to untrusted clients on the network. The process
+/*     can be run chrooted at fixed low privilege.
+/* DIAGNOSTICS
+/*     Problems and transactions are logged to \fBsyslogd\fR(8).
+/* CONFIGURATION PARAMETERS
+/* .ad
+/* .fi
+/*     Changes to \fBmain.cf\fR are not picked up automatically,
+/*     as \fBtlsproxy\fR(8) processes may run for a long time
+/*     depending on mail server load.  Use the command "\fBpostfix
+/*     reload\fR" to speed up a change.
+/*
+/*     The text below provides only a parameter summary. See
+/*     \fBpostconf\fR(5) for more details including examples.
+/* STARTTLS SUPPORT CONTROLS
+/* .ad
+/* .fi
+/* .IP "\fBtlsproxy_tls_CAfile ($smtpd_tls_CAfile)\fR"
+/*     A file containing (PEM format) CA certificates of root CAs
+/*     trusted to sign either remote SMTP client certificates or intermediate
+/*     CA certificates.
+/* .IP "\fBtlsproxy_tls_CApath ($smtpd_tls_CApath)\fR"
+/*     A directory containing (PEM format) CA certificates of root CAs
+/*     trusted to sign either remote SMTP client certificates or intermediate
+/*     CA certificates.
+/* .IP "\fBtlsproxy_tls_always_issue_session_ids ($smtpd_tls_always_issue_session_ids)\fR"
+/*     Force the Postfix \fBtlsproxy\fR(8) server to issue a TLS session id,
+/*     even when TLS session caching is turned off.
+/* .IP "\fBtlsproxy_tls_ask_ccert ($smtpd_tls_ask_ccert)\fR"
+/*     Ask a remote SMTP client for a client certificate.
+/* .IP "\fBtlsproxy_tls_ccert_verifydepth ($smtpd_tls_ccert_verifydepth)\fR"
+/*     The verification depth for remote SMTP client certificates.
+/* .IP "\fBtlsproxy_tls_cert_file ($smtpd_tls_cert_file)\fR"
+/*     File with the Postfix \fBtlsproxy\fR(8) server RSA certificate in PEM
+/*     format.
+/* .IP "\fBtlsproxy_tls_ciphers ($smtpd_tls_ciphers)\fR"
+/*     The minimum TLS cipher grade that the Postfix \fBtlsproxy\fR(8) server
+/*     will use with opportunistic TLS encryption.
+/* .IP "\fBtlsproxy_tls_dcert_file ($smtpd_tls_dcert_file)\fR"
+/*     File with the Postfix \fBtlsproxy\fR(8) server DSA certificate in PEM
+/*     format.
+/* .IP "\fBtlsproxy_tls_dh1024_param_file ($smtpd_tls_dh1024_param_file)\fR"
+/*     File with DH parameters that the Postfix \fBtlsproxy\fR(8) server
+/*     should use with EDH ciphers.
+/* .IP "\fBtlsproxy_tls_dh512_param_file ($smtpd_tls_dh512_param_file)\fR"
+/*     File with DH parameters that the Postfix \fBtlsproxy\fR(8) server
+/*     should use with EDH ciphers.
+/* .IP "\fBtlsproxy_tls_dkey_file ($smtpd_tls_dkey_file)\fR"
+/*     File with the Postfix \fBtlsproxy\fR(8) server DSA private key in PEM
+/*     format.
+/* .IP "\fBtlsproxy_tls_eccert_file ($smtpd_tls_eccert_file)\fR"
+/*     File with the Postfix \fBtlsproxy\fR(8) server ECDSA certificate in
+/*     PEM format.
+/* .IP "\fBtlsproxy_tls_eckey_file ($smtpd_tls_eckey_file)\fR"
+/*     File with the Postfix \fBtlsproxy\fR(8) server ECDSA private key in
+/*     PEM format.
+/* .IP "\fBtlsproxy_tls_eecdh_grade ($smtpd_tls_eecdh_grade)\fR"
+/*     The Postfix \fBtlsproxy\fR(8) server security grade for ephemeral
+/*     elliptic-curve Diffie-Hellman (EECDH) key exchange.
+/* .IP "\fBtlsproxy_tls_exclude_ciphers ($smtpd_tls_exclude_ciphers)\fR"
+/*     List of ciphers or cipher types to exclude from the \fBtlsproxy\fR(8)
+/*     server cipher list at all TLS security levels.
+/* .IP "\fBtlsproxy_tls_fingerprint_digest ($smtpd_tls_fingerprint_digest)\fR"
+/*     The message digest algorithm used to construct client-certificate
+/*     fingerprints.
+/* .IP "\fBtlsproxy_tls_key_file ($smtpd_tls_key_file)\fR"
+/*     File with the Postfix \fBtlsproxy\fR(8) server RSA private key in PEM
+/*     format.
+/* .IP "\fBtlsproxy_tls_loglevel ($smtpd_tls_loglevel)\fR"
+/*     Enable additional Postfix \fBtlsproxy\fR(8) server logging of TLS
+/*     activity.
+/* .IP "\fBtlsproxy_tls_mandatory_ciphers ($smtpd_tls_mandatory_ciphers)\fR"
+/*     The minimum TLS cipher grade that the Postfix \fBtlsproxy\fR(8) server
+/*     will use with mandatory TLS encryption.
+/* .IP "\fBtlsproxy_tls_mandatory_exclude_ciphers ($smtpd_tls_mandatory_exclude_ciphers)\fR"
+/*     Additional list of ciphers or cipher types to exclude from the
+/*     \fBtlsproxy\fR(8) server cipher list at mandatory TLS security levels.
+/* .IP "\fBtlsproxy_tls_mandatory_protocols ($smtpd_tls_mandatory_protocols)\fR"
+/*     The SSL/TLS protocols accepted by the Postfix \fBtlsproxy\fR(8) server
+/*     with mandatory TLS encryption.
+/* .IP "\fBtlsproxy_tls_protocols ($smtpd_tls_protocols)\fR"
+/*     List of TLS protocols that the Postfix \fBtlsproxy\fR(8) server will
+/*     exclude or include with opportunistic TLS encryption.
+/* .IP "\fBtlsproxy_tls_req_ccert ($smtpd_tls_req_ccert)\fR"
+/*     With mandatory TLS encryption, require a trusted remote SMTP
+/*     client certificate in order to allow TLS connections to proceed.
+/* .IP "\fBtlsproxy_tls_security_level ($smtpd_tls_security_level)\fR"
+/*     The SMTP TLS security level for the Postfix \fBtlsproxy\fR(8) server;
+/*     when a non-empty value is specified, this overrides the obsolete
+/*     parameters smtpd_use_tls and smtpd_enforce_tls.
+/* .IP "\fBtlsproxy_tls_session_cache_timeout ($smtpd_tls_session_cache_timeout)\fR"
+/*     The expiration time of Postfix \fBtlsproxy\fR(8) server TLS session
+/*     cache information.
+/* OBSOLETE STARTTLS SUPPORT CONTROLS
+/* .ad
+/* .fi
+/*     These parameters are supported for compatibility with
+/*     \fBsmtpd\fR(8) legacy parameters.
+/* .IP "\fBtlsproxy_use_tls ($smtpd_use_tls)\fR"
+/*     Opportunistic TLS: announce STARTTLS support to SMTP clients,
+/*     but do not require that clients use TLS encryption.
+/* .IP "\fBtlsproxy_enforce_tls ($smtpd_enforce_tls)\fR"
+/*     Mandatory TLS: announce STARTTLS support to SMTP clients, and
+/*     require that clients use TLS encryption.
+/* RESOURCE CONTROLS
+/* .ad
+/* .fi
+/* .IP "\fBtlsproxy_watchdog_timeout (10s)\fR"
+/*     How much time a \fBtlsproxy\fR(8) process may take to process local
+/*     or remote I/O before it is terminated by a built-in watchdog timer.
+/* MISCELLANEOUS CONTROLS
+/* .ad
+/* .fi
+/* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
+/*     The default location of the Postfix main.cf and master.cf
+/*     configuration files.
+/* .IP "\fBprocess_id (read-only)\fR"
+/*     The process ID of a Postfix command or daemon process.
+/* .IP "\fBprocess_name (read-only)\fR"
+/*     The process name of a Postfix command or daemon process.
+/* .IP "\fBsyslog_facility (mail)\fR"
+/*     The syslog facility of Postfix logging.
+/* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
+/*     The mail system name that is prepended to the process name in syslog
+/*     records, so that "smtpd" becomes, for example, "postfix/smtpd".
+/* SEE ALSO
+/*     postscreen(8), Postfix zombie blocker
+/*     smtpd(8), Postfix SMTP server
+/*     postconf(5), configuration parameters
+/*     syslogd(5), system logging
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* HISTORY
+/* .ad
+/* .fi
+/*     This service was introduced with Postfix version 2.8.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+ /*
+  * System library.
+  */
+#include <sys_defs.h>
+
+ /*
+  * Utility library.
+  */
+#include <msg.h>
+#include <vstream.h>
+#include <iostuff.h>
+#include <nbbio.h>
+#include <mymalloc.h>
+
+ /*
+  * Global library.
+  */
+#include <mail_proto.h>
+#include <mail_params.h>
+#include <mail_conf.h>
+#include <mail_version.h>
+
+ /*
+  * Master library.
+  */
+#include <mail_server.h>
+
+ /*
+  * TLS library.
+  */
+#ifdef USE_TLS
+#define TLS_INTERNAL                   /* XXX */
+#include <tls.h>
+
+ /*
+  * Application-specific.
+  */
+#include <tlsproxy.h>
+
+ /*
+  * Tunable parameters. We define our clones of the smtpd(8) parameters to
+  * avoid any confusion about which parameters are used by this program.
+  */
+int     var_smtpd_tls_ccert_vd;
+int     var_smtpd_tls_loglevel;
+int     var_smtpd_tls_scache_timeout;
+bool    var_smtpd_use_tls;
+bool    var_smtpd_enforce_tls;
+bool    var_smtpd_tls_ask_ccert;
+bool    var_smtpd_tls_req_ccert;
+bool    var_smtpd_tls_set_sessid;
+char   *var_smtpd_relay_ccerts;
+char   *var_smtpd_tls_cert_file;
+char   *var_smtpd_tls_key_file;
+char   *var_smtpd_tls_dcert_file;
+char   *var_smtpd_tls_dkey_file;
+char   *var_smtpd_tls_eccert_file;
+char   *var_smtpd_tls_eckey_file;
+char   *var_smtpd_tls_CAfile;
+char   *var_smtpd_tls_CApath;
+char   *var_smtpd_tls_ciph;
+char   *var_smtpd_tls_mand_ciph;
+char   *var_smtpd_tls_excl_ciph;
+char   *var_smtpd_tls_mand_excl;
+char   *var_smtpd_tls_proto;
+char   *var_smtpd_tls_mand_proto;
+char   *var_smtpd_tls_dh512_param_file;
+char   *var_smtpd_tls_dh1024_param_file;
+char   *var_smtpd_tls_eecdh;
+char   *var_smtpd_tls_fpt_dgst;
+char   *var_smtpd_tls_level;
+
+int     var_tlsp_tls_ccert_vd;
+int     var_tlsp_tls_loglevel;
+int     var_tlsp_tls_scache_timeout;
+bool    var_tlsp_use_tls;
+bool    var_tlsp_enforce_tls;
+bool    var_tlsp_tls_ask_ccert;
+bool    var_tlsp_tls_req_ccert;
+bool    var_tlsp_tls_set_sessid;
+char   *var_tlsp_tls_cert_file;
+char   *var_tlsp_tls_key_file;
+char   *var_tlsp_tls_dcert_file;
+char   *var_tlsp_tls_dkey_file;
+char   *var_tlsp_tls_eccert_file;
+char   *var_tlsp_tls_eckey_file;
+char   *var_tlsp_tls_CAfile;
+char   *var_tlsp_tls_CApath;
+char   *var_tlsp_tls_ciph;
+char   *var_tlsp_tls_mand_ciph;
+char   *var_tlsp_tls_excl_ciph;
+char   *var_tlsp_tls_mand_excl;
+char   *var_tlsp_tls_proto;
+char   *var_tlsp_tls_mand_proto;
+char   *var_tlsp_tls_dh512_param_file;
+char   *var_tlsp_tls_dh1024_param_file;
+char   *var_tlsp_tls_eecdh;
+char   *var_tlsp_tls_fpt_dgst;
+char   *var_tlsp_tls_level;
+
+int     var_tlsp_watchdog;
+
+ /*
+  * TLS per-process status.
+  */
+static TLS_APPL_STATE *tlsp_server_ctx;
+static int ask_client_cert;
+static int enforce_tls;
+
+ /*
+  * SLMs.
+  */
+#define STR(x) vstring_str(x)
+
+ /*
+  * This code looks simpler than expected. That is the result of a great deal
+  * of effort, mainly in design and analysis.
+  * 
+  * By design, postscreen(8) is an event-driven server that must scale up to a
+  * large number of clients. This means that postscreen(8) must avoid doing
+  * CPU-intensive operations such as those in OpenSSL.
+  * 
+  * tlsproxy(8) runs the OpenSSL code on behalf of postscreen(8), translating
+  * plaintext SMTP messages from postscreen(8) into SMTP-over-TLS messages to
+  * the remote SMTP client, and vice versa. As long as postscreen(8) does not
+  * receive email messages, the cost of doing TLS operations will be modest.
+  * 
+  * Like postscreen(8), one tlsproxy(8) process services multiple remote SMTP
+  * clients. Unlike postscreen(8), there can be more than one tlsproxy(8)
+  * process, although their number is meant to be much smaller than the
+  * number of remote SMTP clients that talk TLS.
+  * 
+  * As with postscreen(8), all I/O must be event-driven: encrypted traffic
+  * between tlsproxy(8) and remote SMTP clients, and plaintext traffic
+  * between tlsproxy(8) and postscreen(8). Event-driven plaintext I/O is
+  * straightforward enough that it could be abstracted away with the nbbio(3)
+  * module.
+  * 
+  * The event-driven TLS I/O implementation is founded on on-line OpenSSL
+  * documentation, supplemented by statements from OpenSSL developers on
+  * public mailing lists. After some field experience with this code, we may
+  * be able to factor it out as a library module, like nbbio(3), that can
+  * become part of the TLS library.
+  */
+
+static void tlsp_ciphertext_event(int, char *);
+
+#define TLSP_INIT_TIMEOUT      100
+
+/* tlsp_drain - delayed exit after "postfix reload" */
+
+static void tlsp_drain(char *unused_service, char **unused_argv)
+{
+    int     count;
+
+    /*
+     * After "postfix reload", complete work-in-progress in the background,
+     * instead of dropping already-accepted connections on the floor.
+     * 
+     * All error retry counts shall be limited. Instead of blocking here, we
+     * could retry failed fork() operations in the event call-back routines,
+     * but we don't need perfection. The host system is severely overloaded
+     * and service levels are already way down.
+     */
+    for (count = 0; /* see below */ ; count++) {
+       if (count >= 5) {
+           msg_fatal("fork: %m");
+       } else if (event_server_drain() != 0) {
+           msg_warn("fork: %m");
+           sleep(1);
+           continue;
+       } else {
+           return;
+       }
+    }
+}
+
+/* tlsp_eval_tls_error - translate TLS "error" result into action */
+
+static int tlsp_eval_tls_error(TLSP_STATE *state, int err)
+{
+    int     ciphertext_fd = state->ciphertext_fd;
+
+    /*
+     * The ciphertext file descriptor is in non-blocking mode, meaning that
+     * each SSL_accept/connect/read/write/shutdown request may return an
+     * "error" indication that it needs to read or write more ciphertext. The
+     * purpose of this routine is to translate those "error" indications into
+     * the appropriate read/write/timeout event requests.
+     */
+    switch (err) {
+
+       /*
+        * No error from SSL_read and SSL_write means that the plaintext
+        * output buffer is full and that the plaintext input buffer is
+        * empty. Stop read/write events on the ciphertext stream. Keep the
+        * timer alive as a safety mechanism for the case that the plaintext
+        * pseudothreads get stuck.
+        */
+    case SSL_ERROR_NONE:
+       if (state->ssl_last_err != SSL_ERROR_NONE) {
+           event_disable_readwrite(ciphertext_fd);
+           event_request_timer(tlsp_ciphertext_event, (char *) state,
+                               state->timeout);
+           state->ssl_last_err = SSL_ERROR_NONE;
+       }
+       return (0);
+
+       /*
+        * The TLS engine wants to write to the network. Turn on
+        * write/timeout events on the ciphertext stream.
+        */
+    case SSL_ERROR_WANT_WRITE:
+       if (state->ssl_last_err == SSL_ERROR_WANT_READ)
+           event_disable_readwrite(ciphertext_fd);
+       if (state->ssl_last_err != SSL_ERROR_WANT_WRITE) {
+           event_enable_write(ciphertext_fd, tlsp_ciphertext_event,
+                              (char *) state);
+           state->ssl_last_err = SSL_ERROR_WANT_WRITE;
+       }
+       event_request_timer(tlsp_ciphertext_event, (char *) state,
+                           state->timeout);
+       return (0);
+
+       /*
+        * The TLS engine wants to read from the network. Turn on
+        * read/timeout events on the ciphertext stream.
+        */
+    case SSL_ERROR_WANT_READ:
+       if (state->ssl_last_err == SSL_ERROR_WANT_WRITE)
+           event_disable_readwrite(ciphertext_fd);
+       if (state->ssl_last_err != SSL_ERROR_WANT_READ) {
+           event_enable_read(ciphertext_fd, tlsp_ciphertext_event,
+                             (char *) state);
+           state->ssl_last_err = SSL_ERROR_WANT_READ;
+       }
+       event_request_timer(tlsp_ciphertext_event, (char *) state,
+                           state->timeout);
+       return (0);
+
+       /*
+        * Some error. Self-destruct. This automagically cleans up all
+        * pending read/write and timeout event requests, making state a
+        * dangling pointer.
+        */
+    case SSL_ERROR_SSL:
+       tls_print_errors();
+       /* FALLTHROUGH */
+    default:
+       tlsp_state_free(state);
+       return (-1);
+    }
+}
+
+/* tlsp_strategy - decide what to read or write next. */
+
+static void tlsp_strategy(TLSP_STATE *state)
+{
+    TLS_SESS_STATE *tls_context = state->tls_context;
+    NBBIO  *plaintext_buf;
+    int     ssl_stat;
+    int     ssl_read_err;
+    int     ssl_write_err;
+    int     handshake_err;
+
+    /*
+     * Be sure to complete the TLS handshake before enabling plain-text I/O.
+     * In case of an unrecoverable error, this automagically cleans up all
+     * pending read/write and timeout event requests.
+     */
+    if (state->flags & TLSP_FLAG_DO_HANDSHAKE) {
+       ssl_stat = SSL_accept(tls_context->con);
+       if (ssl_stat != 1) {
+           handshake_err = SSL_get_error(tls_context->con, ssl_stat);
+           tlsp_eval_tls_error(state, handshake_err);
+           /* At this point, state could be a dangling pointer. */
+           return;
+       }
+       if ((state->tls_context = tls_server_post_accept(tls_context)) == 0) {
+           tlsp_state_free(state);
+           return;
+       }
+       state->flags &= ~TLSP_FLAG_DO_HANDSHAKE;
+    }
+
+    /*
+     * Shutdown and self-destruct after NBBIO error. This automagically
+     * cleans up all pending read/write and timeout event requests. Before
+     * shutting down TLS, we stop all plain-text I/O events but keep the
+     * NBBIO error flags.
+     */
+    plaintext_buf = state->plaintext_buf;
+    if (NBBIO_ERROR_FLAGS(plaintext_buf)) {
+       if (NBBIO_ACTIVE_FLAGS(plaintext_buf))
+           nbbio_disable_readwrite(state->plaintext_buf);
+       ssl_stat = SSL_shutdown(tls_context->con);
+       /* XXX Wait for return value 1 if sessions are to be reused? */
+       if (ssl_stat < 0) {
+           handshake_err = SSL_get_error(tls_context->con, ssl_stat);
+           tlsp_eval_tls_error(state, handshake_err);
+           /* At this point, state could be a dangling pointer. */
+           return;
+       }
+       tlsp_state_free(state);
+       return;
+    }
+
+    /*
+     * Try to move data from the plaintext input buffer to the TLS engine.
+     * 
+     * XXX We're supposed to repeat the exact same SSL_write() call arguments
+     * after an SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE result. Rumor has
+     * it that this is because each SSL_write() call reads from the buffer
+     * incrementally, and returns > 0 only after the final byte is processed.
+     * Rumor also has it that setting SSL_MODE_ENABLE_PARTIAL_WRITE and
+     * SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER voids this requirement, and that
+     * repeating the request with an increased request size is OK.
+     * Unfortunately all this is not or poorly documented, and one has to
+     * rely on statements from OpenSSL developers in public mailing archives.
+     */
+    ssl_write_err = SSL_ERROR_NONE;
+    while (NBBIO_READ_PEND(plaintext_buf) > 0) {
+       ssl_stat = SSL_write(tls_context->con, NBBIO_READ_BUF(plaintext_buf),
+                            NBBIO_READ_PEND(plaintext_buf));
+       ssl_write_err = SSL_get_error(tls_context->con, ssl_stat);
+       if (ssl_write_err != SSL_ERROR_NONE)
+           break;
+       /* Allow the plaintext pseudothread to read more data. */
+       NBBIO_READ_PEND(plaintext_buf) -= ssl_stat;
+       if (NBBIO_READ_PEND(plaintext_buf) > 0)
+           memmove(NBBIO_READ_BUF(plaintext_buf),
+                   NBBIO_READ_BUF(plaintext_buf) + ssl_stat,
+                   NBBIO_READ_PEND(plaintext_buf));
+    }
+
+    /*
+     * Try to move data from the TLS engine to the plaintext output buffer.
+     * Note: data may arrive as a side effect of calling SSL_write(),
+     * therefore we call SSL_read() after calling SSL_write().
+     * 
+     * XXX We're supposed to repeat the exact same SSL_read() call arguments
+     * after an SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE result. This
+     * supposedly means that our plaintext writer must not memmove() the
+     * plaintext output buffer until after the SSL_read() call succeeds. For
+     * now I'll ignore this, because 1) SSL_read() is documented to return
+     * the bytes available, instead of returning > 0 only after the entire
+     * buffer is processed like SSL_write() does; and 2) there is no "read"
+     * equivalent of the SSL_R_BAD_WRITE_RETRY, SSL_MODE_ENABLE_PARTIAL_WRITE
+     * or SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER features.
+     */
+    ssl_read_err = SSL_ERROR_NONE;
+    while (NBBIO_WRITE_PEND(state->plaintext_buf) < NBBIO_BUFSIZE(plaintext_buf)) {
+       ssl_stat = SSL_read(tls_context->con,
+                           NBBIO_WRITE_BUF(plaintext_buf)
+                           + NBBIO_WRITE_PEND(state->plaintext_buf),
+                           NBBIO_BUFSIZE(plaintext_buf)
+                           - NBBIO_WRITE_PEND(state->plaintext_buf));
+       ssl_read_err = SSL_get_error(tls_context->con, ssl_stat);
+       if (ssl_read_err != SSL_ERROR_NONE)
+           break;
+       NBBIO_WRITE_PEND(plaintext_buf) += ssl_stat;
+    }
+
+    /*
+     * Try to enable/disable ciphertext read/write events. If SSL_write() was
+     * satisfied, see if SSL_read() wants to do some work. In case of an
+     * unrecoverable error, this automagically destroys the session state
+     * after cleaning up all pending read/write and timeout event requests.
+     */
+    if (tlsp_eval_tls_error(state, ssl_write_err != SSL_ERROR_NONE ?
+                           ssl_write_err : ssl_read_err) < 0)
+       return;
+
+    /*
+     * Try to enable/disable plaintext read/write events. Basically, if we
+     * have nothing to write to the postscreen(8) server, see if there is
+     * something to read. If the write buffer is empty and the read buffer is
+     * full, suspend plaintext I/O until conditions change (but keep the
+     * timer active, as a safety mechanism in case ciphertext I/O gets
+     * stuck).
+     * 
+     * XXX In theory, if the client keeps writing fast enough then we would
+     * never read from postscreen(8), and cause postscreen(8) to block. In
+     * practice, postscreen(8) limits the number of client commands, and thus
+     * postscreen(8)'s output will fit in a kernel buffer. This may not be
+     * true in other scenarios where the tlsproxy(8) server could be used.
+     */
+    if (NBBIO_WRITE_PEND(plaintext_buf) > 0) {
+       if (NBBIO_ACTIVE_FLAGS(plaintext_buf) & NBBIO_FLAG_READ)
+           nbbio_disable_readwrite(plaintext_buf);
+       if ((NBBIO_ACTIVE_FLAGS(plaintext_buf) & NBBIO_FLAG_WRITE) == 0)
+           nbbio_enable_write(plaintext_buf, state->timeout);
+    } else if (NBBIO_READ_PEND(plaintext_buf) < NBBIO_BUFSIZE(plaintext_buf)) {
+       if (NBBIO_ACTIVE_FLAGS(plaintext_buf) & NBBIO_FLAG_WRITE)
+           nbbio_disable_readwrite(plaintext_buf);
+       if ((NBBIO_ACTIVE_FLAGS(plaintext_buf) & NBBIO_FLAG_READ) == 0)
+           nbbio_enable_read(plaintext_buf, state->timeout);
+    } else {
+       if (NBBIO_ACTIVE_FLAGS(plaintext_buf))
+           nbbio_slumber(plaintext_buf, state->timeout);
+    }
+}
+
+/* tlsp_plaintext_event - plaintext was read/written */
+
+static void tlsp_plaintext_event(int event, char *context)
+{
+    TLSP_STATE *state = (TLSP_STATE *) context;
+
+    /*
+     * Safety alert: the plaintext pseudothreads have "slumbered" for too
+     * long (see code above). This means that the ciphertext pseudothreads
+     * are stuck.
+     */
+    if ((NBBIO_ERROR_FLAGS(state->plaintext_buf) & NBBIO_FLAG_TIMEOUT) != 0
+       && NBBIO_ACTIVE_FLAGS(state->plaintext_buf) == 0)
+       msg_warn("deadlock on ciphertext stream for %s", state->remote_endpt);
+
+    /*
+     * This is easy, because the NBBIO layer has already done the event
+     * decoding and plaintext I/O for us. All we need to do is decide if we
+     * want to read or write more plaintext.
+     */
+    tlsp_strategy(state);
+}
+
+/* tlsp_ciphertext_event - ciphertext is ready to read/write */
+
+static void tlsp_ciphertext_event(int event, char *context)
+{
+    TLSP_STATE *state = (TLSP_STATE *) context;
+
+    /*
+     * Without a TLS quivalent of the NBBIO layer, we must decode the events
+     * ourselves and do the ciphertext I/O. Then, we can decide if we want to
+     * read or write more ciphertext.
+     */
+    if (event == EVENT_READ || event == EVENT_WRITE) {
+       tlsp_strategy(state);
+    } else {
+       msg_warn("read/write %s for %s",
+                event == EVENT_TIME ? "timeout" : "error",
+                state->remote_endpt);
+       tlsp_state_free(state);
+    }
+}
+
+/* tlsp_start_tls - turn on TLS or force disconnect */
+
+static void tlsp_start_tls(TLSP_STATE *state)
+{
+    TLS_SERVER_START_PROPS props;
+    static char *cipher_grade;
+    static VSTRING *cipher_exclusions;
+
+    /*
+     * The code in this routine is pasted literally from smtpd(8). I am not
+     * going to sanitize this because doing so surely will break things in
+     * unexpected ways.
+     */
+    state->tls_use_tls = var_tlsp_use_tls | var_tlsp_enforce_tls;
+    state->tls_enforce_tls = var_tlsp_enforce_tls;
+
+    /*
+     * Perform the before-handshake portion of the per-session initalization.
+     * Pass a null VSTREAM to indicate that this program, will do the
+     * ciphertext I/O, not libtls.
+     * 
+     * The cipher grade and exclusions don't change between sessions. Compute
+     * just once and cache.
+     */
+#define ADD_EXCLUDE(vstr, str) \
+    do { \
+       if (*(str)) \
+           vstring_sprintf_append((vstr), "%s%s", \
+                                  VSTRING_LEN(vstr) ? " " : "", (str)); \
+    } while (0)
+
+    if (cipher_grade == 0) {
+       cipher_grade =
+           enforce_tls ? var_tlsp_tls_mand_ciph : var_tlsp_tls_ciph;
+       cipher_exclusions = vstring_alloc(10);
+       ADD_EXCLUDE(cipher_exclusions, var_tlsp_tls_excl_ciph);
+       if (enforce_tls)
+           ADD_EXCLUDE(cipher_exclusions, var_tlsp_tls_mand_excl);
+       if (ask_client_cert)
+           ADD_EXCLUDE(cipher_exclusions, "aNULL");
+    }
+    state->tls_context =
+       TLS_SERVER_START(&props,
+                        ctx = tlsp_server_ctx,
+                        stream = (VSTREAM *) 0,/* unused */
+                        log_level = var_tlsp_tls_loglevel,
+                        timeout = 0,           /* unused */
+                        requirecert = (var_tlsp_tls_req_ccert
+                                       && state->tls_enforce_tls),
+                        serverid = state->service,
+                        namaddr = state->remote_endpt,
+                        cipher_grade = cipher_grade,
+                        cipher_exclusions = STR(cipher_exclusions),
+                        fpt_dgst = var_tlsp_tls_fpt_dgst);
+
+    if (state->tls_context == 0) {
+       tlsp_state_free(state);
+       return;
+    }
+
+    /*
+     * This program will do the ciphertext I/O, not libtls. In the future,
+     * the above event-driven engine may be factored out as a libtls library
+     * module.
+     */
+    if (SSL_set_fd(state->tls_context->con, state->ciphertext_fd) != 1) {
+       msg_info("SSL_set_fd error to %s", state->remote_endpt);
+       tls_print_errors();
+       tlsp_state_free(state);
+       return;
+    }
+
+    /*
+     * XXX Do we care about TLS session rate limits? Good postscreen(8)
+     * clients will occasionally require the tlsproxy to renew their
+     * whitelist status, but bad clients hammering the server can suck up
+     * lots of CPU cycles. Per-client concurrency limits in postscreen(8)
+     * will divert only naive security "researchers".
+     * 
+     * XXX Do we care about certificate verification results? Not as long as
+     * postscreen(8) doesn't actually receive email.
+     */
+}
+
+/* tlsp_get_fd_event - receive final postscreen(8) hand-off information */
+
+static void tlsp_get_fd_event(int event, char *context)
+{
+    const char *myname = "tlsp_get_fd_event";
+    TLSP_STATE *state = (TLSP_STATE *) context;
+    int     plaintext_fd = vstream_fileno(state->plaintext_stream);
+
+    /*
+     * At this point we still manually manage plaintext read/write/timeout
+     * events. Disable I/O and timer events. Don't assume that the first
+     * plaintext request will be a read.
+     */
+    event_disable_readwrite(plaintext_fd);
+    if (event != EVENT_TIME)
+       event_cancel_timer(tlsp_get_fd_event, (char *) state);
+
+    /*
+     * Initialize plaintext-related session state.  Once we have this behind
+     * us, the TLSP_STATE destructor will automagically clean up requests for
+     * read/write/timeout events, which makes error recovery easier.
+     * 
+     * Register the plaintext event handler for timer cleanup in the TLSP_STATE
+     * destructor. Insert the NBBIO event-driven I/O layer between the
+     * postscreen(8) server and the TLS engine.
+     */
+    if (event != EVENT_READ
+       || (state->ciphertext_fd = LOCAL_RECV_FD(plaintext_fd)) < 0) {
+       msg_warn("%s: receive SMTP client file descriptor: %m", myname);
+       tlsp_state_free(state);
+       return;
+    }
+    non_blocking(state->ciphertext_fd, NON_BLOCKING);
+    state->ciphertext_timer = tlsp_ciphertext_event;
+    state->plaintext_buf = nbbio_create(plaintext_fd,
+                                       VSTREAM_BUFSIZE, "postscreen",
+                                       tlsp_plaintext_event,
+                                       (char *) state);
+
+    /*
+     * Perform the TLS layer before-handshake initialization. We perform the
+     * remainder after the TLS handshake completes.
+     */
+    tlsp_start_tls(state);
+
+    /*
+     * Trigger the initial proxy server I/Os.
+     */
+    tlsp_strategy(state);
+}
+
+/* tlsp_get_request_event - receive initial postscreen(8) hand-off info */
+
+static void tlsp_get_request_event(int event, char *context)
+{
+    const char *myname = "tlsp_get_request_event";
+    TLSP_STATE *state = (TLSP_STATE *) context;
+    VSTREAM *plaintext_stream = state->plaintext_stream;
+    int     plaintext_fd = vstream_fileno(plaintext_stream);
+    static VSTRING *remote_endpt;
+    static VSTRING *role;
+    int     timeout;
+    int     ready;
+
+    /*
+     * One-time initialization.
+     */
+    if (remote_endpt == 0) {
+       remote_endpt = vstring_alloc(10);
+       role = vstring_alloc(10);
+    }
+
+    /*
+     * At this point we still manually manage plaintext read/write/timeout
+     * events. Turn off timer events. Below we disable read events on error,
+     * and redefine read events on success.
+     */
+    if (event != EVENT_TIME)
+       event_cancel_timer(tlsp_get_request_event, (char *) state);
+
+    /*
+     * We must send some data, after receiving the request attributes and
+     * before receiving the remote file descriptor. We can't assume
+     * UNIX-domain socket semantics here.
+     */
+    if (event != EVENT_READ
+       || attr_scan(plaintext_stream, ATTR_FLAG_STRICT,
+                    ATTR_TYPE_STR, MAIL_ATTR_REMOTE_ENDPT, remote_endpt,
+                    ATTR_TYPE_STR, MAIL_ATTR_ROLE, role,
+                    ATTR_TYPE_INT, MAIL_ATTR_TIMEOUT, &timeout,
+                    ATTR_TYPE_END) != 3) {
+       msg_warn("%s: receive request attributes: %m", myname);
+       event_disable_readwrite(plaintext_fd);
+       tlsp_state_free(state);
+       return;
+    }
+
+    /*
+     * If the requested TLS engine is unavailable, hang up after making sure
+     * that the plaintext peer has received our "sorry" indication.
+     */
+    ready = (strcmp(STR(role), MAIL_ATTR_ROLE_SERVER) == 0
+            && tlsp_server_ctx != 0);
+    if (attr_print(plaintext_stream, ATTR_FLAG_NONE,
+                  ATTR_TYPE_INT, MAIL_ATTR_STATUS, ready,
+                  ATTR_TYPE_END) != 0
+       || vstream_fflush(plaintext_stream) != 0
+       || ready == 0) {
+       read_wait(plaintext_fd, TLSP_INIT_TIMEOUT);     /* XXX */
+       event_disable_readwrite(plaintext_fd);
+       tlsp_state_free(state);
+       return;
+    }
+
+    /*
+     * XXX We use the same fixed timeout throughout the entire session for
+     * both plaintext and ciphertext communication. This timeout is just a
+     * safety feature; the real timeout will be enforced by our plaintext
+     * peer.
+     */
+    else {
+       state->remote_endpt = mystrdup(STR(remote_endpt));
+       msg_info("CONNECT %s", state->remote_endpt);
+       state->timeout = timeout + 10;          /* XXX */
+       event_enable_read(plaintext_fd, tlsp_get_fd_event, (char *) state);
+       event_request_timer(tlsp_get_fd_event, (char *) state,
+                           TLSP_INIT_TIMEOUT);
+       return;
+    }
+}
+
+/* tlsp_service - handle new client connection */
+
+static void tlsp_service(VSTREAM *plaintext_stream,
+                                char *service,
+                                char **argv)
+{
+    TLSP_STATE *state;
+    int     plaintext_fd = vstream_fileno(plaintext_stream);
+
+    /*
+     * Sanity check. This service takes no command-line arguments.
+     */
+    if (argv[0])
+       msg_fatal("unexpected command-line argument: %s", argv[0]);
+
+    /*
+     * This program handles multiple connections, so it must not block. We
+     * use event-driven code for all operations that introduce latency.
+     */
+    non_blocking(plaintext_fd, NON_BLOCKING);
+    vstream_control(plaintext_stream,
+                   VSTREAM_CTL_PATH, "plaintext",
+                   VSTREAM_CTL_END);
+
+    /*
+     * Receive postscreen's remote SMTP client address/port and socket.
+     */
+    state = tlsp_state_create(service, plaintext_stream);
+    event_enable_read(plaintext_fd, tlsp_get_request_event, (char *) state);
+    event_request_timer(tlsp_get_request_event, (char *) state,
+                       TLSP_INIT_TIMEOUT);
+}
+
+/* pre_jail_init - pre-jail initialization */
+
+static void pre_jail_init(char *unused_name, char **unused_argv)
+{
+    TLS_SERVER_INIT_PROPS props;
+    const char *cert_file;
+    int     have_server_cert;
+    int     no_server_cert_ok;
+    int     require_server_cert;
+
+    /*
+     * The code in this routine is pasted literally from smtpd(8). I am not
+     * going to sanitize this because doing so surely will break things in
+     * unexpected ways.
+     * 
+     * Load TLS keys before dropping privileges.
+     * 
+     * Can't use anonymous ciphers if we want client certificates. Must use
+     * anonymous ciphers if we have no certificates.
+     */
+    ask_client_cert = require_server_cert =
+       (var_tlsp_tls_ask_ccert
+        || (enforce_tls && var_tlsp_tls_req_ccert));
+    if (strcasecmp(var_tlsp_tls_cert_file, "none") == 0) {
+       no_server_cert_ok = 1;
+       cert_file = "";
+    } else {
+       no_server_cert_ok = 0;
+       cert_file = var_tlsp_tls_cert_file;
+    }
+    have_server_cert =
+       (*cert_file || *var_tlsp_tls_dcert_file || *var_tlsp_tls_eccert_file);
+
+    /* Some TLS configuration errors are not show stoppers. */
+    if (!have_server_cert && require_server_cert)
+       msg_warn("Need a server cert to request client certs");
+    if (!enforce_tls && var_tlsp_tls_req_ccert)
+       msg_warn("Can't require client certs unless TLS is required");
+    /* After a show-stopper error, log a warning. */
+    if (have_server_cert || (no_server_cert_ok && !require_server_cert))
+
+       /*
+        * Large parameter lists are error-prone, so we emulate a language
+        * feature that C does not have natively: named parameter lists.
+        */
+       tlsp_server_ctx =
+           TLS_SERVER_INIT(&props,
+                           log_level = var_tlsp_tls_loglevel,
+                           verifydepth = var_tlsp_tls_ccert_vd,
+                           cache_type = TLS_MGR_SCACHE_SMTPD,
+                           scache_timeout = var_tlsp_tls_scache_timeout,
+                           set_sessid = var_tlsp_tls_set_sessid,
+                           cert_file = cert_file,
+                           key_file = var_tlsp_tls_key_file,
+                           dcert_file = var_tlsp_tls_dcert_file,
+                           dkey_file = var_tlsp_tls_dkey_file,
+                           eccert_file = var_tlsp_tls_eccert_file,
+                           eckey_file = var_tlsp_tls_eckey_file,
+                           CAfile = var_tlsp_tls_CAfile,
+                           CApath = var_tlsp_tls_CApath,
+                           dh1024_param_file
+                           = var_tlsp_tls_dh1024_param_file,
+                           dh512_param_file
+                           = var_tlsp_tls_dh512_param_file,
+                           eecdh_grade = var_tlsp_tls_eecdh,
+                           protocols = enforce_tls ?
+                           var_tlsp_tls_mand_proto :
+                           var_tlsp_tls_proto,
+                           ask_ccert = ask_client_cert,
+                           fpt_dgst = var_tlsp_tls_fpt_dgst);
+    else
+       msg_warn("No server certs available. TLS can't be enabled");
+
+    /*
+     * To maintain sanity, allow partial SSL_write() operations, and allow
+     * SSL_write() buffer pointers to change after a WANT_READ or WANT_WRITE
+     * result. This is based on OpenSSL developers talking on a mailing list,
+     * but is not supported by documentation. If this code stops working then
+     * no-one can be held responsible.
+     */
+    if (tlsp_server_ctx)
+       SSL_CTX_set_mode(tlsp_server_ctx->ssl_ctx,
+                        SSL_MODE_ENABLE_PARTIAL_WRITE
+                        | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+}
+
+/* post_jail_init - post-jail initialization */
+
+static void post_jail_init(char *unused_name, char **unused_argv)
+{
+     /* void */ ;
+}
+
+MAIL_VERSION_STAMP_DECLARE;
+
+/* main - the main program */
+
+int     main(int argc, char **argv)
+{
+    static const CONFIG_INT_TABLE int_table[] = {
+       VAR_SMTPD_TLS_CCERT_VD, DEF_SMTPD_TLS_CCERT_VD, &var_smtpd_tls_ccert_vd, 0, 0,
+       VAR_SMTPD_TLS_LOGLEVEL, DEF_SMTPD_TLS_LOGLEVEL, &var_smtpd_tls_loglevel, 0, 0,
+       0,
+    };
+    static const CONFIG_NINT_TABLE nint_table[] = {
+       VAR_TLSP_TLS_CCERT_VD, DEF_TLSP_TLS_CCERT_VD, &var_tlsp_tls_ccert_vd, 0, 0,
+       VAR_TLSP_TLS_LOGLEVEL, DEF_TLSP_TLS_LOGLEVEL, &var_tlsp_tls_loglevel, 0, 0,
+       0,
+    };
+    static const CONFIG_TIME_TABLE time_table[] = {
+       VAR_SMTPD_TLS_SCACHTIME, DEF_SMTPD_TLS_SCACHTIME, &var_smtpd_tls_scache_timeout, 0, 0,
+       VAR_TLSP_WATCHDOG, DEF_TLSP_WATCHDOG, &var_tlsp_watchdog, 10, 0,
+       VAR_TLSP_TLS_SCACHTIME, DEF_TLSP_TLS_SCACHTIME, &var_tlsp_tls_scache_timeout, 0, 0,
+       0,
+    };
+    static const CONFIG_BOOL_TABLE bool_table[] = {
+       VAR_SMTPD_USE_TLS, DEF_SMTPD_USE_TLS, &var_smtpd_use_tls,
+       VAR_SMTPD_ENFORCE_TLS, DEF_SMTPD_ENFORCE_TLS, &var_smtpd_enforce_tls,
+       VAR_SMTPD_TLS_ACERT, DEF_SMTPD_TLS_ACERT, &var_smtpd_tls_ask_ccert,
+       VAR_SMTPD_TLS_RCERT, DEF_SMTPD_TLS_RCERT, &var_smtpd_tls_req_ccert,
+       VAR_SMTPD_TLS_SET_SESSID, DEF_SMTPD_TLS_SET_SESSID, &var_smtpd_tls_set_sessid,
+       0,
+    };
+    static const CONFIG_NBOOL_TABLE nbool_table[] = {
+       VAR_TLSP_USE_TLS, DEF_TLSP_USE_TLS, &var_tlsp_use_tls,
+       VAR_TLSP_ENFORCE_TLS, DEF_TLSP_ENFORCE_TLS, &var_tlsp_enforce_tls,
+       VAR_TLSP_TLS_ACERT, DEF_TLSP_TLS_ACERT, &var_tlsp_tls_ask_ccert,
+       VAR_TLSP_TLS_RCERT, DEF_TLSP_TLS_RCERT, &var_tlsp_tls_req_ccert,
+       VAR_TLSP_TLS_SET_SESSID, DEF_TLSP_TLS_SET_SESSID, &var_tlsp_tls_set_sessid,
+       0,
+    };
+    static const CONFIG_STR_TABLE str_table[] = {
+       VAR_SMTPD_TLS_CERT_FILE, DEF_SMTPD_TLS_CERT_FILE, &var_smtpd_tls_cert_file, 0, 0,
+       VAR_SMTPD_TLS_KEY_FILE, DEF_SMTPD_TLS_KEY_FILE, &var_smtpd_tls_key_file, 0, 0,
+       VAR_SMTPD_TLS_DCERT_FILE, DEF_SMTPD_TLS_DCERT_FILE, &var_smtpd_tls_dcert_file, 0, 0,
+       VAR_SMTPD_TLS_DKEY_FILE, DEF_SMTPD_TLS_DKEY_FILE, &var_smtpd_tls_dkey_file, 0, 0,
+       VAR_SMTPD_TLS_ECCERT_FILE, DEF_SMTPD_TLS_ECCERT_FILE, &var_smtpd_tls_eccert_file, 0, 0,
+       VAR_SMTPD_TLS_ECKEY_FILE, DEF_SMTPD_TLS_ECKEY_FILE, &var_smtpd_tls_eckey_file, 0, 0,
+       VAR_SMTPD_TLS_CA_FILE, DEF_SMTPD_TLS_CA_FILE, &var_smtpd_tls_CAfile, 0, 0,
+       VAR_SMTPD_TLS_CA_PATH, DEF_SMTPD_TLS_CA_PATH, &var_smtpd_tls_CApath, 0, 0,
+       VAR_SMTPD_TLS_CIPH, DEF_SMTPD_TLS_CIPH, &var_smtpd_tls_ciph, 1, 0,
+       VAR_SMTPD_TLS_MAND_CIPH, DEF_SMTPD_TLS_MAND_CIPH, &var_smtpd_tls_mand_ciph, 1, 0,
+       VAR_SMTPD_TLS_EXCL_CIPH, DEF_SMTPD_TLS_EXCL_CIPH, &var_smtpd_tls_excl_ciph, 0, 0,
+       VAR_SMTPD_TLS_MAND_EXCL, DEF_SMTPD_TLS_MAND_EXCL, &var_smtpd_tls_mand_excl, 0, 0,
+       VAR_SMTPD_TLS_PROTO, DEF_SMTPD_TLS_PROTO, &var_smtpd_tls_proto, 0, 0,
+       VAR_SMTPD_TLS_MAND_PROTO, DEF_SMTPD_TLS_MAND_PROTO, &var_smtpd_tls_mand_proto, 0, 0,
+       VAR_SMTPD_TLS_512_FILE, DEF_SMTPD_TLS_512_FILE, &var_smtpd_tls_dh512_param_file, 0, 0,
+       VAR_SMTPD_TLS_1024_FILE, DEF_SMTPD_TLS_1024_FILE, &var_smtpd_tls_dh1024_param_file, 0, 0,
+       VAR_SMTPD_TLS_EECDH, DEF_SMTPD_TLS_EECDH, &var_smtpd_tls_eecdh, 1, 0,
+       VAR_SMTPD_TLS_FPT_DGST, DEF_SMTPD_TLS_FPT_DGST, &var_smtpd_tls_fpt_dgst, 1, 0,
+       VAR_SMTPD_TLS_LEVEL, DEF_SMTPD_TLS_LEVEL, &var_smtpd_tls_level, 0, 0,
+       VAR_TLSP_TLS_CERT_FILE, DEF_TLSP_TLS_CERT_FILE, &var_tlsp_tls_cert_file, 0, 0,
+       VAR_TLSP_TLS_KEY_FILE, DEF_TLSP_TLS_KEY_FILE, &var_tlsp_tls_key_file, 0, 0,
+       VAR_TLSP_TLS_DCERT_FILE, DEF_TLSP_TLS_DCERT_FILE, &var_tlsp_tls_dcert_file, 0, 0,
+       VAR_TLSP_TLS_DKEY_FILE, DEF_TLSP_TLS_DKEY_FILE, &var_tlsp_tls_dkey_file, 0, 0,
+       VAR_TLSP_TLS_ECCERT_FILE, DEF_TLSP_TLS_ECCERT_FILE, &var_tlsp_tls_eccert_file, 0, 0,
+       VAR_TLSP_TLS_ECKEY_FILE, DEF_TLSP_TLS_ECKEY_FILE, &var_tlsp_tls_eckey_file, 0, 0,
+       VAR_TLSP_TLS_CA_FILE, DEF_TLSP_TLS_CA_FILE, &var_tlsp_tls_CAfile, 0, 0,
+       VAR_TLSP_TLS_CA_PATH, DEF_TLSP_TLS_CA_PATH, &var_tlsp_tls_CApath, 0, 0,
+       VAR_TLSP_TLS_CIPH, DEF_TLSP_TLS_CIPH, &var_tlsp_tls_ciph, 1, 0,
+       VAR_TLSP_TLS_MAND_CIPH, DEF_TLSP_TLS_MAND_CIPH, &var_tlsp_tls_mand_ciph, 1, 0,
+       VAR_TLSP_TLS_EXCL_CIPH, DEF_TLSP_TLS_EXCL_CIPH, &var_tlsp_tls_excl_ciph, 0, 0,
+       VAR_TLSP_TLS_MAND_EXCL, DEF_TLSP_TLS_MAND_EXCL, &var_tlsp_tls_mand_excl, 0, 0,
+       VAR_TLSP_TLS_PROTO, DEF_TLSP_TLS_PROTO, &var_tlsp_tls_proto, 0, 0,
+       VAR_TLSP_TLS_MAND_PROTO, DEF_TLSP_TLS_MAND_PROTO, &var_tlsp_tls_mand_proto, 0, 0,
+       VAR_TLSP_TLS_512_FILE, DEF_TLSP_TLS_512_FILE, &var_tlsp_tls_dh512_param_file, 0, 0,
+       VAR_TLSP_TLS_1024_FILE, DEF_TLSP_TLS_1024_FILE, &var_tlsp_tls_dh1024_param_file, 0, 0,
+       VAR_TLSP_TLS_EECDH, DEF_TLSP_TLS_EECDH, &var_tlsp_tls_eecdh, 1, 0,
+       VAR_TLSP_TLS_FPT_DGST, DEF_TLSP_TLS_FPT_DGST, &var_tlsp_tls_fpt_dgst, 1, 0,
+       VAR_TLSP_TLS_LEVEL, DEF_TLSP_TLS_LEVEL, &var_tlsp_tls_level, 0, 0,
+       0,
+    };
+
+    /*
+     * Fingerprint executables and core dumps.
+     */
+    MAIL_VERSION_STAMP_ALLOCATE;
+
+    /*
+     * Pass control to the single-threaded service skeleton.
+     */
+    event_server_main(argc, argv, tlsp_service,
+                     MAIL_SERVER_INT_TABLE, int_table,
+                     MAIL_SERVER_NINT_TABLE, nint_table,
+                     MAIL_SERVER_STR_TABLE, str_table,
+                     MAIL_SERVER_BOOL_TABLE, bool_table,
+                     MAIL_SERVER_NBOOL_TABLE, nbool_table,
+                     MAIL_SERVER_TIME_TABLE, time_table,
+                     MAIL_SERVER_PRE_INIT, pre_jail_init,
+                     MAIL_SERVER_POST_INIT, post_jail_init,
+                     MAIL_SERVER_SLOW_EXIT, tlsp_drain,
+                     MAIL_SERVER_WATCHDOG, &var_tlsp_watchdog,
+                     0);
+}
+
+#else
+
+/* tlsp_service - respond to external trigger(s), non-TLS version */
+
+static void tlsp_service(VSTREAM *stream, char *unused_service,
+                                char **unused_argv)
+{
+    msg_info("TLS support is not compiled in -- exiting");
+    event_server_disconnect(stream);
+}
+
+/* main - the main program */
+
+int     main(int argc, char **argv)
+{
+
+    /*
+     * We can't simply use msg_fatal() here, because the logging hasn't been
+     * initialized. The text would disappear because stderr is redirected to
+     * /dev/null.
+     * 
+     * We invoke event_server_main() to complete program initialization
+     * (including logging) and then invoke the tlsp_service() routine to log
+     * the message that says why this program will not run.
+     */
+    multi_server_main(argc, argv, tlsp_service,
+                     0);
+}
+
+#endif
diff --git a/postfix/src/tlsproxy/tlsproxy.h b/postfix/src/tlsproxy/tlsproxy.h
new file mode 100644 (file)
index 0000000..e18e38a
--- /dev/null
@@ -0,0 +1,54 @@
+/*++
+/* NAME
+/*     tlsproxy 3h
+/* SUMMARY
+/*     tlsproxy internal interfaces
+/* SYNOPSIS
+/*     #include <tlsproxy.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <vstream.h>
+#include <nbbio.h>
+
+ /*
+  * TLS library.
+  */
+#include <tls.h>
+
+ /*
+  * Internal interface.
+  */
+typedef struct {
+    int     flags;                     /* see below */
+    char   *service;                   /* argv[0] */
+    VSTREAM *plaintext_stream;         /* local peer: postscreen(8), etc. */
+    NBBIO  *plaintext_buf;             /* plaintext buffer */
+    int     ciphertext_fd;             /* remote peer */
+    EVENT_NOTIFY_FN ciphertext_timer;  /* kludge */
+    int     timeout;                   /* read/write time limit */
+    char   *remote_endpt;              /* printable remote endpoint */
+    TLS_SESS_STATE *tls_context;       /* llibtls state */
+    int     ssl_last_err;              /* TLS I/O state */
+    int     tls_use_tls;               /* legacy libtls API */
+    int     tls_enforce_tls;           /* legacy libtls API */
+} TLSP_STATE;
+
+#define TLSP_FLAG_DO_HANDSHAKE (1<<0)
+
+extern TLSP_STATE *tlsp_state_create(const char *, VSTREAM *);
+extern void tlsp_state_free(TLSP_STATE *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
diff --git a/postfix/src/tlsproxy/tlsproxy_state.c b/postfix/src/tlsproxy/tlsproxy_state.c
new file mode 100644 (file)
index 0000000..8924a99
--- /dev/null
@@ -0,0 +1,134 @@
+/*++
+/* NAME
+/*     tlsp_state 3
+/* SUMMARY
+/*     Postfix SMTP server
+/* SYNOPSIS
+/*     #include <tlsproxy.h>
+/*
+/*     TLSP_STATE *tlsp_state_create(service, plaintext_stream)
+/*     const char *service;
+/*     VSTREAM *plaintext_stream;
+/*
+/*     void    tlsp_state_free(state)
+/*     TLSP_STATE *state;
+/* DESCRIPTION
+/*     This module provides TLSP_STATE constructor and destructor
+/*     routines.
+/*
+/*     tlsp_state_create() initializes session context.
+/*
+/*     tlsp_state_free() destroys session context.
+/*
+/*     Arguments:
+/* .IP service
+/*     The service name for the TLS library. This argument is copied.
+/*     The destructor will automatically destroy the string.
+/* .IP plaintext_stream
+/*     The VSTREAM between postscreen(8) and tlsproxy(8).
+/*     The destructor will automatically close the stream.
+/* .PP
+/*     Other structure members are set by the application. The
+/*     text below describes how the TLSP_STATE destructor
+/*     disposes of them.
+/* .IP plaintext_buf
+/*     NBBIO for plaintext I/O.
+/*     The destructor will automatically turn off read/write/timeout
+/*     events and destroy the NBBIO.
+/* .IP ciphertext_fd
+/*     The file handle for the remote SMTP client socket.
+/*     The destructor will automatically turn off read/write events
+/*     and close the file handle.
+/* .IP ciphertext_timer
+/*     The destructor will automatically turn off this time event.
+/* .IP timeout
+/*     Time limit for plaintext and ciphertext I/O.
+/* .IP remote_endpt
+/*     Printable remote endpoint name.
+/*     The destructor will automatically destroy the string.
+/* DIAGNOSTICS
+/*     All errors are fatal.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+ /*
+  * System library.
+  */
+#include <sys_defs.h>
+
+ /*
+  * Utility library.
+  */
+#include <msg.h>
+#include <mymalloc.h>
+#include <nbbio.h>
+
+ /*
+  * Master library.
+  */
+#include <mail_server.h>
+
+ /*
+  * TLS library.
+  */
+#ifdef USE_TLS
+#define TLS_INTERNAL                   /* XXX */
+#include <tls.h>
+
+ /*
+  * Application-specific.
+  */
+#include <tlsproxy.h>
+
+/* tlsp_state_create - create TLS proxy state object */
+
+TLSP_STATE *tlsp_state_create(const char *service,
+                                     VSTREAM *plaintext_stream)
+{
+    TLSP_STATE *state = (TLSP_STATE *) mymalloc(sizeof(*state));
+
+    state->flags = TLSP_FLAG_DO_HANDSHAKE;
+    state->service = mystrdup(service);
+    state->plaintext_stream = plaintext_stream;
+    state->plaintext_buf = 0;
+    state->ciphertext_fd = -1;
+    state->ciphertext_timer = 0;
+    state->timeout = -1;
+    state->remote_endpt = 0;
+    state->tls_context = 0;
+
+    return (state);
+}
+
+/* tlsp_state_free - destroy state objects, connection and events */
+
+void    tlsp_state_free(TLSP_STATE *state)
+{
+    myfree(state->service);
+    if (state->plaintext_buf)                  /* turns off plaintext events */
+       nbbio_free(state->plaintext_buf);
+    event_server_disconnect(state->plaintext_stream);
+    if (state->ciphertext_fd >= 0) {
+       event_disable_readwrite(state->ciphertext_fd);
+       (void) close(state->ciphertext_fd);
+    }
+    if (state->ciphertext_timer)
+       event_cancel_timer(state->ciphertext_timer, (char *) state);
+    if (state->remote_endpt) {
+       msg_info("DISCONNECT %s", state->remote_endpt);
+       myfree(state->remote_endpt);
+    }
+    if (state->tls_context)
+       tls_free_context(state->tls_context);
+    myfree((char *) state);
+}
+
+#endif
index 69c6698125f74361d1fbf95ff42bdf12fa7ca803..8fefcf18116f21808bdb91fa28adcaf116a1b6ec 100644 (file)
@@ -33,7 +33,7 @@ SRCS  = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
        allascii.c load_file.c killme_after.c vstream_tweak.c upass_connect.c \
        upass_listen.c upass_trigger.c edit_file.c inet_windowsize.c \
        unix_pass_fd_fix.c dict_cache.c valid_utf_8.c dict_thash.c \
-       ip_match.c
+       ip_match.c nbbio.c
 OBJS   = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
        attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
@@ -68,7 +68,7 @@ OBJS  = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        allascii.o load_file.o killme_after.o vstream_tweak.o upass_connect.o \
        upass_listen.o upass_trigger.o edit_file.o inet_windowsize.o \
        unix_pass_fd_fix.o dict_cache.o valid_utf_8.o dict_thash.o \
-       ip_match.o
+       ip_match.o nbbio.o
 HDRS   = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
        chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
        dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
@@ -89,9 +89,9 @@ HDRS  = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
        username.h valid_hostname.h vbuf.h vbuf_print.h vstream.h vstring.h \
        vstring_vstream.h watchdog.h format_tv.h load_file.h killme_after.h \
        edit_file.h dict_cache.h dict_thash.h \
-       ip_match.h
+       ip_match.h nbbio.h
 TESTSRC        = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
-       stream_test.c dup2_pass_on_exec.c test_send_fd test_recv_fd
+       stream_test.c dup2_pass_on_exec.c
 DEFS   = -I. -D$(SYSTYPE)
 CFLAGS = $(DEBUG) $(OPT) $(DEFS)
 FILES  = Makefile $(SRCS) $(HDRS)
@@ -107,7 +107,7 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
        attr_scan0 host_port attr_scan_plain attr_print_plain htable \
        unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd hex_code \
        myaddrinfo myaddrinfo4 inet_proto sane_basename format_tv \
-       test_send_fd test_recv_fd valid_utf_8 ip_match
+       valid_utf_8 ip_match
 
 LIB_DIR        = ../../lib
 INC_DIR        = ../../include
@@ -431,7 +431,7 @@ tests: valid_hostname_test mac_expand_test dict_test unescape_test \
        hex_quote_test ctable_test inet_addr_list_test base64_code_test \
        attr_scan64_test attr_scan0_test dict_pcre_test host_port_test \
        dict_cidr_test attr_scan_plain_test htable_test hex_code_test \
-       myaddrinfo_test format_tv_test ip_match_test
+       myaddrinfo_test format_tv_test ip_match_test name_mask_tests
 
 root_tests:
 
@@ -558,6 +558,60 @@ ip_match_test: ip_match ip_match.in ip_match.ref
        diff ip_match.ref ip_match.tmp
        rm -f ip_match.tmp
 
+name_mask_tests: name_mask_test0 name_mask_test1 name_mask_test2 \
+       name_mask_test3 name_mask_test4 name_mask_test5 name_mask_test6 \
+       name_mask_test7 name_mask_test8 name_mask_test9
+
+name_mask_test0: name_mask name_mask.in name_mask.ref0
+       ./name_mask IGNORE IGNORE < name_mask.in > name_mask.tmp 2>&0
+       diff name_mask.ref0 name_mask.tmp
+       rm -f name_mask.tmp
+
+name_mask_test1: name_mask name_mask.in name_mask.ref1
+       ./name_mask NUMBER,WARN NUMBER < name_mask.in > name_mask.tmp 2>&1
+       diff name_mask.ref1 name_mask.tmp
+       rm -f name_mask.tmp
+
+name_mask_test2: name_mask name_mask.in name_mask.ref2
+       ./name_mask NUMBER,RETURN NUMBER < name_mask.in > name_mask.tmp 2>&1
+       diff name_mask.ref2 name_mask.tmp
+       rm -f name_mask.tmp
+
+name_mask_test3: name_mask name_mask.in name_mask.ref3
+       ./name_mask WARN NUMBER < name_mask.in > name_mask.tmp 2>&1
+       diff name_mask.ref3 name_mask.tmp
+       rm -f name_mask.tmp
+
+name_mask_test4: name_mask name_mask.in name_mask.ref4
+       ./name_mask RETURN NUMBER < name_mask.in > name_mask.tmp 2>&1
+       diff name_mask.ref4 name_mask.tmp
+       rm -f name_mask.tmp
+
+name_mask_test5: name_mask name_mask.in name_mask.ref5
+       ./name_mask NUMBER,WARN RETURN < name_mask.in > name_mask.tmp 2>&1
+       diff name_mask.ref5 name_mask.tmp
+       rm -f name_mask.tmp
+
+name_mask_test6: name_mask name_mask.in name_mask.ref6
+       ./name_mask NUMBER,WARN WARN < name_mask.in > name_mask.tmp 2>&1
+       diff name_mask.ref6 name_mask.tmp
+       rm -f name_mask.tmp
+
+name_mask_test7: name_mask name_mask.in name_mask.ref7
+       ./name_mask NUMBER,WARN IGNORE < name_mask.in > name_mask.tmp 2>&1
+       diff name_mask.ref7 name_mask.tmp
+       rm -f name_mask.tmp
+
+name_mask_test8: name_mask name_mask.in name_mask.ref8
+       ./name_mask NUMBER,WARN NUMBER,COMMA < name_mask.in > name_mask.tmp 2>&1
+       diff name_mask.ref8 name_mask.tmp
+       rm -f name_mask.tmp
+
+name_mask_test9: name_mask name_mask.in name_mask.ref9
+       ./name_mask NUMBER,WARN NUMBER,PIPE < name_mask.in > name_mask.tmp 2>&1
+       diff name_mask.ref9 name_mask.tmp
+       rm -f name_mask.tmp
+
 depend: $(MAKES)
        (sed '1,/^# do not edit/!d' Makefile.in; \
        set -e; for i in [a-z][a-z0-9]*.c; do \
@@ -1352,6 +1406,12 @@ name_mask.o: stringops.h
 name_mask.o: sys_defs.h
 name_mask.o: vbuf.h
 name_mask.o: vstring.h
+nbbio.o: events.h
+nbbio.o: msg.h
+nbbio.o: mymalloc.h
+nbbio.o: nbbio.c
+nbbio.o: nbbio.h
+nbbio.o: sys_defs.h
 netstring.o: msg.h
 netstring.o: netstring.c
 netstring.o: netstring.h
index dfa1e3f6b6b033890c545be013c9517bf41474bd..142a7b6eb650b4aeb51073372174f554382c3857 100644 (file)
  /*
   * External interface.
   */
-typedef void (*EVENT_NOTIFY_RDWR_FN) (int, char *);
-typedef void (*EVENT_NOTIFY_TIME_FN) (int, char *);
+typedef void (*EVENT_NOTIFY_FN) (int, char *);
+
+#define EVENT_NOTIFY_TIME_FN EVENT_NOTIFY_FN   /* legacy */
+#define EVENT_NOTIFY_RDWR_FN EVENT_NOTIFY_FN   /* legacy */
 
 extern time_t event_time(void);
 extern void event_enable_read(int, EVENT_NOTIFY_RDWR_FN, char *);
index cf96d24811fdb0801f3564256589ebcbac8c3732..79b244cbf9e13bfeec1da8879438f9dfa591a515 100644 (file)
@@ -37,6 +37,7 @@
 #include <sys/stat.h>
 #include <errno.h>
 #include <string.h>
+#include <unistd.h>
 
 /* Utility library. */
 
index 7923710cc33ed268525d7909f7c8d552360a1725..6d11dd3ef20578b8d2d3259942428a94702202fa 100644 (file)
 /*     const NAME_MASK *table;
 /*     const char *names;
 /*
+/*     long    long_name_mask(context, table, names)
+/*     const char *context;
+/*     const LONG_NAME_MASK *table;
+/*     const char *names;
+/*
 /*     const char *str_name_mask(context, table, mask)
 /*     const char *context;
 /*     const NAME_MASK *table;
 /*     int     mask;
 /*
+/*     const char *str_long_name_mask(context, table, mask)
+/*     const char *context;
+/*     const LONG_NAME_MASK *table;
+/*     long    mask;
+/*
 /*     int     name_mask_opt(context, table, names, flags)
 /*     const char *context;
 /*     const NAME_MASK *table;
 /*     const char *names;
 /*     int     flags;
 /*
+/*     long    long_name_mask_opt(context, table, names, flags)
+/*     const char *context;
+/*     const LONG_NAME_MASK *table;
+/*     const char *names;
+/*     int     flags;
+/*
 /*     int     name_mask_delim_opt(context, table, names, delim, flags)
 /*     const char *context;
 /*     const NAME_MASK *table;
 /*     const char *delim;
 /*     int     flags;
 /*
+/*     long    long_name_mask_delim_opt(context, table, names, delim, flags)
+/*     const char *context;
+/*     const LONG_NAME_MASK *table;
+/*     const char *names;
+/*     const char *delim;
+/*     int     flags;
+/*
 /*     const char *str_name_mask_opt(buf, context, table, mask, flags)
 /*     VSTRING *buf;
 /*     const char *context;
 /*     const NAME_MASK *table;
 /*     int     mask;
 /*     int     flags;
+/*
+/*     const char *str_long_name_mask_opt(buf, context, table, mask, flags)
+/*     VSTRING *buf;
+/*     const char *context;
+/*     const LONG_NAME_MASK *table;
+/*     long    mask;
+/*     int     flags;
 /* DESCRIPTION
 /*     name_mask() takes a null-terminated \fItable\fR with (name, mask)
 /*     values and computes the bit-wise OR of the masks that correspond
 /*     to the names listed in the \fInames\fR argument, separated by
-/*     comma and/or whitespace characters.
+/*     comma and/or whitespace characters. The "long_" version returns
+/*     a "long int" bitmask, rather than an "int" bitmask.
 /*
-/*     str_name_mask() translates a mask into its equivalent names.
+/*     str_name_mask() translates a mask into its equlvalent names.
 /*     The result is written to a static buffer that is overwritten
-/*     upon each call.
+/*     upon each call. The "long_" version converts a "long int"
+/*     bitmask, rather than an "int" bitmask.
 /*
 /*     name_mask_opt() and str_name_mask_opt() are extended versions
 /*     with additional fine control. name_mask_delim_opt() supports
 /*     A list of names that is to be converted into a bit mask.
 /* .IP mask
 /*     A bit mask.
-/* .IP flags
-/*     Bit-wise OR of zero or more of the following:
 /* .IP delim
 /*     Delimiter characters to use instead of whitespace and commas.
+/* .IP flags
+/*     Bit-wise OR of one or more of the following.  Where features
+/*     would have conflicting results (e.g., FATAL versus IGNORE),
+/*     the feature that takes precedence is described first.
+/*
+/*     When converting from string to mask, at least one of the
+/*     following must be specified: NAME_MASK_FATAL, NAME_MASK_RETURN,
+/*     NAME_MASK_WARN or NAME_MASK_IGNORE.
+/*
+/*     When converting from mask to string, at least one of the
+/*     following must be specified: NAME_MASK_NUMBER, NAME_MASK_FATAL,
+/*     NAME_MASK_RETURN, NAME_MASK_WARN or NAME_MASK_IGNORE.
 /* .RS
+/* .IP NAME_MASK_NUMBER
+/*     When converting from string to mask, accept hexadecimal
+/*     inputs starting with "0x" followed by hexadecimal digits.
+/*     Each hexadecimal input may specify multiple bits.  This
+/*     feature is ignored for hexadecimal inputs that cannot be
+/*     converted (malformed, out of range, etc.).
+/*
+/*     When converting from mask to string, represent bits not
+/*     defined in \fItable\fR as "0x" followed by hexadecimal
+/*     digits. This conversion always succeeds.
 /* .IP NAME_MASK_FATAL
-/*     Require that all names listed in \fIname\fR exist in \fItable\fR,
-/*     and that all bits listed in \fImask\fR exist in \fItable\fR.
-/*     Terminate with a fatal run-time error if this condition is not met.
-/*     This feature is enabled by default when calling name_mask()
-/*     or str_name_mask().
+/*     Require that all names listed in \fIname\fR exist in
+/*     \fItable\fR or that they can be parsed as a hexadecimal
+/*     string, and require that all bits listed in \fImask\fR exist
+/*     in \fItable\fR or that they can be converted to hexadecimal
+/*     string.  Terminate with a fatal run-time error if this
+/*     condition is not met.  This feature is enabled by default
+/*     when calling name_mask() or str_name_mask().
 /* .IP NAME_MASK_RETURN
-/*     Require that all names listed in \fIname\fR exist in \fItable\fR,
-/*     and that all bits listed in \fImask\fR exist in \fItable\fR.
-/*     Log a warning, and return 0 (name_mask()) or a null pointer
-/*     (str_name_mask()) if this condition is not met.
-/* .IP NAME_MASK_NUMBER
-/*     Require that all bits listed in \fImask\fR exist in \fItable\fR.
-/*     For unrecognized bits, print the numerical hexadecimal form.
+/*     Require that all names listed in \fIname\fR exist in
+/*     \fItable\fR or that they can be parsed as a hexadecimal
+/*     string, and require that all bits listed in \fImask\fR exist
+/*     in \fItable\fR or that they can be converted to hexadecimal
+/*     string.  Log a warning, and return 0 (name_mask()) or a
+/*     null pointer (str_name_mask()) if this condition is not
+/*     met.  This feature is not enabled by default when calling
+/*     name_mask() or str_name_mask().
+/* .IP NAME_MASK_WARN
+/*     Require that all names listed in \fIname\fR exist in
+/*     \fItable\fR or that they can be parsed as a hexadecimal
+/*     string, and require that all bits listed in \fImask\fR exist
+/*     in \fItable\fR or that they can be converted to hexadecimal
+/*     string.  Log a warning if this condition is not met, continue
+/*     processing, and return all valid bits or names.  This feature
+/*     is not enabled by default when calling name_mask() or
+/*     str_name_mask().
+/* .IP NAME_MASK_IGNORE
+/*     Silently ignore names listed in \fIname\fR that don't exist
+/*     in \fItable\fR and that can't be parsed as a hexadecimal
+/*     string, and silently ignore bits listed in \fImask\fR that
+/*     don't exist in \fItable\fR and that can't be converted to
+/*     hexadecimal string.
 /* .IP NAME_MASK_ANY_CASE
 /*     Enable case-insensitive matching.
 /*     This feature is not enabled by default when calling name_mask();
 
 #include <sys_defs.h>
 #include <string.h>
+#include <errno.h>
+#include <stdlib.h>
 
 #ifdef STRCASECMP_IN_STRINGS_H
 #include <strings.h>
 #include <name_mask.h>
 #include <vstring.h>
 
+static int hex_to_ulong(char *, unsigned long, unsigned long *);
+
 #define STR(x) vstring_str(x)
 
 /* name_mask_delim_opt - compute mask corresponding to list of names */
@@ -139,6 +213,11 @@ int     name_mask_delim_opt(const char *context, const NAME_MASK *table,
     const NAME_MASK *np;
     char   *name;
     int     (*lookup) (const char *, const char *);
+    unsigned long ulval;
+
+    if ((flags & NAME_MASK_REQUIRED) == 0)
+       msg_panic("%s: missing NAME_MASK_FATAL/RETURN/WARN/IGNORE flag",
+                 myname);
 
     if (flags & NAME_MASK_ANY_CASE)
        lookup = strcasecmp;
@@ -152,13 +231,19 @@ int     name_mask_delim_opt(const char *context, const NAME_MASK *table,
     while ((name = mystrtok(&bp, delim)) != 0) {
        for (np = table; /* void */ ; np++) {
            if (np->name == 0) {
-               if (flags & NAME_MASK_FATAL)
+               if ((flags & NAME_MASK_NUMBER)
+                   && hex_to_ulong(name, ~0U, &ulval)) {
+                   result |= (unsigned int) ulval;
+               } else if (flags & NAME_MASK_FATAL) {
                    msg_fatal("unknown %s value \"%s\" in \"%s\"",
                              context, name, names);
-               if (flags & NAME_MASK_RETURN) {
+               } else if (flags & NAME_MASK_RETURN) {
                    msg_warn("unknown %s value \"%s\" in \"%s\"",
                             context, name, names);
                    return (0);
+               } else if (flags & NAME_MASK_WARN) {
+                   msg_warn("unknown %s value \"%s\" in \"%s\"",
+                            context, name, names);
                }
                break;
            }
@@ -187,6 +272,10 @@ const char *str_name_mask_opt(VSTRING *buf, const char *context,
     int     delim = (flags & NAME_MASK_COMMA ? ',' :
                     (flags & NAME_MASK_PIPE ? '|' : ' '));
 
+    if ((flags & STR_NAME_MASK_REQUIRED) == 0)
+       msg_panic("%s: missing NAME_MASK_NUMBER/FATAL/RETURN/WARN/IGNORE flag",
+                 myname);
+
     if (buf == 0) {
        if (my_buf == 0)
            my_buf = vstring_alloc(1);
@@ -196,15 +285,18 @@ const char *str_name_mask_opt(VSTRING *buf, const char *context,
 
     for (np = table; mask != 0; np++) {
        if (np->name == 0) {
-           if (flags & NAME_MASK_FATAL) {
+           if (flags & NAME_MASK_NUMBER) {
+               vstring_sprintf_append(buf, "0x%x%c", mask, delim);
+           } else if (flags & NAME_MASK_FATAL) {
                msg_fatal("%s: unknown %s bit in mask: 0x%x",
                          myname, context, mask);
            } else if (flags & NAME_MASK_RETURN) {
                msg_warn("%s: unknown %s bit in mask: 0x%x",
                         myname, context, mask);
                return (0);
-           } else if (flags & NAME_MASK_NUMBER) {
-               vstring_sprintf_append(buf, "0x%x%c", mask, delim);
+           } else if (flags & NAME_MASK_WARN) {
+               msg_warn("%s: unknown %s bit in mask: 0x%x",
+                        myname, context, mask);
            }
            break;
        }
@@ -220,6 +312,145 @@ const char *str_name_mask_opt(VSTRING *buf, const char *context,
     return (STR(buf));
 }
 
+/* long_name_mask_delim_opt - compute mask corresponding to list of names */
+
+long    long_name_mask_delim_opt(const char *context,
+                                        const LONG_NAME_MASK * table,
+                                      const char *names, const char *delim,
+                                        int flags)
+{
+    const char *myname = "name_mask";
+    char   *saved_names = mystrdup(names);
+    char   *bp = saved_names;
+    long    result = 0;
+    const LONG_NAME_MASK *np;
+    char   *name;
+    int     (*lookup) (const char *, const char *);
+    unsigned long ulval;
+
+    if ((flags & NAME_MASK_REQUIRED) == 0)
+       msg_panic("%s: missing NAME_MASK_FATAL/RETURN/WARN/IGNORE flag",
+                 myname);
+
+    if (flags & NAME_MASK_ANY_CASE)
+       lookup = strcasecmp;
+    else
+       lookup = strcmp;
+
+    /*
+     * Break up the names string, and look up each component in the table. If
+     * the name is found, merge its mask with the result.
+     */
+    while ((name = mystrtok(&bp, delim)) != 0) {
+       for (np = table; /* void */ ; np++) {
+           if (np->name == 0) {
+               if ((flags & NAME_MASK_NUMBER)
+                   && hex_to_ulong(name, ~0UL, &ulval)) {
+                   result |= ulval;
+               } else if (flags & NAME_MASK_FATAL) {
+                   msg_fatal("unknown %s value \"%s\" in \"%s\"",
+                             context, name, names);
+               } else if (flags & NAME_MASK_RETURN) {
+                   msg_warn("unknown %s value \"%s\" in \"%s\"",
+                            context, name, names);
+                   return (0);
+               } else if (flags & NAME_MASK_WARN) {
+                   msg_warn("unknown %s value \"%s\" in \"%s\"",
+                            context, name, names);
+               }
+               break;
+           }
+           if (lookup(name, np->name) == 0) {
+               if (msg_verbose)
+                   msg_info("%s: %s", myname, name);
+               result |= np->mask;
+               break;
+           }
+       }
+    }
+
+    myfree(saved_names);
+    return (result);
+}
+
+/* str_long_name_mask_opt - mask to string */
+
+const char *str_long_name_mask_opt(VSTRING *buf, const char *context,
+                                          const LONG_NAME_MASK * table,
+                                          long mask, int flags)
+{
+    const char *myname = "name_mask";
+    int     len;
+    static VSTRING *my_buf = 0;
+    int     delim = (flags & NAME_MASK_COMMA ? ',' :
+                    (flags & NAME_MASK_PIPE ? '|' : ' '));
+    const LONG_NAME_MASK *np;
+
+    if ((flags & STR_NAME_MASK_REQUIRED) == 0)
+       msg_panic("%s: missing NAME_MASK_NUMBER/FATAL/RETURN/WARN/IGNORE flag",
+                 myname);
+
+    if (buf == 0) {
+       if (my_buf == 0)
+           my_buf = vstring_alloc(1);
+       buf = my_buf;
+    }
+    VSTRING_RESET(buf);
+
+    for (np = table; mask != 0; np++) {
+       if (np->name == 0) {
+           if (flags & NAME_MASK_NUMBER) {
+               vstring_sprintf_append(buf, "0x%lx%c", mask, delim);
+           } else if (flags & NAME_MASK_FATAL) {
+               msg_fatal("%s: unknown %s bit in mask: 0x%lx",
+                         myname, context, mask);
+           } else if (flags & NAME_MASK_RETURN) {
+               msg_warn("%s: unknown %s bit in mask: 0x%lx",
+                        myname, context, mask);
+               return (0);
+           } else if (flags & NAME_MASK_WARN) {
+               msg_warn("%s: unknown %s bit in mask: 0x%lx",
+                        myname, context, mask);
+           }
+           break;
+       }
+       if (mask & np->mask) {
+           mask &= ~np->mask;
+           vstring_sprintf_append(buf, "%s%c", np->name, delim);
+       }
+    }
+    if ((len = VSTRING_LEN(buf)) > 0)
+       vstring_truncate(buf, len - 1);
+    VSTRING_TERMINATE(buf);
+
+    return (STR(buf));
+}
+
+/* hex_to_ulong - 0x... to unsigned long or smaller */
+
+static int hex_to_ulong(char *value, unsigned long mask, unsigned long *ulp)
+{
+    unsigned long result;
+    char   *cp;
+
+    if (strncasecmp(value, "0x", 2) != 0)
+       return (0);
+
+    /*
+     * Check for valid hex number. Since the value starts with 0x, strtoul()
+     * will not allow a negative sign before the first nibble. So we don't
+     * need to worry about explicit +/- signs.
+     */
+    errno = 0;
+    result = strtoul(value, &cp, 16);
+    if (*cp != '\0' || errno == ERANGE)
+       return (0);
+
+    if (ulp)
+       *ulp = (result & mask);
+    return (*ulp == result);
+}
+
 #ifdef TEST
 
  /*
@@ -227,26 +458,52 @@ const char *str_name_mask_opt(VSTRING *buf, const char *context,
   */
 #include <stdlib.h>
 #include <vstream.h>
+#include <vstring_vstream.h>
 
 int     main(int argc, char **argv)
 {
-    static const NAME_MASK table[] = {
+    static const NAME_MASK demo_table[] = {
        "zero", 1 << 0,
        "one", 1 << 1,
        "two", 1 << 2,
        "three", 1 << 3,
        0, 0,
     };
-    int     mask;
-    VSTRING *buf = vstring_alloc(1);
+    static const NAME_MASK feature_table[] = {
+       "DEFAULT", NAME_MASK_DEFAULT,
+       "FATAL", NAME_MASK_FATAL,
+       "ANY_CASE", NAME_MASK_ANY_CASE,
+       "RETURN", NAME_MASK_RETURN,
+       "COMMA", NAME_MASK_COMMA,
+       "PIPE", NAME_MASK_PIPE,
+       "NUMBER", NAME_MASK_NUMBER,
+       "WARN", NAME_MASK_WARN,
+       "IGNORE", NAME_MASK_IGNORE,
+       0,
+    };
+    int     in_feature_mask;
+    int     out_feature_mask;
+    int     demo_mask;
+    const char *demo_str;
+    VSTRING *out_buf = vstring_alloc(1);
+    VSTRING *in_buf = vstring_alloc(1);
 
-    while (--argc && *++argv) {
-       mask = name_mask("test", table, *argv);
+    if (argc != 3)
+       msg_fatal("usage: %s in-feature-mask out-feature-mask", argv[0]);
+    in_feature_mask = name_mask(argv[1], feature_table, argv[1]);
+    out_feature_mask = name_mask(argv[2], feature_table, argv[2]);
+    while (vstring_get_nonl(in_buf, VSTREAM_IN) != VSTREAM_EOF) {
+       demo_mask = name_mask_opt("name", demo_table,
+                                 STR(in_buf), in_feature_mask);
+       demo_str = str_name_mask_opt(out_buf, "mask", demo_table,
+                                    demo_mask, out_feature_mask);
        vstream_printf("%s -> 0x%x -> %s\n",
-                      *argv, mask, str_name_mask("mask_test", table, mask));
+                      STR(in_buf), demo_mask,
+                      demo_str ? demo_str : "(null)");
        vstream_fflush(VSTREAM_OUT);
     }
-    vstring_free(buf);
+    vstring_free(in_buf);
+    vstring_free(out_buf);
     exit(0);
 }
 
index 91df83f79b37368e77615a8a5487bd4d9a030733..05e45ec38ba93fb7830a19b7d3931a56ee7ca468 100644 (file)
@@ -30,6 +30,12 @@ typedef struct {
 #define NAME_MASK_COMMA                (1<<3)
 #define NAME_MASK_PIPE         (1<<4)
 #define NAME_MASK_NUMBER       (1<<5)
+#define NAME_MASK_WARN         (1<<6)
+#define NAME_MASK_IGNORE       (1<<7)
+
+#define NAME_MASK_REQUIRED \
+    (NAME_MASK_FATAL | NAME_MASK_RETURN | NAME_MASK_WARN | NAME_MASK_IGNORE)
+#define STR_NAME_MASK_REQUIRED (NAME_MASK_REQUIRED | NAME_MASK_NUMBER)
 
 #define NAME_MASK_MATCH_REQ    NAME_MASK_FATAL
 
@@ -48,6 +54,24 @@ typedef struct {
 extern int name_mask_delim_opt(const char *, const NAME_MASK *, const char *, const char *, int);
 extern const char *str_name_mask_opt(VSTRING *, const char *, const NAME_MASK *, int, int);
 
+ /*
+  * "long" API
+  */
+typedef struct {
+    const char *name;
+    long    mask;
+} LONG_NAME_MASK;
+
+#define long_name_mask_opt(tag, table, str, flags) \
+       long_name_mask_delim_opt((tag), (table), (str), NAME_MASK_DEFAULT_DELIM, (flags))
+#define long_name_mask(tag, table, str) \
+       long_name_mask_opt((tag), (table), (str), NAME_MASK_DEFAULT)
+#define str_long_name_mask(tag, table, mask) \
+       str_long_name_mask_opt(((VSTRING *) 0), (tag), (table), (mask), NAME_MASK_DEFAULT)
+
+extern long long_name_mask_delim_opt(const char *, const LONG_NAME_MASK *, const char *, const char *, int);
+extern const char *str_long_name_mask_opt(VSTRING *, const char *, const LONG_NAME_MASK *, long, int);
+
 /* LICENSE
 /* .ad
 /* .fi
diff --git a/postfix/src/util/name_mask.in b/postfix/src/util/name_mask.in
new file mode 100644 (file)
index 0000000..d4c9b16
--- /dev/null
@@ -0,0 +1,9 @@
+zero
+one
+two
+three
+four
+zero one two three four
+0xff
+0xffffffff
+0xffffffffffffffff
diff --git a/postfix/src/util/name_mask.ref0 b/postfix/src/util/name_mask.ref0
new file mode 100644 (file)
index 0000000..603dc26
--- /dev/null
@@ -0,0 +1,9 @@
+zero -> 0x1 -> zero
+one -> 0x2 -> one
+two -> 0x4 -> two
+three -> 0x8 -> three
+four -> 0x0 -> 
+zero one two three four -> 0xf -> zero one two three
+0xff -> 0x0 -> 
+0xffffffff -> 0x0 -> 
+0xffffffffffffffff -> 0x0 -> 
diff --git a/postfix/src/util/name_mask.ref1 b/postfix/src/util/name_mask.ref1
new file mode 100644 (file)
index 0000000..1ae0fca
--- /dev/null
@@ -0,0 +1,12 @@
+zero -> 0x1 -> zero
+one -> 0x2 -> one
+two -> 0x4 -> two
+three -> 0x8 -> three
+unknown: warning: unknown name value "four" in "four"
+four -> 0x0 -> 
+unknown: warning: unknown name value "four" in "zero one two three four"
+zero one two three four -> 0xf -> zero one two three
+0xff -> 0xff -> zero one two three 0xf0
+0xffffffff -> 0xffffffff -> zero one two three 0xfffffff0
+unknown: warning: unknown name value "0xffffffffffffffff" in "0xffffffffffffffff"
+0xffffffffffffffff -> 0x0 -> 
diff --git a/postfix/src/util/name_mask.ref2 b/postfix/src/util/name_mask.ref2
new file mode 100644 (file)
index 0000000..1ac716a
--- /dev/null
@@ -0,0 +1,12 @@
+zero -> 0x1 -> zero
+one -> 0x2 -> one
+two -> 0x4 -> two
+three -> 0x8 -> three
+unknown: warning: unknown name value "four" in "four"
+four -> 0x0 -> 
+unknown: warning: unknown name value "four" in "zero one two three four"
+zero one two three four -> 0x0 -> 
+0xff -> 0xff -> zero one two three 0xf0
+0xffffffff -> 0xffffffff -> zero one two three 0xfffffff0
+unknown: warning: unknown name value "0xffffffffffffffff" in "0xffffffffffffffff"
+0xffffffffffffffff -> 0x0 -> 
diff --git a/postfix/src/util/name_mask.ref3 b/postfix/src/util/name_mask.ref3
new file mode 100644 (file)
index 0000000..82e8850
--- /dev/null
@@ -0,0 +1,14 @@
+zero -> 0x1 -> zero
+one -> 0x2 -> one
+two -> 0x4 -> two
+three -> 0x8 -> three
+unknown: warning: unknown name value "four" in "four"
+four -> 0x0 -> 
+unknown: warning: unknown name value "four" in "zero one two three four"
+zero one two three four -> 0xf -> zero one two three
+unknown: warning: unknown name value "0xff" in "0xff"
+0xff -> 0x0 -> 
+unknown: warning: unknown name value "0xffffffff" in "0xffffffff"
+0xffffffff -> 0x0 -> 
+unknown: warning: unknown name value "0xffffffffffffffff" in "0xffffffffffffffff"
+0xffffffffffffffff -> 0x0 -> 
diff --git a/postfix/src/util/name_mask.ref4 b/postfix/src/util/name_mask.ref4
new file mode 100644 (file)
index 0000000..4ec996b
--- /dev/null
@@ -0,0 +1,14 @@
+zero -> 0x1 -> zero
+one -> 0x2 -> one
+two -> 0x4 -> two
+three -> 0x8 -> three
+unknown: warning: unknown name value "four" in "four"
+four -> 0x0 -> 
+unknown: warning: unknown name value "four" in "zero one two three four"
+zero one two three four -> 0x0 -> 
+unknown: warning: unknown name value "0xff" in "0xff"
+0xff -> 0x0 -> 
+unknown: warning: unknown name value "0xffffffff" in "0xffffffff"
+0xffffffff -> 0x0 -> 
+unknown: warning: unknown name value "0xffffffffffffffff" in "0xffffffffffffffff"
+0xffffffffffffffff -> 0x0 -> 
diff --git a/postfix/src/util/name_mask.ref5 b/postfix/src/util/name_mask.ref5
new file mode 100644 (file)
index 0000000..68c1c30
--- /dev/null
@@ -0,0 +1,14 @@
+zero -> 0x1 -> zero
+one -> 0x2 -> one
+two -> 0x4 -> two
+three -> 0x8 -> three
+unknown: warning: unknown name value "four" in "four"
+four -> 0x0 -> 
+unknown: warning: unknown name value "four" in "zero one two three four"
+zero one two three four -> 0xf -> zero one two three
+unknown: warning: name_mask: unknown mask bit in mask: 0xf0
+0xff -> 0xff -> (null)
+unknown: warning: name_mask: unknown mask bit in mask: 0xfffffff0
+0xffffffff -> 0xffffffff -> (null)
+unknown: warning: unknown name value "0xffffffffffffffff" in "0xffffffffffffffff"
+0xffffffffffffffff -> 0x0 -> 
diff --git a/postfix/src/util/name_mask.ref6 b/postfix/src/util/name_mask.ref6
new file mode 100644 (file)
index 0000000..c86a532
--- /dev/null
@@ -0,0 +1,14 @@
+zero -> 0x1 -> zero
+one -> 0x2 -> one
+two -> 0x4 -> two
+three -> 0x8 -> three
+unknown: warning: unknown name value "four" in "four"
+four -> 0x0 -> 
+unknown: warning: unknown name value "four" in "zero one two three four"
+zero one two three four -> 0xf -> zero one two three
+unknown: warning: name_mask: unknown mask bit in mask: 0xf0
+0xff -> 0xff -> zero one two three
+unknown: warning: name_mask: unknown mask bit in mask: 0xfffffff0
+0xffffffff -> 0xffffffff -> zero one two three
+unknown: warning: unknown name value "0xffffffffffffffff" in "0xffffffffffffffff"
+0xffffffffffffffff -> 0x0 -> 
diff --git a/postfix/src/util/name_mask.ref7 b/postfix/src/util/name_mask.ref7
new file mode 100644 (file)
index 0000000..156d7aa
--- /dev/null
@@ -0,0 +1,12 @@
+zero -> 0x1 -> zero
+one -> 0x2 -> one
+two -> 0x4 -> two
+three -> 0x8 -> three
+unknown: warning: unknown name value "four" in "four"
+four -> 0x0 -> 
+unknown: warning: unknown name value "four" in "zero one two three four"
+zero one two three four -> 0xf -> zero one two three
+0xff -> 0xff -> zero one two three
+0xffffffff -> 0xffffffff -> zero one two three
+unknown: warning: unknown name value "0xffffffffffffffff" in "0xffffffffffffffff"
+0xffffffffffffffff -> 0x0 -> 
diff --git a/postfix/src/util/name_mask.ref8 b/postfix/src/util/name_mask.ref8
new file mode 100644 (file)
index 0000000..7463fb7
--- /dev/null
@@ -0,0 +1,12 @@
+zero -> 0x1 -> zero
+one -> 0x2 -> one
+two -> 0x4 -> two
+three -> 0x8 -> three
+unknown: warning: unknown name value "four" in "four"
+four -> 0x0 -> 
+unknown: warning: unknown name value "four" in "zero one two three four"
+zero one two three four -> 0xf -> zero,one,two,three
+0xff -> 0xff -> zero,one,two,three,0xf0
+0xffffffff -> 0xffffffff -> zero,one,two,three,0xfffffff0
+unknown: warning: unknown name value "0xffffffffffffffff" in "0xffffffffffffffff"
+0xffffffffffffffff -> 0x0 -> 
diff --git a/postfix/src/util/name_mask.ref9 b/postfix/src/util/name_mask.ref9
new file mode 100644 (file)
index 0000000..e50a73a
--- /dev/null
@@ -0,0 +1,12 @@
+zero -> 0x1 -> zero
+one -> 0x2 -> one
+two -> 0x4 -> two
+three -> 0x8 -> three
+unknown: warning: unknown name value "four" in "four"
+four -> 0x0 -> 
+unknown: warning: unknown name value "four" in "zero one two three four"
+zero one two three four -> 0xf -> zero|one|two|three
+0xff -> 0xff -> zero|one|two|three|0xf0
+0xffffffff -> 0xffffffff -> zero|one|two|three|0xfffffff0
+unknown: warning: unknown name value "0xffffffffffffffff" in "0xffffffffffffffff"
+0xffffffffffffffff -> 0x0 -> 
diff --git a/postfix/src/util/nbbio.c b/postfix/src/util/nbbio.c
new file mode 100644 (file)
index 0000000..f85bf68
--- /dev/null
@@ -0,0 +1,371 @@
+/*++
+/* NAME
+/*     nbbio 3
+/* SUMMARY
+/*     non-blocking buffered I/O
+/* SYNOPSIS
+/*     #include <nbbio.h>
+/*
+/*     NBBIO   *nbbio_create(fd, bufsize, label, action, context)
+/*     int     fd;
+/*     ssize_t bufsize;
+/*     const char *label;
+/*     void    (*action)(int event, char *context);
+/*     char    *context;
+/*
+/*     void    nbbio_free(np)
+/*     NBBIO   *np;
+/*
+/*     void    nbbio_enable_read(np, timeout)
+/*     NBBIO   *np;
+/*     int     timeout;
+/*
+/*     void    nbbio_enable_write(np, timeout)
+/*     NBBIO   *np;
+/*     int     timeout;
+/*
+/*     void    nbbio_disable_readwrite(np)
+/*     NBBIO   *np;
+/*
+/*     void    nbbio_slumber(np, timeout)
+/*     NBBIO   *np;
+/*     int     timeout;
+/*
+/*     int     NBBIO_ACTIVE_FLAGS(np)
+/*     NBBIO   *np;
+/*
+/*     int     NBBIO_ERROR_FLAGS(np)
+/*     NBBIO   *np;
+/*
+/*     const ssize_t NBBIO_BUFSIZE(np)
+/*     NBBIO   *np;
+/*
+/*     ssize_t NBBIO_READ_PEND(np)
+/*     NBBIO   *np;
+/*
+/*     char    *NBBIO_READ_BUF(np)
+/*     NBBIO   *np;
+/*
+/*     const ssize_t NBBIO_WRITE_PEND(np)
+/*     NBBIO   *np;
+/*
+/*     char    *NBBIO_WRITE_BUF(np)
+/*     NBBIO   *np;
+/* DESCRIPTION
+/*     This module implements low-level support for event-driven
+/*     I/O on a full-duplex stream. Read/write events are handled
+/*     by pseudothreads that run under control by the events(5)
+/*     module.  After each I/O operation, the application is
+/*     notified via a call-back routine.
+/*
+/*     It is up to the call-back routine to turn on/off read/write
+/*     events as appropriate.  It is an error to leave read events
+/*     enabled for a buffer that is full, or to leave write events
+/*     enabled for a buffer that is empty.
+/*
+/*     nbbio_create() creates a pair of buffers of the named size
+/*     for the named stream. The label specifies the purpose of
+/*     the stream, and is used for diagnostic messages.  The
+/*     nbbio(3) event handler invokes the application call-back
+/*     routine with the current event type (EVENT_READ etc.) and
+/*     with the application-specified context.
+/*
+/*     nbbio_free() terminates any pseudothreads associated with
+/*     the named buffer pair, closes the stream, and destroys the
+/*     buffer pair.
+/*
+/*     nbbio_enable_read() enables a read pseudothread for the
+/*     named buffer pair.  It is an error to enable a read
+/*     pseudothread while the read buffer is full, or while a read
+/*     or write pseudothread is still enabled.
+/*
+/*     nbbio_enable_write() enables a write pseudothread for the
+/*     named buffer pair.  It is an error to enable a write
+/*     pseudothread while the write buffer is empty, or while a
+/*     read or write pseudothread is still enabled.
+/*
+/*     nbbio_disable_readwrite() disables any read/write pseudothreads
+/*     for the named buffer pair, including timeouts. To ensure
+/*     buffer liveness, use nbbio_slumber() instead of
+/*     nbbio_disable_readwrite().  It is no error to call this
+/*     function while no read/write pseudothread is enabled.
+/*
+/*     nbbio_slumber() disables any read/write pseudothreads for
+/*     the named buffer pair, but keeps the timer active to ensure
+/*     buffer liveness. It is no error to call this function while
+/*     no read/write pseudothread is enabled.
+/*
+/*     NBBIO_ERROR_FLAGS() returns the error flags for the named buffer
+/*     pair: zero or more of NBBIO_FLAG_EOF (read EOF), NBBIO_FLAG_ERROR
+/*     (read/write error) or NBBIO_FLAG_TIMEOUT (time limit
+/*     exceeded).
+/*
+/*     NBBIO_ACTIVE_FLAGS() returns the pseudothread flags for the
+/*     named buffer pair: NBBIO_FLAG_READ (read pseudothread is
+/*     active), NBBIO_FLAG_WRITE (write pseudothread is active),
+/*     or zero (no pseudothread is active).
+/*
+/*     NBBIO_WRITE_PEND() and NBBIO_WRITE_BUF() evaluate to the
+/*     number of to-be-written bytes and the write buffer for the
+/*     named buffer pair. NBBIO_WRITE_PEND() must be updated by
+/*     the application code that fills the write buffer; no more
+/*     than NBBIO_BUFSIZE() bytes may be filled.
+/*
+/*     NBBIO_READ_PEND() and NBBIO_READ_BUF() evaluate to the
+/*     number of unread bytes and the read buffer for the named
+/*     buffer pair. NBBIO_READ_PEND() and NBBIO_READ_BUF() must
+/*     be updated by the application code that drains the read
+/*     buffer.
+/* SEE ALSO
+/*     events(3) event manager
+/* DIAGNOSTICS
+/*     Panic: interface violation.
+/*
+/*     Fatal: out of memory.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+ /*
+  * System library.
+  */
+#include <sys_defs.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>                    /* memmove() */
+
+ /*
+  * Utility library.
+  */
+#include <mymalloc.h>
+#include <msg.h>
+#include <events.h>
+#include <nbbio.h>
+
+/* nbbio_event - non-blocking event handler */
+
+static void nbbio_event(int event, char *context)
+{
+    const char *myname = "nbbio_event";
+    NBBIO  *np = (NBBIO *) context;
+    ssize_t count;
+
+    switch (event) {
+
+       /*
+        * Read data into the read buffer. Leave it up to the application to
+        * drain the buffer until it is empty.
+        */
+    case EVENT_READ:
+       if (np->read_pend == np->bufsize)
+           msg_panic("%s: socket fd=%d: read buffer is full",
+                     myname, np->fd);
+       if (np->read_pend < 0 || np->read_pend > np->bufsize)
+           msg_panic("%s: socket fd=%d: bad pending read count %ld",
+                     myname, np->fd, (long) np->read_pend);
+       count = read(np->fd, np->read_buf + np->read_pend,
+                    np->bufsize - np->read_pend);
+       if (count > 0) {
+           np->read_pend += count;
+           if (msg_verbose)
+               msg_info("%s: read %ld on %s fd=%d",
+                        myname, (long) count, np->label, np->fd);
+       } else if (count == 0) {
+           np->flags |= NBBIO_FLAG_EOF;
+           if (msg_verbose)
+               msg_info("%s: read EOF on %s fd=%d",
+                        myname, np->label, np->fd);
+       } else {
+           if (errno == EAGAIN)
+               msg_warn("%s: read() returns EAGAIN on readable descriptor",
+                        myname);
+           np->flags |= NBBIO_FLAG_ERROR;
+           if (msg_verbose)
+               msg_info("%s: read %s fd=%d: %m", myname, np->label, np->fd);
+       }
+       break;
+
+       /*
+        * Drain data from the output buffer.  Notify the application
+        * whenever some bytes are written.
+        * 
+        * XXX Enforce a total time limit to ensure liveness when a hostile
+        * receiver sets a very small TCP window size.
+        */
+    case EVENT_WRITE:
+       if (np->write_pend == 0)
+           msg_panic("%s: socket fd=%d: empty write buffer", myname, np->fd);
+       if (np->write_pend < 0 || np->write_pend > np->bufsize)
+           msg_panic("%s: socket fd=%d: bad pending write count %ld",
+                     myname, np->fd, (long) np->write_pend);
+       count = write(np->fd, np->write_buf, np->write_pend);
+       if (count > 0) {
+           np->write_pend -= count;
+           if (np->write_pend > 0)
+               memmove(np->write_buf, np->write_buf + count, np->write_pend);
+       } else {
+           if (errno == EAGAIN)
+               msg_warn("%s: write() returns EAGAIN on writable descriptor",
+                        myname);
+           np->flags |= NBBIO_FLAG_ERROR;
+           if (msg_verbose)
+               msg_info("%s: write %s fd=%d: %m", myname, np->label, np->fd);
+       }
+       break;
+
+       /*
+        * Something bad happened.
+        */
+    case EVENT_XCPT:
+       np->flags |= NBBIO_FLAG_ERROR;
+       if (msg_verbose)
+           msg_info("%s: error on %s fd=%d: %m", myname, np->label, np->fd);
+       break;
+
+       /*
+        * Something good didn't happen.
+        */
+    case EVENT_TIME:
+       np->flags |= NBBIO_FLAG_TIMEOUT;
+       if (msg_verbose)
+           msg_info("%s: %s timeout on %s fd=%d",
+                    myname, NBBIO_OP_NAME(np), np->label, np->fd);
+       break;
+
+    default:
+       msg_panic("%s: unknown event %d", myname, event);
+    }
+
+    /*
+     * Application notification. The application will check for any error
+     * flags, copy application data from or to our buffer pair, and decide
+     * what I/O happens next.
+     */
+    np->action(event, np->context);
+}
+
+/* nbbio_enable_read - enable reading from socket into buffer */
+
+void    nbbio_enable_read(NBBIO *np, int timeout)
+{
+    const char *myname = "nbbio_enable_read";
+
+    /*
+     * Sanity checks.
+     */
+    if (np->flags & NBBIO_MASK_ACTIVE)
+       msg_panic("%s: socket fd=%d is enabled for %s",
+                 myname, np->fd, NBBIO_OP_NAME(np));
+    if (timeout <= 0)
+       msg_panic("%s: socket fd=%d: bad timeout %d",
+                 myname, np->fd, timeout);
+    if (np->read_pend >= np->bufsize)
+       msg_panic("%s: socket fd=%d: read buffer is full",
+                 myname, np->fd);
+
+    /*
+     * Enable events.
+     */
+    event_enable_read(np->fd, nbbio_event, (char *) np);
+    event_request_timer(nbbio_event, (char *) np, timeout);
+    np->flags |= NBBIO_FLAG_READ;
+}
+
+/* nbbio_enable_write - enable writing from buffer to socket */
+
+void    nbbio_enable_write(NBBIO *np, int timeout)
+{
+    const char *myname = "nbbio_enable_write";
+
+    /*
+     * Sanity checks.
+     */
+    if (np->flags & NBBIO_MASK_ACTIVE)
+       msg_panic("%s: socket fd=%d is enabled for %s",
+                 myname, np->fd, NBBIO_OP_NAME(np));
+    if (timeout <= 0)
+       msg_panic("%s: socket fd=%d bad timeout %d",
+                 myname, np->fd, timeout);
+    if (np->write_pend <= 0)
+       msg_panic("%s: socket fd=%d: empty write buffer",
+                 myname, np->fd);
+
+    /*
+     * Enable events.
+     */
+    event_enable_write(np->fd, nbbio_event, (char *) np);
+    event_request_timer(nbbio_event, (char *) np, timeout);
+    np->flags |= NBBIO_FLAG_WRITE;
+}
+
+/* nbbio_disable_readwrite - disable read/write/timer events */
+
+void    nbbio_disable_readwrite(NBBIO *np)
+{
+    np->flags &= ~NBBIO_MASK_ACTIVE;
+    event_disable_readwrite(np->fd);
+    event_cancel_timer(nbbio_event, (char *) np);
+}
+
+/* nbbio_slumber - disable read/write events, keep timer */
+
+void    nbbio_slumber(NBBIO *np, int timeout)
+{
+    np->flags &= ~NBBIO_MASK_ACTIVE;
+    event_disable_readwrite(np->fd);
+    event_request_timer(nbbio_event, (char *) np, timeout);
+}
+
+/* nbbio_create - create socket buffer */
+
+NBBIO  *nbbio_create(int fd, ssize_t bufsize, const char *label,
+                            NBBIO_ACTION action, char *context)
+{
+    NBBIO  *np;
+
+    /*
+     * Sanity checks.
+     */
+    if (fd < 0)
+       msg_panic("nbbio_create: bad file descriptor: %d", fd);
+    if (bufsize <= 0)
+       msg_panic("nbbio_create: bad buffer size: %ld", (long) bufsize);
+
+    /*
+     * Create a new buffer pair.
+     */
+    np = (NBBIO *) mymalloc(sizeof(*np));
+    np->fd = fd;
+    np->bufsize = bufsize;
+    np->label = mystrdup(label);
+    np->action = action;
+    np->context = context;
+    np->flags = 0;
+
+    np->read_buf = mymalloc(bufsize);
+    np->read_pend = 0;
+
+    np->write_buf = mymalloc(bufsize);
+    np->write_pend = 0;
+
+    return (np);
+}
+
+/* nbbio_free - destroy socket buffer */
+
+void    nbbio_free(NBBIO *np)
+{
+    nbbio_disable_readwrite(np);
+    (void) close(np->fd);
+    myfree(np->label);
+    myfree(np->read_buf);
+    myfree(np->write_buf);
+    myfree((char *) np);
+}
diff --git a/postfix/src/util/nbbio.h b/postfix/src/util/nbbio.h
new file mode 100644 (file)
index 0000000..91d0ade
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef _NBBIO_H_INCLUDED_
+#define _NBBIO_H_INCLUDED_
+
+/*++
+/* NAME
+/*     nbbio 3h
+/* SUMMARY
+/*     non-blocking buffered I/O
+/* SYNOPSIS
+/*     #include "nbbio.h"
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <events.h>                    /* Needed for EVENT_READ etc. */
+
+ /*
+  * External interface. All structure members are private.
+  */
+typedef void (*NBBIO_ACTION) (int, char *);
+
+typedef struct {
+    int     fd;                                /* socket file descriptor */
+    ssize_t bufsize;                   /* read/write buffer size */
+    char   *label;                     /* diagnostics */
+    NBBIO_ACTION action;               /* call-back routine */
+    char   *context;                   /* call-back context */
+    int     flags;                     /* buffer-pair status */
+
+    char   *read_buf;                  /* start of buffer */
+    ssize_t read_pend;                 /* nr of unread bytes */
+
+    char   *write_buf;                 /* start of buffer */
+    ssize_t write_pend;                        /* nr of unwritten bytes */
+} NBBIO;
+
+#define NBBIO_FLAG_READ                (1<<0)
+#define NBBIO_FLAG_WRITE       (1<<1)
+#define NBBIO_FLAG_EOF         (1<<2)
+#define NBBIO_FLAG_ERROR       (1<<3)
+#define NBBIO_FLAG_TIMEOUT     (1<<4)
+
+#define NBBIO_OP_NAME(np) \
+       (((np)->flags & NBBIO_FLAG_READ) ? "read" : \
+        ((np)->flags & NBBIO_FLAG_WRITE) ? "write" : \
+        "unknown")
+
+#define NBBIO_MASK_ACTIVE \
+       (NBBIO_FLAG_READ | NBBIO_FLAG_WRITE)
+
+#define NBBIO_MASK_ERROR \
+       (NBBIO_FLAG_EOF | NBBIO_FLAG_ERROR | NBBIO_FLAG_TIMEOUT)
+
+#define NBBIO_BUFSIZE(np)              (((np)->bufsize) + 0)   /* Read-only */
+
+#define NBBIO_READ_PEND(np)            ((np)->read_pend)
+#define NBBIO_READ_BUF(np)             ((np)->read_buf + 0)    /* Read-only */
+
+#define NBBIO_WRITE_PEND(np)           ((np)->write_pend)
+#define NBBIO_WRITE_BUF(np)            ((np)->write_buf + 0)   /* Read-only */
+
+#define NBBIO_ACTIVE_FLAGS(np)         ((np)->flags & NBBIO_MASK_ACTIVE)
+#define NBBIO_ERROR_FLAGS(np)          ((np)->flags & NBBIO_MASK_ERROR)
+
+extern NBBIO *nbbio_create(int, ssize_t, const char *, NBBIO_ACTION, char *);
+extern void nbbio_free(NBBIO *);
+extern void nbbio_enable_read(NBBIO *, int);
+extern void nbbio_enable_write(NBBIO *, int);
+extern void nbbio_disable_readwrite(NBBIO *);
+extern void nbbio_slumber(NBBIO *, int);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
index f3f333ba7b5028ef56009533f2927f9f0d5ebd29..28e4c0a873e584cfff6d864ee5830f4964367ad8 100644 (file)
@@ -79,6 +79,9 @@
 /*     int     vstream_fileno(stream)
 /*     VSTREAM *stream;
 /*
+/*     const ssize_t vstream_req_bufsize(stream)
+/*     VSTREAM *stream;
+/*
 /*     void    *vstream_context(stream)
 /*     VSTREAM *stream;
 /*
 /*     ignored. Requests to change a fixed-size buffer (stdin,
 /*     stdout, stderr) are not allowed.
 /*
+/*     NOTE: the VSTREAM_CTL_BUFSIZE request specifies intent, not
+/*     reality.  Actual buffer sizes are not updated immediately.
+/*     Instead, an existing write buffer will be resized when it
+/*     is full, and an existing read buffer will be resized when
+/*     the buffer is filled.
+/*
 /*     NOTE: the VSTREAM_CTL_BUFSIZE argument type is ssize_t, not
 /*     int. Use an explicit cast to avoid problems on LP64
 /*     environments and other environments where ssize_t is larger
 /*     a buffered stream. With streams that have separate read/write
 /*     file descriptors, the result is the current descriptor.
 /*
+/*     vstream_req_bufsize() returns the requested buffer size for
+/*     the named stream (default: VSTREAM_BUFSIZE). The result
+/*     value reflects intent, not reality: actual buffer sizes are
+/*     not updated immediately when the requested buffer size is
+/*     specified with vstream_control().  Instead, an existing
+/*     write buffer will be resized when it is full, and an existing
+/*     read buffer will be resized when the buffer is filled.
+/*
 /*     vstream_context() returns the application context that is passed on to
 /*     the application-specified read/write routines.
 /*
@@ -408,13 +425,6 @@ static int vstream_buf_space(VBUF *, ssize_t);
   * Initialization of the three pre-defined streams. Pre-allocate a static
   * I/O buffer for the standard error stream, so that the error handler can
   * produce a diagnostic even when memory allocation fails.
-  * 
-  * XXX We don't (yet) statically initialize the req_bufsize field: it is the
-  * last VSTREAM member so we don't break Postfix 2.4 binary compatibility,
-  * and Wietse doesn't know how to specify an initializer for the jmp_buf
-  * VSTREAM member (which can be a struct or an array) without collateral
-  * damage to the source code. We can fix the initialization later in the
-  * Postfix 2.5 development cycle.
   */
 static unsigned char vstream_fstd_buf[VSTREAM_BUFSIZE];
 
@@ -423,17 +433,20 @@ VSTREAM vstream_fstd[] = {
            0,                          /* flags */
            0, 0, 0, 0,                 /* buffer */
            vstream_buf_get_ready, vstream_buf_put_ready, vstream_buf_space,
-    }, STDIN_FILENO, (VSTREAM_FN) timed_read, (VSTREAM_FN) timed_write,},
+    }, STDIN_FILENO, (VSTREAM_FN) timed_read, (VSTREAM_FN) timed_write,
+    VSTREAM_BUFSIZE,},
     {{
            0,                          /* flags */
            0, 0, 0, 0,                 /* buffer */
            vstream_buf_get_ready, vstream_buf_put_ready, vstream_buf_space,
-    }, STDOUT_FILENO, (VSTREAM_FN) timed_read, (VSTREAM_FN) timed_write,},
+    }, STDOUT_FILENO, (VSTREAM_FN) timed_read, (VSTREAM_FN) timed_write,
+    VSTREAM_BUFSIZE,},
     {{
            VBUF_FLAG_FIXED | VSTREAM_FLAG_WRITE,
            vstream_fstd_buf, VSTREAM_BUFSIZE, VSTREAM_BUFSIZE, vstream_fstd_buf,
            vstream_buf_get_ready, vstream_buf_put_ready, vstream_buf_space,
-    }, STDERR_FILENO, (VSTREAM_FN) timed_read, (VSTREAM_FN) timed_write,},
+    }, STDERR_FILENO, (VSTREAM_FN) timed_read, (VSTREAM_FN) timed_write,
+    VSTREAM_BUFSIZE,},
 };
 
 #define VSTREAM_STATIC(v) ((v) >= VSTREAM_IN && (v) <= VSTREAM_ERR)
@@ -717,8 +730,6 @@ static int vstream_buf_get_ready(VBUF *bp)
      * allocation gives the application a chance to override the default
      * buffering policy.
      */
-    if (stream->req_bufsize == 0)
-       stream->req_bufsize = VSTREAM_BUFSIZE;
     if (bp->len < stream->req_bufsize)
        vstream_buf_alloc(bp, stream->req_bufsize);
 
@@ -802,8 +813,6 @@ static int vstream_buf_put_ready(VBUF *bp)
      * new buffer; obviously there is no data to be flushed yet. Otherwise,
      * flush the buffer.
      */
-    if (stream->req_bufsize == 0)
-       stream->req_bufsize = VSTREAM_BUFSIZE;  /* Postfix 2.4 binary compat. */
     if (bp->len < stream->req_bufsize) {
        vstream_buf_alloc(bp, stream->req_bufsize);
     } else if (bp->cnt <= 0) {
@@ -859,8 +868,6 @@ static int vstream_buf_space(VBUF *bp, ssize_t want)
 #define VSTREAM_ROUNDUP(count, base)   VSTREAM_TRUNCATE(count + base - 1, base)
 
     if (want > bp->cnt) {
-       if (stream->req_bufsize == 0)
-           stream->req_bufsize = VSTREAM_BUFSIZE;      /* 2.4 binary compat. */
        if ((used = bp->len - bp->cnt) > stream->req_bufsize)
            if (vstream_fflush_some(stream, VSTREAM_TRUNCATE(used, stream->req_bufsize)))
                return (VSTREAM_EOF);
@@ -1304,8 +1311,6 @@ void    vstream_control(VSTREAM *stream, int name,...)
            if (req_bufsize < 0)
                msg_panic("VSTREAM_CTL_BUFSIZE with negative size: %ld",
                          (long) req_bufsize);
-           if (stream->req_bufsize == 0)
-               stream->req_bufsize = VSTREAM_BUFSIZE;  /* 2.4 binary compat. */
            if (stream != VSTREAM_ERR
                && req_bufsize > stream->req_bufsize)
                stream->req_bufsize = req_bufsize;
index 7695c23025df5756e1f018e7c20a539746e04aa3..943953f6787fa3751f990d52d662ab9dd5c065d0 100644 (file)
@@ -44,6 +44,7 @@ typedef struct VSTREAM {
     int     fd;                                /* file handle, no 256 limit */
     VSTREAM_FN read_fn;                        /* buffer fill action */
     VSTREAM_FN write_fn;               /* buffer fill action */
+    ssize_t req_bufsize;               /* requested read/write buffer size */
     void   *context;                   /* application context */
     off_t   offset;                    /* cached seek info */
     char   *path;                      /* give it at least try */
@@ -56,8 +57,6 @@ typedef struct VSTREAM {
     int     timeout;                   /* read/write timout */
     VSTREAM_JMP_BUF *jbuf;             /* exception handling */
     struct timeval iotime;             /* time of last fill/flush */
-    /* At bottom for Postfix 2.4 binary compatibility. */
-    ssize_t req_bufsize;               /* write buffer size */
 } VSTREAM;
 
 extern VSTREAM vstream_fstd[];         /* pre-defined streams */
@@ -106,6 +105,7 @@ extern int vstream_fdclose(VSTREAM *);
 #define VSTREAM_GETCHAR()      VSTREAM_GETC(VSTREAM_IN)
 
 #define vstream_fileno(vp)     ((vp)->fd)
+#define vstream_req_bufsize(vp)        ((const ssize_t) ((vp)->req_bufsize))
 #define vstream_context(vp)    ((vp)->context)
 #define vstream_ferror(vp)     vbuf_error(&(vp)->buf)
 #define vstream_feof(vp)       vbuf_eof(&(vp)->buf)
index 5fc1e0f7d0d411a92e706e78714a21f02239ad5b..be7f82249cc537e38253912199fffa5b9ff98084 100644 (file)
@@ -323,7 +323,8 @@ static int xsasl_dovecot_server_connect(XSASL_DOVECOT_SERVER_IMPL *xp)
                sec_props =
                    name_mask_delim_opt(myname,
                                        xsasl_dovecot_serv_sec_props,
-                                       line, "\t", NAME_MASK_ANY_CASE);
+                                       line, "\t",
+                                    NAME_MASK_ANY_CASE | NAME_MASK_IGNORE);
                if ((sec_props & SEC_PROPS_PRIVATE) != 0)
                    continue;
            } else