]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.4-20180617
authorWietse Venema <wietse@porcupine.org>
Sun, 17 Jun 2018 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Tue, 19 Jun 2018 16:23:38 +0000 (12:23 -0400)
64 files changed:
postfix/HISTORY
postfix/README_FILES/CONNECTION_CACHE_README
postfix/README_FILES/TLS_README
postfix/RELEASE_NOTES
postfix/WISHLIST
postfix/html/CONNECTION_CACHE_README.html
postfix/html/TLS_README.html
postfix/html/lmtp.8.html
postfix/html/postconf.5.html
postfix/html/posttls-finger.1.html
postfix/html/smtp.8.html
postfix/html/tlsproxy.8.html
postfix/man/man1/posttls-finger.1
postfix/man/man5/postconf.5
postfix/man/man8/smtp.8
postfix/man/man8/tlsproxy.8
postfix/mantools/postlink
postfix/proto/CONNECTION_CACHE_README.html
postfix/proto/TLS_README.html
postfix/proto/postconf.proto
postfix/src/global/mail_params.h
postfix/src/global/mail_proto.h
postfix/src/global/mail_version.h
postfix/src/local/mailbox.c
postfix/src/local/unknown.c
postfix/src/master/mail_server.h
postfix/src/master/master.h
postfix/src/master/master_sig.c
postfix/src/postscreen/postscreen_starttls.c
postfix/src/posttls-finger/posttls-finger.c
postfix/src/smtp/Makefile.in
postfix/src/smtp/lmtp_params.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp.h
postfix/src/smtp/smtp_connect.c
postfix/src/smtp/smtp_key.c
postfix/src/smtp/smtp_params.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtp/smtp_reuse.c
postfix/src/smtp/smtp_session.c
postfix/src/smtp/smtp_tls_policy.c
postfix/src/smtpd/smtpd.c
postfix/src/tls/Makefile.in
postfix/src/tls/tls.h
postfix/src/tls/tls_client.c
postfix/src/tls/tls_dane.c
postfix/src/tls/tls_proxy.h
postfix/src/tls/tls_proxy_client_print.c [new file with mode: 0644]
postfix/src/tls/tls_proxy_client_scan.c [new file with mode: 0644]
postfix/src/tls/tls_proxy_clnt.c
postfix/src/tls/tls_proxy_context_print.c [moved from postfix/src/tls/tls_proxy_print.c with 63% similarity]
postfix/src/tls/tls_proxy_context_scan.c [new file with mode: 0644]
postfix/src/tls/tls_proxy_scan.c [deleted file]
postfix/src/tls/tls_proxy_server_print.c [new file with mode: 0644]
postfix/src/tls/tls_proxy_server_scan.c [new file with mode: 0644]
postfix/src/tlsproxy/Makefile.in
postfix/src/tlsproxy/tlsproxy.c
postfix/src/tlsproxy/tlsproxy.h
postfix/src/tlsproxy/tlsproxy_state.c
postfix/src/util/Makefile.in
postfix/src/util/argv_attr.h [new file with mode: 0644]
postfix/src/util/argv_attr_print.c [new file with mode: 0644]
postfix/src/util/argv_attr_scan.c [new file with mode: 0644]
postfix/src/util/killme_after.c

index c8412f1dde3c9f7e51fb8b807b2aedef5792a17c..1ef6ecf5b1202b33b92d96d9249198271964d08e 100644 (file)
@@ -23399,6 +23399,38 @@ Apologies for any names omitted.
        TLS handshake error. Found during code maintenance. File:
        tlsproxy/tlsproxy.c.
 
+       Connection reuse for TLS-encrypted SMTP sessions. This is
+       work-in-progress, #ifdef USE_TLSPROXY, to avoid contamination
+       of existing code.
+
+       The idea is to have smtp(8) talk plaintext while tlsproxy(8)
+       converts between local plaintext and remote ciphertext.
+       Then, smtp(8) can save plaintext connections to the cache,
+       and scache(8) holds the handles to the tlsproxy(8) processes.
+
+       This preliminary implementation does not yet support proxying
+       of DANE attributes from smtp(8) to tlsproxy(8). tlsproxy(8)
+       does not have permissions to read private key files that
+       smtp(8) can read. And the name of a connection cache entry
+       does not yet depend on whether the cached connection uses
+       TLS, nor does it depend on DANE information.
+
+       Files: global/mail_proto.h, postscreen/postscreen_starttls.c,
+       posttls-finger/posttls-finger.c, smtp/smtp.c, smtp/smtp.h,
+       smtp/smtp_params.c, smtp/smtp_proto.c, smtp/smtp_session.c,
+       smtpd/smtpd.c, tls/tls.h, tls/tls_client.c, tls/tls_proxy.h,
+       tls/tls_proxy_client_init_print.c,
+       tls/tls_proxy_client_init_scan.c,
+       tls/tls_proxy_client_start_print.c,
+       tls/tls_proxy_client_start_scan.c, tls/tls_proxy_clnt.c,
+       tls/tls_proxy_context_print.c, tls/tls_proxy_context_scan.c,
+       tls/tls_proxy_server_init_print.c,
+       tls/tls_proxy_server_init_scan.c,
+       tls/tls_proxy_server_start_print.c,
+       tls/tls_proxy_server_start_scan.c, tlsproxy/tlsproxy.c,
+       tlsproxy/tlsproxy.h, tlsproxy/tlsproxy_state.c, util/argv_attr.h,
+       util/argv_attr_print.c, util/argv_attr_scan.c.
+
 20180425
 
        Cleanup: dnsblog proccesses now retire voluntarily after 
@@ -23445,3 +23477,61 @@ Apologies for any names omitted.
        Documentation: bash syntax to eliminate or view default
        settings in "postconf -n" output. File: postconf/postconf.c.
        Contributed by various postfix-users list members.
+
+20180603
+
+       TLS reuse: serializer/deserializer support for TLS_DANE and
+       related data structures. Files: tls/tls_proxy_client_print.c,
+       tls/tls_proxy_client_scan.c, tls/tls_proxy.h, util/argv_attr.h,
+       util/argv_attr_print.c, util/argv_attr_scan.c.
+
+       TLS reuse: posttls-finger -X test flag for quick tests.
+       File: posttls-finger/posttls-finger.c.
+
+       TLS reuse: smtp_use_tlsproxy boolean parameter. This is a
+       preliminary implementation that should support override via
+       smtp_tls_policy_maps. Files: smtp.c, smtp_connect.c,
+       smtp_params.c, smtp_proto.c, smtp_session.c.
+
+       TLS reuse: the SMTP client now includes the requested TLS
+       security level in the scache(8) key.
+
+       TLS reuse: address-based reuse is allowed only for TLS
+       levels that require no certificate checks. Perhaps it still
+       makes sense to save such sessions for reuse by less sensitive
+       deliveries. Files: smtp/smtp.h smtp/smtp_reuse.c.
+
+20180604
+
+       TLS reuse: smtp_tls_connection_reuse boolean parameter, and
+       corresponding override with "connection_reuse" boolean
+       attribute in smtp_policy_maps. Files: global/mail_params.h,
+       smtp.c, smtp.h, smtp_params.c, smtp_proto.c, smtp_session.c,
+       smtp_tls_policy.c. proto/postconf.proto. mantools/postlink.
+
+20180605
+
+       TLS reuse: updated TLS_README and CONNECTION_CACHE_README,
+       added comments in tlsproxy.c to explain why it works.
+
+20180617
+
+       Bugfix (introduced: Postfix 2.11): minor memory leak when
+       minting issuer certs. This affects a tiny minority of use
+       cases. Fix by Viktor Dukhovni, based on a fix by Juan
+       Altmayer Pizzorno for Viktor's ssl_dane library.
+
+       Cleanup: support for longer timeouts after the TLS handshake,
+       so that the tlsproxy server won't time out too soon, while
+       the SMTP client waits for the end-of-data response. This
+       tlxproxy timeout is a redundant safety feature for the case
+       that the SMTP client does not enforce the SMTP-level time
+       limit.  Files: tls/tls_proxy.h, tls/tls_proxy_clnt.c,
+       tlsproxy/tlsproxy.c, posttls-finger/posttls-finger.c,
+       postcreen/postscreen_starttls.c, smtp/smtp_proto.c.
+
+       Cleanup: earlier purging of unexpected plaintext. Files:
+       posttls-finger/posttls-finger.c, smtp/smtp_proto.c.
+
+       Release: first production snapshot with multiple outbound
+       deliveries per TLS-encrypted connection.
index 5067f7aea2cc8563e0dcb66dd0caa46385fb4ee7..408d3b54d15e4865c16d21efe228277660d615e6 100644 (file)
@@ -7,6 +7,9 @@ I\bIn\bnt\btr\bro\bod\bdu\buc\bct\bti\bio\bon\bn
 This document describes the Postfix connection cache implementation, which is
 available with Postfix version 2.2 and later.
 
+See Client-side TLS connection reuse for how this connection cache is used to
+implement multiple deliveries per TLS-encrypted connection.
+
 Topics covered in this document:
 
   * What SMTP connection caching can do for you
@@ -64,14 +67,14 @@ to access this cache.
 
             /-- smtp(8) --> Internet
 
-    qmgr(8)       |  
-                  |
-            \--   | smtp(8) --> Internet
-                  |
-                  ^          
-                  |
+    qmgr(8)
+                 |
+            \--  | smtp(8) --> Internet
+                 |
+                 ^
+                 |
 
-                  scache(8)
+                 scache(8)
 
 When SMTP connection caching is enabled (see next section), the smtp(8) client
 does not disconnect after a mail transaction, but gives the connection to the
index 15b5e52c351a4261f5c0b9fc820e38efbf391b38..37622d38371088bb5804f1699cdbe0f8f70552af 100644 (file)
@@ -707,6 +707,7 @@ Topics covered in this section:
   * Configuring TLS in the SMTP/LMTP client
   * Client-side TLS activity logging
   * Client-side certificate and private key configuration
+  * Client-side TLS connection reuse
   * Client-side TLS session cache
   * Client TLS limitations
   * Per-destination TLS policy
@@ -1432,6 +1433,43 @@ Example:
         smtp_tls_CAfile = /etc/postfix/CAcert.pem
         smtp_tls_CApath = /etc/postfix/certs
 
+C\bCl\bli\bie\ben\bnt\bt-\b-s\bsi\bid\bde\be T\bTL\bLS\bS c\bco\bon\bnn\bne\bec\bct\bti\bio\bon\bn r\bre\beu\bus\bse\be
+
+Historically, the Postfix SMTP client has supported multiple deliveries per
+connection only for plaintext connections. Postfix 3.4 introduces the ability
+to make multiple deliveries per TLS-encrypted connection. This is primarily to
+improve mail delivery performance for destinations that throttle clients when
+they don't combine deliveries.
+
+To enable multiple deliveries per TLS connection, specify:
+
+    /etc/postfix/main.cf:
+        smtp_tls_connection_reuse = yes
+
+Alternatively, specify the attribute "connection_reuse=yes" in an
+smtp_tls_policy_maps entry.
+
+The implementation of TLS connection reuse relies on the same scache(8) service
+as used for delivering plaintext SMTP mail, the same tlsproxy(8) daemon as used
+by the postscreen(8) service, and relies on the same hints from the qmgr(8)
+daemon. See "Postfix Connection Cache" for a description of the underlying
+connection reuse infrastructure.
+
+Initial SMTP handshake:
+
+    smtp(8) -> remote SMTP server
+
+Reused SMTP/TLS connection, or new SMTP/TLS connection:
+
+    smtp(8) -> tlsproxy(8) -> remote SMTP server
+
+Cached SMTP/TLS connection:
+
+    scache(8) -> tlsproxy(8) -> remote SMTP server
+
+As of Postfix 3.4, TLS connection reuse is disabled by default. This may change
+once the impact on over-all performance is undestood.
+
 C\bCl\bli\bie\ben\bnt\bt-\b-s\bsi\bid\bde\be T\bTL\bLS\bS s\bse\bes\bss\bsi\bio\bon\bn c\bca\bac\bch\bhe\be
 
 The remote SMTP server and the Postfix SMTP client negotiate a session, which
index 653024e74ac0bf495c91640bf17f311a21e58824..591c9ab4a40ba0f89188cb31b2435385a39f0922 100644 (file)
@@ -24,3 +24,46 @@ historical IBM Public License 1.0, it is now also distributed with the
 more recent Eclipse Public License 2.0. Recipients can choose to take
 the software under the license of their choice. Those who are more
 comfortable with the IPL can continue with that license.
+
+Major changes with snapshot 20180617
+====================================
+
+Preliminary Postfix SMTP client support for multiple deliveries per
+TLS-encrypted connection. This is primarily to improve mail delivery
+performance for destinations that throttle clients when they don't
+combine deliveries.
+
+This feature is enabled with "smtp_tls_connection_reuse=yes" in
+main.cf, or with "tls_connection_reuse=yes" in smtp_tls_policy_maps.
+It supports all Postfix TLS security levels including dane and
+dane-only.
+
+With connection reuse enabled as described above, the Postfix SMTP
+client uses the tlsproxy(8) server to encrypt a connection (even under
+low-traffic conditions). The tlsproxy(8) service was introduced in
+Postfix 2.8, to support STARTTLS in postscreen(8).
+
+Under high-traffic conditions, the Postfix SMTP client will use the
+scache(8) connection cache to store and retrieve open connections.
+This part already existed for plaintext SMTP, and it works in the
+same way for TLS-encryped connections.
+
+The following illustrates how TLS connections are reused:
+
+    Initial plaintext SMTP handshake:
+      smtp(8) -> remote SMTP server
+
+    Reused SMTP/TLS connection, or new SMTP/TLS connection:
+      smtp(8) -> tlsproxy(8) -> remote SMTP server
+
+    Cached SMTP/TLS connection:
+      scache(8) -> tlsproxy(8) -> remote SMTP server
+
+There are a few refinements planned:
+
+- Log the TLS properties every time a connection is reused.
+  Currently, the properties are logged when a TLS session is created.
+
+- Retire a tlsproxy(8) process after max_idle*max_use seconds, even
+  if it is not idle. This limits the impact of memory leaks in
+  libraries or in Postfix itself.
index 42106f2c395e7f7f5f60657a91ed9e61f7f40ccd..07ca8baf936f504404e9e5d8116102839eef5b36 100644 (file)
@@ -1,5 +1,21 @@
 Wish list:
 
+       Add 'retire after max_use * max_idle' support to the
+       event-server, so that tlsproxy processes will terminate
+       even on a busy server. This can build on the retirement
+       support for the dnsblog server.
+
+       With smtpd_reject_footer=$foo in master.cf, and foo defined
+       in main.cf, postconf complains about an unused setting in
+       main.cf. Note that "postconf -Px" will expand $name in
+       the parameter value, which is probably why the warning
+       exists.
+
+       Optionally save application attributes in scache(8) connection
+       store requests, and optionally request such attributes upon
+       connection retrieval. This would allow the SMTP client to
+       log the TLS properties of a reused session.
+
        Things to do before the stable release:
 
        Spell-check, double-word check, HTML validator check,
index b0201dc93ab5fda74b804731dc3794e595252194..e808180a76a33dcd0c08c130b4b41968c8a5d629 100644 (file)
 <p> This document describes the Postfix connection cache implementation,
 which is available with Postfix version 2.2 and later. </p>
 
+<p> See <a href="TLS_README.html#client_tls_reuse">Client-side TLS
+connection reuse</a> for how this connection cache is used to
+implement multiple deliveries per TLS-encrypted connection. </p>
+
 <p> Topics covered in this document: </p>
 
 <ul>
index c732b4f34543dac8e96880550441a4a7b454b5c7..fecd87884549d79565301bd8a8857c1b71dd7fc7 100644 (file)
@@ -992,6 +992,8 @@ solution.  </p>
 <li><a href="#client_cert_key">Client-side certificate and private
 key configuration </a>
 
+<li><a href="#client_tls_reuse">Client-side TLS connection reuse</a>
+
 <li><a href="#client_tls_cache">Client-side TLS session cache</a>
 
 <li><a href="#client_tls_limits"> Client TLS limitations </a>
@@ -1908,6 +1910,49 @@ when the certificate is needed.  </p>
 </pre>
 </blockquote>
 
+<h3><a name="client_tls_reuse">Client-side TLS connection reuse</a> </h3>
+
+<p> Historically, the Postfix SMTP client has supported multiple
+deliveries per connection only for plaintext connections. Postfix
+3.4 introduces the ability to make multiple deliveries per TLS-encrypted
+connection. This is primarily to improve mail delivery performance
+for destinations that throttle clients when they don't combine
+deliveries. </p>
+
+<p> To enable multiple deliveries per TLS connection, specify:</p>
+
+<blockquote>
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    <a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> = yes
+</pre>
+</blockquote>
+
+<p> Alternatively, specify the attribute "connection_reuse=yes" in
+an <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> entry. </p>
+
+<p> The implementation of TLS connection reuse relies on the same
+<a href="scache.8.html">scache(8)</a> service as used for delivering plaintext SMTP mail, the
+same <a href="tlsproxy.8.html">tlsproxy(8)</a> daemon as used by the <a href="postscreen.8.html">postscreen(8)</a> service, and
+relies on the same hints from the <a href="qmgr.8.html">qmgr(8)</a> daemon.
+
+See "<a href="CONNECTION_CACHE_README.html">Postfix Connection
+Cache</a>" for a description of the underlying connection reuse
+infrastructure.  </p>
+
+<p> Initial SMTP handshake:</p>
+<pre>    <a href="smtp.8.html">smtp(8)</a> -&gt; remote SMTP server</pre>
+
+<p> Reused SMTP/TLS connection, or new SMTP/TLS connection: </p>
+<pre>    <a href="smtp.8.html">smtp(8)</a> -&gt; <a href="tlsproxy.8.html">tlsproxy(8)</a> -&gt; remote SMTP server </pre>
+
+<p> Cached SMTP/TLS connection:</p>
+<pre>    <a href="scache.8.html">scache(8)</a> -&gt; <a href="tlsproxy.8.html">tlsproxy(8)</a> -&gt; remote SMTP server</pre>
+
+<p> As of Postfix 3.4, TLS connection reuse is disabled by default.
+This may change once the impact on over-all performance is undestood.
+</p>
+
 <h3><a name="client_tls_cache">Client-side TLS session cache</a> </h3>
 
 <p> The remote SMTP server and the Postfix SMTP client negotiate a
index e5e0259c74c242c969505f3c1fb71374c08757ca..2ac36e297d159a70195be1321be991ce251ff257 100644 (file)
@@ -573,6 +573,11 @@ SMTP(8)                                                                SMTP(8)
               nexthop destination security level is <b>dane</b>, but  the  MX  record
               was found via an "insecure" MX lookup.
 
+       Available in Postfix version 3.4 and later:
+
+       <b><a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> (no)</b>
+              Try to make multiple deliveries per TLS-encrypted connection.
+
 <b>OBSOLETE STARTTLS CONTROLS</b>
        The  following  configuration  parameters  exist for compatibility with
        Postfix versions before 2.3. Support for these will  be  removed  in  a
@@ -704,6 +709,11 @@ SMTP(8)                                                                SMTP(8)
               that  an SMTP session may be reused before it is closed, or zero
               (no limit).
 
+       Available in Postfix version 3.4 and later:
+
+       <b><a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> (no)</b>
+              Try to make multiple deliveries per TLS-encrypted connection.
+
        Implemented in the <a href="qmgr.8.html">qmgr(8)</a> daemon:
 
        <b>transport_destination_concurrency_limit   ($<a href="postconf.5.html#default_destination_concurrency_limit">default_destination_concur</a>-</b>
index 093a3c6b5a2524ab217f4fbe37a0b2624de4f223..766ae42ea5aedafaa2c639569369320adc125d18 100644 (file)
@@ -5184,6 +5184,17 @@ parameter. See there for details. </p>
 <p> This feature is available in Postfix 2.6 and later. </p>
 
 
+</DD>
+
+<DT><b><a name="lmtp_tls_connection_reuse">lmtp_tls_connection_reuse</a>
+(default: no)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 3.4 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="lmtp_tls_dcert_file">lmtp_tls_dcert_file</a>
@@ -11997,6 +12008,22 @@ releases only the <a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_
 and opportunistic TLS always uses "export" or better (i.e. all) ciphers. </p>
 
 
+</DD>
+
+<DT><b><a name="smtp_tls_connection_reuse">smtp_tls_connection_reuse</a>
+(default: no)</b></DT><DD>
+
+<p> Try to make multiple deliveries per TLS-encrypted connection.
+This uses the <a href="tlsproxy.8.html">tlsproxy(8)</a> service to encrypt an SMTP connection,
+uses the <a href="scache.8.html">scache(8)</a> service to save that connection, and relies on
+hints from the <a href="qmgr.8.html">qmgr(8)</a> daemon. </p>
+
+<p> See "<a href="TLS_README.html#client_tls_reuse">Client-side
+TLS connection reuse</a>" for background details. </p>
+
+<p> This feature is available in Postfix 3.4 and later.  </p>
+
+
 </DD>
 
 <DT><b><a name="smtp_tls_dane_insecure_mx_policy">smtp_tls_dane_insecure_mx_policy</a>
@@ -12702,11 +12729,13 @@ security are: </p>
 <dt><b><a href="TLS_README.html#client_tls_may">may</a></b></dt>
 <dd>Opportunistic TLS. Since sending in the clear is acceptable,
 demanding stronger than default TLS security merely reduces
-interoperability. The optional "ciphers", "exclude" and "protocols"
+interoperability. The optional "ciphers", "exclude", and "protocols"
 attributes (available for opportunistic TLS with Postfix &ge; 2.6)
-override the "<a href="postconf.5.html#smtp_tls_ciphers">smtp_tls_ciphers</a>", "<a href="postconf.5.html#smtp_tls_exclude_ciphers">smtp_tls_exclude_ciphers</a>" and
-"<a href="postconf.5.html#smtp_tls_protocols">smtp_tls_protocols</a>" configuration parameters. When opportunistic TLS
-handshakes fail, Postfix retries the connection with TLS disabled.
+and "connection_reuse" attribute (Postfix &ge; 3.4) override the
+"<a href="postconf.5.html#smtp_tls_ciphers">smtp_tls_ciphers</a>", "<a href="postconf.5.html#smtp_tls_exclude_ciphers">smtp_tls_exclude_ciphers</a>", "<a href="postconf.5.html#smtp_tls_protocols">smtp_tls_protocols</a>",
+and
+"<a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a>" configuration parameters. When opportunistic
+TLS handshakes fail, Postfix retries the connection with TLS disabled.
 This allows mail delivery to sites with non-interoperable TLS
 implementations.</dd>
 
@@ -12714,9 +12743,11 @@ implementations.</dd>
 <dd>Mandatory TLS encryption. At this level
 and higher, the optional "protocols" attribute overrides the <a href="postconf.5.html">main.cf</a>
 <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> parameter, the optional "ciphers" attribute
-overrides the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> parameter, and the
+overrides the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> parameter, the
 optional "exclude" attribute (Postfix &ge; 2.6) overrides the <a href="postconf.5.html">main.cf</a>
-<a href="postconf.5.html#smtp_tls_mandatory_exclude_ciphers">smtp_tls_mandatory_exclude_ciphers</a> parameter. In the policy table,
+<a href="postconf.5.html#smtp_tls_mandatory_exclude_ciphers">smtp_tls_mandatory_exclude_ciphers</a> parameter, and the optional
+"connection_reuse" attribute (Postfix &ge; 3.4) overrides the
+<a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> parameter. In the policy table,
 multiple protocols or excluded ciphers must be separated by colons,
 as attribute values may not contain whitespace or commas. </dd>
 
@@ -12730,7 +12761,9 @@ href="TLS_README.html#client_tls_encrypt">encrypt</a>.  When usable
 TLSA records are obtained for the remote SMTP server, the
 server certificate must match the TLSA records.  <a href="http://tools.ietf.org/html/rfc7672">RFC 7672</a> (DANE)
 TLS authentication and DNSSEC support is available with Postfix
-2.11 and later.  </dd>
+2.11 and later. The optional "connection_reuse" attribute (Postfix
+&ge; 3.4) overrides the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> parameter.
+</dd>
 
 <dt><b><a href="TLS_README.html#client_tls_dane">dane-only</a></b></dt>
 <dd>Mandatory DANE TLS.  The TLS policy for the destination is
@@ -12739,7 +12772,9 @@ or none are usable, no connection is made to the server.  When
 usable TLSA records are obtained for the remote SMTP server, the
 server certificate must match the TLSA records.  <a href="http://tools.ietf.org/html/rfc7672">RFC 7672</a> (DANE) TLS
 authentication and DNSSEC support is available with Postfix 2.11
-and later.  </dd>
+and later. The optional "connection_reuse" attribute (Postfix &ge;
+3.4) overrides the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> parameter.
+</dd>
 
 <dt><b><a href="TLS_README.html#client_tls_fprint">fingerprint</a></b></dt>
 <dd>Certificate fingerprint
@@ -12755,7 +12790,8 @@ algorithm used to calculate the fingerprint is selected by the
 be combined with a "|" delimiter in a single match attribute, or multiple
 match attributes can be employed. The ":" character is not used as a
 delimiter as it occurs between each pair of fingerprint (hexadecimal)
-digits. </dd>
+digits. The optional "connection_reuse" attribute (Postfix &ge; 3.4)
+overrides the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> parameter. </dd>
 
 <dt><b><a href="TLS_README.html#client_tls_verify">verify</a></b></dt>
 <dd>Mandatory TLS verification.  At this security
@@ -12765,7 +12801,9 @@ unauthenticated DNS MX lookups.  The optional "match" attribute overrides
 the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_verify_cert_match">smtp_tls_verify_cert_match</a> parameter. In the policy table,
 multiple match patterns and strategies must be separated by colons.
 In practice explicit control over matching is more common with the
-"secure" policy, described below. </dd>
+"secure" policy, described below. The optional "connection_reuse"
+attribute (Postfix &ge; 3.4) overrides the <a href="postconf.5.html">main.cf</a>
+<a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> parameter. </dd>
 
 <dt><b><a href="TLS_README.html#client_tls_secure">secure</a></b></dt>
 <dd>Secure-channel TLS. At this security level, DNS
@@ -12783,7 +12821,9 @@ routing the secondary domains to the primary nexthop also allow secure
 verification, they risk delivery to the wrong destination when domains
 change hands or are re-assigned to new gateways. With the "match"
 attribute approach, routing is not perturbed, and mail is deferred if
-verification of a new MX host fails. </dd>
+verification of a new MX host fails. The optional "connection_reuse"
+attribute (Postfix &ge; 3.4) overrides the <a href="postconf.5.html">main.cf</a>
+<a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> parameter. </dd>
 
 </dl>
 
index 44dbd9eaa5dd9fac6c01ce4bf28d1f11651a81a6..780b5e26797aaaeba401e96953c16e538772d0b7 100644 (file)
@@ -280,17 +280,20 @@ POSTTLS-FINGER(1)                                            POSTTLS-FINGER(1)
               STARTTLS protocol.  The destination <i>domain</i>:<i>port</i> should of course
               provide such a service.
 
+       <b>-X</b>     Enable  <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a>  mode. This is an unsupported mode, for pro-
+              gram development only.
+
        [<b>inet:</b>]<i>domain</i>[:<i>port</i>]
               Connect via TCP to domain <i>domain</i>, port <i>port</i>. The default port is
-              <b>smtp</b> (or 24 with LMTP).  With SMTP an MX lookup is performed  to
-              resolve  the  domain to a host, unless the domain is enclosed in
-              <b>[]</b>.  If you want to connect to a specific MX host, for  instance
-              <i>mx1.example.com</i>,  specify  [<i>mx1.example.com</i>]  as the destination
+              <b>smtp</b>  (or 24 with LMTP).  With SMTP an MX lookup is performed to
+              resolve the domain to a host, unless the domain is  enclosed  in
+              <b>[]</b>.   If you want to connect to a specific MX host, for instance
+              <i>mx1.example.com</i>, specify [<i>mx1.example.com</i>]  as  the  destination
               and <i>example.com</i> as a <b>match</b> argument.  When using DNS, the desti-
-              nation  domain  is assumed fully qualified and no <a href="ADDRESS_CLASS_README.html#default_domain_class">default domain</a>
-              or search suffixes are applied;  you  must  use  fully-qualified
-              names  or  also  enable <b>native</b> host lookups (these don't support
-              <b>dane</b> or <b>dane-only</b> as no DNSSEC validation information is  avail-
+              nation domain is assumed fully qualified and no  default  domain
+              or  search  suffixes  are  applied; you must use fully-qualified
+              names or also enable <b>native</b> host lookups  (these  don't  support
+              <b>dane</b>  or <b>dane-only</b> as no DNSSEC validation information is avail-
               able via <b>native</b> lookups).
 
        <b>unix:</b><i>pathname</i>
@@ -299,8 +302,8 @@ POSTTLS-FINGER(1)                                            POSTTLS-FINGER(1)
        <b>match ...</b>
               With no match arguments specified, certificate peername matching
               uses the compiled-in default strategies for each security level.
-              If  you specify one or more arguments, these will be used as the
-              list of certificate or public-key digests to match for the  <b>fin-</b>
+              If you specify one or more arguments, these will be used as  the
+              list  of certificate or public-key digests to match for the <b>fin-</b>
               <b>gerprint</b> level, or as the list of DNS names to match in the cer-
               tificate at the <b>verify</b> and <b>secure</b> levels.  If the security level
               is <b>dane</b>, or <b>dane-only</b> the match names are ignored, and <b>hostname,</b>
@@ -329,6 +332,11 @@ POSTTLS-FINGER(1)                                            POSTTLS-FINGER(1)
        P.O. Box 704
        Yorktown Heights, NY 10598, USA
 
+       Wietse Venema
+       Google, Inc.
+       111 8th Avenue
+       New York, NY 10011, USA
+
        Viktor Dukhovni
 
                                                              POSTTLS-FINGER(1)
index e5e0259c74c242c969505f3c1fb71374c08757ca..2ac36e297d159a70195be1321be991ce251ff257 100644 (file)
@@ -573,6 +573,11 @@ SMTP(8)                                                                SMTP(8)
               nexthop destination security level is <b>dane</b>, but  the  MX  record
               was found via an "insecure" MX lookup.
 
+       Available in Postfix version 3.4 and later:
+
+       <b><a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> (no)</b>
+              Try to make multiple deliveries per TLS-encrypted connection.
+
 <b>OBSOLETE STARTTLS CONTROLS</b>
        The  following  configuration  parameters  exist for compatibility with
        Postfix versions before 2.3. Support for these will  be  removed  in  a
@@ -704,6 +709,11 @@ SMTP(8)                                                                SMTP(8)
               that  an SMTP session may be reused before it is closed, or zero
               (no limit).
 
+       Available in Postfix version 3.4 and later:
+
+       <b><a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> (no)</b>
+              Try to make multiple deliveries per TLS-encrypted connection.
+
        Implemented in the <a href="qmgr.8.html">qmgr(8)</a> daemon:
 
        <b>transport_destination_concurrency_limit   ($<a href="postconf.5.html#default_destination_concurrency_limit">default_destination_concur</a>-</b>
index de6084708779cc10fd30de45f7cb682b6d20c0f8..56b75c51c0a729e48c48a51f1aff826cc44ef75e 100644 (file)
@@ -13,34 +13,35 @@ TLSPROXY(8)                                                        TLSPROXY(8)
        <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. It is used
-       by <a href="postscreen.8.html"><b>postscreen</b>(8)</a> to talk SMTP-over-TLS with remote  SMTP  clients  that
-       are  not  whitelisted  (including  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  sessions  at  the
-       same  time,  it  is  a  good  idea  to allow the number of processes to
+       The  <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a>  server  implements a two-way TLS proxy. It is used by
+       the <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server to talk SMTP-over-TLS with remote SMTP clients
+       that  are not whitelisted (including clients whose whitelist status has
+       expired), and by the <a href="smtp.8.html"><b>smtp</b>(8)</a> client to support  TLS  connection  reuse,
+       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 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 responsive.
 
 <b>PROTOCOL EXAMPLE</b>
-       The example below  concerns  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>.  However,  the  <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a>
+       The  example  below  concerns  <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 protocol, and the example is eas-
        ily adapted to other applications.
 
-       After receiving a  valid  remote  SMTP  client  STARTTLS  command,  the
-       <a href="postscreen.8.html"><b>postscreen</b>(8)</a>  server sends the remote SMTP client endpoint 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
+       After  receiving  a  valid  remote  SMTP  client  STARTTLS command, the
+       <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server sends the remote SMTP client endpoint 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 plain-
        text 220 greeting to the remote SMTP client.  This triggers TLS negoti-
        ations 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
+       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
+       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>
@@ -48,26 +49,26 @@ TLSPROXY(8)                                                        TLSPROXY(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> pro-
-       cesses may run for a long time depending on mail server load.  Use  the
+       cesses  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
+       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
+              A  file  containing  (PEM  format)  CA  certificates of root CAs
               trusted to sign either remote SMTP client certificates or inter-
               mediate 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
+              A  directory containing (PEM format) CA certificates of root CAs
               trusted to sign either remote SMTP client certificates or inter-
               mediate CA certificates.
 
        <b><a href="postconf.5.html#tlsproxy_tls_always_issue_session_ids">tlsproxy_tls_always_issue_session_ids</a>     ($<a href="postconf.5.html#smtpd_tls_always_issue_session_ids">smtpd_tls_always_issue_ses</a>-</b>
        <b><a href="postconf.5.html#smtpd_tls_always_issue_session_ids">sion_ids</a>)</b>
-              Force the Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server to issue a TLS session  id,
+              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>
@@ -77,7 +78,7 @@ TLSPROXY(8)                                                        TLSPROXY(8)
               The verification depth for remote SMTP client certificates.
 
        <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 certificate in PEM
+              File with the Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server RSA certificate 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>
@@ -85,47 +86,47 @@ TLSPROXY(8)                                                        TLSPROXY(8)
               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 certificate in PEM
+              File with the Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server DSA certificate in  PEM
               format.
 
        <b><a href="postconf.5.html#tlsproxy_tls_dh1024_param_file">tlsproxy_tls_dh1024_param_file</a> ($<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
+              File  with  DH  parameters  that  the Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server
               should use with non-export EDH ciphers.
 
        <b><a href="postconf.5.html#tlsproxy_tls_dh512_param_file">tlsproxy_tls_dh512_param_file</a> ($<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
+              File with DH parameters  that  the  Postfix  <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a>  server
               should use with export-grade 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 private key in  PEM
+              File  with the Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server DSA private 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 certificate in
+              File with the Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server  ECDSA  certificate  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  private  key  in
+              File  with  the  Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server ECDSA private 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
+              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>
+              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_fingerprint_digest</a>)</b>
-              The   message   digest   algorithm   to  construct  remote  SMTP
+              The  message  digest  algorithm   to   construct   remote   SMTP
               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 private key in  PEM
+              File  with the Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server RSA private 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  logging of TLS
+              Enable additional Postfix  <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a>  server  logging  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_mandatory_ciphers</a>)</b>
@@ -134,7 +135,7 @@ TLSPROXY(8)                                                        TLSPROXY(8)
 
        <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
+              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_mandatory_protocols</a>)</b>
@@ -142,15 +143,15 @@ TLSPROXY(8)                                                        TLSPROXY(8)
               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
+              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
+              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;
+              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 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>.
 
@@ -160,11 +161,11 @@ TLSPROXY(8)                                                        TLSPROXY(8)
               The name of the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a> service entry in <a href="master.5.html">master.cf</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
+       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  remote  SMTP
+              Opportunistic  TLS:  announce  STARTTLS  support  to remote 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>
@@ -178,7 +179,7 @@ TLSPROXY(8)                                                        TLSPROXY(8)
 
 <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>  con-
+              The  default  location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
               figuration files.
 
        <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
@@ -191,7 +192,7 @@ TLSPROXY(8)                                                        TLSPROXY(8)
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
-              A  prefix  that  is  prepended  to  the  process  name in syslog
+              A prefix that  is  prepended  to  the  process  name  in  syslog
               records, so that, for example, "smtpd" becomes "prefix/smtpd".
 
        Available in Postfix 3.3 and later:
index ca773102a01916fb8feeb66e8df5a9b875828251..1ba35da25d8a6b09d4e2e4b3a846363bc65beba4 100644 (file)
@@ -251,6 +251,9 @@ provided on port 465 by servers that are compatible with the ad\-hoc
 SMTP in SSL protocol, rather than the standard STARTTLS protocol.
 The destination \fIdomain\fR:\fIport\fR should of course provide such
 a service.
+.IP "\fB\-X\fR"
+Enable \fBtlsproxy\fR(8) mode. This is an unsupported mode,
+for program development only.
 .IP "[\fBinet:\fR]\fIdomain\fR[:\fIport\fR]"
 Connect via TCP to domain \fIdomain\fR, port \fIport\fR. The default
 port is \fBsmtp\fR (or 24 with LMTP).  With SMTP an MX lookup is
@@ -315,4 +318,9 @@ IBM T.J. Watson Research
 P.O. Box 704
 Yorktown Heights, NY 10598, USA
 
+Wietse Venema
+Google, Inc.
+111 8th Avenue
+New York, NY 10011, USA
+
 Viktor Dukhovni
index b2dff862ea9d67a09ed10975916d79f756b40581..e3c510f80b6bc309057d20c9cc534776770f3803 100644 (file)
@@ -3101,6 +3101,11 @@ The LMTP\-specific version of the smtp_tls_ciphers configuration
 parameter. See there for details.
 .PP
 This feature is available in Postfix 2.6 and later.
+.SH lmtp_tls_connection_reuse (default: no)
+The LMTP\-specific version of the smtp_tls_connection_reuse configuration
+parameter. See there for details.
+.PP
+This feature is available in Postfix 3.4 and later.
 .SH lmtp_tls_dcert_file (default: empty)
 The LMTP\-specific version of the smtp_tls_dcert_file
 configuration parameter.  See there for details.
@@ -7593,6 +7598,16 @@ ciphers on a per\-destination basis.
 This feature is available in Postfix 2.6 and later. With earlier Postfix
 releases only the smtp_tls_mandatory_ciphers parameter is implemented,
 and opportunistic TLS always uses "export" or better (i.e. all) ciphers.
+.SH smtp_tls_connection_reuse (default: no)
+Try to make multiple deliveries per TLS\-encrypted connection.
+This uses the \fBtlsproxy\fR(8) service to encrypt an SMTP connection,
+uses the \fBscache\fR(8) service to save that connection, and relies on
+hints from the \fBqmgr\fR(8) daemon.
+.PP
+See "Client\-side
+TLS connection reuse" for background details.
+.PP
+This feature is available in Postfix 3.4 and later.
 .SH smtp_tls_dane_insecure_mx_policy (default: dane)
 The TLS policy for MX hosts with "secure" TLSA records when the
 nexthop destination security level is \fBdane\fR, but the MX
@@ -8235,11 +8250,13 @@ No TLS. No additional attributes are supported at this level.
 .IP "\fBmay\fR"
 Opportunistic TLS. Since sending in the clear is acceptable,
 demanding stronger than default TLS security merely reduces
-interoperability. The optional "ciphers", "exclude" and "protocols"
+interoperability. The optional "ciphers", "exclude", and "protocols"
 attributes (available for opportunistic TLS with Postfix >= 2.6)
-override the "smtp_tls_ciphers", "smtp_tls_exclude_ciphers" and
-"smtp_tls_protocols" configuration parameters. When opportunistic TLS
-handshakes fail, Postfix retries the connection with TLS disabled.
+and "connection_reuse" attribute (Postfix >= 3.4) override the
+"smtp_tls_ciphers", "smtp_tls_exclude_ciphers", "smtp_tls_protocols",
+and
+"smtp_tls_connection_reuse" configuration parameters. When opportunistic
+TLS handshakes fail, Postfix retries the connection with TLS disabled.
 This allows mail delivery to sites with non\-interoperable TLS
 implementations.
 .br
@@ -8247,9 +8264,11 @@ implementations.
 Mandatory TLS encryption. At this level
 and higher, the optional "protocols" attribute overrides the main.cf
 smtp_tls_mandatory_protocols parameter, the optional "ciphers" attribute
-overrides the main.cf smtp_tls_mandatory_ciphers parameter, and the
+overrides the main.cf smtp_tls_mandatory_ciphers parameter, the
 optional "exclude" attribute (Postfix >= 2.6) overrides the main.cf
-smtp_tls_mandatory_exclude_ciphers parameter. In the policy table,
+smtp_tls_mandatory_exclude_ciphers parameter, and the optional
+"connection_reuse" attribute (Postfix >= 3.4) overrides the
+main.cf smtp_tls_connection_reuse parameter. In the policy table,
 multiple protocols or excluded ciphers must be separated by colons,
 as attribute values may not contain whitespace or commas.
 .br
@@ -8261,7 +8280,8 @@ found, but none are usable, the effective security level is encrypt.  When usabl
 TLSA records are obtained for the remote SMTP server, the
 server certificate must match the TLSA records.  RFC 7672 (DANE)
 TLS authentication and DNSSEC support is available with Postfix
-2.11 and later.
+2.11 and later. The optional "connection_reuse" attribute (Postfix
+>= 3.4) overrides the main.cf smtp_tls_connection_reuse parameter.
 .br
 .IP "\fBdane\-only\fR"
 Mandatory DANE TLS.  The TLS policy for the destination is
@@ -8270,7 +8290,8 @@ or none are usable, no connection is made to the server.  When
 usable TLSA records are obtained for the remote SMTP server, the
 server certificate must match the TLSA records.  RFC 7672 (DANE) TLS
 authentication and DNSSEC support is available with Postfix 2.11
-and later.
+and later. The optional "connection_reuse" attribute (Postfix >=
+3.4) overrides the main.cf smtp_tls_connection_reuse parameter.
 .br
 .IP "\fBfingerprint\fR"
 Certificate fingerprint
@@ -8286,7 +8307,8 @@ algorithm used to calculate the fingerprint is selected by the
 be combined with a "|" delimiter in a single match attribute, or multiple
 match attributes can be employed. The ":" character is not used as a
 delimiter as it occurs between each pair of fingerprint (hexadecimal)
-digits.
+digits. The optional "connection_reuse" attribute (Postfix >= 3.4)
+overrides the main.cf smtp_tls_connection_reuse parameter.
 .br
 .IP "\fBverify\fR"
 Mandatory TLS verification.  At this security
@@ -8296,7 +8318,9 @@ unauthenticated DNS MX lookups.  The optional "match" attribute overrides
 the main.cf smtp_tls_verify_cert_match parameter. In the policy table,
 multiple match patterns and strategies must be separated by colons.
 In practice explicit control over matching is more common with the
-"secure" policy, described below.
+"secure" policy, described below. The optional "connection_reuse"
+attribute (Postfix >= 3.4) overrides the main.cf
+smtp_tls_connection_reuse parameter.
 .br
 .IP "\fBsecure\fR"
 Secure\-channel TLS. At this security level, DNS
@@ -8314,7 +8338,9 @@ routing the secondary domains to the primary nexthop also allow secure
 verification, they risk delivery to the wrong destination when domains
 change hands or are re\-assigned to new gateways. With the "match"
 attribute approach, routing is not perturbed, and mail is deferred if
-verification of a new MX host fails.
+verification of a new MX host fails. The optional "connection_reuse"
+attribute (Postfix >= 3.4) overrides the main.cf
+smtp_tls_connection_reuse parameter.
 .br
 .br
 .PP
index f3f24c5b88306f64e5bac7e51beba06e72a7cbf5..08563720d2ecd9243cd7a0a2460923d5255999f6 100644 (file)
@@ -508,6 +508,10 @@ Available in Postfix version 3.1 and later:
 The TLS policy for MX hosts with "secure" TLSA records when the
 nexthop destination security level is \fBdane\fR, but the MX
 record was found via an "insecure" MX lookup.
+.PP
+Available in Postfix version 3.4 and later:
+.IP "\fBsmtp_tls_connection_reuse (no)\fR"
+Try to make multiple deliveries per TLS\-encrypted connection.
 .SH "OBSOLETE STARTTLS CONTROLS"
 .na
 .nf
@@ -618,6 +622,10 @@ When SMTP connection caching is enabled, the number of times
 that an SMTP session may be reused before it is closed, or zero (no
 limit).
 .PP
+Available in Postfix version 3.4 and later:
+.IP "\fBsmtp_tls_connection_reuse (no)\fR"
+Try to make multiple deliveries per TLS\-encrypted connection.
+.PP
 Implemented in the qmgr(8) daemon:
 .IP "\fBtransport_destination_concurrency_limit ($default_destination_concurrency_limit)\fR"
 A transport\-specific override for the
index 2d439ac28b59f14e2f3999b150867bd85459e8a0..88a022a7c7037d3257f77e0af922ca3d6b04b9be 100644 (file)
@@ -12,11 +12,12 @@ Postfix TLS proxy
 .SH DESCRIPTION
 .ad
 .fi
-The \fBtlsproxy\fR(8) server implements a server\-side TLS
-proxy. It is used by \fBpostscreen\fR(8) to talk SMTP\-over\-TLS
+The \fBtlsproxy\fR(8) server implements a two\-way TLS proxy. It
+is used by the \fBpostscreen\fR(8) server to talk SMTP\-over\-TLS
 with remote SMTP clients that are not whitelisted (including
-clients whose whitelist status has expired),
-but it should also work for non\-SMTP protocols.
+clients whose whitelist status has expired), and by the
+\fBsmtp\fR(8) client to support TLS connection reuse, 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
index 4f07119a1098541422338e84e1579248a5cace40..77abb31ba7b4aeee440785f16f1049e323e45fcd 100755 (executable)
@@ -690,6 +690,8 @@ while (<>) {
     s;\bsmtp_per_record_deadline\b;<a href="postconf.5.html#smtp_per_record_deadline">$&</a>;g;
     s;\bsmtp_send_dummy_mail_auth\b;<a href="postconf.5.html#smtp_send_dummy_mail_auth">$&</a>;g;
     s;\bsmtp_balance_inet_protocols\b;<a href="postconf.5.html#smtp_balance_inet_protocols">$&</a>;g;
+    s;\bsmtp_tls_connection_reuse\b;<a href="postconf.5.html#smtp_tls_connection_reuse">$&</a>;g;
+    s;\blmtp_tls_connection_reuse\b;<a href="postconf.5.html#lmtp_tls_connection_reuse">$&</a>;g;
     s;\bsmtpd_enforce_tls\b;<a href="postconf.5.html#smtpd_enforce_tls">$&</a>;g;
     s;\bsmtpd_sasl_tls_security_options\b;<a href="postconf.5.html#smtpd_sasl_tls_security_options">$&</a>;g;
     s;\bsmtpd_sasl_type\b;<a href="postconf.5.html#smtpd_sasl_type">$&</a>;g;
index ef10848cbf89473c41fc2d49234a3947313afad2..7dd80c7137f95eb954176ea9bcc6c63026e9ae94 100644 (file)
 <p> This document describes the Postfix connection cache implementation,
 which is available with Postfix version 2.2 and later. </p>
 
+<p> See <a href="TLS_README.html#client_tls_reuse">Client-side TLS
+connection reuse</a> for how this connection cache is used to
+implement multiple deliveries per TLS-encrypted connection. </p>
+
 <p> Topics covered in this document: </p>
 
 <ul>
index 8d291ea2d4dc65a6a9816c312441edc5591739c8..4a1c6b8b111f7d3cdd32b941ba4c712a3ca85a98 100644 (file)
@@ -992,6 +992,8 @@ solution.  </p>
 <li><a href="#client_cert_key">Client-side certificate and private
 key configuration </a>
 
+<li><a href="#client_tls_reuse">Client-side TLS connection reuse</a>
+
 <li><a href="#client_tls_cache">Client-side TLS session cache</a>
 
 <li><a href="#client_tls_limits"> Client TLS limitations </a>
@@ -1908,6 +1910,49 @@ when the certificate is needed.  </p>
 </pre>
 </blockquote>
 
+<h3><a name="client_tls_reuse">Client-side TLS connection reuse</a> </h3>
+
+<p> Historically, the Postfix SMTP client has supported multiple
+deliveries per connection only for plaintext connections. Postfix
+3.4 introduces the ability to make multiple deliveries per TLS-encrypted
+connection. This is primarily to improve mail delivery performance
+for destinations that throttle clients when they don't combine
+deliveries. </p>
+
+<p> To enable multiple deliveries per TLS connection, specify:</p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+    smtp_tls_connection_reuse = yes
+</pre>
+</blockquote>
+
+<p> Alternatively, specify the attribute "connection_reuse=yes" in
+an smtp_tls_policy_maps entry. </p>
+
+<p> The implementation of TLS connection reuse relies on the same
+scache(8) service as used for delivering plaintext SMTP mail, the
+same tlsproxy(8) daemon as used by the postscreen(8) service, and
+relies on the same hints from the qmgr(8) daemon.
+
+See "<a href="CONNECTION_CACHE_README.html">Postfix Connection
+Cache</a>" for a description of the underlying connection reuse
+infrastructure.  </p>
+
+<p> Initial SMTP handshake:</p>
+<pre>    smtp(8) -&gt; remote SMTP server</pre>
+
+<p> Reused SMTP/TLS connection, or new SMTP/TLS connection: </p>
+<pre>    smtp(8) -&gt; tlsproxy(8) -&gt; remote SMTP server </pre>
+
+<p> Cached SMTP/TLS connection:</p>
+<pre>    scache(8) -&gt; tlsproxy(8) -&gt; remote SMTP server</pre>
+
+<p> As of Postfix 3.4, TLS connection reuse is disabled by default.
+This may change once the impact on over-all performance is undestood.
+</p>
+
 <h3><a name="client_tls_cache">Client-side TLS session cache</a> </h3>
 
 <p> The remote SMTP server and the Postfix SMTP client negotiate a
index 23f4f63e6a91af80fe3da5ec7b9782481ca677f3..f458093856dd9c31061763fbdd5dbae76add14b0 100644 (file)
@@ -11050,11 +11050,13 @@ security are: </p>
 <dt><b><a href="TLS_README.html#client_tls_may">may</a></b></dt>
 <dd>Opportunistic TLS. Since sending in the clear is acceptable,
 demanding stronger than default TLS security merely reduces
-interoperability. The optional "ciphers", "exclude" and "protocols"
+interoperability. The optional "ciphers", "exclude", and "protocols"
 attributes (available for opportunistic TLS with Postfix &ge; 2.6)
-override the "smtp_tls_ciphers", "smtp_tls_exclude_ciphers" and
-"smtp_tls_protocols" configuration parameters. When opportunistic TLS
-handshakes fail, Postfix retries the connection with TLS disabled.
+and "connection_reuse" attribute (Postfix &ge; 3.4) override the
+"smtp_tls_ciphers", "smtp_tls_exclude_ciphers", "smtp_tls_protocols",
+and
+"smtp_tls_connection_reuse" configuration parameters. When opportunistic
+TLS handshakes fail, Postfix retries the connection with TLS disabled.
 This allows mail delivery to sites with non-interoperable TLS
 implementations.</dd>
 
@@ -11062,9 +11064,11 @@ implementations.</dd>
 <dd>Mandatory TLS encryption. At this level
 and higher, the optional "protocols" attribute overrides the main.cf
 smtp_tls_mandatory_protocols parameter, the optional "ciphers" attribute
-overrides the main.cf smtp_tls_mandatory_ciphers parameter, and the
+overrides the main.cf smtp_tls_mandatory_ciphers parameter, the
 optional "exclude" attribute (Postfix &ge; 2.6) overrides the main.cf
-smtp_tls_mandatory_exclude_ciphers parameter. In the policy table,
+smtp_tls_mandatory_exclude_ciphers parameter, and the optional
+"connection_reuse" attribute (Postfix &ge; 3.4) overrides the
+main.cf smtp_tls_connection_reuse parameter. In the policy table,
 multiple protocols or excluded ciphers must be separated by colons,
 as attribute values may not contain whitespace or commas. </dd>
 
@@ -11078,7 +11082,9 @@ href="TLS_README.html#client_tls_encrypt">encrypt</a>.  When usable
 TLSA records are obtained for the remote SMTP server, the
 server certificate must match the TLSA records.  RFC 7672 (DANE)
 TLS authentication and DNSSEC support is available with Postfix
-2.11 and later.  </dd>
+2.11 and later. The optional "connection_reuse" attribute (Postfix
+&ge; 3.4) overrides the main.cf smtp_tls_connection_reuse parameter.
+</dd>
 
 <dt><b><a href="TLS_README.html#client_tls_dane">dane-only</a></b></dt>
 <dd>Mandatory DANE TLS.  The TLS policy for the destination is
@@ -11087,7 +11093,9 @@ or none are usable, no connection is made to the server.  When
 usable TLSA records are obtained for the remote SMTP server, the
 server certificate must match the TLSA records.  RFC 7672 (DANE) TLS
 authentication and DNSSEC support is available with Postfix 2.11
-and later.  </dd>
+and later. The optional "connection_reuse" attribute (Postfix &ge;
+3.4) overrides the main.cf smtp_tls_connection_reuse parameter.
+</dd>
 
 <dt><b><a href="TLS_README.html#client_tls_fprint">fingerprint</a></b></dt>
 <dd>Certificate fingerprint
@@ -11103,7 +11111,8 @@ algorithm used to calculate the fingerprint is selected by the
 be combined with a "|" delimiter in a single match attribute, or multiple
 match attributes can be employed. The ":" character is not used as a
 delimiter as it occurs between each pair of fingerprint (hexadecimal)
-digits. </dd>
+digits. The optional "connection_reuse" attribute (Postfix &ge; 3.4)
+overrides the main.cf smtp_tls_connection_reuse parameter. </dd>
 
 <dt><b><a href="TLS_README.html#client_tls_verify">verify</a></b></dt>
 <dd>Mandatory TLS verification.  At this security
@@ -11113,7 +11122,9 @@ unauthenticated DNS MX lookups.  The optional "match" attribute overrides
 the main.cf smtp_tls_verify_cert_match parameter. In the policy table,
 multiple match patterns and strategies must be separated by colons.
 In practice explicit control over matching is more common with the
-"secure" policy, described below. </dd>
+"secure" policy, described below. The optional "connection_reuse"
+attribute (Postfix &ge; 3.4) overrides the main.cf
+smtp_tls_connection_reuse parameter. </dd>
 
 <dt><b><a href="TLS_README.html#client_tls_secure">secure</a></b></dt>
 <dd>Secure-channel TLS. At this security level, DNS
@@ -11131,7 +11142,9 @@ routing the secondary domains to the primary nexthop also allow secure
 verification, they risk delivery to the wrong destination when domains
 change hands or are re-assigned to new gateways. With the "match"
 attribute approach, routing is not perturbed, and mail is deferred if
-verification of a new MX host fails. </dd>
+verification of a new MX host fails. The optional "connection_reuse"
+attribute (Postfix &ge; 3.4) overrides the main.cf
+smtp_tls_connection_reuse parameter. </dd>
 
 </dl>
 
@@ -16582,6 +16595,25 @@ Postfix versions. </p>
 
 <p> This feature is available in Postfix 3.0 and later.  </p>
 
+%PARAM smtp_tls_connection_reuse no
+
+<p> Try to make multiple deliveries per TLS-encrypted connection.
+This uses the tlsproxy(8) service to encrypt an SMTP connection,
+uses the scache(8) service to save that connection, and relies on
+hints from the qmgr(8) daemon. </p>
+
+<p> See "<a href="TLS_README.html#client_tls_reuse">Client-side
+TLS connection reuse</a>" for background details. </p>
+
+<p> This feature is available in Postfix 3.4 and later.  </p>
+
+%PARAM lmtp_tls_connection_reuse no
+
+<p> The LMTP-specific version of the smtp_tls_connection_reuse configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 3.4 and later. </p>
+
 %PARAM virtual_alias_address_length_limit 1000
 
 <p>
index dd2589fe0aecdd9e2906b67ef0a2ad756410fe5b..211d7cf744adab88bf4143ccae97db50eb2dc451 100644 (file)
@@ -4008,6 +4008,15 @@ extern char *var_smtp_dns_re_filter;
 #define DEF_SMTPD_DNS_RE_FILTER                ""
 extern char *var_smtpd_dns_re_filter;
 
+ /*
+  * Share TLS sessions through tlproxy(8).
+  */
+#define VAR_SMTP_TLS_CONN_REUSE                "smtp_tls_connection_reuse"
+#define DEF_SMTP_TLS_CONN_REUSE                0
+#define VAR_LMTP_TLS_CONN_REUSE                "lmtp_tls_connection_reuse"
+#define DEF_LMTP_TLS_CONN_REUSE                0
+extern bool var_smtp_tls_conn_reuse;
+
  /*
   * Location of shared-library files.
   * 
index 363bc71ec84d0510ada614ea91217846ead322cc..9fc9ab68eaea59784d9db152439858ed68979961 100644 (file)
@@ -276,25 +276,6 @@ extern char *mail_pathname(const char *, const char *);
 #define MAIL_ATTR_DSN_ORCPT    "dsn_orig_rcpt" /* dsn original recipient */
 #define MAIL_ATTR_SMTPUTF8     "smtputf8"      /* RFC6531 support */
 
- /*
-  * TLSPROXY 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"
-#define MAIL_ATTR_PEER_CN      "peer_CN"
-#define MAIL_ATTR_ISSUER_CN    "issuer_CN"
-#define MAIL_ATTR_PEER_CERT_FPT        "peer_fingerprint"
-#define MAIL_ATTR_PEER_PKEY_FPT        "peer_pubkey_fingerprint"
-#define MAIL_ATTR_PEER_STATUS  "peer_status"
-#define MAIL_ATTR_CIPHER_PROTOCOL "cipher_protocol"
-#define MAIL_ATTR_CIPHER_NAME  "cipher_name"
-#define MAIL_ATTR_CIPHER_USEBITS "cipher_usebits"
-#define MAIL_ATTR_CIPHER_ALGBITS "cipher_algbits"
-#define MAIL_ATTR_SERVER_ID    "server_id"
-
  /*
   * SMTP reply footer support.
   */
index ae82be407d07a39ef5c91b6eaf5d824c496398f9..762261a23bacef82d4f28767c9a7824ffc76b334 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      "20180603"
+#define MAIL_RELEASE_DATE      "20180617"
 #define MAIL_VERSION_NUMBER    "3.4"
 
 #ifdef SNAPSHOT
index d4f01bf714bc829841a884cf0ca0f836a28d4f8a..d31bc6bd54707d6251004f45e6db19ad5cca63fd 100644 (file)
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
 /* System library. */
index c97cef39bf1557c17614e32e12f0b5608385b7b4..e643aad6882254e5d2d83516e3609e79f4e27167 100644 (file)
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
 /* System library. */
index 64a394d1d3c001d33e63afb353ce4ab205d05864..56a3072b7fb737ec1851831ed01110bc1f9ffe51 100644 (file)
@@ -134,4 +134,9 @@ extern NORETURN trigger_server_main(int, char **, TRIGGER_SERVER_FN,...);
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
index 60f5f81ec5156ea1fc1d3ce79346178575f9a815..55bdf74db78bcfffe3211b8fea70d35a6a3a1ab0 100644 (file)
@@ -237,4 +237,9 @@ extern int master_monitor(int);
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
index 0560b1ab3efa05f9225fb5c4f1dae7c65639e0de..db5e39d2f2516504219331be9f4351a6816ee27c 100644 (file)
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
 /* System libraries. */
index a5d6906e695ca42049c524200cb67e15a9cce627..3056d7130b94a7198758e9242b7721f4a6fc9eae 100644 (file)
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
 /* System library. */
@@ -226,10 +231,11 @@ void    psc_starttls_open(PSC_STATE *smtp_state, EVENT_NOTIFY_FN resume_event)
     vstring_sprintf(remote_endpt, "[%s]:%s", smtp_state->smtp_client_addr,
                    smtp_state->smtp_client_port);
     attr_print(tlsproxy_stream, ATTR_FLAG_NONE,
-              SEND_ATTR_STR(MAIL_ATTR_REMOTE_ENDPT, STR(remote_endpt)),
-              SEND_ATTR_INT(MAIL_ATTR_FLAGS, TLS_PROXY_FLAG_ROLE_SERVER),
-              SEND_ATTR_INT(MAIL_ATTR_TIMEOUT, psc_normal_cmd_time_limit),
-              SEND_ATTR_STR(MAIL_ATTR_SERVER_ID, MAIL_SERVICE_SMTPD),  /* XXX */
+              SEND_ATTR_STR(TLS_ATTR_REMOTE_ENDPT, STR(remote_endpt)),
+              SEND_ATTR_INT(TLS_ATTR_FLAGS, TLS_PROXY_FLAG_ROLE_SERVER),
+              SEND_ATTR_INT(TLS_ATTR_TIMEOUT, psc_normal_cmd_time_limit),
+              SEND_ATTR_INT(TLS_ATTR_TIMEOUT, psc_normal_cmd_time_limit),
+              SEND_ATTR_STR(TLS_ATTR_SERVERID, MAIL_SERVICE_SMTPD),    /* XXX */
               ATTR_TYPE_END);
     if (vstream_fflush(tlsproxy_stream) != 0) {
        msg_warn("error sending request to %s service: %m", psc_tlsp_service);
index 5f559b4fd06d8bdc6510077b5b16864315d1e723..6162f77a97266a996fd56d959300bbb8043a8915 100644 (file)
 /*     SMTP in SSL protocol, rather than the standard STARTTLS protocol.
 /*     The destination \fIdomain\fR:\fIport\fR should of course provide such
 /*     a service.
+/* .IP "\fB-X\fR"
+/*     Enable \fBtlsproxy\fR(8) mode. This is an unsupported mode,
+/*     for program development only.
 /* .IP "[\fBinet:\fR]\fIdomain\fR[:\fIport\fR]"
 /*     Connect via TCP to domain \fIdomain\fR, port \fIport\fR. The default
 /*     port is \fBsmtp\fR (or 24 with LMTP).  With SMTP an MX lookup is
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
 /*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*
 /*     Viktor Dukhovni
 /*--*/
 
 #include <smtp_stream.h>
 #include <dsn_buf.h>
 #include <mail_parm_split.h>
+#include <mail_proto.h>
 
 /* DNS library. */
 
 #include <tls.h>
 
 #ifdef USE_TLS
+#include <tls_proxy.h>
 #include <openssl/engine.h>
 #endif
 
@@ -431,6 +441,7 @@ typedef struct STATE {
     int     force_tlsa;                        /* -f option */
     unsigned port;                     /* TCP port */
     char   *dest;                      /* Full destination spec */
+    char   *paddr;                     /* XXX printable addr for proxy */
     char   *addrport;                  /* [addr]:port */
     char   *namaddrport;               /* name[addr]:port */
     char   *nexthop;                   /* Nexthop domain for verification */
@@ -461,6 +472,7 @@ typedef struct STATE {
     char   *grade;                     /* Minimum cipher grade */
     char   *protocols;                 /* Protocol inclusion/exclusion */
     int     mxinsec_level;             /* DANE for insecure MX RRs? */
+    int     tlsproxy_mode;
 #endif
     OPTIONS options;                   /* JCL */
 } STATE;
@@ -699,7 +711,11 @@ static int starttls(STATE *state)
     int     except;
     RESPONSE *resp;
     VSTREAM *stream = state->stream;
-    TLS_CLIENT_START_PROPS tls_props;
+    TLS_CLIENT_START_PROPS start_props;
+    TLS_CLIENT_INIT_PROPS init_props;
+    VSTREAM *tlsproxy;
+    VSTRING *port_buf;
+    int     cwd_fd;
 
     if (state->wrapper_mode == 0) {
        /* SMTP stream with deadline timeouts */
@@ -743,24 +759,138 @@ static int starttls(STATE *state)
     else
        ADD_EXCLUDE(cipher_exclusions, "eNULL");
 
-    state->tls_context =
-       TLS_CLIENT_START(&tls_props,
-                        ctx = state->tls_ctx,
-                        stream = stream,
-                        timeout = smtp_tmout,
-                        tls_level = state->level,
-                        nexthop = state->nexthop,
-                        host = state->hostname,
-                        namaddr = state->namaddrport,
-                        serverid = state->addrport,
-                        helo = state->helo ? state->helo : "",
-                        protocols = state->protocols,
-                        cipher_grade = state->grade,
-                        cipher_exclusions
-                        = vstring_str(cipher_exclusions),
-                        matchargv = state->match,
-                        mdalg = state->mdalg,
-                        dane = state->ddane ? state->ddane : state->dane);
+    if (state->tlsproxy_mode) {
+
+       /*
+        * Send all our wishes in one big request.
+        */
+       TLS_PROXY_CLIENT_INIT_PROPS(&init_props,
+                                   log_param = "-L option",
+                                   log_level = state->options.logopts,
+                                   verifydepth = DEF_SMTP_TLS_SCERT_VD,
+                                   cache_type = "memory",
+                                   cert_file = state->certfile,
+                                   key_file = state->keyfile,
+                                   dcert_file = "",
+                                   dkey_file = "",
+                                   eccert_file = "",
+                                   eckey_file = "",
+                                   CAfile = state->CAfile,
+                                   CApath = state->CApath,
+                                   mdalg = state->mdalg);
+       TLS_PROXY_CLIENT_START_PROPS(&start_props,
+                                    timeout = smtp_tmout,
+                                    tls_level = state->level,
+                                    nexthop = state->nexthop,
+                                    host = state->hostname,
+                                    namaddr = state->namaddrport,
+                                    serverid = state->addrport,
+                                    helo = state->helo ? state->helo : "",
+                                    protocols = state->protocols,
+                                    cipher_grade = state->grade,
+                                    cipher_exclusions
+                                    = vstring_str(cipher_exclusions),
+                                    matchargv = state->match,
+                                    mdalg = state->mdalg,
+                                    dane = state->ddane ?
+                                    state->ddane : state->dane);
+
+#define PROXY_OPEN_FLAGS \
+        (TLS_PROXY_FLAG_ROLE_CLIENT | TLS_PROXY_FLAG_SEND_CONTEXT)
+#define var_tlsproxy_service
+
+       if ((cwd_fd = open(".", O_RDONLY)) < 0)
+           msg_fatal("open(\".\", O_RDONLY): %m");
+       if (chdir(var_queue_dir) < 0)
+           msg_fatal("chdir(%s): %m", var_queue_dir);
+       port_buf = vstring_alloc(100);
+       vstring_sprintf(port_buf, "%d", ntohs(state->port));
+       tlsproxy =
+           tls_proxy_open(DEF_TLSPROXY_SERVICE /* TODO */ , PROXY_OPEN_FLAGS,
+                          state->stream, state->paddr,
+                          STR(port_buf), smtp_tmout, smtp_tmout,
+                          state->addrport, &init_props, &start_props);
+       vstring_free(port_buf);
+       if (fchdir(cwd_fd) < 0)
+           msg_fatal("fchdir: %m");
+       (void) close(cwd_fd);
+
+       /*
+        * To insert tlsproxy(8) between this process and the remote SMTP
+        * server, we swap the file descriptors between the tlsproxy and
+        * session->stream VSTREAMS, so that we don't lose all the
+        * user-configurable session->stream attributes (such as longjump
+        * buffers or timeouts).
+        * 
+        * TODO: the tlsproxy RPCs should return more error detail than a "NO"
+        * result.
+        */
+       if (tlsproxy == 0) {
+           state->tls_context = 0;
+       } else {
+           vstream_control(tlsproxy,
+                           CA_VSTREAM_CTL_DOUBLE,
+                           CA_VSTREAM_CTL_END);
+           vstream_control(state->stream,
+                           CA_VSTREAM_CTL_SWAP_FD(tlsproxy),
+                           CA_VSTREAM_CTL_END);
+           (void) vstream_fclose(tlsproxy);    /* direct-to-server stream! */
+
+           /*
+            * There must not be any pending data in the stream buffers
+            * before we read the TLS context attributes.
+            */
+           vstream_fpurge(state->stream, VSTREAM_PURGE_BOTH);
+
+           /*
+            * After plumbing the plaintext stream, receive the TLS context
+            * object. For this we use the same VSTREAM buffer that we also
+            * use to receive subsequent SMTP commands, therefore we must be
+            * prepared for the possibility that the remote SMTP server
+            * starts talking immediately. The tlsproxy implementation sends
+            * the TLS context before remote content. The attribute protocol
+            * is robust enough that an adversary cannot insert their own TLS
+            * context attributes.
+            */
+           state->tls_context = tls_proxy_context_receive(state->stream);
+           msg_info("%s: subject_CN=%s, issuer_CN=%s, "
+                    "fingerprint=%s, pkey_fingerprint=%s",
+                    state->namaddrport, state->tls_context->peer_CN,
+                    state->tls_context->issuer_CN,
+                    state->tls_context->peer_cert_fprint,
+                    state->tls_context->peer_pkey_fprint);
+           msg_info("%s TLS connection established to %s: %s with cipher %s "
+                    "(%d/%d bits)",
+                    !TLS_CERT_IS_PRESENT(state->tls_context) ? "Anonymous" :
+                    TLS_CERT_IS_SECURED(state->tls_context) ? "Verified" :
+                    TLS_CERT_IS_TRUSTED(state->tls_context) ? "Trusted" :
+                    "Untrusted", state->namaddrport,
+                    state->tls_context->protocol,
+                    state->tls_context->cipher_name,
+                    state->tls_context->cipher_usebits,
+                    state->tls_context->cipher_algbits);
+       }
+    } else {                                   /* tls_proxy_mode */
+       state->tls_context =
+           TLS_CLIENT_START(&start_props,
+                            ctx = state->tls_ctx,
+                            stream = stream,
+                            fd = -1,
+                            timeout = smtp_tmout,
+                            tls_level = state->level,
+                            nexthop = state->nexthop,
+                            host = state->hostname,
+                            namaddr = state->namaddrport,
+                            serverid = state->addrport,
+                            helo = state->helo ? state->helo : "",
+                            protocols = state->protocols,
+                            cipher_grade = state->grade,
+                            cipher_exclusions
+                            = vstring_str(cipher_exclusions),
+                            matchargv = state->match,
+                            mdalg = state->mdalg,
+                         dane = state->ddane ? state->ddane : state->dane);
+    }                                          /* tlsproxy_mode */
     vstring_free(cipher_exclusions);
     if (state->helo) {
        myfree(state->helo);
@@ -780,12 +910,14 @@ static int starttls(STATE *state)
        ehlo(state);
        if (!TLS_CERT_IS_PRESENT(state->tls_context))
            msg_info("Server is anonymous");
-       else if (state->print_trust)
-           print_trust_info(state);
-       state->log_mask &= ~(TLS_LOG_CERTMATCH | TLS_LOG_PEERCERT |
-                            TLS_LOG_VERBOSE | TLS_LOG_UNTRUSTED);
-       state->log_mask |= TLS_LOG_CACHE | TLS_LOG_SUMMARY;
-       tls_update_app_logmask(state->tls_ctx, state->log_mask);
+       else if (state->tlsproxy_mode == 0) {
+           if (state->print_trust)
+               print_trust_info(state);
+           state->log_mask &= ~(TLS_LOG_CERTMATCH | TLS_LOG_PEERCERT |
+                                TLS_LOG_VERBOSE | TLS_LOG_UNTRUSTED);
+           state->log_mask |= TLS_LOG_CACHE | TLS_LOG_SUMMARY;
+           tls_update_app_logmask(state->tls_ctx, state->log_mask);
+       }
     }
     return (0);
 }
@@ -879,6 +1011,8 @@ static VSTREAM *connect_sock(int sock, struct sockaddr *sa, int salen,
                       vstring_sprintf(vstring_alloc(10), "[%s]:%u",
                                       addr, ntohs(state->port)));
 
+    state->paddr = mystrdup(addr);             /* XXX for tlsproxy */
+
     /*
      * Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE.
      */
@@ -1426,9 +1560,14 @@ static int connect_dest(STATE *state)
 static void disconnect_dest(STATE *state)
 {
 #ifdef USE_TLS
-    if (state->tls_context)
-       tls_client_stop(state->tls_ctx, state->stream,
-                       smtp_tmout, 0, state->tls_context);
+    if (state->tls_context) {
+       if (state->tlsproxy_mode) {
+           tls_proxy_context_free(state->tls_context);
+       } else {
+           tls_client_stop(state->tls_ctx, state->stream,
+                           smtp_tmout, 0, state->tls_context);
+       }
+    }
     state->tls_context = 0;
     if (state->ddane)
        tls_dane_free(state->ddane);
@@ -1447,6 +1586,10 @@ static void disconnect_dest(STATE *state)
        myfree(state->addrport);
     state->addrport = 0;
 
+    if (state->paddr)
+       myfree(state->paddr);
+    state->paddr = 0;
+
     /* Reused on reconnect */
     if (state->reconnect <= 0) {
        if (state->addr)
@@ -1491,7 +1634,7 @@ static int finger(STATE *state)
        return (1);
 
 #ifdef USE_TLS
-    if (state->reconnect > 0) {
+    if (state->tlsproxy_mode == 0 && state->reconnect > 0) {
        int     cache_enabled;
        int     cache_count;
        int     cache_hits;
@@ -1620,6 +1763,7 @@ static void tls_init(STATE *state)
     if (state->level <= TLS_LEV_NONE)
        return;
 
+    /* Needed for tls_dane_avail() and other DANE-related processing. */
     state->tls_ctx =
        TLS_CLIENT_INIT(&props,
                        log_param = "-L option",
@@ -1672,7 +1816,7 @@ static void parse_options(STATE *state, int argc, char *argv[])
 
 #define OPTS "a:ch:o:St:T:v"
 #ifdef USE_TLS
-#define TLSOPTS "A:Cd:fF:g:k:K:l:L:m:M:p:P:r:w"
+#define TLSOPTS "A:Cd:fF:g:k:K:l:L:m:M:p:P:r:wX"
 
     state->mdalg = mystrdup("sha1");
     state->CApath = mystrdup("");
@@ -1683,6 +1827,7 @@ static void parse_options(STATE *state, int argc, char *argv[])
     state->options.logopts = 0;
     state->level = TLS_LEV_DANE;
     state->mxinsec_level = TLS_LEV_DANE;
+    state->tlsproxy_mode = 0;
 #else
 #define TLSOPTS ""
     state->level = TLS_LEV_NONE;
@@ -1792,6 +1937,8 @@ static void parse_options(STATE *state, int argc, char *argv[])
            break;
        case 'w':
            state->wrapper_mode = 1;
+       case 'X':
+           state->tlsproxy_mode = 1;
            break;
 #endif
        }
index acd830264dc94290d858c1f2e49e7693b0ebcafb..7d455649699ff5f65d1be592e25524522874dda0 100644 (file)
@@ -101,8 +101,10 @@ smtp.o: ../../include/flush_clnt.h
 smtp.o: ../../include/header_body_checks.h
 smtp.o: ../../include/header_opts.h
 smtp.o: ../../include/htable.h
+smtp.o: ../../include/iostuff.h
 smtp.o: ../../include/mail_conf.h
 smtp.o: ../../include/mail_params.h
+smtp.o: ../../include/mail_proto.h
 smtp.o: ../../include/mail_server.h
 smtp.o: ../../include/mail_version.h
 smtp.o: ../../include/maps.h
@@ -124,6 +126,7 @@ smtp.o: ../../include/string_list.h
 smtp.o: ../../include/stringops.h
 smtp.o: ../../include/sys_defs.h
 smtp.o: ../../include/tls.h
+smtp.o: ../../include/tls_proxy.h
 smtp.o: ../../include/tok822.h
 smtp.o: ../../include/vbuf.h
 smtp.o: ../../include/vstream.h
@@ -168,6 +171,7 @@ smtp_addr.o: ../../include/string_list.h
 smtp_addr.o: ../../include/stringops.h
 smtp_addr.o: ../../include/sys_defs.h
 smtp_addr.o: ../../include/tls.h
+smtp_addr.o: ../../include/tls_proxy.h
 smtp_addr.o: ../../include/tok822.h
 smtp_addr.o: ../../include/vbuf.h
 smtp_addr.o: ../../include/vstream.h
@@ -217,6 +221,7 @@ smtp_chat.o: ../../include/string_list.h
 smtp_chat.o: ../../include/stringops.h
 smtp_chat.o: ../../include/sys_defs.h
 smtp_chat.o: ../../include/tls.h
+smtp_chat.o: ../../include/tls_proxy.h
 smtp_chat.o: ../../include/tok822.h
 smtp_chat.o: ../../include/vbuf.h
 smtp_chat.o: ../../include/vstream.h
@@ -266,6 +271,7 @@ smtp_connect.o: ../../include/stringops.h
 smtp_connect.o: ../../include/sys_defs.h
 smtp_connect.o: ../../include/timed_connect.h
 smtp_connect.o: ../../include/tls.h
+smtp_connect.o: ../../include/tls_proxy.h
 smtp_connect.o: ../../include/tok822.h
 smtp_connect.o: ../../include/vbuf.h
 smtp_connect.o: ../../include/vstream.h
@@ -305,6 +311,7 @@ smtp_key.o: ../../include/sock_addr.h
 smtp_key.o: ../../include/string_list.h
 smtp_key.o: ../../include/sys_defs.h
 smtp_key.o: ../../include/tls.h
+smtp_key.o: ../../include/tls_proxy.h
 smtp_key.o: ../../include/tok822.h
 smtp_key.o: ../../include/vbuf.h
 smtp_key.o: ../../include/vstream.h
@@ -344,6 +351,7 @@ smtp_map11.o: ../../include/sock_addr.h
 smtp_map11.o: ../../include/string_list.h
 smtp_map11.o: ../../include/sys_defs.h
 smtp_map11.o: ../../include/tls.h
+smtp_map11.o: ../../include/tls_proxy.h
 smtp_map11.o: ../../include/tok822.h
 smtp_map11.o: ../../include/vbuf.h
 smtp_map11.o: ../../include/vstream.h
@@ -405,6 +413,7 @@ smtp_proto.o: ../../include/string_list.h
 smtp_proto.o: ../../include/stringops.h
 smtp_proto.o: ../../include/sys_defs.h
 smtp_proto.o: ../../include/tls.h
+smtp_proto.o: ../../include/tls_proxy.h
 smtp_proto.o: ../../include/tok822.h
 smtp_proto.o: ../../include/uxtext.h
 smtp_proto.o: ../../include/vbuf.h
@@ -450,6 +459,7 @@ smtp_rcpt.o: ../../include/string_list.h
 smtp_rcpt.o: ../../include/stringops.h
 smtp_rcpt.o: ../../include/sys_defs.h
 smtp_rcpt.o: ../../include/tls.h
+smtp_rcpt.o: ../../include/tls_proxy.h
 smtp_rcpt.o: ../../include/tok822.h
 smtp_rcpt.o: ../../include/vbuf.h
 smtp_rcpt.o: ../../include/vstream.h
@@ -487,6 +497,7 @@ smtp_reuse.o: ../../include/string_list.h
 smtp_reuse.o: ../../include/stringops.h
 smtp_reuse.o: ../../include/sys_defs.h
 smtp_reuse.o: ../../include/tls.h
+smtp_reuse.o: ../../include/tls_proxy.h
 smtp_reuse.o: ../../include/tok822.h
 smtp_reuse.o: ../../include/vbuf.h
 smtp_reuse.o: ../../include/vstream.h
@@ -527,6 +538,7 @@ smtp_sasl_auth_cache.o: ../../include/string_list.h
 smtp_sasl_auth_cache.o: ../../include/stringops.h
 smtp_sasl_auth_cache.o: ../../include/sys_defs.h
 smtp_sasl_auth_cache.o: ../../include/tls.h
+smtp_sasl_auth_cache.o: ../../include/tls_proxy.h
 smtp_sasl_auth_cache.o: ../../include/tok822.h
 smtp_sasl_auth_cache.o: ../../include/vbuf.h
 smtp_sasl_auth_cache.o: ../../include/vstream.h
@@ -569,6 +581,7 @@ smtp_sasl_glue.o: ../../include/string_list.h
 smtp_sasl_glue.o: ../../include/stringops.h
 smtp_sasl_glue.o: ../../include/sys_defs.h
 smtp_sasl_glue.o: ../../include/tls.h
+smtp_sasl_glue.o: ../../include/tls_proxy.h
 smtp_sasl_glue.o: ../../include/tok822.h
 smtp_sasl_glue.o: ../../include/vbuf.h
 smtp_sasl_glue.o: ../../include/vstream.h
@@ -609,6 +622,7 @@ smtp_sasl_proto.o: ../../include/string_list.h
 smtp_sasl_proto.o: ../../include/stringops.h
 smtp_sasl_proto.o: ../../include/sys_defs.h
 smtp_sasl_proto.o: ../../include/tls.h
+smtp_sasl_proto.o: ../../include/tls_proxy.h
 smtp_sasl_proto.o: ../../include/tok822.h
 smtp_sasl_proto.o: ../../include/vbuf.h
 smtp_sasl_proto.o: ../../include/vstream.h
@@ -648,6 +662,7 @@ smtp_session.o: ../../include/string_list.h
 smtp_session.o: ../../include/stringops.h
 smtp_session.o: ../../include/sys_defs.h
 smtp_session.o: ../../include/tls.h
+smtp_session.o: ../../include/tls_proxy.h
 smtp_session.o: ../../include/tok822.h
 smtp_session.o: ../../include/vbuf.h
 smtp_session.o: ../../include/vstream.h
@@ -685,6 +700,7 @@ smtp_state.o: ../../include/sock_addr.h
 smtp_state.o: ../../include/string_list.h
 smtp_state.o: ../../include/sys_defs.h
 smtp_state.o: ../../include/tls.h
+smtp_state.o: ../../include/tls_proxy.h
 smtp_state.o: ../../include/tok822.h
 smtp_state.o: ../../include/vbuf.h
 smtp_state.o: ../../include/vstream.h
@@ -724,6 +740,7 @@ smtp_tls_policy.o: ../../include/string_list.h
 smtp_tls_policy.o: ../../include/stringops.h
 smtp_tls_policy.o: ../../include/sys_defs.h
 smtp_tls_policy.o: ../../include/tls.h
+smtp_tls_policy.o: ../../include/tls_proxy.h
 smtp_tls_policy.o: ../../include/tok822.h
 smtp_tls_policy.o: ../../include/valid_hostname.h
 smtp_tls_policy.o: ../../include/valid_utf8_hostname.h
@@ -768,6 +785,7 @@ smtp_trouble.o: ../../include/string_list.h
 smtp_trouble.o: ../../include/stringops.h
 smtp_trouble.o: ../../include/sys_defs.h
 smtp_trouble.o: ../../include/tls.h
+smtp_trouble.o: ../../include/tls_proxy.h
 smtp_trouble.o: ../../include/tok822.h
 smtp_trouble.o: ../../include/vbuf.h
 smtp_trouble.o: ../../include/vstream.h
@@ -804,6 +822,7 @@ smtp_unalias.o: ../../include/sock_addr.h
 smtp_unalias.o: ../../include/string_list.h
 smtp_unalias.o: ../../include/sys_defs.h
 smtp_unalias.o: ../../include/tls.h
+smtp_unalias.o: ../../include/tls_proxy.h
 smtp_unalias.o: ../../include/tok822.h
 smtp_unalias.o: ../../include/vbuf.h
 smtp_unalias.o: ../../include/vstream.h
index 68d611e265b77c2628b2cc8138bf077e2cbc63fa..c4e16966be2e88ad524c2f4bdcd3caa871b77df9 100644 (file)
@@ -61,6 +61,7 @@
        VAR_LMTP_DNS_RES_OPT, DEF_LMTP_DNS_RES_OPT, &var_smtp_dns_res_opt, 0, 0,
        VAR_LMTP_DSN_FILTER, DEF_LMTP_DSN_FILTER, &var_smtp_dsn_filter, 0, 0,
        VAR_LMTP_DNS_RE_FILTER, DEF_LMTP_DNS_RE_FILTER, &var_smtp_dns_re_filter, 0, 0,
+       VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
        0,
     };
     static const CONFIG_TIME_TABLE lmtp_time_table[] = {
        VAR_LMTP_CACHE_DEMAND, DEF_LMTP_CACHE_DEMAND, &var_smtp_cache_demand,
        VAR_LMTP_USE_TLS, DEF_LMTP_USE_TLS, &var_smtp_use_tls,
        VAR_LMTP_ENFORCE_TLS, DEF_LMTP_ENFORCE_TLS, &var_smtp_enforce_tls,
+       VAR_LMTP_TLS_CONN_REUSE, DEF_LMTP_TLS_CONN_REUSE, &var_smtp_tls_conn_reuse,
 #ifdef USE_TLS
        VAR_LMTP_TLS_ENFORCE_PN, DEF_LMTP_TLS_ENFORCE_PN, &var_smtp_tls_enforce_peername,
        VAR_LMTP_TLS_NOTEOFFER, DEF_LMTP_TLS_NOTEOFFER, &var_smtp_tls_note_starttls_offer,
index ed27be96ae3771ef97cbbd6cf98bfda6647fc8c8..1477a70689ad66992cf9078aeeac4b473d4f0d76 100644 (file)
 /*     The TLS policy for MX hosts with "secure" TLSA records when the
 /*     nexthop destination security level is \fBdane\fR, but the MX
 /*     record was found via an "insecure" MX lookup.
+/* .PP
+/*     Available in Postfix version 3.4 and later:
+/* .IP "\fBsmtp_tls_connection_reuse (no)\fR"
+/*     Try to make multiple deliveries per TLS-encrypted connection.
 /* OBSOLETE STARTTLS CONTROLS
 /* .ad
 /* .fi
 /*     that an SMTP session may be reused before it is closed, or zero (no
 /*     limit).
 /* .PP
+/*     Available in Postfix version 3.4 and later:
+/* .IP "\fBsmtp_tls_connection_reuse (no)\fR"
+/*     Try to make multiple deliveries per TLS-encrypted connection.
+/* .PP
 /*     Implemented in the qmgr(8) daemon:
 /* .IP "\fBtransport_destination_concurrency_limit ($default_destination_concurrency_limit)\fR"
 /*     A transport-specific override for the
 /* Global library. */
 
 #include <deliver_request.h>
+#include <mail_proto.h>
 #include <mail_params.h>
 #include <mail_version.h>
 #include <mail_conf.h>
@@ -895,6 +904,8 @@ bool    var_smtp_enforce_tls;
 char   *var_smtp_tls_per_site;
 char   *var_smtp_tls_policy;
 bool    var_smtp_tls_wrappermode;
+bool    var_smtp_tls_conn_reuse;
+char   *var_tlsproxy_service;
 
 #ifdef USE_TLS
 char   *var_smtp_sasl_tls_opts;
@@ -1219,6 +1230,9 @@ static void pre_init(char *unused_name, char **unused_argv)
         * 
         * Large parameter lists are error-prone, so we emulate a language
         * feature that C does not have natively: named parameter lists.
+        * 
+        * With tlsproxy(8) turned on, this is still needed for DANE-related
+        * initializations.
         */
        smtp_tls_ctx =
            TLS_CLIENT_INIT(&props,
index 11beb440683c97dc736d2f904e5413d4dc5f2e2b..041745f5de84dbd2c25fcc98aa28a245350ff3e1 100644 (file)
   */
 #include <tls.h>
 
+ /*
+  * tlsproxy client.
+  */
+#include <tls_proxy.h>
+
  /*
   * Global iterator support. This is updated by the connection-management
   * loop, and contains dynamic context that appears in lookup keys for SASL
@@ -98,6 +103,7 @@ typedef struct SMTP_TLS_POLICY {
     ARGV   *matchargv;                 /* Cert match patterns */
     DSN_BUF *why;                      /* Lookup error status */
     TLS_DANE *dane;                    /* DANE TLSA digests */
+    int     conn_reuse;                        /* enable connection reuse */
 } SMTP_TLS_POLICY;
 
  /*
@@ -131,6 +137,7 @@ extern void smtp_tls_policy_cache_flush(void);
        _tls_policy_init_tmp->matchargv = 0; \
        _tls_policy_init_tmp->why = (w); \
        _tls_policy_init_tmp->dane = 0; \
+       _tls_policy_init_tmp->conn_reuse = 0; \
     } while (0)
 
 #endif
@@ -614,12 +621,13 @@ char   *smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int);
 #define SMTP_KEY_FLAG_HOSTNAME         (1<<4)  /* remote host name */
 #define SMTP_KEY_FLAG_ADDR             (1<<5)  /* remote address */
 #define SMTP_KEY_FLAG_PORT             (1<<6)  /* remote port */
+#define SMTP_KEY_FLAG_TLS_LEVEL                (1<<7)  /* requested TLS level */
 
 #define SMTP_KEY_MASK_ALL \
        (SMTP_KEY_FLAG_SERVICE | SMTP_KEY_FLAG_SENDER | \
        SMTP_KEY_FLAG_REQ_NEXTHOP | \
        SMTP_KEY_FLAG_NEXTHOP | SMTP_KEY_FLAG_HOSTNAME | \
-       SMTP_KEY_FLAG_ADDR | SMTP_KEY_FLAG_PORT)
+       SMTP_KEY_FLAG_ADDR | SMTP_KEY_FLAG_PORT | SMTP_KEY_FLAG_TLS_LEVEL)
 
  /*
   * Conditional lookup-key flags for cached connections that may be
@@ -647,7 +655,7 @@ char   *smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int);
   */
 #define SMTP_KEY_MASK_SCACHE_DEST_LABEL \
        (SMTP_KEY_FLAG_SERVICE | COND_SASL_SMTP_KEY_FLAG_SENDER \
-       | SMTP_KEY_FLAG_REQ_NEXTHOP)
+       | SMTP_KEY_FLAG_REQ_NEXTHOP | SMTP_KEY_FLAG_TLS_LEVEL)
 
  /*
   * Connection-cache endpoint lookup key. The SENDER, NEXTHOP, and HOSTNAME
@@ -658,7 +666,7 @@ char   *smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int);
 #define SMTP_KEY_MASK_SCACHE_ENDP_LABEL \
        (SMTP_KEY_FLAG_SERVICE | COND_SASL_SMTP_KEY_FLAG_SENDER \
        | COND_SASL_SMTP_KEY_FLAG_NEXTHOP | COND_SASL_SMTP_KEY_FLAG_HOSTNAME \
-       | SMTP_KEY_FLAG_ADDR | SMTP_KEY_FLAG_PORT)
+       | SMTP_KEY_FLAG_ADDR | SMTP_KEY_FLAG_PORT | SMTP_KEY_FLAG_TLS_LEVEL)
 
  /*
   * Silly little macros.
@@ -686,6 +694,11 @@ extern int smtp_mode;
 /*     111 8th Avenue
 /*     New York, NY 10011, USA
 /*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*
 /*     TLS support originally by:
 /*     Lutz Jaenicke
 /*     BTU Cottbus
index 2bf209d92596acb3eacab6264685974a4b8a9efa..abccb57c9ba4060ad38908103ad0806eb7fc0779 100644 (file)
@@ -667,13 +667,16 @@ static int smtp_reuse_session(SMTP_STATE *state, DNS_RR **addr_list,
      * and restore it here, so that subsequent connections will use the
      * proper nexthop information.
      * 
-     * We request a dummy "TLS disabled" policy for connection-cache lookup by
-     * request nexthop only. If we find a saved connection, then we know that
-     * plaintext was permitted, because we never save a connection after
-     * turning on TLS.
+     * If TLS is proxied, lookup the TLS policy now so that we reuse only
+     * matching sessions. Otherwise, request a dummy "TLS disabled" policy
+     * for connection-cache lookup by request nexthop only.
      */
 #ifdef USE_TLS
-    smtp_tls_policy_dummy(state->tls);
+    if (!smtp_tls_policy_cache_query(why, state->tls, iter)) {
+       msg_warn("TLS policy lookup error for %s/%s: %s",
+                STR(iter->dest), STR(iter->host), STR(why->reason));
+       return (0);                             /* XXX */
+    }
 #endif
     SMTP_ITER_SAVE_DEST(state->iterator);
     if (*addr_list && SMTP_RCPT_LEFT(state) > 0
index 78d7959234cd1f23b9c0f9bb7c8cc0c5031e9483..6f72b803e65dc3bc41543cee8f7a70c50bd33588 100644 (file)
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
  /*
@@ -191,7 +196,17 @@ char   *smtp_key_prefix(VSTRING *buffer, const char *delim_na,
     if (flags & SMTP_KEY_FLAG_PORT)
        smtp_key_append_uint(buffer, ntohs(iter->port), delim_na);
 
-    /* Similarly, provide unique TLS fingerprint when applicable. */
+    /*
+     * Requested TLS level, if applicable. TODO(tlsproxy) should the lookup
+     * engine also try the requested TLS level and 'stronger', in case a
+     * server hosts multiple domains with different TLS requirements?
+     */
+    if (flags & SMTP_KEY_FLAG_TLS_LEVEL)
+#ifdef USE_TLS
+       smtp_key_append_uint(buffer, state->tls->level, delim_na);
+#else
+       smtp_key_append_na(buffer, delim_na);
+#endif
 
     VSTRING_TERMINATE(buffer);
 
index ed5ea455ba7079e3c0e8b3aa498ada33dc7ee353..198119e10678333229c40caf6354680919b05e8d 100644 (file)
@@ -62,6 +62,7 @@
        VAR_SMTP_DNS_RES_OPT, DEF_SMTP_DNS_RES_OPT, &var_smtp_dns_res_opt, 0, 0,
        VAR_SMTP_DSN_FILTER, DEF_SMTP_DSN_FILTER, &var_smtp_dsn_filter, 0, 0,
        VAR_SMTP_DNS_RE_FILTER, DEF_SMTP_DNS_RE_FILTER, &var_smtp_dns_re_filter, 0, 0,
+       VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
        0,
     };
     static const CONFIG_TIME_TABLE smtp_time_table[] = {
        VAR_SMTP_CACHE_DEMAND, DEF_SMTP_CACHE_DEMAND, &var_smtp_cache_demand,
        VAR_SMTP_USE_TLS, DEF_SMTP_USE_TLS, &var_smtp_use_tls,
        VAR_SMTP_ENFORCE_TLS, DEF_SMTP_ENFORCE_TLS, &var_smtp_enforce_tls,
+       VAR_SMTP_TLS_CONN_REUSE, DEF_SMTP_TLS_CONN_REUSE, &var_smtp_tls_conn_reuse,
 #ifdef USE_TLS
        VAR_SMTP_TLS_ENFORCE_PN, DEF_SMTP_TLS_ENFORCE_PN, &var_smtp_tls_enforce_peername,
        VAR_SMTP_TLS_NOTEOFFER, DEF_SMTP_TLS_NOTEOFFER, &var_smtp_tls_note_starttls_offer,
index 15a15db171e0c7311d029f54f75f0acc20bb6f39..0169f1716a4a3a4c783ded63471dd52b7c113c74 100644 (file)
@@ -848,20 +848,29 @@ static int smtp_start_tls(SMTP_STATE *state)
 {
     SMTP_SESSION *session = state->session;
     SMTP_ITERATOR *iter = state->iterator;
-    TLS_CLIENT_START_PROPS tls_props;
+    TLS_CLIENT_START_PROPS start_props;
     VSTRING *serverid;
     SMTP_RESP fake;
+    TLS_CLIENT_INIT_PROPS init_props;
+    VSTREAM *tlsproxy;
+    VSTRING *port_buf;
 
     /*
-     * Turn off SMTP connection caching. When the TLS handshake succeeds, we
-     * can't reuse the SMTP connection. Reason: we can't turn off TLS in one
-     * process, save the connection to the cache which is shared with all
-     * SMTP clients, migrate the connection to another SMTP client, and
-     * resume TLS there. When the TLS handshake fails, we can't reuse the
-     * SMTP connection either, because the conversation is in an unknown
-     * state.
+     * When the TLS handshake succeeds, we can reuse a connection only if TLS
+     * remains turned on for the lifetime of that connection. This requires
+     * that the TLS library state is maintained in some proxy process, for
+     * example, in tlsproxy(8). We then store the proxy file handle in the
+     * connection cache, and reuse that file handle.
+     * 
+     * Otherwise, we must turn off connection caching. We can't turn off TLS in
+     * one SMTP client process, save the open connection to a cache which is
+     * shared with all SMTP clients, migrate the connection to another SMTP
+     * client, and resume TLS there. When the TLS handshake fails, we can't
+     * reuse the SMTP connection either, because the conversation is in an
+     * unknown state.
      */
-    DONT_CACHE_THIS_SESSION;
+    if (state->tls->conn_reuse == 0)
+       DONT_CACHE_THIS_SESSION;
 
     /*
      * The following assumes sites that use TLS in a perverse configuration:
@@ -894,37 +903,164 @@ static int smtp_start_tls(SMTP_STATE *state)
                    | SMTP_KEY_FLAG_HOSTNAME
                    | SMTP_KEY_FLAG_ADDR);
 
-    /*
-     * As of Postfix 2.5, tls_client_start() tries hard to always complete
-     * the TLS handshake. It records the verification and match status in the
-     * resulting TLScontext. It is now up to the application to abort the TLS
-     * connection if it chooses.
-     * 
-     * XXX When tls_client_start() fails then we don't know what state the SMTP
-     * connection is in, so we give up on this connection even if we are not
-     * required to use TLS.
-     * 
-     * Large parameter lists are error-prone, so we emulate a language feature
-     * that C does not have natively: named parameter lists.
-     */
-    session->tls_context =
-       TLS_CLIENT_START(&tls_props,
-                        ctx = smtp_tls_ctx,
-                        stream = session->stream,
-                        timeout = var_smtp_starttls_tmout,
-                        tls_level = state->tls->level,
-                        nexthop = session->tls_nexthop,
-                        host = STR(iter->host),
-                        namaddr = session->namaddrport,
-                        serverid = vstring_str(serverid),
-                        helo = session->helo,
-                        protocols = state->tls->protocols,
-                        cipher_grade = state->tls->grade,
-                        cipher_exclusions
-                        = vstring_str(state->tls->exclusions),
-                        matchargv = state->tls->matchargv,
-                        mdalg = var_smtp_tls_fpt_dgst,
-                        dane = state->tls->dane);
+    if (state->tls->conn_reuse) {
+
+       /*
+        * Send all our wishes in one big request.
+        */
+       TLS_PROXY_CLIENT_INIT_PROPS(&init_props,
+                                   log_param = VAR_LMTP_SMTP(TLS_LOGLEVEL),
+                                   log_level = var_smtp_tls_loglevel,
+                                   verifydepth = var_smtp_tls_scert_vd,
+                                   cache_type
+                                   = LMTP_SMTP_SUFFIX(TLS_MGR_SCACHE),
+                                   cert_file = var_smtp_tls_cert_file,
+                                   key_file = var_smtp_tls_key_file,
+                                   dcert_file = var_smtp_tls_dcert_file,
+                                   dkey_file = var_smtp_tls_dkey_file,
+                                   eccert_file = var_smtp_tls_eccert_file,
+                                   eckey_file = var_smtp_tls_eckey_file,
+                                   CAfile = var_smtp_tls_CAfile,
+                                   CApath = var_smtp_tls_CApath,
+                                   mdalg = var_smtp_tls_fpt_dgst);
+       TLS_PROXY_CLIENT_START_PROPS(&start_props,
+                                    timeout = var_smtp_starttls_tmout,
+                                    tls_level = state->tls->level,
+                                    nexthop = session->tls_nexthop,
+                                    host = STR(iter->host),
+                                    namaddr = session->namaddrport,
+                                    serverid = vstring_str(serverid),
+                                    helo = session->helo,
+                                    protocols = state->tls->protocols,
+                                    cipher_grade = state->tls->grade,
+                                    cipher_exclusions
+                                    = vstring_str(state->tls->exclusions),
+                                    matchargv = state->tls->matchargv,
+                                    mdalg = var_smtp_tls_fpt_dgst,
+                                    dane = state->tls->dane);
+
+       /*
+        * The tlsproxy(8) server enforces timeouts that are larger than
+        * those specified by the tlsproxy(8) client. These timeouts are a
+        * safety net for the case that the tlsproxy(8) client fails to
+        * enforce time limits. Normally, the tlsproxy(8) client would time
+        * out and trigger a plaintext event in the tlsproxy(8) server, and
+        * cause it to tear down the session.
+        * 
+        * However, the tlsproxy(8) server has no insight into the SMTP
+        * protocol, and therefore it cannot by itself support different
+        * timeouts at different SMTP protocol stages. Instead, we specify
+        * the largest timeout (end-of-data) and rely on the SMTP client to
+        * time out first, which normally results in a plaintext event in the
+        * tlsproxy(8) server. Unfortunately, we cannot permit plaintext
+        * events during the TLS handshake, so we specify a separate timeout
+        * for that stage (the end-of-data timeout would be unreasonably
+        * large anyway).
+        */
+#define PROXY_OPEN_FLAGS \
+        (TLS_PROXY_FLAG_ROLE_CLIENT | TLS_PROXY_FLAG_SEND_CONTEXT)
+
+       port_buf = vstring_alloc(100);          /* minimize fragmentation */
+       vstring_sprintf(port_buf, "%d", ntohs(iter->port));
+       tlsproxy =
+           tls_proxy_open(var_tlsproxy_service, PROXY_OPEN_FLAGS,
+                          session->stream, STR(iter->addr),
+                          STR(port_buf), var_smtp_starttls_tmout,
+                          var_smtp_data2_tmout, state->service,
+                          &init_props, &start_props);
+       vstring_free(port_buf);
+
+       /*
+        * To insert tlsproxy(8) between this process and the remote SMTP
+        * server, we swap the file descriptors between the tlsproxy and
+        * session->stream VSTREAMS, so that we don't lose all the
+        * user-configurable session->stream attributes (such as longjump
+        * buffers or timeouts).
+        * 
+        * TODO: the tlsproxy RPCs should return more error detail than a "NO"
+        * result. OTOH, the in-process TLS engine does not return such info
+        * either.
+        * 
+        * If the tlsproxy request fails we do not fall back to the in-process
+        * TLS stack. Reason: the admin enabled connection reuse to respect
+        * receiver policy; silently violating such policy would not be
+        * useful.
+        * 
+        * We also don't fall back to the in-process TLS stack under low-traffic
+        * conditions, to avoid frustrating attempts to debug a problem with
+        * using the tlsproxy(8) service.
+        */
+       if (tlsproxy == 0) {
+           session->tls_context = 0;
+       } else {
+           vstream_control(tlsproxy,
+                           CA_VSTREAM_CTL_DOUBLE,
+                           CA_VSTREAM_CTL_END);
+           vstream_control(session->stream,
+                           CA_VSTREAM_CTL_SWAP_FD(tlsproxy),
+                           CA_VSTREAM_CTL_END);
+           (void) vstream_fclose(tlsproxy);    /* direct-to-server stream! */
+
+           /*
+            * There must not be any pending data in the stream buffers
+            * before we read the TLS context attributes.
+            */
+           vstream_fpurge(session->stream, VSTREAM_PURGE_BOTH);
+
+           /*
+            * After plumbing the plaintext stream, receive the TLS context
+            * object. For this we use the same VSTREAM buffer that we also
+            * use to receive subsequent SMTP commands, therefore we must be
+            * prepared for the possibility that the remote SMTP server
+            * starts talking immediately. The tlsproxy implementation sends
+            * the TLS context before remote content. The attribute protocol
+            * is robust enough that an adversary cannot insert their own TLS
+            * context attributes.
+            */
+           session->tls_context = tls_proxy_context_receive(session->stream);
+       }
+    } else {                                   /* state->tls->conn_reuse */
+
+       /*
+        * As of Postfix 2.5, tls_client_start() tries hard to always
+        * complete the TLS handshake. It records the verification and match
+        * status in the resulting TLScontext. It is now up to the
+        * application to abort the TLS connection if it chooses.
+        * 
+        * XXX When tls_client_start() fails then we don't know what state the
+        * SMTP connection is in, so we give up on this connection even if we
+        * are not required to use TLS.
+        * 
+        * Large parameter lists are error-prone, so we emulate a language
+        * feature that C does not have natively: named parameter lists.
+        */
+       session->tls_context =
+           TLS_CLIENT_START(&start_props,
+                            ctx = smtp_tls_ctx,
+                            stream = session->stream,
+                            fd = -1,
+                            timeout = var_smtp_starttls_tmout,
+                            tls_level = state->tls->level,
+                            nexthop = session->tls_nexthop,
+                            host = STR(iter->host),
+                            namaddr = session->namaddrport,
+                            serverid = vstring_str(serverid),
+                            helo = session->helo,
+                            protocols = state->tls->protocols,
+                            cipher_grade = state->tls->grade,
+                            cipher_exclusions
+                            = vstring_str(state->tls->exclusions),
+                            matchargv = state->tls->matchargv,
+                            mdalg = var_smtp_tls_fpt_dgst,
+                            dane = state->tls->dane);
+
+       /*
+        * At this point there must not be any pending data in the stream
+        * buffers.
+        */
+       vstream_fpurge(session->stream, VSTREAM_PURGE_BOTH);
+    }                                          /* state->tls->conn_reuse */
+
     vstring_free(serverid);
 
     if (session->tls_context == 0) {
@@ -932,7 +1068,6 @@ static int smtp_start_tls(SMTP_STATE *state)
        /*
         * We must avoid further I/O, the peer is in an undefined state.
         */
-       (void) vstream_fpurge(session->stream, VSTREAM_PURGE_BOTH);
        DONT_USE_FORBIDDEN_SESSION;
 
        /*
@@ -983,9 +1118,6 @@ static int smtp_start_tls(SMTP_STATE *state)
                                   SMTP_RESP_FAKE(&fake, "4.7.5"),
                                   "Server certificate not verified"));
 
-    /* At this point there must not be any pending plaintext. */
-    vstream_fpurge(session->stream, VSTREAM_PURGE_BOTH);
-
     /*
      * At this point we have to re-negotiate the "EHLO" to reget the
      * feature-list.
index da23692fd1f616e41a5af8f4eb68fdb4791cca20..2bc5c5ed0ec07c98ce6f33c74f1eb7329aae2452 100644 (file)
@@ -41,6 +41,8 @@
 /*     The restored session information does not include the "best
 /*     MX" bit, and does not override the iterator dest, host and
 /*     addr fields.
+/*     This function is a NOOP for TLS levels stronger than "encrypt",
+/*     because stronger levels require certificate checks,
 /*     The result is null in case of failure.
 /*
 /*     Arguments:
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
 /* System library. */
@@ -159,10 +166,9 @@ static SMTP_SESSION *smtp_reuse_common(SMTP_STATE *state, int fd,
     SMTP_SESSION *session;
 
     /*
-     * Can't happen. Both smtp_reuse_nexthop() and smtp_reuse_addr() decline
-     * the request when the TLS policy is not TLS_LEV_NONE.
+     * Obsolete.
      */
-#ifdef USE_TLS
+#ifdef notdef
     if (state->tls->level > TLS_LEV_NONE)
        msg_panic("%s: unexpected plain-text cached session to %s",
                  myname, label);
@@ -211,10 +217,10 @@ SMTP_SESSION *smtp_reuse_nexthop(SMTP_STATE *state, int name_key_flags)
     int     fd;
 
     /*
-     * Don't look up an existing plaintext connection when a new connection
-     * would (try to) use TLS.
+     * Obsolete: the TLS level and nexthop are part of the connection cache
+     * key. TODO(tlsproxy) is the port included in the nexthop?
      */
-#ifdef USE_TLS
+#ifdef notdef
     if (state->tls->level > TLS_LEV_NONE)
        return (0);
 #endif
@@ -244,11 +250,11 @@ SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, int endp_key_flags)
     int     fd;
 
     /*
-     * Don't look up an existing plaintext connection when a new connection
-     * would (try to) use TLS.
+     * Allow address-based reuse only for security levels that don't require
+     * certificate checks.
      */
 #ifdef USE_TLS
-    if (state->tls->level > TLS_LEV_NONE)
+    if (state->tls->level > TLS_LEV_ENCRYPT)
        return (0);
 #endif
 
index 806d8de060bd38214268c0d57d0728802fdf9b26..9fa8cd285e42029c7d98080220e4a6a9c56abb0f 100644 (file)
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
 /*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*
 /*     Viktor Dukhovni
 /*--*/
 
@@ -176,7 +181,11 @@ void    smtp_session_free(SMTP_SESSION *session)
 #ifdef USE_TLS
     if (session->stream) {
        vstream_fflush(session->stream);
-       if (session->tls_context)
+    }
+    if (session->tls_context) {
+       if (session->state->tls->conn_reuse)
+           tls_proxy_context_free(session->tls_context);
+       else
            tls_client_stop(smtp_tls_ctx, session->stream,
                          var_smtp_starttls_tmout, 0, session->tls_context);
     }
@@ -223,9 +232,11 @@ int     smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop,
      * serialize the properties with attr_print() instead of using ad-hoc,
      * non-reusable, code and hard-coded format strings.
      * 
+     * TODO(tlsproxy): save TLS_SESS_STATE information so that we can 
+     * restore TLS session properties.
+     * 
      * TODO: save SASL username and password information so that we can
      * correctly save a reused authenticated connection.
-     * 
      */
     vstring_sprintf(dest_prop, "%s\n%s\n%s\n%u",
                    STR(iter->dest), STR(iter->host), STR(iter->addr),
index 9dfc41896e0342963f4271e62aafa5b2a57874b8..13735b21056922be82f0c88254df573a86c47ea1 100644 (file)
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
 /*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*
 /*     Viktor Dukhovni
 /*--*/
 
@@ -356,6 +361,18 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
            }
            continue;
        }
+       /* Last one wins. */
+       if (!strcasecmp(name, "connection_reuse")) {
+           if (strcasecmp(val, "yes") == 0) {
+               tls->conn_reuse = 1;
+           } else if (strcasecmp(val, "no") == 0) {
+               tls->conn_reuse = 0;
+           } else {
+               msg_warn("%s: attribute \"%s\" has bad value: \"%s\"",
+                       WHERE, name, val);
+               INVALID_RETURN(tls->why, site_level);
+           }
+       }
        msg_warn("%s: invalid attribute name: \"%s\"", WHERE, name);
        INVALID_RETURN(tls->why, site_level);
     }
@@ -483,6 +500,7 @@ static void *policy_create(const char *unused_key, void *context)
     SMTP_TLS_POLICY *tls = (SMTP_TLS_POLICY *) mymalloc(sizeof(*tls));
 
     smtp_tls_policy_init(tls, dsb_create());
+    tls->conn_reuse = var_smtp_tls_conn_reuse;
 
     /*
      * Compute the per-site TLS enforcement level. For compatibility with the
index 20598992b7db35f94be471f65066fd21b61b1f72..5006e7449197770427ff0e98c80e282f32edec70 100644 (file)
@@ -1496,9 +1496,11 @@ static void tls_reset(SMTPD_STATE *);
  /*
   * TLS initialization status.
   */
+#ifndef USE_TLSPROXY
 static TLS_APPL_STATE *smtpd_tls_ctx;
 static int ask_client_cert;
 
+#endif                                 /* USE_TLSPROXY */
 #endif
 
  /*
@@ -4704,9 +4706,11 @@ static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
 #define PROXY_OPEN_FLAGS \
        (TLS_PROXY_FLAG_ROLE_SERVER | TLS_PROXY_FLAG_SEND_CONTEXT)
 
-    state->tlsproxy = tls_proxy_open(var_tlsproxy_service, PROXY_OPEN_FLAGS,
-                                    state->client, state->addr,
-                                    state->port, var_smtpd_tmout);
+    state->tlsproxy =
+       tls_proxy_legacy_open(var_tlsproxy_service, PROXY_OPEN_FLAGS,
+                             state->client, state->addr,
+                             state->port, var_smtpd_tmout,
+                             state->service);
     if (state->tlsproxy == 0) {
        state->error_mask |= MAIL_ERROR_SOFTWARE;
        /* RFC 3207 Section 4. */
@@ -4963,10 +4967,12 @@ static void smtpd_proto(SMTPD_STATE *state)
        if (SMTPD_STAND_ALONE(state) == 0 && var_smtpd_tls_wrappermode) {
 #ifdef USE_TLSPROXY
            /* We garbage-collect the VSTREAM in smtpd_state_reset() */
-           state->tlsproxy = tls_proxy_open(var_tlsproxy_service,
-                                            PROXY_OPEN_FLAGS,
-                                            state->client, state->addr,
-                                            state->port, var_smtpd_tmout);
+           state->tlsproxy =
+               tls_proxy_legacy_open(var_tlsproxy_service,
+                                     PROXY_OPEN_FLAGS,
+                                     state->client, state->addr,
+                                     state->port, var_smtpd_tmout,
+                                     state->service);
            if (state->tlsproxy == 0) {
                msg_warn("Wrapper-mode request dropped from %s for service %s."
                       " TLS context initialization failed. For details see"
index 55dfd1ecce917733b3d2534f7f8d7d9be215c006..16efff4dceadf0de8c9ee19f17c35688204e6d3f 100644 (file)
@@ -4,13 +4,19 @@ SRCS  = tls_prng_dev.c tls_prng_egd.c tls_prng_file.c tls_fprint.c \
        tls_rsa.c tls_verify.c tls_dane.c tls_certkey.c tls_session.c \
        tls_client.c tls_server.c tls_scache.c tls_mgr.c tls_seed.c \
        tls_level.c \
-       tls_proxy_clnt.c tls_proxy_print.c tls_proxy_scan.c
+       tls_proxy_clnt.c tls_proxy_context_print.c tls_proxy_context_scan.c \
+       tls_proxy_client_init_print.c tls_proxy_client_init_scan.c \
+       tls_proxy_server_init_print.c tls_proxy_server_init_scan.c \
+       tls_proxy_client_start_print.c tls_proxy_client_start_scan.c \
+       tls_proxy_server_start_print.c tls_proxy_server_start_scan.c
 OBJS   = tls_prng_dev.o tls_prng_egd.o tls_prng_file.o tls_fprint.o \
        tls_prng_exch.o tls_stream.o tls_bio_ops.o tls_misc.o tls_dh.o \
        tls_rsa.o tls_verify.o tls_dane.o tls_certkey.o tls_session.o \
        tls_client.o tls_server.o tls_scache.o tls_mgr.o tls_seed.o \
        tls_level.o \
-       tls_proxy_clnt.o tls_proxy_print.o tls_proxy_scan.o
+       tls_proxy_clnt.o tls_proxy_context_print.o tls_proxy_context_scan.o \
+       tls_proxy_client_print.o tls_proxy_client_scan.o \
+       tls_proxy_server_print.o tls_proxy_server_scan.o
 HDRS   = tls.h tls_prng.h tls_scache.h tls_mgr.h tls_proxy.h
 TESTSRC        = 
 DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
@@ -294,6 +300,46 @@ tls_prng_file.o: ../../include/mymalloc.h
 tls_prng_file.o: ../../include/sys_defs.h
 tls_prng_file.o: tls_prng.h
 tls_prng_file.o: tls_prng_file.c
+tls_proxy_client_print.o: ../../include/argv.h
+tls_proxy_client_print.o: ../../include/argv_attr.h
+tls_proxy_client_print.o: ../../include/attr.h
+tls_proxy_client_print.o: ../../include/check_arg.h
+tls_proxy_client_print.o: ../../include/dns.h
+tls_proxy_client_print.o: ../../include/htable.h
+tls_proxy_client_print.o: ../../include/msg.h
+tls_proxy_client_print.o: ../../include/myaddrinfo.h
+tls_proxy_client_print.o: ../../include/mymalloc.h
+tls_proxy_client_print.o: ../../include/name_code.h
+tls_proxy_client_print.o: ../../include/name_mask.h
+tls_proxy_client_print.o: ../../include/nvtable.h
+tls_proxy_client_print.o: ../../include/sock_addr.h
+tls_proxy_client_print.o: ../../include/sys_defs.h
+tls_proxy_client_print.o: ../../include/vbuf.h
+tls_proxy_client_print.o: ../../include/vstream.h
+tls_proxy_client_print.o: ../../include/vstring.h
+tls_proxy_client_print.o: tls.h
+tls_proxy_client_print.o: tls_proxy.h
+tls_proxy_client_print.o: tls_proxy_client_print.c
+tls_proxy_client_scan.o: ../../include/argv.h
+tls_proxy_client_scan.o: ../../include/argv_attr.h
+tls_proxy_client_scan.o: ../../include/attr.h
+tls_proxy_client_scan.o: ../../include/check_arg.h
+tls_proxy_client_scan.o: ../../include/dns.h
+tls_proxy_client_scan.o: ../../include/htable.h
+tls_proxy_client_scan.o: ../../include/msg.h
+tls_proxy_client_scan.o: ../../include/myaddrinfo.h
+tls_proxy_client_scan.o: ../../include/mymalloc.h
+tls_proxy_client_scan.o: ../../include/name_code.h
+tls_proxy_client_scan.o: ../../include/name_mask.h
+tls_proxy_client_scan.o: ../../include/nvtable.h
+tls_proxy_client_scan.o: ../../include/sock_addr.h
+tls_proxy_client_scan.o: ../../include/sys_defs.h
+tls_proxy_client_scan.o: ../../include/vbuf.h
+tls_proxy_client_scan.o: ../../include/vstream.h
+tls_proxy_client_scan.o: ../../include/vstring.h
+tls_proxy_client_scan.o: tls.h
+tls_proxy_client_scan.o: tls_proxy.h
+tls_proxy_client_scan.o: tls_proxy_client_scan.c
 tls_proxy_clnt.o: ../../include/argv.h
 tls_proxy_clnt.o: ../../include/attr.h
 tls_proxy_clnt.o: ../../include/check_arg.h
@@ -318,46 +364,79 @@ tls_proxy_clnt.o: ../../include/vstring.h
 tls_proxy_clnt.o: tls.h
 tls_proxy_clnt.o: tls_proxy.h
 tls_proxy_clnt.o: tls_proxy_clnt.c
-tls_proxy_print.o: ../../include/argv.h
-tls_proxy_print.o: ../../include/attr.h
-tls_proxy_print.o: ../../include/check_arg.h
-tls_proxy_print.o: ../../include/dns.h
-tls_proxy_print.o: ../../include/htable.h
-tls_proxy_print.o: ../../include/iostuff.h
-tls_proxy_print.o: ../../include/mail_proto.h
-tls_proxy_print.o: ../../include/myaddrinfo.h
-tls_proxy_print.o: ../../include/mymalloc.h
-tls_proxy_print.o: ../../include/name_code.h
-tls_proxy_print.o: ../../include/name_mask.h
-tls_proxy_print.o: ../../include/nvtable.h
-tls_proxy_print.o: ../../include/sock_addr.h
-tls_proxy_print.o: ../../include/sys_defs.h
-tls_proxy_print.o: ../../include/vbuf.h
-tls_proxy_print.o: ../../include/vstream.h
-tls_proxy_print.o: ../../include/vstring.h
-tls_proxy_print.o: tls.h
-tls_proxy_print.o: tls_proxy.h
-tls_proxy_print.o: tls_proxy_print.c
-tls_proxy_scan.o: ../../include/argv.h
-tls_proxy_scan.o: ../../include/attr.h
-tls_proxy_scan.o: ../../include/check_arg.h
-tls_proxy_scan.o: ../../include/dns.h
-tls_proxy_scan.o: ../../include/htable.h
-tls_proxy_scan.o: ../../include/iostuff.h
-tls_proxy_scan.o: ../../include/mail_proto.h
-tls_proxy_scan.o: ../../include/myaddrinfo.h
-tls_proxy_scan.o: ../../include/mymalloc.h
-tls_proxy_scan.o: ../../include/name_code.h
-tls_proxy_scan.o: ../../include/name_mask.h
-tls_proxy_scan.o: ../../include/nvtable.h
-tls_proxy_scan.o: ../../include/sock_addr.h
-tls_proxy_scan.o: ../../include/sys_defs.h
-tls_proxy_scan.o: ../../include/vbuf.h
-tls_proxy_scan.o: ../../include/vstream.h
-tls_proxy_scan.o: ../../include/vstring.h
-tls_proxy_scan.o: tls.h
-tls_proxy_scan.o: tls_proxy.h
-tls_proxy_scan.o: tls_proxy_scan.c
+tls_proxy_context_print.o: ../../include/argv.h
+tls_proxy_context_print.o: ../../include/attr.h
+tls_proxy_context_print.o: ../../include/check_arg.h
+tls_proxy_context_print.o: ../../include/dns.h
+tls_proxy_context_print.o: ../../include/htable.h
+tls_proxy_context_print.o: ../../include/myaddrinfo.h
+tls_proxy_context_print.o: ../../include/mymalloc.h
+tls_proxy_context_print.o: ../../include/name_code.h
+tls_proxy_context_print.o: ../../include/name_mask.h
+tls_proxy_context_print.o: ../../include/nvtable.h
+tls_proxy_context_print.o: ../../include/sock_addr.h
+tls_proxy_context_print.o: ../../include/sys_defs.h
+tls_proxy_context_print.o: ../../include/vbuf.h
+tls_proxy_context_print.o: ../../include/vstream.h
+tls_proxy_context_print.o: ../../include/vstring.h
+tls_proxy_context_print.o: tls.h
+tls_proxy_context_print.o: tls_proxy.h
+tls_proxy_context_print.o: tls_proxy_context_print.c
+tls_proxy_context_scan.o: ../../include/argv.h
+tls_proxy_context_scan.o: ../../include/attr.h
+tls_proxy_context_scan.o: ../../include/check_arg.h
+tls_proxy_context_scan.o: ../../include/dns.h
+tls_proxy_context_scan.o: ../../include/htable.h
+tls_proxy_context_scan.o: ../../include/msg.h
+tls_proxy_context_scan.o: ../../include/myaddrinfo.h
+tls_proxy_context_scan.o: ../../include/mymalloc.h
+tls_proxy_context_scan.o: ../../include/name_code.h
+tls_proxy_context_scan.o: ../../include/name_mask.h
+tls_proxy_context_scan.o: ../../include/nvtable.h
+tls_proxy_context_scan.o: ../../include/sock_addr.h
+tls_proxy_context_scan.o: ../../include/sys_defs.h
+tls_proxy_context_scan.o: ../../include/vbuf.h
+tls_proxy_context_scan.o: ../../include/vstream.h
+tls_proxy_context_scan.o: ../../include/vstring.h
+tls_proxy_context_scan.o: tls.h
+tls_proxy_context_scan.o: tls_proxy.h
+tls_proxy_context_scan.o: tls_proxy_context_scan.c
+tls_proxy_server_print.o: ../../include/argv.h
+tls_proxy_server_print.o: ../../include/attr.h
+tls_proxy_server_print.o: ../../include/check_arg.h
+tls_proxy_server_print.o: ../../include/dns.h
+tls_proxy_server_print.o: ../../include/htable.h
+tls_proxy_server_print.o: ../../include/myaddrinfo.h
+tls_proxy_server_print.o: ../../include/mymalloc.h
+tls_proxy_server_print.o: ../../include/name_code.h
+tls_proxy_server_print.o: ../../include/name_mask.h
+tls_proxy_server_print.o: ../../include/nvtable.h
+tls_proxy_server_print.o: ../../include/sock_addr.h
+tls_proxy_server_print.o: ../../include/sys_defs.h
+tls_proxy_server_print.o: ../../include/vbuf.h
+tls_proxy_server_print.o: ../../include/vstream.h
+tls_proxy_server_print.o: ../../include/vstring.h
+tls_proxy_server_print.o: tls.h
+tls_proxy_server_print.o: tls_proxy.h
+tls_proxy_server_print.o: tls_proxy_server_print.c
+tls_proxy_server_scan.o: ../../include/argv.h
+tls_proxy_server_scan.o: ../../include/attr.h
+tls_proxy_server_scan.o: ../../include/check_arg.h
+tls_proxy_server_scan.o: ../../include/dns.h
+tls_proxy_server_scan.o: ../../include/htable.h
+tls_proxy_server_scan.o: ../../include/myaddrinfo.h
+tls_proxy_server_scan.o: ../../include/mymalloc.h
+tls_proxy_server_scan.o: ../../include/name_code.h
+tls_proxy_server_scan.o: ../../include/name_mask.h
+tls_proxy_server_scan.o: ../../include/nvtable.h
+tls_proxy_server_scan.o: ../../include/sock_addr.h
+tls_proxy_server_scan.o: ../../include/sys_defs.h
+tls_proxy_server_scan.o: ../../include/vbuf.h
+tls_proxy_server_scan.o: ../../include/vstream.h
+tls_proxy_server_scan.o: ../../include/vstring.h
+tls_proxy_server_scan.o: tls.h
+tls_proxy_server_scan.o: tls_proxy.h
+tls_proxy_server_scan.o: tls_proxy_server_scan.c
 tls_rsa.o: ../../include/argv.h
 tls_rsa.o: ../../include/check_arg.h
 tls_rsa.o: ../../include/dns.h
index 79b8d73a3b10903f7ed422e16898b12af1bb5955..a9c4d7885e3ef29e583ce5231788eb52b55d6dfe 100644 (file)
@@ -448,6 +448,7 @@ typedef struct {
 typedef struct {
     TLS_APPL_STATE *ctx;
     VSTREAM *stream;
+    int     fd;                                /* Event-driven file descriptor */
     int     timeout;
     int     tls_level;                 /* Security level */
     const char *nexthop;               /* destination domain */
@@ -465,6 +466,8 @@ typedef struct {
 
 extern TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *);
 extern TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *);
+extern TLS_SESS_STATE *tls_client_post_connect(TLS_SESS_STATE *,
+                                           const TLS_CLIENT_START_PROPS *);
 
 #define tls_client_stop(ctx, stream, timeout, failure, TLScontext) \
        tls_session_stop(ctx, (stream), (timeout), (failure), (TLScontext))
@@ -477,11 +480,12 @@ extern TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *);
     ((props)->a12), ((props)->a13), (props)))
 
 #define TLS_CLIENT_START(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \
-    a10, a11, a12, a13, a14, a15) \
+    a10, a11, a12, a13, a14, a15, a16) \
     tls_client_start((((props)->a1), ((props)->a2), ((props)->a3), \
     ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
     ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \
-    ((props)->a12), ((props)->a13), ((props)->a14), ((props)->a15), (props)))
+    ((props)->a12), ((props)->a13), ((props)->a14), ((props)->a15), \
+    ((props)->a16), (props)))
 
  /*
   * tls_server.c
@@ -674,6 +678,11 @@ extern int tls_ext_seed(int);
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
 /*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*
 /*     Victor Duchovni
 /*     Morgan Stanley
 /*--*/
index bbe18f9050fba1cd5aff8ce8842914567b6f919e..6b4dfda71dbfc7c21ee5ae099dbdc9710dcdc37c 100644 (file)
 /*     TLS_SESS_STATE *tls_client_start(start_props)
 /*     const TLS_CLIENT_START_PROPS *start_props;
 /*
+/*     TLS_SESS_STATE *tls_client_post_connect(TLScontext, start_props)
+/*     TLS_SESS_STATE *TLScontext;
+/*     const TLS_CLIENT_START_PROPS *start_props;
+/*
 /*     void    tls_client_stop(app_ctx, stream, failure, TLScontext)
 /*     TLS_APPL_STATE *app_ctx;
 /*     VSTREAM *stream;
 /*     the fingerprint of the certificate.
 /* .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 TLS library historically provides,
+/*     including tls_client_stop() and the underlying tls_stream(3)
+/*     and tls_bio_ops(3) routines.
+/*
+/*     With the current TLS library implementation, this means
+/*     that an event-driven application is responsible for calling
+/*     and retrying SSL_connect(), SSL_read(), SSL_write() and
+/*     SSL_shutdown().
+/*
+/*     To maintain control over TLS I/O, an event-driven client
+/*     invokes tls_client_start() with a null VSTREAM argument and
+/*     with an fd argument that specifies the I/O file descriptor.
+/*     Then, tls_client_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_connect(), and if successful,
+/*     for invoking tls_client_post_connect() to finish the work
+/*     that was started by tls_client_start(). In case of unrecoverable
+/*     failure, tls_client_post_connect() destroys the TLS context
+/*     and returns a null pointer value.
 /* LICENSE
 /* .ad
 /* .fi
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
 /*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*
 /*     Victor Duchovni
 /*     Morgan Stanley
 /*--*/
@@ -837,8 +871,6 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
     int     protomask;
     const char *cipher_list;
     SSL_SESSION *session = 0;
-    SSL_CIPHER_const SSL_CIPHER *cipher;
-    X509   *peercert;
     TLS_SESS_STATE *TLScontext;
     TLS_APPL_STATE *app_ctx = props->ctx;
     char   *myserverid;
@@ -1018,7 +1050,8 @@ 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) {
+    if (SSL_set_fd(TLScontext->con, props->stream == 0 ? props->fd :
+                  vstream_fileno(props->stream)) != 1) {
        msg_info("SSL_set_fd error to %s", props->namaddr);
        tls_print_errors();
        uncache_session(app_ctx->ssl_ctx, TLScontext);
@@ -1026,12 +1059,6 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
        return (0);
     }
 
-    /*
-     * Turn on non-blocking I/O so that we can enforce timeouts on network
-     * I/O.
-     */
-    non_blocking(vstream_fileno(props->stream), NON_BLOCKING);
-
     /*
      * If the debug level selected is high enough, all of the data is dumped:
      * TLS_LOG_TLSPKTS will dump the SSL negotiation, TLS_LOG_ALLPKTS will
@@ -1046,6 +1073,19 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
 
     tls_dane_set_callback(app_ctx->ssl_ctx, TLScontext);
 
+    /*
+     * If we don't trigger the handshake in the library, leave control over
+     * SSL_connect/read/write/etc with the application.
+     */
+    if (props->stream == 0)
+       return (TLScontext);
+
+    /*
+     * Turn on non-blocking I/O so that we can enforce timeouts on network
+     * I/O.
+     */
+    non_blocking(vstream_fileno(props->stream), NON_BLOCKING);
+
     /*
      * Start TLS negotiations. This process is a black box that invokes our
      * call-backs for certificate verification.
@@ -1069,8 +1109,19 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
        tls_free_context(TLScontext);
        return (0);
     }
+    return (tls_client_post_connect(TLScontext, props));
+}
+
+/* tls_client_post_connect - post-handshake processing */
+
+TLS_SESS_STATE *tls_client_post_connect(TLS_SESS_STATE *TLScontext,
+                                       const TLS_CLIENT_START_PROPS *props)
+{
+    SSL_CIPHER_const SSL_CIPHER *cipher;
+    X509   *peercert;
+
     /* Turn off packet dump if only dumping the handshake */
-    if ((log_mask & TLS_LOG_ALLPKTS) == 0)
+    if ((TLScontext->log_mask & TLS_LOG_ALLPKTS) == 0)
        BIO_set_callback(SSL_get_rbio(TLScontext->con), 0);
 
     /*
@@ -1078,7 +1129,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
      * session was negotiated.
      */
     TLScontext->session_reused = SSL_session_reused(TLScontext->con);
-    if ((log_mask & TLS_LOG_CACHE) && TLScontext->session_reused)
+    if ((TLScontext->log_mask & TLS_LOG_CACHE) && TLScontext->session_reused)
        msg_info("%s: Reusing old session", TLScontext->namaddr);
 
     /*
@@ -1125,7 +1176,8 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
      * The TLS engine is active. Switch to the tls_timed_read/write()
      * functions and make the TLScontext available to those functions.
      */
-    tls_stream_start(props->stream, TLScontext);
+    if (TLScontext->stream != 0)
+       tls_stream_start(props->stream, TLScontext);
 
     /*
      * Fully secured only if trusted, matched and not insecure like halfdane.
@@ -1142,7 +1194,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
     /*
      * All the key facts in a single log entry.
      */
-    if (log_mask & TLS_LOG_SUMMARY)
+    if (TLScontext->log_mask & TLS_LOG_SUMMARY)
        msg_info("%s TLS connection established to %s: %s with cipher %s "
                 "(%d/%d bits)",
                 !TLS_CERT_IS_PRESENT(TLScontext) ? "Anonymous" :
index 5cee6663f82367f9740a21fab89d2f6b8935b0bb..de7ba77ff3a2567ed19b4fa0a4d8fc7d9fd05459 100644 (file)
@@ -1346,26 +1346,20 @@ int     tls_dane_match(TLS_SESS_STATE *TLScontext, int usage,
     return (matched);
 }
 
-/* push_ext - push extension onto certificate's stack, else free it */
-
-static int push_ext(X509 *cert, X509_EXTENSION *ext)
-{
-    if (ext) {
-       if (X509_add_ext(cert, ext, -1))
-           return 1;
-       X509_EXTENSION_free(ext);
-    }
-    return 0;
-}
-
 /* add_ext - add simple extension (no config section references) */
 
 static int add_ext(X509 *issuer, X509 *subject, int ext_nid, char *ext_val)
 {
+    int ret = 0;
     X509V3_CTX v3ctx;
+    X509_EXTENSION *ext;
 
     X509V3_set_ctx(&v3ctx, issuer, subject, 0, 0, 0);
-    return push_ext(subject, X509V3_EXT_conf_nid(0, &v3ctx, ext_nid, ext_val));
+    if ((ext = X509V3_EXT_conf_nid(0, &v3ctx, ext_nid, ext_val)) != 0) {
+       ret = X509_add_ext(subject, ext, -1);
+       X509_EXTENSION_free(ext);
+    }
+    return ret;
 }
 
 /* set_serial - set serial number to match akid or use subject's plus 1 */
index e677c67aba9d38e562198afb8832cd13c373a24d..cdfdf6388470d22f67d2e51a799e7e4a5c7e1f92 100644 (file)
 
 #ifdef USE_TLS
 
+#define tls_proxy_legacy_open(service, flags, peer_stream, peer_addr, \
+                                          peer_port, timeout, serverid) \
+    tls_proxy_open((service), (flags), (peer_stream), (peer_addr), \
+       (peer_port), (timeout), (timeout), (serverid), (void *) 0, (void *) 0)
+
 extern VSTREAM *tls_proxy_open(const char *, int, VSTREAM *, const char *,
-                                      const char *, int);
+                                      const char *, int, int, const char *,
+                                      void *, void *);
+
+#define TLS_PROXY_CLIENT_INIT_PROPS(props, a1, a2, a3, a4, a5, a6, a7, a8, \
+    a9, a10, a11, a12, a13) \
+    (((props)->a1), ((props)->a2), ((props)->a3), \
+    ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
+    ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \
+    ((props)->a12), ((props)->a13))
+
+#define TLS_PROXY_CLIENT_START_PROPS(props, a1, a2, a3, a4, a5, a6, a7, a8, \
+    a9, a10, a11, a12, a13) \
+    (((props)->a1), ((props)->a2), ((props)->a3), \
+    ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
+    ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \
+    ((props)->a12), ((props)->a13))
+
 extern TLS_SESS_STATE *tls_proxy_context_receive(VSTREAM *);
 extern void tls_proxy_context_free(TLS_SESS_STATE *);
 extern int tls_proxy_context_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *);
 extern int tls_proxy_context_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *);
 
+extern int tls_proxy_client_init_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *);
+extern int tls_proxy_client_init_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *);
+extern void tls_proxy_client_init_free(TLS_CLIENT_INIT_PROPS *);
+extern char *tls_proxy_client_init_to_string(VSTRING *, TLS_CLIENT_INIT_PROPS *);
+
+extern int tls_proxy_client_start_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *);
+extern int tls_proxy_client_start_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *);
+extern void tls_proxy_client_start_free(TLS_CLIENT_START_PROPS *);
+
+extern int tls_proxy_server_init_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *);
+extern int tls_proxy_server_init_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *);
+extern void tls_proxy_server_init_free(TLS_SERVER_INIT_PROPS *);
+
+extern int tls_proxy_server_start_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *);
+extern int tls_proxy_server_start_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *);
+
+extern void tls_proxy_server_start_free(TLS_SERVER_START_PROPS *);
+
+#endif                                 /* USE_TLS */
+
+ /*
+  * TLSPROXY attributes, unconditionally exposed.
+  */
+#define TLS_ATTR_REMOTE_ENDPT  "remote_endpoint"       /* name[addr]:port */
+#define TLS_ATTR_FLAGS         "flags"
+#define TLS_ATTR_TIMEOUT       "timeout"
+#define TLS_ATTR_SERVERID      "serverid"
+
+#ifdef USE_TLS
+
+ /*
+  * Misc attributes.
+  */
+#define TLS_ATTR_COUNT         "count"
+
+ /*
+  * TLS_SESS_STATE attributes.
+  */
+#define TLS_ATTR_PEER_CN       "peer_CN"
+#define TLS_ATTR_ISSUER_CN     "issuer_CN"
+#define TLS_ATTR_PEER_CERT_FPT "peer_fingerprint"
+#define TLS_ATTR_PEER_PKEY_FPT "peer_pubkey_fingerprint"
+#define TLS_ATTR_PEER_STATUS   "peer_status"
+#define TLS_ATTR_CIPHER_PROTOCOL "cipher_protocol"
+#define TLS_ATTR_CIPHER_NAME   "cipher_name"
+#define TLS_ATTR_CIPHER_USEBITS        "cipher_usebits"
+#define TLS_ATTR_CIPHER_ALGBITS        "cipher_algbits"
+
+ /*
+  * TLS_SERVER_INIT_PROPS attributes.
+  */
+#define TLS_ATTR_LOG_PARAM     "log_param"
+#define TLS_ATTR_LOG_LEVEL     "log_level"
+#define TLS_ATTR_VERIFYDEPTH   "verifydepth"
+#define TLS_ATTR_CACHE_TYPE    "cache_type"
+#define TLS_ATTR_SET_SESSID    "set_sessid"
+#define TLS_ATTR_CERT_FILE     "cert_file"
+#define TLS_ATTR_KEY_FILE      "key_file"
+#define TLS_ATTR_DCERT_FILE    "dcert_file"
+#define TLS_ATTR_DKEY_FILE     "dkey_file"
+#define TLS_ATTR_ECCERT_FILE   "eccert_file"
+#define TLS_ATTR_ECKEY_FILE    "eckey_file"
+#define TLS_ATTR_CAFILE                "CAfile"
+#define TLS_ATTR_CAPATH                "CApath"
+#define TLS_ATTR_PROTOCOLS     "protocols"
+#define TLS_ATTR_EECDH_GRADE   "eecdh_grade"
+#define TLS_ATTR_DH1K_PARAM_FILE "dh1024_param_file"
+#define TLS_ATTR_DH512_PARAM_FILE "dh512_param_file"
+#define TLS_ATTR_ASK_CCERT     "ask_ccert"
+#define TLS_ATTR_MDALG         "mdalg"
+
+ /*
+  * TLS_SERVER_START_PROPS attributes.
+  */
+#define TLS_ATTR_TIMEOUT       "timeout"
+#define TLS_ATTR_REQUIRECERT   "requirecert"
+#define TLS_ATTR_SERVERID      "serverid"
+#define TLS_ATTR_NAMADDR       "namaddr"
+#define TLS_ATTR_CIPHER_GRADE  "cipher_grade"
+#define TLS_ATTR_CIPHER_EXCLUSIONS "cipher_exclusions"
+#define TLS_ATTR_MDALG         "mdalg"
+
+ /*
+  * TLS_CLIENT_INIT_PROPS attributes.
+  */
+#define TLS_ATTR_LOG_PARAM     "log_param"
+#define TLS_ATTR_LOG_LEVEL     "log_level"
+#define TLS_ATTR_VERIFYDEPTH   "verifydepth"
+#define TLS_ATTR_CACHE_TYPE    "cache_type"
+#define TLS_ATTR_CERT_FILE     "cert_file"
+#define TLS_ATTR_KEY_FILE      "key_file"
+#define TLS_ATTR_DCERT_FILE    "dcert_file"
+#define TLS_ATTR_DKEY_FILE     "dkey_file"
+#define TLS_ATTR_ECCERT_FILE   "eccert_file"
+#define TLS_ATTR_ECKEY_FILE    "eckey_file"
+#define TLS_ATTR_CAFILE                "CAfile"
+#define TLS_ATTR_CAPATH                "CApath"
+#define TLS_ATTR_MDALG         "mdalg"
+
+ /*
+  * TLS_CLIENT_START_PROPS attributes.
+  */
+#define TLS_ATTR_TIMEOUT       "timeout"
+#define TLS_ATTR_TLS_LEVEL     "tls_level"
+#define TLS_ATTR_NEXTHOP       "nexthop"
+#define TLS_ATTR_HOST          "host"
+#define TLS_ATTR_NAMADDR       "namaddr"
+#define TLS_ATTR_SERVERID      "serverid"
+#define TLS_ATTR_HELO          "helo"
+#define TLS_ATTR_PROTOCOLS     "protocols"
+#define TLS_ATTR_CIPHER_GRADE  "cipher_grade"
+#define TLS_ATTR_CIPHER_EXCLUSIONS "cipher_exclusions"
+#define TLS_ATTR_MATCHARGV     "matchargv"
+#define TLS_ATTR_MDALG         "mdalg"
+#define        TLS_ATTR_DANE           "dane"
+
+ /*
+  * TLS_TLSA attributes.
+  */
+#define TLS_ATTR_MDALG         "mdalg"
+#define TLS_ATTR_CERTS         "certs"
+#define TLS_ATTR_PKEYS         "pkeys"
+
+ /*
+  * TLS_CERTS attributes.
+  */
+#define TLS_ATTR_CERT          "cert"
+
+ /*
+  * TLS_PKEYS attributes.
+  */
+#define TLS_ATTR_PKEY          "pkey"
+
+ /*
+  * TLS_DANE attributes.
+  */
+#define TLS_ATTR_TA            "ta"
+#define TLS_ATTR_EE            "ee"
+#define TLS_ATTR_CERTS         "certs"
+#define TLS_ATTR_PKEYS         "pkeys"
+#define TLS_ATTR_DOMAIN                "domain"
+#define TLS_ATTR_FLAGS         "flags"
+#define TLS_ATTR_EXP           "exp"
+
 #endif
 
 /* LICENSE
@@ -49,6 +214,11 @@ extern int tls_proxy_context_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *);
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
 #endif
diff --git a/postfix/src/tls/tls_proxy_client_print.c b/postfix/src/tls/tls_proxy_client_print.c
new file mode 100644 (file)
index 0000000..7ed66b9
--- /dev/null
@@ -0,0 +1,324 @@
+/*++
+/* NAME
+/*     tls_proxy_client_print 3
+/* SUMMARY
+/*     write TLS_CLIENT_XXX structures to stream
+/* SYNOPSIS
+/*     #include <tls_proxy.h>
+/*
+/*     int     tls_proxy_client_init_print(print_fn, stream, flags, ptr)
+/*     ATTR_PRINT_MASTER_FN print_fn;
+/*     VSTREAM *stream;
+/*     int     flags;
+/*     void    *ptr;
+/*
+/*     int     tls_proxy_client_start_print(print_fn, stream, flags, ptr)
+/*     ATTR_PRINT_MASTER_FN print_fn;
+/*     VSTREAM *stream;
+/*     int     flags;
+/*     void    *ptr;
+/* DESCRIPTION
+/*     tls_proxy_client_init_print() writes a full TLS_CLIENT_INIT_PROPS
+/*     structure to the named stream using the specified attribute
+/*     print routine. tls_proxy_client_init_print() is meant to
+/*     be passed as a call-back to attr_print(), thusly:
+/*
+/*     SEND_ATTR_FUNC(tls_proxy_client_init_print, (void *) init_props), ...
+/*
+/*     tls_proxy_client_start_print() writes a TLS_CLIENT_START_PROPS
+/*     structure, without stream or file descriptor members, to
+/*     the named stream using the specified attribute print routine.
+/*     tls_proxy_client_start_print() is meant to be passed as a
+/*     call-back to attr_print(), thusly:
+/*
+/*     SEND_ATTR_FUNC(tls_proxy_client_start_print, (void *) start_props), ...
+/* DIAGNOSTICS
+/*     Fatal: out of memory.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*--*/
+
+#ifdef USE_TLS
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library */
+
+#include <argv_attr.h>
+#include <attr.h>
+#include <msg.h>
+
+/* TLS library. */
+
+#include <tls.h>
+#include <tls_proxy.h>
+
+
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
+/* tls_proxy_client_init_print - send TLS_CLIENT_INIT_PROPS over stream */
+
+int     tls_proxy_client_init_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp,
+                                           int flags, void *ptr)
+{
+    TLS_CLIENT_INIT_PROPS *props = (TLS_CLIENT_INIT_PROPS *) ptr;
+    int     ret;
+
+    if (msg_verbose)
+       msg_info("begin tls_proxy_client_init_print");
+
+#define STRING_OR_EMPTY(s) ((s) ? (s) : "")
+
+    ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                  SEND_ATTR_STR(TLS_ATTR_LOG_PARAM,
+                                STRING_OR_EMPTY(props->log_param)),
+                  SEND_ATTR_STR(TLS_ATTR_LOG_LEVEL,
+                                STRING_OR_EMPTY(props->log_level)),
+                  SEND_ATTR_INT(TLS_ATTR_VERIFYDEPTH, props->verifydepth),
+                  SEND_ATTR_STR(TLS_ATTR_CACHE_TYPE,
+                                STRING_OR_EMPTY(props->cache_type)),
+                  SEND_ATTR_STR(TLS_ATTR_CERT_FILE,
+                                STRING_OR_EMPTY(props->cert_file)),
+                  SEND_ATTR_STR(TLS_ATTR_KEY_FILE,
+                                STRING_OR_EMPTY(props->key_file)),
+                  SEND_ATTR_STR(TLS_ATTR_DCERT_FILE,
+                                STRING_OR_EMPTY(props->dcert_file)),
+                  SEND_ATTR_STR(TLS_ATTR_DKEY_FILE,
+                                STRING_OR_EMPTY(props->dkey_file)),
+                  SEND_ATTR_STR(TLS_ATTR_ECCERT_FILE,
+                                STRING_OR_EMPTY(props->eccert_file)),
+                  SEND_ATTR_STR(TLS_ATTR_ECKEY_FILE,
+                                STRING_OR_EMPTY(props->eckey_file)),
+                  SEND_ATTR_STR(TLS_ATTR_CAFILE,
+                                STRING_OR_EMPTY(props->CAfile)),
+                  SEND_ATTR_STR(TLS_ATTR_CAPATH,
+                                STRING_OR_EMPTY(props->CApath)),
+                  SEND_ATTR_STR(TLS_ATTR_MDALG,
+                                STRING_OR_EMPTY(props->mdalg)),
+                  ATTR_TYPE_END);
+    /* Do not flush the stream. */
+    if (msg_verbose)
+       msg_info("tls_proxy_client_init_print ret=%d", ret);
+    return (ret);
+}
+
+/* tls_proxy_client_certs_print - send x509 certificates over stream */
+
+static int tls_proxy_client_certs_print(ATTR_PRINT_MASTER_FN print_fn,
+                                         VSTREAM *fp, int flags, void *ptr)
+{
+    TLS_CERTS *tls_certs = (TLS_CERTS *) ptr;
+    TLS_CERTS *tp;
+    int     count;
+    int     ret;
+
+    for (tp = tls_certs, count = 0; tp != 0; tp = tp->next, count++)
+        /* void */ ;
+    if (msg_verbose)
+       msg_info("tls_proxy_client_certs_print count=%d", count);
+
+    ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                  SEND_ATTR_INT(TLS_ATTR_COUNT, count),
+                  ATTR_TYPE_END);
+
+    if (ret == 0 && count > 0) {
+       VSTRING *buf = vstring_alloc(100);
+       int     n;
+
+       for (tp = tls_certs, n = 0; ret == 0 && n < count; tp = tp->next, n++) {
+           size_t  len = i2d_X509(tp->cert, (unsigned char **) 0);
+           unsigned char *bp;
+
+           VSTRING_RESET(buf);
+           VSTRING_SPACE(buf, len);
+           bp = (unsigned char *) STR(buf);
+           i2d_X509(tp->cert, &bp);
+           if ((char *) bp - STR(buf) != len)
+               msg_panic("i2d_X509 failed to encode certificate");
+           ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                          SEND_ATTR_DATA(TLS_ATTR_CERT, LEN(buf), STR(buf)),
+                          ATTR_TYPE_END);
+       }
+       vstring_free(buf);
+    }
+    /* Do not flush the stream. */
+    if (msg_verbose)
+       msg_info("tls_proxy_client_certs_print ret=%d", count);
+    return (ret);
+}
+
+/* tls_proxy_client_pkeys_print - send public keys over stream */
+
+static int tls_proxy_client_pkeys_print(ATTR_PRINT_MASTER_FN print_fn,
+                                         VSTREAM *fp, int flags, void *ptr)
+{
+    TLS_PKEYS *tls_pkeys = (TLS_PKEYS *) ptr;
+    TLS_PKEYS *tp;
+    int     count;
+    int     ret;
+
+    for (tp = tls_pkeys, count = 0; tp != 0; tp = tp->next, count++)
+        /* void */ ;
+    if (msg_verbose)
+       msg_info("tls_proxy_client_pkeys_print count=%d", count);
+
+    ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                  SEND_ATTR_INT(TLS_ATTR_COUNT, count),
+                  ATTR_TYPE_END);
+
+    if (ret == 0 && count > 0) {
+       VSTRING *buf = vstring_alloc(100);
+       int     n;
+
+       for (tp = tls_pkeys, n = 0; ret == 0 && n < count; tp = tp->next, n++) {
+           size_t  len = i2d_PUBKEY(tp->pkey, (unsigned char **) 0);
+           unsigned char *bp;
+
+           VSTRING_RESET(buf);
+           VSTRING_SPACE(buf, len);
+           bp = (unsigned char *) STR(buf);
+           i2d_PUBKEY(tp->pkey, &bp);
+           if ((char *) bp - STR(buf) != len)
+               msg_panic("i2d_PUBKEY failed to encode public key");
+           ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                          SEND_ATTR_DATA(TLS_ATTR_PKEY, LEN(buf), STR(buf)),
+                          ATTR_TYPE_END);
+       }
+       vstring_free(buf);
+    }
+    /* Do not flush the stream. */
+    if (msg_verbose)
+       msg_info("tls_proxy_client_pkeys_print ret=%d", count);
+    return (ret);
+}
+
+/* tls_proxy_client_tlsa_print - send TLS_TLSA over stream */
+
+static int tls_proxy_client_tlsa_print(ATTR_PRINT_MASTER_FN print_fn,
+                                         VSTREAM *fp, int flags, void *ptr)
+{
+    TLS_TLSA *tls_tlsa = (TLS_TLSA *) ptr;
+    TLS_TLSA *tp;
+    int     count;
+    int     ret;
+
+    for (tp = tls_tlsa, count = 0; tp != 0; tp = tp->next, count++)
+        /* void */ ;
+    if (msg_verbose)
+       msg_info("tls_proxy_client_tlsa_print count=%d", count);
+
+    ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                  SEND_ATTR_INT(TLS_ATTR_COUNT, count),
+                  ATTR_TYPE_END);
+
+    if (ret == 0 && count > 0) {
+       int     n;
+
+       for (tp = tls_tlsa, n = 0; ret == 0 && n < count; tp = tp->next, n++) {
+           ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                          SEND_ATTR_STR(TLS_ATTR_MDALG, tp->mdalg),
+                          SEND_ATTR_FUNC(argv_attr_print,
+                                         (void *) tp->certs),
+                          SEND_ATTR_FUNC(argv_attr_print,
+                                         (void *) tp->pkeys),
+                          ATTR_TYPE_END);
+       }
+    }
+    /* Do not flush the stream. */
+    if (msg_verbose)
+       msg_info("tls_proxy_client_tlsa_print ret=%d", count);
+    return (ret);
+}
+
+/* tls_proxy_client_dane_print - send TLS_DANE over stream */
+
+static int tls_proxy_client_dane_print(ATTR_PRINT_MASTER_FN print_fn,
+                                         VSTREAM *fp, int flags, void *ptr)
+{
+    TLS_DANE *dane = (TLS_DANE *) ptr;
+    int     ret;
+
+    ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                  SEND_ATTR_INT(TLS_ATTR_DANE, dane != 0),
+                  ATTR_TYPE_END);
+    if (msg_verbose)
+       msg_info("tls_proxy_client_dane_print dane=%d", dane != 0);
+
+    if (ret == 0 && dane != 0) {
+       ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                      SEND_ATTR_FUNC(tls_proxy_client_tlsa_print,
+                                     (void *) dane->ta),
+                      SEND_ATTR_FUNC(tls_proxy_client_tlsa_print,
+                                     (void *) dane->ee),
+                      SEND_ATTR_FUNC(tls_proxy_client_certs_print,
+                                     (void *) dane->certs),
+                      SEND_ATTR_FUNC(tls_proxy_client_pkeys_print,
+                                     (void *) dane->pkeys),
+                      SEND_ATTR_STR(TLS_ATTR_DOMAIN,
+                                    STRING_OR_EMPTY(dane->base_domain)),
+                      SEND_ATTR_INT(TLS_ATTR_FLAGS, dane->flags),
+                      SEND_ATTR_LONG(TLS_ATTR_EXP, dane->expires),
+                      ATTR_TYPE_END);
+    }
+    /* Do not flush the stream. */
+    if (msg_verbose)
+       msg_info("tls_proxy_client_dane_print ret=%d", ret);
+    return (ret);
+}
+
+/* tls_proxy_client_start_print - send TLS_CLIENT_START_PROPS over stream */
+
+int     tls_proxy_client_start_print(ATTR_PRINT_MASTER_FN print_fn,
+                                         VSTREAM *fp, int flags, void *ptr)
+{
+    TLS_CLIENT_START_PROPS *props = (TLS_CLIENT_START_PROPS *) ptr;
+    int     ret;
+
+    if (msg_verbose)
+       msg_info("begin tls_proxy_client_start_print");
+
+#define STRING_OR_EMPTY(s) ((s) ? (s) : "")
+
+    ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                  SEND_ATTR_INT(TLS_ATTR_TIMEOUT, props->timeout),
+                  SEND_ATTR_INT(TLS_ATTR_TLS_LEVEL, props->tls_level),
+                  SEND_ATTR_STR(TLS_ATTR_NEXTHOP,
+                                STRING_OR_EMPTY(props->nexthop)),
+                  SEND_ATTR_STR(TLS_ATTR_HOST,
+                                STRING_OR_EMPTY(props->host)),
+                  SEND_ATTR_STR(TLS_ATTR_NAMADDR,
+                                STRING_OR_EMPTY(props->namaddr)),
+                  SEND_ATTR_STR(TLS_ATTR_SERVERID,
+                                STRING_OR_EMPTY(props->serverid)),
+                  SEND_ATTR_STR(TLS_ATTR_HELO,
+                                STRING_OR_EMPTY(props->helo)),
+                  SEND_ATTR_STR(TLS_ATTR_PROTOCOLS,
+                                STRING_OR_EMPTY(props->protocols)),
+                  SEND_ATTR_STR(TLS_ATTR_CIPHER_GRADE,
+                                STRING_OR_EMPTY(props->cipher_grade)),
+                  SEND_ATTR_STR(TLS_ATTR_CIPHER_EXCLUSIONS,
+                                STRING_OR_EMPTY(props->cipher_exclusions)),
+                  SEND_ATTR_FUNC(argv_attr_print,
+                                 (void *) props->matchargv),
+                  SEND_ATTR_STR(TLS_ATTR_MDALG,
+                                STRING_OR_EMPTY(props->mdalg)),
+                  SEND_ATTR_FUNC(tls_proxy_client_dane_print,
+                                 (void *) props->dane),
+                  ATTR_TYPE_END);
+    /* Do not flush the stream. */
+    if (msg_verbose)
+       msg_info("tls_proxy_client_start_print ret=%d", ret);
+    return (ret);
+}
+
+#endif
diff --git a/postfix/src/tls/tls_proxy_client_scan.c b/postfix/src/tls/tls_proxy_client_scan.c
new file mode 100644 (file)
index 0000000..4577939
--- /dev/null
@@ -0,0 +1,568 @@
+/*++
+/* NAME
+/*     tls_proxy_client_scan 3
+/* SUMMARY
+/*     read TLS_CLIENT_XXX structures from stream
+/* SYNOPSIS
+/*     #include <tls_proxy.h>
+/*
+/*     int     tls_proxy_client_init_scan(scan_fn, stream, flags, ptr)
+/*     ATTR_SCAN_MASTER_FN scan_fn;
+/*     VSTREAM *stream;
+/*     int     flags;
+/*     void    *ptr;
+/*
+/*     char    *tls_proxy_client_init_to_string(buf, init_props)
+/*     VSTRING *buf;
+/*     TLS_CLIENT_INIT_PROPS *init_props;
+/*
+/*     void    tls_proxy_client_init_free(init_props)
+/*     TLS_CLIENT_INIT_PROPS *init_props;
+/*
+/*     int     tls_proxy_client_start_scan(scan_fn, stream, flags, ptr)
+/*     ATTR_SCAN_MASTER_FN scan_fn;
+/*     VSTREAM *stream;
+/*     int     flags;
+/*     void    *ptr;
+/*
+/*     void    tls_proxy_client_start_free(start_props)
+/*     TLS_CLIENT_START_PROPS *start_props;
+/* DESCRIPTION
+/*     tls_proxy_client_init_scan() reads a full TLS_CLIENT_INIT_PROPS
+/*     structure from the named stream using the specified attribute
+/*     scan routine. tls_proxy_client_init_scan() is meant to be passed
+/*     as a call-back function to attr_scan(), as shown below.
+/*
+/*     tls_proxy_client_init_to_string() produces a lookup key
+/*     that is unique for the properties received by
+/*     tls_proxy_client_init_scan().
+/*
+/*     tls_proxy_client_init_free() destroys a TLS_CLIENT_INIT_PROPS
+/*     structure that was created by tls_proxy_client_init_scan().
+/*
+/*     TLS_CLIENT_INIT_PROPS *init_props = 0;
+/*     ...
+/*     ... RECV_ATTR_FUNC(tls_proxy_client_init_scan, (void *) &init_props)
+/*     ...
+/*     if (init_props != 0)
+/*         tls_proxy_client_init_free(init_props);
+/*
+/*     tls_proxy_client_start_scan() reads a TLS_CLIENT_START_PROPS
+/*     structure, without the stream of file descriptor members,
+/*     from the named stream using the specified attribute scan
+/*     routine. tls_proxy_client_start_scan() is meant to be passed
+/*     as a call-back function to attr_scan(), as shown below.
+/*
+/*     tls_proxy_client_start_free() destroys a TLS_CLIENT_START_PROPS
+/*     structure that was created by tls_proxy_client_start_scan().
+/*
+/*     TLS_CLIENT_START_PROPS *start_props = 0;
+/*     ...
+/*     ... RECV_ATTR_FUNC(tls_proxy_client_start_scan, (void *) &start_props)
+/*     ...
+/*     if (start_props != 0)
+/*         tls_proxy_client_start_free(start_props);
+/* DIAGNOSTICS
+/*     Fatal: out of memory.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*--*/
+
+#ifdef USE_TLS
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library */
+
+#include <argv_attr.h>
+#include <attr.h>
+#include <msg.h>
+#include <vstring.h>
+
+/* TLS library. */
+
+#include <tls.h>
+#include <tls_proxy.h>
+
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
+/* tls_proxy_client_init_free - destroy TLS_CLIENT_INIT_PROPS structure */
+
+void    tls_proxy_client_init_free(TLS_CLIENT_INIT_PROPS *props)
+{
+    myfree((void *) props->log_param);
+    myfree((void *) props->log_level);
+    myfree((void *) props->cache_type);
+    myfree((void *) props->cert_file);
+    myfree((void *) props->key_file);
+    myfree((void *) props->dcert_file);
+    myfree((void *) props->dkey_file);
+    myfree((void *) props->eccert_file);
+    myfree((void *) props->eckey_file);
+    myfree((void *) props->CAfile);
+    myfree((void *) props->CApath);
+    myfree((void *) props->mdalg);
+    myfree((void *) props);
+}
+
+/* tls_proxy_client_init_scan - receive TLS_CLIENT_INIT_PROPS from stream */
+
+int     tls_proxy_client_init_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
+                                          int flags, void *ptr)
+{
+    TLS_CLIENT_INIT_PROPS *props
+    = (TLS_CLIENT_INIT_PROPS *) mymalloc(sizeof(*props));
+    int     ret;
+    VSTRING *log_param = vstring_alloc(25);
+    VSTRING *log_level = vstring_alloc(25);
+    VSTRING *cache_type = vstring_alloc(25);
+    VSTRING *cert_file = vstring_alloc(25);
+    VSTRING *key_file = vstring_alloc(25);
+    VSTRING *dcert_file = vstring_alloc(25);
+    VSTRING *dkey_file = vstring_alloc(25);
+    VSTRING *eccert_file = vstring_alloc(25);
+    VSTRING *eckey_file = vstring_alloc(25);
+    VSTRING *CAfile = vstring_alloc(25);
+    VSTRING *CApath = vstring_alloc(25);
+    VSTRING *mdalg = vstring_alloc(25);
+
+    if (msg_verbose)
+       msg_info("begin tls_proxy_client_init_scan");
+
+    /*
+     * Note: memset() is not a portable way to initialize non-integer types.
+     */
+    memset(props, 0, sizeof(*props));
+    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                 RECV_ATTR_STR(TLS_ATTR_LOG_PARAM, log_param),
+                 RECV_ATTR_STR(TLS_ATTR_LOG_LEVEL, log_level),
+                 RECV_ATTR_INT(TLS_ATTR_VERIFYDEPTH, &props->verifydepth),
+                 RECV_ATTR_STR(TLS_ATTR_CACHE_TYPE, cache_type),
+                 RECV_ATTR_STR(TLS_ATTR_CERT_FILE, cert_file),
+                 RECV_ATTR_STR(TLS_ATTR_KEY_FILE, key_file),
+                 RECV_ATTR_STR(TLS_ATTR_DCERT_FILE, dcert_file),
+                 RECV_ATTR_STR(TLS_ATTR_DKEY_FILE, dkey_file),
+                 RECV_ATTR_STR(TLS_ATTR_ECCERT_FILE, eccert_file),
+                 RECV_ATTR_STR(TLS_ATTR_ECKEY_FILE, eckey_file),
+                 RECV_ATTR_STR(TLS_ATTR_CAFILE, CAfile),
+                 RECV_ATTR_STR(TLS_ATTR_CAPATH, CApath),
+                 RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
+                 ATTR_TYPE_END);
+    /* Always construct a well-formed structure. */
+    props->log_param = vstring_export(log_param);
+    props->log_level = vstring_export(log_level);
+    props->cache_type = vstring_export(cache_type);
+    props->cert_file = vstring_export(cert_file);
+    props->key_file = vstring_export(key_file);
+    props->dcert_file = vstring_export(dcert_file);
+    props->dkey_file = vstring_export(dkey_file);
+    props->eccert_file = vstring_export(eccert_file);
+    props->eckey_file = vstring_export(eckey_file);
+    props->CAfile = vstring_export(CAfile);
+    props->CApath = vstring_export(CApath);
+    props->mdalg = vstring_export(mdalg);
+    ret = (ret == 13 ? 1 : -1);
+    if (ret != 1) {
+       tls_proxy_client_init_free(props);
+       props = 0;
+    }
+    *(TLS_CLIENT_INIT_PROPS **) ptr = props;
+    if (msg_verbose)
+       msg_info("tls_proxy_client_init_scan ret=%d", ret);
+    return (ret);
+}
+
+/* tls_proxy_client_init_to_string - serialize to string */
+
+char   *tls_proxy_client_init_to_string(VSTRING *buf,
+                                               TLS_CLIENT_INIT_PROPS *props)
+{
+    vstring_sprintf(buf, "%s\n%s\n%d\n%s\n%s\n%s\n%s\n%s\n"
+                   "%s\n%s\n%s\n%s\n%s\n", props->log_param,
+                   props->log_level, props->verifydepth,
+                   props->cache_type, props->cert_file, props->key_file,
+                   props->dcert_file, props->dkey_file,
+                   props->eccert_file, props->eckey_file,
+                   props->CAfile, props->CApath, props->mdalg);
+    return (vstring_str(buf));
+}
+
+/* tls_proxy_client_certs_free - destroy TLS_PKEYS from stream */
+
+static void tls_proxy_client_certs_free(TLS_CERTS *tp)
+{
+    if (tp->next)
+       tls_proxy_client_certs_free(tp->next);
+    if (tp->cert)
+       X509_free(tp->cert);
+    myfree((void *) tp);
+}
+
+/* tls_proxy_client_pkeys_free - destroy TLS_PKEYS from stream */
+
+static void tls_proxy_client_pkeys_free(TLS_PKEYS *tp)
+{
+    if (tp->next)
+       tls_proxy_client_pkeys_free(tp->next);
+    if (tp->pkey)
+       EVP_PKEY_free(tp->pkey);
+    myfree((void *) tp);
+}
+
+/* tls_proxy_client_tlsa_free - destroy TLS_TLSA from stream */
+
+static void tls_proxy_client_tlsa_free(TLS_TLSA *tp)
+{
+    if (tp->next)
+       tls_proxy_client_tlsa_free(tp->next);
+    myfree(tp->mdalg);
+    if (tp->certs)
+       argv_free(tp->certs);
+    if (tp->pkeys)
+       argv_free(tp->pkeys);
+    myfree((void *) tp);
+}
+
+/* tls_proxy_client_dane_free - destroy TLS_DANE from stream */
+
+static void tls_proxy_client_dane_free(TLS_DANE *dane)
+{
+    if (dane->ta)
+       tls_proxy_client_tlsa_free(dane->ta);
+    if (dane->ee)
+       tls_proxy_client_tlsa_free(dane->ee);
+    if (dane->certs)
+       tls_proxy_client_certs_free(dane->certs);
+    if (dane->pkeys)
+       tls_proxy_client_pkeys_free(dane->pkeys);
+    myfree(dane->base_domain);
+    if (dane->refs-- == 1)
+       myfree((void *) dane);
+}
+
+/* tls_proxy_client_start_free - destroy TLS_CLIENT_START_PROPS structure */
+
+void    tls_proxy_client_start_free(TLS_CLIENT_START_PROPS *props)
+{
+    myfree((void *) props->nexthop);
+    myfree((void *) props->host);
+    myfree((void *) props->namaddr);
+    myfree((void *) props->serverid);
+    myfree((void *) props->helo);
+    myfree((void *) props->protocols);
+    myfree((void *) props->cipher_grade);
+    myfree((void *) props->cipher_exclusions);
+    if (props->matchargv)
+       argv_free((ARGV *) props->matchargv);
+    myfree((void *) props->mdalg);
+    if (props->dane)
+       tls_proxy_client_dane_free((TLS_DANE *) props->dane);
+    myfree((void *) props);
+}
+
+/* tls_proxy_client_certs_scan - receive TLS_CERTS from stream */
+
+static int tls_proxy_client_certs_scan(ATTR_SCAN_MASTER_FN scan_fn,
+                                         VSTREAM *fp, int flags, void *ptr)
+{
+    int     ret;
+    int     count;
+    VSTRING *buf = 0;
+    TLS_CERTS **tpp;
+    TLS_CERTS *head = 0;
+    TLS_CERTS *tp;
+    int     n;
+
+    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                 RECV_ATTR_INT(TLS_ATTR_COUNT, &count),
+                 ATTR_TYPE_END);
+    if (msg_verbose)
+       msg_info("tls_proxy_client_certs_scan count=%d", count);
+
+    for (tpp = &head, n = 0; ret == 1 && n < count; n++, tpp = &tp->next) {
+       *tpp = tp = (TLS_CERTS *) mymalloc(sizeof(*tp));
+       D2I_const unsigned char *bp;
+
+       if (buf == 0)
+           buf = vstring_alloc(100);
+
+       /*
+        * Note: memset() is not a portable way to initialize non-integer
+        * types.
+        */
+       memset(tp, 0, sizeof(*tp));
+       ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                     RECV_ATTR_DATA(TLS_ATTR_CERT, buf),
+                     ATTR_TYPE_END);
+       /* Always construct a well-formed structure. */
+       if (ret == 1) {
+           bp = (D2I_const unsigned char *) STR(buf);
+           if (d2i_X509(&tp->cert, &bp, LEN(buf)) == 0
+               || LEN(buf) != ((char *) bp) - STR(buf)) {
+               msg_warn("malformed certificate in TLS_CERTS");
+               ret = -1;
+           }
+       } else {
+           tp->cert = 0;
+       }
+       tp->next = 0;
+    }
+    if (buf)
+       vstring_free(buf);
+    if (ret != 1) {
+       tls_proxy_client_certs_free(head);
+       head = 0;
+    }
+    *(TLS_CERTS **) ptr = head;
+    if (msg_verbose)
+       msg_info("tls_proxy_client_certs_scan ret=%d", ret);
+    return (ret);
+}
+
+/* tls_proxy_client_pkeys_scan - receive TLS_PKEYS from stream */
+
+static int tls_proxy_client_pkeys_scan(ATTR_SCAN_MASTER_FN scan_fn,
+                                         VSTREAM *fp, int flags, void *ptr)
+{
+    int     ret;
+    int     count;
+    VSTRING *buf = vstring_alloc(100);
+    TLS_PKEYS **tpp;
+    TLS_PKEYS *head = 0;
+    TLS_PKEYS *tp;
+    int     n;
+
+    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                 RECV_ATTR_INT(TLS_ATTR_COUNT, &count),
+                 ATTR_TYPE_END);
+    if (msg_verbose)
+       msg_info("tls_proxy_client_pkeys_scan count=%d", count);
+
+    for (tpp = &head, n = 0; ret == 1 && n < count; n++, tpp = &tp->next) {
+       *tpp = tp = (TLS_PKEYS *) mymalloc(sizeof(*tp));
+       D2I_const unsigned char *bp;
+
+       if (buf == 0)
+           buf = vstring_alloc(100);
+
+       /*
+        * Note: memset() is not a portable way to initialize non-integer
+        * types.
+        */
+       memset(tp, 0, sizeof(*tp));
+       ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                     RECV_ATTR_DATA(TLS_ATTR_PKEY, buf),
+                     ATTR_TYPE_END);
+       /* Always construct a well-formed structure. */
+       if (ret == 1) {
+           bp = (D2I_const unsigned char *) STR(buf);
+           if (d2i_PUBKEY(&tp->pkey, &bp, LEN(buf)) == 0
+               || LEN(buf) != (char *) bp - STR(buf)) {
+               msg_warn("malformed public key in TLS_PKEYS");
+               ret = -1;
+           }
+       } else {
+           tp->pkey = 0;
+       }
+       tp->next = 0;
+    }
+    if (buf)
+       vstring_free(buf);
+    if (ret != 1) {
+       tls_proxy_client_pkeys_free(head);
+       head = 0;
+    }
+    *(TLS_PKEYS **) ptr = head;
+    if (msg_verbose)
+       msg_info("tls_proxy_client_pkeys_scan ret=%d", ret);
+    return (ret);
+}
+
+/* tls_proxy_client_tlsa_scan - receive TLS_TLSA from stream */
+
+static int tls_proxy_client_tlsa_scan(ATTR_SCAN_MASTER_FN scan_fn,
+                                         VSTREAM *fp, int flags, void *ptr)
+{
+    int     ret;
+    int     count;
+    TLS_TLSA **tpp;
+    TLS_TLSA *head = 0;
+    TLS_TLSA *tp;
+    int     n;
+
+    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                 RECV_ATTR_INT(TLS_ATTR_COUNT, &count),
+                 ATTR_TYPE_END);
+    if (msg_verbose)
+       msg_info("tls_proxy_client_tlsa_scan count=%d", count);
+
+    for (tpp = &head, n = 0; ret == 1 && n < count; n++, tpp = &tp->next) {
+       *tpp = tp = (TLS_TLSA *) mymalloc(sizeof(*tp));
+       VSTRING *mdalg = vstring_alloc(25);
+
+       /*
+        * Note: memset() is not a portable way to initialize non-integer
+        * types.
+        */
+       memset(tp, 0, sizeof(*tp));
+       /* Always construct a well-formed structure. */
+       tp->certs = 0;                          /* scan_fn may return early */
+       tp->pkeys = 0;
+       ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                     RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
+                     RECV_ATTR_FUNC(argv_attr_scan, &tp->certs),
+                     RECV_ATTR_FUNC(argv_attr_scan, &tp->pkeys),
+                     ATTR_TYPE_END);
+       tp->mdalg = vstring_export(mdalg);
+       tp->next = 0;
+       ret = (ret == 3 ? 1 : -1);
+    }
+    if (ret != 1) {
+       tls_proxy_client_tlsa_free(head);
+       head = 0;
+    }
+    *(TLS_TLSA **) ptr = head;
+    if (msg_verbose)
+       msg_info("tls_proxy_client_tlsa_scan ret=%d", ret);
+    return (ret);
+}
+
+/* tls_proxy_client_dane_scan - receive TLS_DANE from stream */
+
+static int tls_proxy_client_dane_scan(ATTR_SCAN_MASTER_FN scan_fn,
+                                         VSTREAM *fp, int flags, void *ptr)
+{
+    TLS_DANE *dane = 0;
+    int     ret;
+    int     have_dane = 0;
+
+    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                 RECV_ATTR_INT(TLS_ATTR_DANE, &have_dane),
+                 ATTR_TYPE_END);
+    if (msg_verbose)
+       msg_info("tls_proxy_client_dane_scan have_dane=%d", have_dane);
+
+    if (ret == 1 && have_dane) {
+       VSTRING *base_domain = vstring_alloc(25);
+       long    expires;
+
+       dane = (TLS_DANE *) mymalloc(sizeof(*dane));
+
+       /*
+        * Note: memset() is not a portable way to initialize non-integer
+        * types.
+        */
+       memset(dane, 0, sizeof(*dane));
+       /* Always construct a well-formed structure. */
+       dane->ta = 0;                           /* scan_fn may return early */
+       dane->ee = 0;
+       dane->certs = 0;
+       dane->pkeys = 0;
+       ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                     RECV_ATTR_FUNC(tls_proxy_client_tlsa_scan,
+                                    &dane->ta),
+                     RECV_ATTR_FUNC(tls_proxy_client_tlsa_scan,
+                                    &dane->ee),
+                     RECV_ATTR_FUNC(tls_proxy_client_certs_scan,
+                                    &dane->certs),
+                     RECV_ATTR_FUNC(tls_proxy_client_pkeys_scan,
+                                    &dane->pkeys),
+                     RECV_ATTR_STR(TLS_ATTR_DOMAIN, base_domain),
+                     RECV_ATTR_INT(TLS_ATTR_FLAGS, &dane->flags),
+                     RECV_ATTR_LONG(TLS_ATTR_EXP, &expires),
+                     ATTR_TYPE_END);
+       /* Always construct a well-formed structure. */
+       dane->base_domain = vstring_export(base_domain);
+       dane->expires = expires;
+       dane->refs = 1;
+       ret = (ret == 7 ? 1 : -1);
+       /* XXX if scan_fn() completed normally, sanity check dane->flags. */
+       if (ret != 1) {
+           tls_proxy_client_dane_free(dane);
+           dane = 0;
+       }
+    }
+    *(TLS_DANE **) ptr = dane;
+    if (msg_verbose)
+       msg_info("tls_proxy_client_dane_scan ret=%d", ret);
+    return (ret);
+}
+
+/* tls_proxy_client_start_scan - receive TLS_CLIENT_START_PROPS from stream */
+
+int     tls_proxy_client_start_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
+                                           int flags, void *ptr)
+{
+    TLS_CLIENT_START_PROPS *props
+    = (TLS_CLIENT_START_PROPS *) mymalloc(sizeof(*props));
+    int     ret;
+    VSTRING *nexthop = vstring_alloc(25);
+    VSTRING *host = vstring_alloc(25);
+    VSTRING *namaddr = vstring_alloc(25);
+    VSTRING *serverid = vstring_alloc(25);
+    VSTRING *helo = vstring_alloc(25);
+    VSTRING *protocols = vstring_alloc(25);
+    VSTRING *cipher_grade = vstring_alloc(25);
+    VSTRING *cipher_exclusions = vstring_alloc(25);
+    VSTRING *mdalg = vstring_alloc(25);
+
+    if (msg_verbose)
+       msg_info("begin tls_proxy_client_start_scan");
+
+    /*
+     * Note: memset() is not a portable way to initialize non-integer types.
+     */
+    memset(props, 0, sizeof(*props));
+    props->ctx = 0;
+    props->stream = 0;
+    props->fd = -1;
+    props->dane = 0;                           /* scan_fn may return early */
+    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                 RECV_ATTR_INT(TLS_ATTR_TIMEOUT, &props->timeout),
+                 RECV_ATTR_INT(TLS_ATTR_TLS_LEVEL, &props->tls_level),
+                 RECV_ATTR_STR(TLS_ATTR_NEXTHOP, nexthop),
+                 RECV_ATTR_STR(TLS_ATTR_HOST, host),
+                 RECV_ATTR_STR(TLS_ATTR_NAMADDR, namaddr),
+                 RECV_ATTR_STR(TLS_ATTR_SERVERID, serverid),
+                 RECV_ATTR_STR(TLS_ATTR_HELO, helo),
+                 RECV_ATTR_STR(TLS_ATTR_PROTOCOLS, protocols),
+                 RECV_ATTR_STR(TLS_ATTR_CIPHER_GRADE, cipher_grade),
+                 RECV_ATTR_STR(TLS_ATTR_CIPHER_EXCLUSIONS,
+                               cipher_exclusions),
+                 RECV_ATTR_FUNC(argv_attr_scan, &props->matchargv),
+                 RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
+                 RECV_ATTR_FUNC(tls_proxy_client_dane_scan,
+                                &props->dane),
+                 ATTR_TYPE_END);
+    /* Always construct a well-formed structure. */
+    props->nexthop = vstring_export(nexthop);
+    props->host = vstring_export(host);
+    props->namaddr = vstring_export(namaddr);
+    props->serverid = vstring_export(serverid);
+    props->helo = vstring_export(helo);
+    props->protocols = vstring_export(protocols);
+    props->cipher_grade = vstring_export(cipher_grade);
+    props->cipher_exclusions = vstring_export(cipher_exclusions);
+    props->mdalg = vstring_export(mdalg);
+    ret = (ret == 13 ? 1 : -1);
+    if (ret != 1) {
+       tls_proxy_client_start_free(props);
+       props = 0;
+    }
+    *(TLS_CLIENT_START_PROPS **) ptr = props;
+    if (msg_verbose)
+       msg_info("tls_proxy_client_start_scan ret=%d", ret);
+    return (ret);
+}
+
+#endif
index 97d096264c04b7deec4385d1fc129cac0ad9632f..3dd0aa364bb007021ab3f42c5710a468d946a646 100644 (file)
@@ -2,24 +2,37 @@
 /* NAME
 /*     tlsproxy_clnt 3
 /* SUMMARY
-/*     postscreen TLS proxy support
+/*     tlsproxy(8) client support
 /* SYNOPSIS
 /*     #include <tlsproxy_clnt.h>
 /*
 /*     VSTREAM *tls_proxy_open(service, flags, peer_stream, peer_addr,
-/*                               peer_port, timeout)
+/*                             peer_port, handshake_timeout, session_timeout,
+                               serverid, init_props, start_props)
 /*     const char *service;
 /*     int     flags;
 /*     VSTREAM *peer_stream;
 /*     const char *peer_addr;
 /*     const char *peer_port;
-/*     int     timeout;
+/*     int     handshake_timeout;
+/*     int     session_timeout;
+/*     const char *serverid;
+/*     void    *init_props;
+/*     void    *start_props;
 /*
 /*     TLS_SESS_STATE *tls_proxy_context_receive(proxy_stream)
 /*     VSTREAM *proxy_stream;
-/*
-/*     void    tls_proxy_context_free(tls_context)
-/*     TLS_SESS_STATE *tls_context;
+/* AUXILIARY FUNCTIONS
+/*     VSTREAM *tls_proxy_legacy_open(service, flags, peer_stream,
+/*                                     peer_addr, peer_port,
+/*                                     timeout, serverid)
+/*     const char *service;
+/*     int     flags;
+/*     VSTREAM *peer_stream;
+/*     const char *peer_addr;
+/*     const char *peer_port;
+/*     int     timeout;
+/*     const char *serverid;
 /* DESCRIPTION
 /*     tls_proxy_open() prepares for inserting the tlsproxy(8)
 /*     daemon between the current process and a remote peer (the
@@ -44,8 +57,8 @@
 /*
 /*     After this, the proxy_stream is ready for plain-text I/O.
 /*
-/*     tls_proxy_context_free() destroys a TLS context object that
-/*     was received with tls_proxy_context_receive().
+/*     tls_proxy_legacy_open() is a backwards-compatibility feature
+/*     that provides a historical interface.
 /*
 /*     Arguments:
 /* .IP service
 /*     Printable IP address of the remote peer_stream endpoint.
 /* .IP peer_port
 /*     Printable TCP port of the remote peer_stream endpoint.
-/* .IP timeout
-/*     Time limit that the tlsproxy(8) daemon should use.
+/* .IP handshake_timeout
+/*     Time limit that the tlsproxy(8) daemon should use during
+/*     the TLS handshake.
+/* .IP session_timeout
+/*     Time limit that the tlsproxy(8) daemon should use after the
+/*     TLS handshake.
+/* .IP serverid
+/*     Unique service identifier.
+/* .IP init_props
+/*     Pointer to TLS_CLIENT_INIT_PROPS or TLS_SERVER_INIT_PROPS.
+/* .IP start_props
+/*     Pointer to TLS_CLIENT_START_PROPS or TLS_SERVER_START_PROPS.
 /* .IP proxy_stream
 /*     Stream from tls_proxy_open().
 /* .IP tls_context
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
 #ifdef USE_TLS
@@ -119,8 +147,13 @@ VSTREAM *tls_proxy_open(const char *service, int flags,
                                VSTREAM *peer_stream,
                                const char *peer_addr,
                                const char *peer_port,
-                               int timeout)
+                               int handshake_timeout,
+                               int session_timeout,
+                               const char *serverid,
+                               void *init_props,
+                               void *start_props)
 {
+    const char myname[] = "tls_proxy_open";
     VSTREAM *tlsproxy_stream;
     int     status;
     int     fd;
@@ -146,19 +179,43 @@ VSTREAM *tls_proxy_open(const char *service, int flags,
     }
 
     /*
-     * Initial handshake. Send the data attributes now, and send the client
-     * file descriptor in a later transaction.
-     * 
-     * XXX The formatted endpoint should be a state member. Then, we can
-     * simplify all the format strings throughout the program.
+     * Initial handshake. Send common data attributes now, and send the
+     * remote peer file descriptor in a later transaction.
      */
     tlsproxy_stream = vstream_fdopen(fd, O_RDWR);
     vstring_sprintf(remote_endpt, "[%s]:%s", peer_addr, peer_port);
     attr_print(tlsproxy_stream, ATTR_FLAG_NONE,
-              SEND_ATTR_STR(MAIL_ATTR_REMOTE_ENDPT, STR(remote_endpt)),
-              SEND_ATTR_INT(MAIL_ATTR_FLAGS, flags),
-              SEND_ATTR_INT(MAIL_ATTR_TIMEOUT, timeout),
+              SEND_ATTR_STR(TLS_ATTR_REMOTE_ENDPT, STR(remote_endpt)),
+              SEND_ATTR_INT(TLS_ATTR_FLAGS, flags),
+              SEND_ATTR_INT(TLS_ATTR_TIMEOUT, handshake_timeout),
+              SEND_ATTR_INT(TLS_ATTR_TIMEOUT, session_timeout),
+              SEND_ATTR_STR(TLS_ATTR_SERVERID, serverid),
               ATTR_TYPE_END);
+    /* Do not flush the stream yet. */
+    if (vstream_ferror(tlsproxy_stream) != 0) {
+       msg_warn("error sending request to %s service: %m",
+                STR(tlsproxy_service));
+       vstream_fclose(tlsproxy_stream);
+       return (0);
+    }
+    switch (flags & (TLS_PROXY_FLAG_ROLE_CLIENT | TLS_PROXY_FLAG_ROLE_SERVER)) {
+    case TLS_PROXY_FLAG_ROLE_CLIENT:
+       attr_print(tlsproxy_stream, ATTR_FLAG_NONE,
+                  SEND_ATTR_FUNC(tls_proxy_client_init_print, init_props),
+                  SEND_ATTR_FUNC(tls_proxy_client_start_print, start_props),
+                  ATTR_TYPE_END);
+       break;
+    case TLS_PROXY_FLAG_ROLE_SERVER:
+#if 0
+       attr_print(tlsproxy_stream, ATTR_FLAG_NONE,
+                  SEND_ATTR_FUNC(tls_proxy_server_init_print, init_props),
+                  SEND_ATTR_FUNC(tls_proxy_server_start_print, start_props),
+                  ATTR_TYPE_END);
+#endif
+       break;
+    default:
+       msg_panic("%s: bad flags: 0x%x", myname, flags);
+    }
     if (vstream_fflush(tlsproxy_stream) != 0) {
        msg_warn("error sending request to %s service: %m",
                 STR(tlsproxy_service));
@@ -170,11 +227,12 @@ VSTREAM *tls_proxy_open(const char *service, int flags,
      * 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
+     * sending the request attributes and sending the plaintext file
      * descriptor. We can't assume UNIX-domain socket semantics here.
      */
     if (attr_scan(tlsproxy_stream, ATTR_FLAG_STRICT,
                  RECV_ATTR_INT(MAIL_ATTR_STATUS, &status),
+    /* TODO: informative message. */
                  ATTR_TYPE_END) != 1 || status == 0) {
 
        /*
@@ -191,7 +249,7 @@ VSTREAM *tls_proxy_open(const char *service, int flags,
     }
 
     /*
-     * Send the remote SMTP client file descriptor.
+     * Send the remote peer file descriptor.
      */
     if (LOCAL_SEND_FD(vstream_fileno(tlsproxy_stream),
                      vstream_fileno(peer_stream)) < 0) {
@@ -207,41 +265,22 @@ VSTREAM *tls_proxy_open(const char *service, int flags,
     return (tlsproxy_stream);
 }
 
+
 /* tls_proxy_context_receive - receive TLS session object from tlsproxy(8) */
 
 TLS_SESS_STATE *tls_proxy_context_receive(VSTREAM *proxy_stream)
 {
-    TLS_SESS_STATE *tls_context;
-
-    tls_context = (TLS_SESS_STATE *) mymalloc(sizeof(*tls_context));
+    TLS_SESS_STATE *tls_context = 0;
 
     if (attr_scan(proxy_stream, ATTR_FLAG_STRICT,
-              RECV_ATTR_FUNC(tls_proxy_context_scan, (void *) tls_context),
+             RECV_ATTR_FUNC(tls_proxy_context_scan, (void *) &tls_context),
                  ATTR_TYPE_END) != 1) {
-       tls_proxy_context_free(tls_context);
+       if (tls_context)
+           tls_proxy_context_free(tls_context);
        return (0);
     } else {
        return (tls_context);
     }
 }
 
-/* tls_proxy_context_free - destroy object from tls_proxy_context_receive() */
-
-void    tls_proxy_context_free(TLS_SESS_STATE *tls_context)
-{
-    if (tls_context->peer_CN)
-       myfree(tls_context->peer_CN);
-    if (tls_context->issuer_CN)
-       myfree(tls_context->issuer_CN);
-    if (tls_context->peer_cert_fprint)
-       myfree(tls_context->peer_cert_fprint);
-    if (tls_context->peer_pkey_fprint)
-       myfree(tls_context->peer_pkey_fprint);
-    if (tls_context->protocol)
-       myfree((void *) tls_context->protocol);
-    if (tls_context->cipher_name)
-       myfree((void *) tls_context->cipher_name);
-    myfree((void *) tls_context);
-}
-
 #endif
similarity index 63%
rename from postfix/src/tls/tls_proxy_print.c
rename to postfix/src/tls/tls_proxy_context_print.c
index e30e8be88beea626dd26ef4e108f98ebed450354..a597024b2bbbf8440e2a0974ac0cb73c9ec7e626 100644 (file)
@@ -1,8 +1,8 @@
 /*++
 /* NAME
-/*     tls_proxy_print
+/*     tls_proxy_context_print
 /* SUMMARY
-/*     write DSN structure to stream
+/*     write TLS_ATTR_STATE structure to stream
 /* SYNOPSIS
 /*     #include <tls_proxy.h>
 /*
 /*     int     flags;
 /*     void    *ptr;
 /* DESCRIPTION
-/*     tls_proxy_context_print() writes a TLS_SESS_STATE structure
-/*     to the named stream using the specified attribute print
-/*     routine. TLS_SESS_STATE() is meant to be passed as a call-back
-/*     to attr_print(), thusly:
+/*     tls_proxy_context_print() writes the public members of a
+/*     TLS_ATTR_STATE structure to the named stream using the
+/*     specified attribute print routine. tls_proxy_context_print()
+/*     is meant to be passed as a call-back to attr_print(), thusly:
 /*
 /*     ... SEND_ATTR_FUNC(tls_proxy_context_print, (void *) tls_context), ...
 /* DIAGNOSTICS
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
 #ifdef USE_TLS
 
 #include <attr.h>
 
-/* Global library. */
-
-#include <mail_proto.h>
-
 /* TLS library. */
 
 #include <tls.h>
@@ -61,25 +62,26 @@ int     tls_proxy_context_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp,
 #define STRING_OR_EMPTY(s) ((s) ? (s) : "")
 
     ret = print_fn(fp, flags | ATTR_FLAG_MORE,
-                  SEND_ATTR_STR(MAIL_ATTR_PEER_CN,
+                  SEND_ATTR_STR(TLS_ATTR_PEER_CN,
                                 STRING_OR_EMPTY(tp->peer_CN)),
-                  SEND_ATTR_STR(MAIL_ATTR_ISSUER_CN,
+                  SEND_ATTR_STR(TLS_ATTR_ISSUER_CN,
                                 STRING_OR_EMPTY(tp->issuer_CN)),
-                  SEND_ATTR_STR(MAIL_ATTR_PEER_CERT_FPT,
+                  SEND_ATTR_STR(TLS_ATTR_PEER_CERT_FPT,
                                 STRING_OR_EMPTY(tp->peer_cert_fprint)),
-                  SEND_ATTR_STR(MAIL_ATTR_PEER_PKEY_FPT,
+                  SEND_ATTR_STR(TLS_ATTR_PEER_PKEY_FPT,
                                 STRING_OR_EMPTY(tp->peer_pkey_fprint)),
-                  SEND_ATTR_INT(MAIL_ATTR_PEER_STATUS,
+                  SEND_ATTR_INT(TLS_ATTR_PEER_STATUS,
                                 tp->peer_status),
-                  SEND_ATTR_STR(MAIL_ATTR_CIPHER_PROTOCOL,
+                  SEND_ATTR_STR(TLS_ATTR_CIPHER_PROTOCOL,
                                 STRING_OR_EMPTY(tp->protocol)),
-                  SEND_ATTR_STR(MAIL_ATTR_CIPHER_NAME,
+                  SEND_ATTR_STR(TLS_ATTR_CIPHER_NAME,
                                 STRING_OR_EMPTY(tp->cipher_name)),
-                  SEND_ATTR_INT(MAIL_ATTR_CIPHER_USEBITS,
+                  SEND_ATTR_INT(TLS_ATTR_CIPHER_USEBITS,
                                 tp->cipher_usebits),
-                  SEND_ATTR_INT(MAIL_ATTR_CIPHER_ALGBITS,
+                  SEND_ATTR_INT(TLS_ATTR_CIPHER_ALGBITS,
                                 tp->cipher_algbits),
                   ATTR_TYPE_END);
+    /* Do not flush the stream. */
     return (ret);
 }
 
diff --git a/postfix/src/tls/tls_proxy_context_scan.c b/postfix/src/tls/tls_proxy_context_scan.c
new file mode 100644 (file)
index 0000000..74f109b
--- /dev/null
@@ -0,0 +1,140 @@
+/*++
+/* NAME
+/*     tls_proxy_context_scan
+/* SUMMARY
+/*     read TLS session state from stream
+/* SYNOPSIS
+/*     #include <tls_proxy.h>
+/*
+/*     int     tls_proxy_context_scan(scan_fn, stream, flags, ptr)
+/*     ATTR_SCAN_MASTER_FN scan_fn;
+/*     VSTREAM *stream;
+/*     int     flags;
+/*     void    *ptr;
+/*
+/*     void    tls_proxy_context_free(tls_context)
+/*     TLS_SESS_STATE *tls_context;
+/* DESCRIPTION
+/*     tls_proxy_context_scan() reads the public members of a
+/*     TLS_ATTR_STATE structure from the named stream using the
+/*     specified attribute scan routine.  tls_proxy_context_scan()
+/*     is meant to be passed as a call-back to attr_scan() as shown
+/*     below.
+/*
+/*     tls_proxy_context_free() destroys a TLS context object that
+/*     was received with tls_proxy_context_scan().
+/*
+/*     TLS_ATTR_STATE *tls_context = 0;
+/*     ...
+/*     ... RECV_ATTR_FUNC(tls_proxy_context_scan, (void *) &tls_context), ...
+/*     ...
+/*     if (tls_context)
+/*         tls_proxy_context_free(tls_context);
+/* DIAGNOSTICS
+/*     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
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*--*/
+
+#ifdef USE_TLS
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library */
+
+#include <attr.h>
+#include <msg.h>
+
+/* TLS library. */
+
+#include <tls.h>
+#include <tls_proxy.h>
+
+/* tls_proxy_context_scan - receive TLS session state from stream */
+
+int     tls_proxy_context_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
+                                      int flags, void *ptr)
+{
+    TLS_SESS_STATE *tls_context
+    = (TLS_SESS_STATE *) mymalloc(sizeof(*tls_context));;
+    int     ret;
+    VSTRING *peer_CN = vstring_alloc(25);
+    VSTRING *issuer_CN = vstring_alloc(25);
+    VSTRING *peer_cert_fprint = vstring_alloc(60);     /* 60 for SHA-1 */
+    VSTRING *peer_pkey_fprint = vstring_alloc(60);     /* 60 for SHA-1 */
+    VSTRING *protocol = vstring_alloc(25);
+    VSTRING *cipher_name = vstring_alloc(25);
+
+    if (msg_verbose)
+       msg_info("begin tls_proxy_context_scan");
+
+    /*
+     * Note: memset() is not a portable way to initialize non-integer types.
+     */
+    memset(tls_context, 0, sizeof(*tls_context));
+    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                 RECV_ATTR_STR(TLS_ATTR_PEER_CN, peer_CN),
+                 RECV_ATTR_STR(TLS_ATTR_ISSUER_CN, issuer_CN),
+                 RECV_ATTR_STR(TLS_ATTR_PEER_CERT_FPT, peer_cert_fprint),
+                 RECV_ATTR_STR(TLS_ATTR_PEER_PKEY_FPT, peer_pkey_fprint),
+                 RECV_ATTR_INT(TLS_ATTR_PEER_STATUS,
+                               &tls_context->peer_status),
+                 RECV_ATTR_STR(TLS_ATTR_CIPHER_PROTOCOL, protocol),
+                 RECV_ATTR_STR(TLS_ATTR_CIPHER_NAME, cipher_name),
+                 RECV_ATTR_INT(TLS_ATTR_CIPHER_USEBITS,
+                               &tls_context->cipher_usebits),
+                 RECV_ATTR_INT(TLS_ATTR_CIPHER_ALGBITS,
+                               &tls_context->cipher_algbits),
+                 ATTR_TYPE_END);
+    /* Always construct a well-formed structure. */
+    tls_context->peer_CN = vstring_export(peer_CN);
+    tls_context->issuer_CN = vstring_export(issuer_CN);
+    tls_context->peer_cert_fprint = vstring_export(peer_cert_fprint);
+    tls_context->peer_pkey_fprint = vstring_export(peer_pkey_fprint);
+    tls_context->protocol = vstring_export(protocol);
+    tls_context->cipher_name = vstring_export(cipher_name);
+    ret = (ret == 9 ? 1 : -1);
+    if (ret != 1) {
+       tls_proxy_context_free(tls_context);
+       tls_context = 0;
+    }
+    *(TLS_SESS_STATE **) ptr = tls_context;
+    if (msg_verbose)
+       msg_info("tls_proxy_context_scan ret=%d", ret);
+    return (ret);
+}
+
+/* tls_proxy_context_free - destroy object from tls_proxy_context_receive() */
+
+void    tls_proxy_context_free(TLS_SESS_STATE *tls_context)
+{
+    if (tls_context->peer_CN)
+       myfree(tls_context->peer_CN);
+    if (tls_context->issuer_CN)
+       myfree(tls_context->issuer_CN);
+    if (tls_context->peer_cert_fprint)
+       myfree(tls_context->peer_cert_fprint);
+    if (tls_context->peer_pkey_fprint)
+       myfree(tls_context->peer_pkey_fprint);
+    if (tls_context->protocol)
+       myfree((void *) tls_context->protocol);
+    if (tls_context->cipher_name)
+       myfree((void *) tls_context->cipher_name);
+    myfree((void *) tls_context);
+}
+
+#endif
diff --git a/postfix/src/tls/tls_proxy_scan.c b/postfix/src/tls/tls_proxy_scan.c
deleted file mode 100644 (file)
index 29a0cd9..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*++
-/* NAME
-/*     tls_proxy_scan
-/* SUMMARY
-/*     read TLS session state from stream
-/* SYNOPSIS
-/*     #include <tls_proxy.h>
-/*
-/*     int     tls_proxy_context_scan(scan_fn, stream, flags, ptr)
-/*     ATTR_SCAN_MASTER_FN scan_fn;
-/*     VSTREAM *stream;
-/*     int     flags;
-/*     void    *ptr;
-/* DESCRIPTION
-/*     tls_proxy_context_scan() reads a TLS_SESS_STATE structure
-/*     from the named stream using the specified attribute scan
-/*     routine.  tls_proxy_context_scan() is meant to be passed as
-/*     a call-back to attr_scan(), thusly:
-/*
-/*     ... RECV_ATTR_FUNC(tls_proxy_context_scan, (void *) tls_context), ...
-/* DIAGNOSTICS
-/*     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
-/*--*/
-
-#ifdef USE_TLS
-
-/* System library. */
-
-#include <sys_defs.h>
-
-/* Utility library */
-
-#include <attr.h>
-
-/* Global library. */
-
-#include <mail_proto.h>
-
-/* TLS library. */
-
-#include <tls.h>
-#include <tls_proxy.h>
-
-/* tls_proxy_context_scan - receive TLS session state from stream */
-
-int     tls_proxy_context_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
-                                      int flags, void *ptr)
-{
-    TLS_SESS_STATE *tls_context = (TLS_SESS_STATE *) ptr;
-    int     ret;
-    VSTRING *peer_CN = vstring_alloc(25);
-    VSTRING *issuer_CN = vstring_alloc(25);
-    VSTRING *peer_cert_fprint = vstring_alloc(60);     /* 60 for SHA-1 */
-    VSTRING *peer_pkey_fprint = vstring_alloc(60);     /* 60 for SHA-1 */
-    VSTRING *protocol = vstring_alloc(25);
-    VSTRING *cipher_name = vstring_alloc(25);
-
-    /*
-     * Note: memset() is not a portable way to initialize non-integer types.
-     */
-    memset(ptr, 0, sizeof(TLS_SESS_STATE));
-    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
-                 RECV_ATTR_STR(MAIL_ATTR_PEER_CN, peer_CN),
-                 RECV_ATTR_STR(MAIL_ATTR_ISSUER_CN, issuer_CN),
-                 RECV_ATTR_STR(MAIL_ATTR_PEER_CERT_FPT, peer_cert_fprint),
-                 RECV_ATTR_STR(MAIL_ATTR_PEER_PKEY_FPT, peer_pkey_fprint),
-                 RECV_ATTR_INT(MAIL_ATTR_PEER_STATUS,
-                               &tls_context->peer_status),
-                 RECV_ATTR_STR(MAIL_ATTR_CIPHER_PROTOCOL, protocol),
-                 RECV_ATTR_STR(MAIL_ATTR_CIPHER_NAME, cipher_name),
-                 RECV_ATTR_INT(MAIL_ATTR_CIPHER_USEBITS,
-                               &tls_context->cipher_usebits),
-                 RECV_ATTR_INT(MAIL_ATTR_CIPHER_ALGBITS,
-                               &tls_context->cipher_algbits),
-                 ATTR_TYPE_END);
-    tls_context->peer_CN = vstring_export(peer_CN);
-    tls_context->issuer_CN = vstring_export(issuer_CN);
-    tls_context->peer_cert_fprint = vstring_export(peer_cert_fprint);
-    tls_context->peer_pkey_fprint = vstring_export(peer_pkey_fprint);
-    tls_context->protocol = vstring_export(protocol);
-    tls_context->cipher_name = vstring_export(cipher_name);
-    return (ret == 9 ? 1 : -1);
-}
-
-#endif
diff --git a/postfix/src/tls/tls_proxy_server_print.c b/postfix/src/tls/tls_proxy_server_print.c
new file mode 100644 (file)
index 0000000..670f841
--- /dev/null
@@ -0,0 +1,141 @@
+/*++
+/* NAME
+/*     tls_proxy_server_print 3
+/* SUMMARY
+/*     write TLS_SERVER_XXX structures to stream
+/* SYNOPSIS
+/*     #include <tls_proxy.h>
+/*
+/*     int     tls_proxy_server_init_print(print_fn, stream, flags, ptr)
+/*     ATTR_PRINT_MASTER_FN print_fn;
+/*     VSTREAM *stream;
+/*     int     flags;
+/*     void    *ptr;
+/*
+/*     int     tls_proxy_server_start_print(print_fn, stream, flags, ptr)
+/*     ATTR_PRINT_MASTER_FN print_fn;
+/*     VSTREAM *stream;
+/*     int     flags;
+/*     void    *ptr;
+/* DESCRIPTION
+/*     tls_proxy_server_init_print() writes a TLS_SERVER_INIT_PROPS
+/*     structure to the named stream using the specified attribute print
+/*     routine. tls_proxy_server_init_print() is meant to be passed as
+/*     a call-back to attr_print(), thusly:
+/*
+/*     ... SEND_ATTR_FUNC(tls_proxy_server_init_print, (void *) init_props), ...
+/*
+/*     tls_proxy_server_start_print() writes a TLS_SERVER_START_PROPS
+/*     structure to the named stream using the specified attribute print
+/*     routine. tls_proxy_server_start_print() is meant to be passed as
+/*     a call-back to attr_print(), thusly:
+/*
+/*     ... SEND_ATTR_FUNC(tls_proxy_server_start_print, (void *) start_props), ...
+/* DIAGNOSTICS
+/*     Fatal: out of memory.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*--*/
+
+#ifdef USE_TLS
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library */
+
+#include <attr.h>
+
+/* TLS library. */
+
+#include <tls.h>
+#include <tls_proxy.h>
+
+/* tls_proxy_server_init_print - send TLS_SERVER_INIT_PROPS over stream */
+
+int     tls_proxy_server_init_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp,
+                                           int flags, void *ptr)
+{
+    TLS_SERVER_INIT_PROPS *props = (TLS_SERVER_INIT_PROPS *) ptr;
+    int     ret;
+
+#define STRING_OR_EMPTY(s) ((s) ? (s) : "")
+
+    ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                  SEND_ATTR_STR(TLS_ATTR_LOG_PARAM,
+                                STRING_OR_EMPTY(props->log_param)),
+                  SEND_ATTR_STR(TLS_ATTR_LOG_LEVEL,
+                                STRING_OR_EMPTY(props->log_level)),
+                  SEND_ATTR_INT(TLS_ATTR_VERIFYDEPTH, props->verifydepth),
+                  SEND_ATTR_STR(TLS_ATTR_CACHE_TYPE,
+                                STRING_OR_EMPTY(props->cache_type)),
+                  SEND_ATTR_INT(TLS_ATTR_SET_SESSID, props->set_sessid),
+                  SEND_ATTR_STR(TLS_ATTR_CERT_FILE,
+                                STRING_OR_EMPTY(props->cert_file)),
+                  SEND_ATTR_STR(TLS_ATTR_KEY_FILE,
+                                STRING_OR_EMPTY(props->key_file)),
+                  SEND_ATTR_STR(TLS_ATTR_DCERT_FILE,
+                                STRING_OR_EMPTY(props->dcert_file)),
+                  SEND_ATTR_STR(TLS_ATTR_DKEY_FILE,
+                                STRING_OR_EMPTY(props->dkey_file)),
+                  SEND_ATTR_STR(TLS_ATTR_ECCERT_FILE,
+                                STRING_OR_EMPTY(props->eccert_file)),
+                  SEND_ATTR_STR(TLS_ATTR_ECKEY_FILE,
+                                STRING_OR_EMPTY(props->eckey_file)),
+                  SEND_ATTR_STR(TLS_ATTR_CAFILE,
+                                STRING_OR_EMPTY(props->CAfile)),
+                  SEND_ATTR_STR(TLS_ATTR_CAPATH,
+                                STRING_OR_EMPTY(props->CApath)),
+                  SEND_ATTR_STR(TLS_ATTR_PROTOCOLS,
+                                STRING_OR_EMPTY(props->protocols)),
+                  SEND_ATTR_STR(TLS_ATTR_EECDH_GRADE,
+                                STRING_OR_EMPTY(props->eecdh_grade)),
+                  SEND_ATTR_STR(TLS_ATTR_DH1K_PARAM_FILE,
+                                STRING_OR_EMPTY(props->dh1024_param_file)),
+                  SEND_ATTR_STR(TLS_ATTR_DH512_PARAM_FILE,
+                                STRING_OR_EMPTY(props->dh512_param_file)),
+                  SEND_ATTR_INT(TLS_ATTR_ASK_CCERT, props->ask_ccert),
+                  SEND_ATTR_STR(TLS_ATTR_MDALG,
+                                STRING_OR_EMPTY(props->mdalg)),
+                  ATTR_TYPE_END);
+    /* Do not flush the stream. */
+    return (ret);
+}
+
+/* tls_proxy_server_start_print - send TLS_SERVER_START_PROPS over stream */
+
+int     tls_proxy_server_start_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp,
+                                            int flags, void *ptr)
+{
+    TLS_SERVER_START_PROPS *props = (TLS_SERVER_START_PROPS *) ptr;
+    int     ret;
+
+#define STRING_OR_EMPTY(s) ((s) ? (s) : "")
+
+    ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                  SEND_ATTR_INT(TLS_ATTR_TIMEOUT, props->timeout),
+                  SEND_ATTR_INT(TLS_ATTR_REQUIRECERT, props->requirecert),
+                  SEND_ATTR_STR(TLS_ATTR_SERVERID,
+                                STRING_OR_EMPTY(props->serverid)),
+                  SEND_ATTR_STR(TLS_ATTR_NAMADDR,
+                                STRING_OR_EMPTY(props->namaddr)),
+                  SEND_ATTR_STR(TLS_ATTR_CIPHER_GRADE,
+                                STRING_OR_EMPTY(props->cipher_grade)),
+                  SEND_ATTR_STR(TLS_ATTR_CIPHER_EXCLUSIONS,
+                                STRING_OR_EMPTY(props->cipher_exclusions)),
+                  SEND_ATTR_STR(TLS_ATTR_MDALG,
+                                STRING_OR_EMPTY(props->mdalg)),
+                  ATTR_TYPE_END);
+    /* Do not flush the stream. */
+    return (ret);
+}
+
+#endif
diff --git a/postfix/src/tls/tls_proxy_server_scan.c b/postfix/src/tls/tls_proxy_server_scan.c
new file mode 100644 (file)
index 0000000..62487d8
--- /dev/null
@@ -0,0 +1,241 @@
+/*++
+/* NAME
+/*     tls_proxy_server_scan 3
+/* SUMMARY
+/*     read TLS_SERVER_XXX structures from stream
+/* SYNOPSIS
+/*     #include <tls_proxy.h>
+/*
+/*     int     tls_proxy_server_init_scan(scan_fn, stream, flags, ptr)
+/*     ATTR_SCAN_MASTER_FN scan_fn;
+/*     VSTREAM *stream;
+/*     int     flags;
+/*     void    *ptr;
+/*
+/*     tls_proxy_server_init_free(init_props)
+/*     TLS_SERVER_INIT_PROPS *init_props;
+/*
+/*     int     tls_proxy_server_start_scan(scan_fn, stream, flags, ptr)
+/*     ATTR_SCAN_MASTER_FN scan_fn;
+/*     VSTREAM *stream;
+/*     int     flags;
+/*     void    *ptr;
+/*
+/*     void    tls_proxy_server_start_free(start_props)
+/*     TLS_SERVER_START_PROPS *start_props;
+/* DESCRIPTION
+/*     tls_proxy_server_init_scan() reads a TLS_SERVER_INIT_PROPS
+/*     structure from the named stream using the specified attribute
+/*     scan routine. tls_proxy_server_init_scan() is meant to be passed
+/*     as a call-back function to attr_scan(), as shown below.
+/*
+/*     tls_proxy_server_init_free() destroys a TLS_SERVER_INIT_PROPS
+/*     structure that was created by tls_proxy_server_init_scan().
+/*
+/*     TLS_SERVER_INIT_PROPS *init_props = 0;
+/*     ...
+/*     ... RECV_ATTR_FUNC(tls_proxy_server_init_scan, (void *) &init_props)
+/*     ...
+/*     if (init_props)
+/*         tls_proxy_client_init_free(init_props);
+/*
+/*     tls_proxy_server_start_scan() reads a TLS_SERVER_START_PROPS
+/*     structure from the named stream using the specified attribute
+/*     scan routine. tls_proxy_server_start_scan() is meant to be passed
+/*     as a call-back function to attr_scan(), as shown below.
+/*
+/*     tls_proxy_server_start_free() destroys a TLS_SERVER_START_PROPS
+/*     structure that was created by tls_proxy_server_start_scan().
+/*
+/*     TLS_SERVER_START_PROPS *start_props = 0;
+/*     ...
+/*     ... RECV_ATTR_FUNC(tls_proxy_server_start_scan, (void *) &start_props)
+/*     ...
+/*     if (start_props)
+/*         tls_proxy_server_start_free(start_props);
+/* DIAGNOSTICS
+/*     Fatal: out of memory.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*--*/
+
+#ifdef USE_TLS
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library */
+
+#include <attr.h>
+
+/* TLS library. */
+
+#include <tls.h>
+#include <tls_proxy.h>
+
+/* tls_proxy_server_init_scan - receive TLS_SERVER_INIT_PROPS from stream */
+
+int     tls_proxy_server_init_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
+                                          int flags, void *ptr)
+{
+    TLS_SERVER_INIT_PROPS *props
+    = (TLS_SERVER_INIT_PROPS *) mymalloc(sizeof(*props));
+    int     ret;
+    VSTRING *log_param = vstring_alloc(25);
+    VSTRING *log_level = vstring_alloc(25);
+    VSTRING *cache_type = vstring_alloc(25);
+    VSTRING *cert_file = vstring_alloc(25);
+    VSTRING *key_file = vstring_alloc(25);
+    VSTRING *dcert_file = vstring_alloc(25);
+    VSTRING *dkey_file = vstring_alloc(25);
+    VSTRING *eccert_file = vstring_alloc(25);
+    VSTRING *eckey_file = vstring_alloc(25);
+    VSTRING *CAfile = vstring_alloc(25);
+    VSTRING *CApath = vstring_alloc(25);
+    VSTRING *protocols = vstring_alloc(25);
+    VSTRING *eecdh_grade = vstring_alloc(25);
+    VSTRING *dh1024_param_file = vstring_alloc(25);
+    VSTRING *dh512_param_file = vstring_alloc(25);
+    VSTRING *mdalg = vstring_alloc(25);
+
+    /*
+     * Note: memset() is not a portable way to initialize non-integer types.
+     */
+    memset(props, 0, sizeof(*props));
+    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                 RECV_ATTR_STR(TLS_ATTR_LOG_PARAM, log_param),
+                 RECV_ATTR_STR(TLS_ATTR_LOG_LEVEL, log_level),
+                 RECV_ATTR_INT(TLS_ATTR_VERIFYDEPTH, &props->verifydepth),
+                 RECV_ATTR_STR(TLS_ATTR_CACHE_TYPE, cache_type),
+                 RECV_ATTR_INT(TLS_ATTR_SET_SESSID, &props->set_sessid),
+                 RECV_ATTR_STR(TLS_ATTR_CERT_FILE, cert_file),
+                 RECV_ATTR_STR(TLS_ATTR_KEY_FILE, key_file),
+                 RECV_ATTR_STR(TLS_ATTR_DCERT_FILE, dcert_file),
+                 RECV_ATTR_STR(TLS_ATTR_DKEY_FILE, dkey_file),
+                 RECV_ATTR_STR(TLS_ATTR_ECCERT_FILE, eccert_file),
+                 RECV_ATTR_STR(TLS_ATTR_ECKEY_FILE, eckey_file),
+                 RECV_ATTR_STR(TLS_ATTR_CAFILE, CAfile),
+                 RECV_ATTR_STR(TLS_ATTR_CAPATH, CApath),
+                 RECV_ATTR_STR(TLS_ATTR_PROTOCOLS, protocols),
+                 RECV_ATTR_STR(TLS_ATTR_EECDH_GRADE, eecdh_grade),
+                 RECV_ATTR_STR(TLS_ATTR_DH1K_PARAM_FILE, dh1024_param_file),
+                 RECV_ATTR_STR(TLS_ATTR_DH512_PARAM_FILE, dh512_param_file),
+                 RECV_ATTR_INT(TLS_ATTR_ASK_CCERT, &props->ask_ccert),
+                 RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
+                 ATTR_TYPE_END);
+    /* Always construct a well-formed structure. */
+    props->log_param = vstring_export(log_param);
+    props->log_level = vstring_export(log_level);
+    props->cache_type = vstring_export(cache_type);
+    props->cert_file = vstring_export(cert_file);
+    props->key_file = vstring_export(key_file);
+    props->dcert_file = vstring_export(dcert_file);
+    props->dkey_file = vstring_export(dkey_file);
+    props->eccert_file = vstring_export(eccert_file);
+    props->eckey_file = vstring_export(eckey_file);
+    props->CAfile = vstring_export(CAfile);
+    props->CApath = vstring_export(CApath);
+    props->protocols = vstring_export(protocols);
+    props->eecdh_grade = vstring_export(eecdh_grade);
+    props->dh1024_param_file = vstring_export(dh1024_param_file);
+    props->dh512_param_file = vstring_export(dh512_param_file);
+    props->mdalg = vstring_export(mdalg);
+    ret = (ret == 19 ? 1 : -1);
+    if (ret != 1) {
+       tls_proxy_server_init_free(props);
+       props = 0;
+    }
+    *(TLS_SERVER_INIT_PROPS **) ptr = props;
+    return (ret);
+}
+
+/* tls_proxy_server_init_free - destroy TLS_SERVER_INIT_PROPS structure */
+
+void    tls_proxy_server_init_free(TLS_SERVER_INIT_PROPS *props)
+{
+    myfree((void *) props->log_param);
+    myfree((void *) props->log_level);
+    myfree((void *) props->cache_type);
+    myfree((void *) props->cert_file);
+    myfree((void *) props->key_file);
+    myfree((void *) props->dcert_file);
+    myfree((void *) props->dkey_file);
+    myfree((void *) props->eccert_file);
+    myfree((void *) props->eckey_file);
+    myfree((void *) props->CAfile);
+    myfree((void *) props->CApath);
+    myfree((void *) props->protocols);
+    myfree((void *) props->eecdh_grade);
+    myfree((void *) props->dh1024_param_file);
+    myfree((void *) props->dh512_param_file);
+    myfree((void *) props->mdalg);
+    myfree((void *) props);
+}
+
+/* tls_proxy_server_start_scan - receive TLS_SERVER_START_PROPS from stream */
+
+int     tls_proxy_server_start_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
+                                           int flags, void *ptr)
+{
+    TLS_SERVER_START_PROPS *props
+    = (TLS_SERVER_START_PROPS *) mymalloc(sizeof(*props));
+    int     ret;
+    VSTRING *serverid = vstring_alloc(25);
+    VSTRING *namaddr = vstring_alloc(25);
+    VSTRING *cipher_grade = vstring_alloc(25);
+    VSTRING *cipher_exclusions = vstring_alloc(25);
+    VSTRING *mdalg = vstring_alloc(25);
+
+    /*
+     * Note: memset() is not a portable way to initialize non-integer types.
+     */
+    memset(props, 0, sizeof(*props));
+    props->ctx = 0;
+    props->stream = 0;
+    /* XXX Caller sets fd. */
+    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                 RECV_ATTR_INT(TLS_ATTR_TIMEOUT, &props->timeout),
+                 RECV_ATTR_INT(TLS_ATTR_REQUIRECERT, &props->requirecert),
+                 RECV_ATTR_STR(TLS_ATTR_SERVERID, serverid),
+                 RECV_ATTR_STR(TLS_ATTR_NAMADDR, namaddr),
+                 RECV_ATTR_STR(TLS_ATTR_CIPHER_GRADE, cipher_grade),
+                 RECV_ATTR_STR(TLS_ATTR_CIPHER_EXCLUSIONS,
+                               cipher_exclusions),
+                 RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
+                 ATTR_TYPE_END);
+    props->serverid = vstring_export(serverid);
+    props->namaddr = vstring_export(namaddr);
+    props->cipher_grade = vstring_export(cipher_grade);
+    props->cipher_exclusions = vstring_export(cipher_exclusions);
+    props->mdalg = vstring_export(mdalg);
+    ret = (ret == 7 ? 1 : -1);
+    if (ret != 1) {
+       tls_proxy_server_start_free(props);
+       props = 0;
+    }
+    *(TLS_SERVER_START_PROPS **) ptr = props;
+    return (ret);
+}
+
+/* tls_proxy_server_start_free - destroy TLS_SERVER_START_PROPS structure */
+
+void    tls_proxy_server_start_free(TLS_SERVER_START_PROPS *props)
+{
+    /* XXX Caller closes fd. */
+    myfree((void *) props->serverid);
+    myfree((void *) props->namaddr);
+    myfree((void *) props->cipher_grade);
+    myfree((void *) props->cipher_exclusions);
+    myfree((void *) props->mdalg);
+    myfree((void *) props);
+}
+
+#endif
index 087721bf7597e127bede771c857af5043ab085b2..e248f8501c22e6eba99126b0acf18ea3209b7d6c 100644 (file)
@@ -61,6 +61,7 @@ depend: $(MAKES)
        @$(EXPORT) make -f Makefile.in Makefile 1>&2
 
 # do not edit below this line - it is generated by 'make depend'
+tls_client.o: tls_client.c
 tlsproxy.o: ../../include/argv.h
 tlsproxy.o: ../../include/attr.h
 tlsproxy.o: ../../include/check_arg.h
@@ -90,9 +91,11 @@ tlsproxy.o: ../../include/vstring.h
 tlsproxy.o: tlsproxy.c
 tlsproxy.o: tlsproxy.h
 tlsproxy_state.o: ../../include/argv.h
+tlsproxy_state.o: ../../include/attr.h
 tlsproxy_state.o: ../../include/check_arg.h
 tlsproxy_state.o: ../../include/dns.h
 tlsproxy_state.o: ../../include/events.h
+tlsproxy_state.o: ../../include/htable.h
 tlsproxy_state.o: ../../include/mail_conf.h
 tlsproxy_state.o: ../../include/mail_server.h
 tlsproxy_state.o: ../../include/msg.h
@@ -101,9 +104,11 @@ 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/nvtable.h
 tlsproxy_state.o: ../../include/sock_addr.h
 tlsproxy_state.o: ../../include/sys_defs.h
 tlsproxy_state.o: ../../include/tls.h
+tlsproxy_state.o: ../../include/tls_proxy.h
 tlsproxy_state.o: ../../include/vbuf.h
 tlsproxy_state.o: ../../include/vstream.h
 tlsproxy_state.o: ../../include/vstring.h
index 2c855ffcc72077fb38a924f68c4de886d23c24ab..241e83b2ae91684648d9a2f0f1b4d47b853854c2 100644 (file)
@@ -6,11 +6,12 @@
 /* SYNOPSIS
 /*     \fBtlsproxy\fR [generic Postfix daemon options]
 /* DESCRIPTION
-/*     The \fBtlsproxy\fR(8) server implements a server-side TLS
-/*     proxy. It is used by \fBpostscreen\fR(8) to talk SMTP-over-TLS
+/*     The \fBtlsproxy\fR(8) server implements a two-way TLS proxy. It
+/*     is used by the \fBpostscreen\fR(8) server to talk SMTP-over-TLS
 /*     with remote SMTP clients that are not whitelisted (including
-/*     clients whose whitelist status has expired),
-/*     but it should also work for non-SMTP protocols.
+/*     clients whose whitelist status has expired), and by the
+/*     \fBsmtp\fR(8) client to support TLS connection reuse, 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
@@ -309,14 +310,33 @@ int     var_tlsp_watchdog;
 static TLS_APPL_STATE *tlsp_server_ctx;
 static int ask_client_cert;
 
+ /*
+  * TLS per-client status.
+  */
+static HTABLE *tlsp_client_app_cache;
+
+ /*
+  * Error handling: if a function detects an error, then that function is
+  * responsible for destroying TLSP_STATE. Exceptions to this principle are
+  * indicated in the code.
+  */
+
+ /*
+  * Internal status API.
+  */
+#define TLSP_STAT_OK   0
+#define TLSP_STAT_ERR  (-1)
+
  /*
   * 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.
+  * The code that implements the TLS engine looks simpler than expected. That
+  * is the result of a great deal of effort, mainly in design and analysis.
+  * 
+  * The initial use case was to provide TLS support for postscreen(8).
   * 
   * 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
@@ -343,12 +363,17 @@ static int ask_client_cert;
   * 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.
+  * 
+  * Later in the life cycle, tlsproxy(8) has also become an enabler for TLS
+  * connection reuse across different SMTP client processes.
   */
 
 static void tlsp_ciphertext_event(int, void *);
 
 #define TLSP_INIT_TIMEOUT      100
 
+static void tlsp_plaintext_event(int event, void *context);
+
 /* tlsp_drain - delayed exit after "postfix reload" */
 
 static void tlsp_drain(char *unused_service, char **unused_argv)
@@ -406,7 +431,7 @@ static int tlsp_eval_tls_error(TLSP_STATE *state, int err)
                                state->timeout);
            state->ssl_last_err = SSL_ERROR_NONE;
        }
-       return (0);
+       return (TLSP_STAT_OK);
 
        /*
         * The TLS engine wants to write to the network. Turn on
@@ -422,7 +447,7 @@ static int tlsp_eval_tls_error(TLSP_STATE *state, int err)
        }
        event_request_timer(tlsp_ciphertext_event, (void *) state,
                            state->timeout);
-       return (0);
+       return (TLSP_STAT_OK);
 
        /*
         * The TLS engine wants to read from the network. Turn on
@@ -438,7 +463,7 @@ static int tlsp_eval_tls_error(TLSP_STATE *state, int err)
        }
        event_request_timer(tlsp_ciphertext_event, (void *) state,
                            state->timeout);
-       return (0);
+       return (TLSP_STAT_OK);
 
        /*
         * Some error. Self-destruct. This automagically cleans up all
@@ -450,8 +475,61 @@ static int tlsp_eval_tls_error(TLSP_STATE *state, int err)
        /* FALLTHROUGH */
     default:
        tlsp_state_free(state);
-       return (-1);
+       return (TLSP_STAT_ERR);
+    }
+}
+
+/* tlsp_post_handshake - post-handshake processing */
+
+static int tlsp_post_handshake(TLSP_STATE *state)
+{
+
+    /*
+     * Do not assume that tls_server_post_accept() and
+     * tls_client_post_connect() will always succeed.
+     */
+    if (state->is_server_role)
+       state->tls_context = tls_server_post_accept(state->tls_context);
+    else
+       state->tls_context = tls_client_post_connect(state->tls_context,
+                                                state->client_start_props);
+    if (state->tls_context == 0) {
+       tlsp_state_free(state);
+       return (TLSP_STAT_ERR);
+    }
+
+    /*
+     * Report TLS handshake results to the tlsproxy client.
+     * 
+     * Security: this sends internal data over the same local plaintext stream
+     * that will also be used for sending decrypted remote content from an
+     * arbitrary remote peer. For this reason we enable decrypted I/O only
+     * after reporting the TLS handshake results. The Postfix attribute
+     * protocol is robust enough that an attacker cannot append content.
+     */
+    if ((state->req_flags & TLS_PROXY_FLAG_SEND_CONTEXT) != 0
+       && (attr_print(state->plaintext_stream, ATTR_FLAG_NONE,
+                      SEND_ATTR_FUNC(tls_proxy_context_print,
+                                     (void *) state->tls_context),
+                      ATTR_TYPE_END) != 0
+           || vstream_fflush(state->plaintext_stream) != 0)) {
+       msg_warn("cannot send TLS context: %m");
+       tlsp_state_free(state);
+       return (TLSP_STAT_ERR);
     }
+
+    /*
+     * Initialize plaintext-related session state. Once we have this behind
+     * us, the TLSP_STATE destructor will automagically clean up requests for
+     * plaintext read/write/timeout events, which makes error recovery
+     * easier.
+     */
+    state->plaintext_buf =
+       nbbio_create(vstream_fileno(state->plaintext_stream),
+                    VSTREAM_BUFSIZE, state->server_id,
+                    tlsp_plaintext_event,
+                    (void *) state);
+    return (TLSP_STAT_OK);
 }
 
 /* tlsp_strategy - decide what to read or write next. */
@@ -466,33 +544,28 @@ static void tlsp_strategy(TLSP_STATE *state)
     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.
+     * Do not enable plain-text I/O before completing the TLS handshake.
+     * Otherwise the remote peer can prepend plaintext to the optional
+     * TLS_SESS_STATE object.
      */
     if (state->flags & TLSP_FLAG_DO_HANDSHAKE) {
-       ssl_stat = SSL_accept(tls_context->con);
+       state->timeout = state->handshake_timeout;
+       if (state->is_server_role)
+           ssl_stat = SSL_accept(tls_context->con);
+       else
+           ssl_stat = SSL_connect(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;
-       }
-       if ((state->req_flags & TLS_PROXY_FLAG_SEND_CONTEXT) != 0
-           && (attr_print(state->plaintext_stream, ATTR_FLAG_NONE,
-                          SEND_ATTR_FUNC(tls_proxy_context_print,
-                                         (void *) state->tls_context),
-                          ATTR_TYPE_END) != 0
-               || vstream_fflush(state->plaintext_stream) != 0)) {
-           msg_warn("cannot send TLS context: %m");
-           tlsp_state_free(state);
+       state->flags &= ~TLSP_FLAG_DO_HANDSHAKE;
+       state->timeout = state->session_timeout;
+       if (tlsp_post_handshake(state) != TLSP_STAT_OK) {
+           /* At this point, state is a dangling pointer. */
            return;
        }
-       state->flags &= ~TLSP_FLAG_DO_HANDSHAKE;
     }
 
     /*
@@ -581,21 +654,24 @@ static void tlsp_strategy(TLSP_STATE *state)
      */
     if (tlsp_eval_tls_error(state, ssl_write_err != SSL_ERROR_NONE ?
                            ssl_write_err : ssl_read_err) < 0)
+       /* At this point, state is a dangling pointer. */
        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
+     * have nothing to write to the plaintext stream, 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.
+     * XXX In theory, if the ciphertext peer keeps writing fast enough then we
+     * would never read from the plaintext stream and cause the latter to
+     * block. In practice, postscreen(8) limits the number of client
+     * commands, and thus postscreen(8)'s output will fit in a kernel buffer.
+     * A remote SMTP server is not supposed to flood the local SMTP client
+     * with massive replies; it it does, then the local SMTP client should
+     * deal with it.
      */
     if (NBBIO_WRITE_PEND(plaintext_buf) > 0) {
        if (NBBIO_ACTIVE_FLAGS(plaintext_buf) & NBBIO_FLAG_READ)
@@ -634,6 +710,7 @@ static void tlsp_plaintext_event(int event, void *context)
      * want to read or write more plaintext.
      */
     tlsp_strategy(state);
+    /* At this point, state could be a dangling pointer. */
 }
 
 /* tlsp_ciphertext_event - ciphertext is ready to read/write */
@@ -649,6 +726,7 @@ static void tlsp_ciphertext_event(int event, void *context)
      */
     if (event == EVENT_READ || event == EVENT_WRITE) {
        tlsp_strategy(state);
+       /* At this point, state could be a dangling pointer. */
     } else {
        if (event == EVENT_TIME && state->ssl_last_err == SSL_ERROR_NONE)
            msg_warn("deadlock on plaintext stream for %s",
@@ -661,9 +739,23 @@ static void tlsp_ciphertext_event(int event, void *context)
     }
 }
 
-/* tlsp_start_tls - turn on TLS or force disconnect */
+/* tlsp_client_start_pre_handshake - turn on TLS or force disconnect */
 
-static int tlsp_start_tls(TLSP_STATE *state)
+static int tlsp_client_start_pre_handshake(TLSP_STATE *state)
+{
+    state->client_start_props->ctx = state->appl_state;
+    state->client_start_props->fd = state->ciphertext_fd;
+    state->tls_context = tls_client_start(state->client_start_props);
+    if (state->tls_context != 0)
+       return (TLSP_STAT_OK);
+
+    tlsp_state_free(state);
+    return (TLSP_STAT_ERR);
+}
+
+/* tlsp_server_start_pre_handshake - turn on TLS or force disconnect */
+
+static int tlsp_server_start_pre_handshake(TLSP_STATE *state)
 {
     TLS_SERVER_START_PROPS props;
     static char *cipher_grade;
@@ -676,8 +768,8 @@ static int tlsp_start_tls(TLSP_STATE *state)
      */
 
     /*
-     * Perform the before-handshake portion of the per-session initialization.
-     * Pass a null VSTREAM to indicate that this program, will do the
+     * Perform the before-handshake portion of per-session initialization.
+     * 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
@@ -716,7 +808,7 @@ static int tlsp_start_tls(TLSP_STATE *state)
 
     if (state->tls_context == 0) {
        tlsp_state_free(state);
-       return (-1);
+       return (TLSP_STAT_ERR);
     }
 
     /*
@@ -725,68 +817,140 @@ static int tlsp_start_tls(TLSP_STATE *state)
      * 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.
      */
-    return (0);
+    return (TLSP_STAT_OK);
+}
+
+ /*
+  * From here on down is low-level code that sets up the plumbing before
+  * passing control to the TLS engine above.
+  */
+
+/* tlsp_request_read_event - pre-handshake event boiler plate */
+
+static void tlsp_request_read_event(int fd, EVENT_NOTIFY_FN handler,
+                                           int timeout, void *context)
+{
+    event_enable_read(fd, handler, context);
+    event_request_timer(handler, context, timeout);
+}
+
+/* tlsp_accept_event - pre-handshake event boiler plate */
+
+static void tlsp_accept_event(int event, EVENT_NOTIFY_FN handler,
+                                     void *context)
+{
+    if (event != EVENT_TIME)
+       event_cancel_timer(handler, context);
+    else
+       errno = ETIMEDOUT;
+    /* tlsp_state_free() disables pre-handshake plaintext I/O events. */
 }
 
-/* tlsp_get_fd_event - receive final postscreen(8) hand-off information */
+/* tlsp_get_fd_event - receive final connection hand-off information */
 
 static void tlsp_get_fd_event(int event, void *context)
 {
     const char *myname = "tlsp_get_fd_event";
     TLSP_STATE *state = (TLSP_STATE *) context;
     int     plaintext_fd = vstream_fileno(state->plaintext_stream);
+    int     status;
 
     /*
      * 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.
+     * events. Disable I/O events on the plaintext stream until the TLS
+     * handshake is completed. Every code path must either destroy state, or
+     * request the next event, otherwise we have a file and memory leak.
      */
+    tlsp_accept_event(event, tlsp_get_fd_event, (void *) state);
     event_disable_readwrite(plaintext_fd);
-    if (event != EVENT_TIME)
-       event_cancel_timer(tlsp_get_fd_event, (void *) state);
-    else
-       errno = ETIMEDOUT;
 
-    /*
-     * 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);
+       msg_warn("%s: receive remote SMTP peer file descriptor: %m", myname);
        tlsp_state_free(state);
        return;
     }
-    non_blocking(state->ciphertext_fd, NON_BLOCKING);
+
+    /*
+     * This is a bit early, to ensure that timer events for this file handle
+     * are guaranteed to be turned off by the TLSP_STATE destructor.
+     */
     state->ciphertext_timer = tlsp_ciphertext_event;
-    state->plaintext_buf = nbbio_create(plaintext_fd,
-                                       VSTREAM_BUFSIZE, "postscreen",
-                                       tlsp_plaintext_event,
-                                       (void *) state);
+    non_blocking(state->ciphertext_fd, NON_BLOCKING);
 
     /*
      * Perform the TLS layer before-handshake initialization. We perform the
-     * remainder after the TLS handshake completes.
+     * remainder after the actual TLS handshake completes.
      */
-    if (tlsp_start_tls(state) < 0)
+    if (state->is_server_role)
+       status = tlsp_server_start_pre_handshake(state);
+    else
+       status = tlsp_client_start_pre_handshake(state);
+    if (status != TLSP_STAT_OK)
+       /* At this point, state is a dangling pointer. */
        return;
 
     /*
      * Trigger the initial proxy server I/Os.
      */
     tlsp_strategy(state);
+    /* At this point, state could be a dangling pointer. */
+}
+
+ /*
+  * This function does not destroy TLSP_STATE in case of error, because that
+  * would complicate the caller.
+  */
+
+/* tlsp_client_init_no_tlsp_state_free - initialize a TLS client engine */
+
+static int tlsp_client_init_no_tlsp_state_free(TLSP_STATE *state)
+{
+    VSTRING *buf;
+    char   *key;
+
+    /*
+     * Share a TLS_APPL_STATE object among multiple requests that specify the
+     * same TLS_CLIENT_INIT_PROPS. TLS_APPL_STATE owns an SSL_CTX which is
+     * expensive.
+     */
+    buf = vstring_alloc(100);
+    key = tls_proxy_client_init_to_string(buf, state->client_init_props);
+    if ((state->appl_state = (TLS_APPL_STATE *)
+        htable_find(tlsp_client_app_cache, key)) == 0
+       && (state->appl_state =
+           tls_client_init(state->client_init_props)) != 0) {
+       (void) htable_enter(tlsp_client_app_cache, key,
+                           (void *) state->appl_state);
+
+       /*
+        * 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 (state->appl_state)
+           SSL_CTX_set_mode(state->appl_state->ssl_ctx,
+                            SSL_MODE_ENABLE_PARTIAL_WRITE
+                            | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+    }
+    vstring_free(buf);
+    return (state->appl_state != 0);
+}
+
+/* tlsp_close_event - pre-handshake plaintext-client close event */
+
+static void tlsp_close_event(int event, void *context)
+{
+    TLSP_STATE *state = (TLSP_STATE *) context;
+
+    tlsp_accept_event(event, tlsp_close_event, (void *) state);
+    tlsp_state_free(state);
 }
 
-/* tlsp_get_request_event - receive initial postscreen(8) hand-off info */
+/* tlsp_get_request_event - receive initial hand-off info */
 
 static void tlsp_get_request_event(int event, void *context)
 {
@@ -797,8 +961,17 @@ static void tlsp_get_request_event(int event, void *context)
     static VSTRING *remote_endpt;
     static VSTRING *server_id;
     int     req_flags;
-    int     timeout;
-    int     ready;
+    int     handshake_timeout;
+    int     session_timeout;
+    int     ready = 0;
+
+    /*
+     * At this point we still manually manage plaintext read/write/timeout
+     * events. Every code path must either destroy state or request the next
+     * event, otherwise this pseudo-thread is idle until the client goes
+     * away.
+     */
+    tlsp_accept_event(event, tlsp_get_request_event, (void *) state);
 
     /*
      * One-time initialization.
@@ -809,68 +982,87 @@ static void tlsp_get_request_event(int event, void *context)
     }
 
     /*
-     * 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, (void *) state);
-    else
-       errno = ETIMEDOUT;
-
-    /*
-     * 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.
+     * Receive the initial request attributes. Receive the remainder after we
+     * figure out what role we are expected to play.
      */
     if (event != EVENT_READ
        || attr_scan(plaintext_stream, ATTR_FLAG_STRICT,
-                    RECV_ATTR_STR(MAIL_ATTR_REMOTE_ENDPT, remote_endpt),
-                    RECV_ATTR_INT(MAIL_ATTR_FLAGS, &req_flags),
-                    RECV_ATTR_INT(MAIL_ATTR_TIMEOUT, &timeout),
-                    RECV_ATTR_STR(MAIL_ATTR_SERVER_ID, server_id),
-                    ATTR_TYPE_END) != 4) {
+                    RECV_ATTR_STR(TLS_ATTR_REMOTE_ENDPT, remote_endpt),
+                    RECV_ATTR_INT(TLS_ATTR_FLAGS, &req_flags),
+                    RECV_ATTR_INT(TLS_ATTR_TIMEOUT, &handshake_timeout),
+                    RECV_ATTR_INT(TLS_ATTR_TIMEOUT, &session_timeout),
+                    RECV_ATTR_STR(TLS_ATTR_SERVERID, server_id),
+                    ATTR_TYPE_END) != 5) {
        msg_warn("%s: receive request attributes: %m", myname);
-       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 (except during TLS the handshake, when we intentionally disable
+     * plaintext I/O).
+     */
+    state->remote_endpt = mystrdup(STR(remote_endpt));
+    state->server_id = mystrdup(STR(server_id));
+    msg_info("CONNECT %s %s",
+            (req_flags & TLS_PROXY_FLAG_ROLE_SERVER) ? "from" :
+            (req_flags & TLS_PROXY_FLAG_ROLE_CLIENT) ? "to" :
+            "(bogus_direction)", state->remote_endpt);
+    state->req_flags = req_flags;
+    /* state->is_server_role is set below. */
+    state->handshake_timeout = handshake_timeout + 10; /* XXX */
+    state->session_timeout = session_timeout + 10;     /* XXX */
+
+    /*
+     * Receive the TLS preferences now, to reduce the number of protocol
+     * roundtrips.
+     */
+    switch (req_flags & (TLS_PROXY_FLAG_ROLE_CLIENT | TLS_PROXY_FLAG_ROLE_SERVER)) {
+    case TLS_PROXY_FLAG_ROLE_CLIENT:
+       state->is_server_role = 0;
+       if (attr_scan(plaintext_stream, ATTR_FLAG_STRICT,
+                     RECV_ATTR_FUNC(tls_proxy_client_init_scan,
+                                    (void *) &state->client_init_props),
+                     RECV_ATTR_FUNC(tls_proxy_client_start_scan,
+                                    (void *) &state->client_start_props),
+                     ATTR_TYPE_END) != 2) {
+           msg_warn("%s: receive client TLS settings: %m", myname);
+           tlsp_state_free(state);
+           return;
+       }
+       ready = tlsp_client_init_no_tlsp_state_free(state);
+       break;
+    case TLS_PROXY_FLAG_ROLE_SERVER:
+       state->is_server_role = 1;
+       ready = (tlsp_server_ctx != 0);
+       break;
+    default:
+       state->is_server_role = 0;
+       msg_warn("%s: bad request flags: 0x%x", myname, req_flags);
+       ready = 0;
+    }
+
+    /*
+     * For portability we must send some data, after receiving the request
+     * attributes and before receiving the remote file descriptor.
+     * 
      * If the requested TLS engine is unavailable, hang up after making sure
      * that the plaintext peer has received our "sorry" indication.
      */
-    ready = ((req_flags & TLS_PROXY_FLAG_ROLE_SERVER) != 0
-            && tlsp_server_ctx != 0);
     if (attr_print(plaintext_stream, ATTR_FLAG_NONE,
                   SEND_ATTR_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);
+       tlsp_request_read_event(plaintext_fd, tlsp_close_event,
+                               TLSP_INIT_TIMEOUT, (void *) 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));
-       state->server_id = mystrdup(STR(server_id));
-       msg_info("CONNECT %s %s",
-                (req_flags & TLS_PROXY_FLAG_ROLE_SERVER) ? "from" :
-                (req_flags & TLS_PROXY_FLAG_ROLE_CLIENT) ? "to" :
-                "(bogus_direction)", state->remote_endpt);
-       state->req_flags = req_flags;
-       state->timeout = timeout + 10;          /* XXX */
-       event_enable_read(plaintext_fd, tlsp_get_fd_event, (void *) state);
-       event_request_timer(tlsp_get_fd_event, (void *) state,
-                           TLSP_INIT_TIMEOUT);
+    } else {
+       tlsp_request_read_event(plaintext_fd, tlsp_get_fd_event,
+                               TLSP_INIT_TIMEOUT, (void *) state);
        return;
     }
 }
@@ -906,9 +1098,8 @@ static void tlsp_service(VSTREAM *plaintext_stream,
      * 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, (void *) state);
-    event_request_timer(tlsp_get_request_event, (void *) state,
-                       TLSP_INIT_TIMEOUT);
+    tlsp_request_read_event(plaintext_fd, tlsp_get_request_event,
+                           TLSP_INIT_TIMEOUT, (void *) state);
 }
 
 /* pre_jail_init - pre-jail initialization */
@@ -1033,7 +1224,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
 
 static void post_jail_init(char *unused_name, char **unused_argv)
 {
-     /* void */ ;
+    tlsp_client_app_cache = htable_create(10);
 }
 
 MAIL_VERSION_STAMP_DECLARE;
@@ -1120,7 +1311,7 @@ int     main(int argc, char **argv)
     MAIL_VERSION_STAMP_ALLOCATE;
 
     /*
-     * Pass control to the single-threaded service skeleton.
+     * Pass control to the event-driven service skeleton.
      */
     event_server_main(argc, argv, tlsp_service,
                      CA_MAIL_SERVER_INT_TABLE(int_table),
index e3e1d11fa38df2a8ed2b84c800799d369642eb8f..fe560644ec28fd260e20cdcbf83a0905159b694a 100644 (file)
 typedef struct {
     int     flags;                     /* see below */
     int     req_flags;                 /* request flags, see tls_proxy.h */
+    int     is_server_role;            /* avoid clumsy handler code */
     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 */
+    int     handshake_timeout;         /* in-handshake time limit */
+    int     session_timeout;           /* post-handshake time limit */
     char   *remote_endpt;              /* printable remote endpoint */
     char   *server_id;                 /* cache management */
-    TLS_SESS_STATE *tls_context;       /* llibtls state */
+    TLS_APPL_STATE *appl_state;                /* libtls state */
+    TLS_SESS_STATE *tls_context;       /* libtls state */
     int     ssl_last_err;              /* TLS I/O state */
+    TLS_SERVER_INIT_PROPS *server_init_props;
+    TLS_SERVER_START_PROPS *server_start_props;
+    TLS_CLIENT_INIT_PROPS *client_init_props;
+    TLS_CLIENT_START_PROPS *client_start_props;
 } TLSP_STATE;
 
 #define TLSP_FLAG_DO_HANDSHAKE (1<<0)
@@ -51,4 +59,9 @@ extern void tlsp_state_free(TLSP_STATE *);
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
index e327649207fe1d189c65a7c34859c4dc2b688c5b..d6b88f598bfa409c4b264d1f03db220f372a78cf 100644 (file)
@@ -18,7 +18,8 @@
 /*
 /*     tlsp_state_create() initializes session context.
 /*
-/*     tlsp_state_free() destroys session context.
+/*     tlsp_state_free() destroys session context. If the handshake
+/*     was in progress, it logs a 'handshake failed' message.
 /*
 /*     Arguments:
 /* .IP service
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
  /*
@@ -85,6 +91,7 @@
 #ifdef USE_TLS
 #define TLS_INTERNAL                   /* XXX */
 #include <tls.h>
+#include <tls_proxy.h>
 
  /*
   * Application-specific.
@@ -108,6 +115,10 @@ TLSP_STATE *tlsp_state_create(const char *service,
     state->remote_endpt = 0;
     state->server_id = 0;
     state->tls_context = 0;
+    state->server_init_props = 0;
+    state->server_start_props = 0;
+    state->client_init_props = 0;
+    state->client_start_props = 0;
 
     return (state);
 }
@@ -116,9 +127,16 @@ TLSP_STATE *tlsp_state_create(const char *service,
 
 void    tlsp_state_free(TLSP_STATE *state)
 {
+    /* Don't log failure after plaintext EOF. */
+    if (state->remote_endpt && state->server_id
+       && (state->flags & TLSP_FLAG_DO_HANDSHAKE))
+       msg_info("TLS handshake failed for service=%s peer=%s",
+                state->server_id, state->remote_endpt);
     myfree(state->service);
     if (state->plaintext_buf)                  /* turns off plaintext events */
        nbbio_free(state->plaintext_buf);
+    else
+       event_disable_readwrite(vstream_fileno(state->plaintext_stream));
     event_server_disconnect(state->plaintext_stream);
     if (state->ciphertext_fd >= 0) {
        event_disable_readwrite(state->ciphertext_fd);
@@ -134,6 +152,14 @@ void    tlsp_state_free(TLSP_STATE *state)
        myfree(state->server_id);
     if (state->tls_context)
        tls_free_context(state->tls_context);
+    if (state->server_init_props)
+       tls_proxy_server_init_free(state->server_init_props);
+    if (state->server_start_props)
+       tls_proxy_server_start_free(state->server_start_props);
+    if (state->client_init_props)
+       tls_proxy_client_init_free(state->client_init_props);
+    if (state->client_start_props)
+       tls_proxy_client_start_free(state->client_start_props);
     myfree((void *) state);
 }
 
index 32cefbc0773ec74a02ff2fcd47b58ae2903593a6..d419cb3975562a4fe7a2618be37ef61fe5d0eb37 100644 (file)
@@ -40,7 +40,7 @@ SRCS  = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
        poll_fd.c timecmp.c slmdb.c dict_pipe.c dict_random.c \
        valid_utf8_hostname.c midna_domain.c argv_splitq.c balpar.c dict_union.c \
        extpar.c dict_inline.c casefold.c dict_utf8.c strcasecmp_utf8.c \
-       split_qnameval.c
+       split_qnameval.c argv_attr_print.c argv_attr_scan.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 \
@@ -82,7 +82,7 @@ OBJS  = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        poll_fd.o timecmp.o $(NON_PLUGIN_MAP_OBJ) dict_pipe.o dict_random.o \
        valid_utf8_hostname.o midna_domain.o argv_splitq.o balpar.o dict_union.o \
        extpar.o dict_inline.o casefold.o dict_utf8.o strcasecmp_utf8.o \
-       split_qnameval.o
+       split_qnameval.o argv_attr_print.o argv_attr_scan.o
 # MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf.
 # When hard-linking these, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ),
 # otherwise it sets the PLUGIN_* macros.
@@ -111,7 +111,8 @@ HDRS        = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
        edit_file.h dict_cache.h dict_thash.h ip_match.h nbbio.h base32_code.h \
        dict_fail.h warn_stat.h dict_sockmap.h line_number.h timecmp.h \
        slmdb.h compat_va_copy.h dict_pipe.h dict_random.h \
-       valid_utf8_hostname.h midna_domain.h dict_union.h dict_inline.h check_arg.h
+       valid_utf8_hostname.h midna_domain.h dict_union.h dict_inline.h \
+       check_arg.h argv_attr.h
 TESTSRC        = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
        stream_test.c dup2_pass_on_exec.c
 DEFS   = -I. -D$(SYSTYPE)
@@ -879,6 +880,32 @@ argv.o: argv.h
 argv.o: msg.h
 argv.o: mymalloc.h
 argv.o: sys_defs.h
+argv_attr_print.o: argv.h
+argv_attr_print.o: argv_attr.h
+argv_attr_print.o: argv_attr_print.c
+argv_attr_print.o: attr.h
+argv_attr_print.o: check_arg.h
+argv_attr_print.o: htable.h
+argv_attr_print.o: msg.h
+argv_attr_print.o: mymalloc.h
+argv_attr_print.o: nvtable.h
+argv_attr_print.o: sys_defs.h
+argv_attr_print.o: vbuf.h
+argv_attr_print.o: vstream.h
+argv_attr_print.o: vstring.h
+argv_attr_scan.o: argv.h
+argv_attr_scan.o: argv_attr.h
+argv_attr_scan.o: argv_attr_scan.c
+argv_attr_scan.o: attr.h
+argv_attr_scan.o: check_arg.h
+argv_attr_scan.o: htable.h
+argv_attr_scan.o: msg.h
+argv_attr_scan.o: mymalloc.h
+argv_attr_scan.o: nvtable.h
+argv_attr_scan.o: sys_defs.h
+argv_attr_scan.o: vbuf.h
+argv_attr_scan.o: vstream.h
+argv_attr_scan.o: vstring.h
 argv_split.o: argv.h
 argv_split.o: argv_split.c
 argv_split.o: check_arg.h
@@ -1785,6 +1812,8 @@ load_file.o: vbuf.h
 load_file.o: vstream.h
 load_file.o: warn_stat.h
 load_lib.o: load_lib.c
+load_lib.o: load_lib.h
+load_lib.o: msg.h
 load_lib.o: sys_defs.h
 lowercase.o: check_arg.h
 lowercase.o: lowercase.c
@@ -2363,6 +2392,7 @@ vbuf.o: vbuf.c
 vbuf.o: vbuf.h
 vbuf_print.o: check_arg.h
 vbuf_print.o: msg.h
+vbuf_print.o: mymalloc.h
 vbuf_print.o: sys_defs.h
 vbuf_print.o: vbuf.h
 vbuf_print.o: vbuf_print.c
diff --git a/postfix/src/util/argv_attr.h b/postfix/src/util/argv_attr.h
new file mode 100644 (file)
index 0000000..65cfa55
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _ARGV_ATTR_H_INCLUDED_
+#define _ARGV_ATTR_H_INCLUDED_
+
+/*++
+/* NAME
+/*     argv_attr 3h
+/* SUMMARY
+/*     argv serialization/deserialization
+/* SYNOPSIS
+/*     #include <argv_attr.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <argv.h>
+#include <attr.h>
+#include <check_arg.h>
+#include <vstream.h>
+
+ /*
+  * External API.
+  */
+#define ARGV_ATTR_SIZE "argv_size"
+#define ARGV_ATTR_VALUE        "argv_value"
+#define ARGV_ATTR_MAX  1024
+
+extern int argv_attr_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *);
+extern int argv_attr_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*--*/
+
+#endif
diff --git a/postfix/src/util/argv_attr_print.c b/postfix/src/util/argv_attr_print.c
new file mode 100644 (file)
index 0000000..87b086a
--- /dev/null
@@ -0,0 +1,73 @@
+/*++
+/* NAME
+/*     argv_attr_print
+/* SUMMARY
+/*     write ARGV to stream
+/* SYNOPSIS
+/*     #include <argv_attr.h>
+/*
+/*     int     argv_attr_print(print_fn, stream, flags, ptr)
+/*     ATTR_PRINT_MASTER_FN print_fn;
+/*     VSTREAM *stream;
+/*     int     flags;
+/*     void    *ptr;
+/* DESCRIPTION
+/*     argv_attr_print() writes an ARGV to the named stream using
+/*     the specified attribute print routine. argv_attr_print() is meant
+/*     to be passed as a call-back to attr_print(), thusly:
+/*
+/*     ... SEND_ATTR_FUNC(argv_attr_print, (void *) argv), ...
+/* DIAGNOSTICS
+/*     Fatal: out of memory.
+/*
+/*     The result value is zero in case of success, non-zero
+/*     otherwise.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*--*/
+
+ /*
+  * System library.
+  */
+#include <sys_defs.h>
+
+ /*
+  * Utility library.
+  */
+#include <argv.h>
+#include <argv_attr.h>
+#include <attr.h>
+#include <vstream.h>
+#include <msg.h>
+
+/* argv_attr_print - write ARGV to stream */
+
+int     argv_attr_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp,
+                               int flags, void *ptr)
+{
+    ARGV   *argv = (ARGV *) ptr;
+    int     n;
+    int     ret;
+    int     argc = argv ? argv->argc : 0;
+
+    ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                  SEND_ATTR_INT(ARGV_ATTR_SIZE, argc),
+                  ATTR_TYPE_END);
+    if (msg_verbose)
+       msg_info("argv_attr_print count=%d", argc);
+    for (n = 0; ret == 0 && n < argc; n++)
+       ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                      SEND_ATTR_STR(ARGV_ATTR_VALUE, argv->argv[n]),
+                      ATTR_TYPE_END);
+    if (msg_verbose)
+       msg_info("argv_attr_print ret=%d", ret);
+    /* Do not flush the stream. */
+    return (ret);
+}
diff --git a/postfix/src/util/argv_attr_scan.c b/postfix/src/util/argv_attr_scan.c
new file mode 100644 (file)
index 0000000..3005cb2
--- /dev/null
@@ -0,0 +1,93 @@
+/*++
+/* NAME
+/*     argv_attr_scan
+/* SUMMARY
+/*     read ARGV from stream
+/* SYNOPSIS
+/*     #include <argv_attr.h>
+/*
+/*     int     argv_attr_scan(scan_fn, stream, flags, ptr)
+/*     ATTR_SCAN_MASTER_FN scan_fn;
+/*     VSTREAM *stream;
+/*     int     flags;
+/*     void    *ptr;
+/* DESCRIPTION
+/*     argv_attr_scan() creates an ARGV and reads its contents
+/*     from the named stream using the specified attribute scan
+/*     routine. argv_attr_scan() is meant to be passed as a call-back
+/*     to attr_scan(), thusly:
+/*
+/*     ARGV *argv = 0;
+/*     ...
+/*     ... RECV_ATTR_FUNC(argv_attr_scan, (void *) &argv), ...
+/*     ...
+/*     if (argv)
+/*         argv_free(argv);
+/* DIAGNOSTICS
+/*     Fatal: out of memory.
+/*
+/*     In case of error, this function returns non-zero and creates
+/*     an ARGV null pointer.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*--*/
+
+ /*
+  * System library.
+  */
+#include <sys_defs.h>
+
+ /*
+  * Utility library.
+  */
+#include <argv.h>
+#include <argv_attr.h>
+#include <attr.h>
+#include <msg.h>
+#include <vstream.h>
+#include <vstring.h>
+
+/* argv_attr_scan - write ARGV to stream */
+
+int     argv_attr_scan(ATTR_PRINT_MASTER_FN scan_fn, VSTREAM *fp,
+                              int flags, void *ptr)
+{
+    ARGV   *argv = 0;
+    int     size;
+    int     ret;
+
+    if ((ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                      RECV_ATTR_INT(ARGV_ATTR_SIZE, &size),
+                      ATTR_TYPE_END)) == 1) {
+       if (msg_verbose)
+           msg_info("argv_attr_scan count=%d", size);
+       if (size < 0 || size > ARGV_ATTR_MAX) {
+           msg_warn("invalid size %d from %s while reading ARGV",
+                    size, VSTREAM_PATH(fp));
+           ret = -1;
+       } else if (size > 0) {
+           VSTRING *buffer = vstring_alloc(100);
+
+           argv = argv_alloc(size);
+           while (ret == 1 && size-- > 0) {
+               if ((ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                                  RECV_ATTR_STR(ARGV_ATTR_VALUE, buffer),
+                                  ATTR_TYPE_END)) == 1)
+                   argv_add(argv, vstring_str(buffer), ARGV_END);
+           }
+           argv_terminate(argv);
+           vstring_free(buffer);
+       }
+    }
+    *(ARGV **) ptr = argv;
+    if (msg_verbose)
+       msg_info("argv_attr_scan ret=%d", ret);
+    return (ret);
+}
index 5d461706f5a15bd4194d04d055f16f9e41441132..34e04343e2828a97cd7e417e544972239d46659b 100644 (file)
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
 /* System library. */