]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.12-20260514
authorWietse Z Venema <wietse@porcupine.org>
Thu, 14 May 2026 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <ietf-dane@dukhovni.org>
Fri, 15 May 2026 07:46:59 +0000 (17:46 +1000)
55 files changed:
postfix/HISTORY
postfix/INSTALL
postfix/README_FILES/INSTALL
postfix/RELEASE_NOTES
postfix/conf/postfix-files
postfix/html/INSTALL.html
postfix/html/anvil.8.html
postfix/html/lmtp.8.html
postfix/html/makedefs.1.html
postfix/html/postconf.5.html
postfix/html/postscreen.8.html
postfix/html/posttls-finger.1.html
postfix/html/smtp.8.html
postfix/html/smtpd.8.html
postfix/makedefs
postfix/man/man1/makedefs.1
postfix/man/man1/posttls-finger.1
postfix/man/man5/postconf.5
postfix/man/man8/anvil.8
postfix/man/man8/postscreen.8
postfix/man/man8/smtp.8
postfix/man/man8/smtpd.8
postfix/mantools/postlink
postfix/proto/INSTALL.html
postfix/proto/postconf.proto
postfix/proto/stop
postfix/proto/stop.double-history
postfix/proto/stop.spell-cc
postfix/src/anvil/anvil.c
postfix/src/global/anvil_clnt.c
postfix/src/global/anvil_clnt.h
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/postscreen/postscreen.c
postfix/src/postscreen/postscreen_tls_conf.c
postfix/src/posttls-finger/posttls-finger.c
postfix/src/smtp/lmtp_params.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp_params.c
postfix/src/smtp/smtp_proto.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_misc.c
postfix/src/tls/tls_proxy_attr.h
postfix/src/tls/tls_proxy_client_start_proto.c
postfix/src/tls/tls_proxy_client_start_proto.h
postfix/src/tls/tls_proxy_context_print.c
postfix/src/tls/tls_proxy_context_scan.c
postfix/src/tls/tls_proxy_server_start_proto.c
postfix/src/tls/tls_proxy_server_start_proto.h
postfix/src/tls/tls_server.c
postfix/src/util/sys_defs.h
postfix/src/util/vbuf_print.c

index 53a20f71893e9f8b74cd3078334f096f6f7428b1..c934825e9aa93c6e95ab95f0339f0c30f3feb6d3 100644 (file)
@@ -31107,7 +31107,7 @@ Apologies for any names omitted.
 
        Bitrot fixes: deprecation warning with OpenSSL 4.0
        (tls/tls_dane.c); race condition fix in a test script
-       (tls/dls_dane.sh). Viktor Dukhovni.
+       (tls/tls_dane.sh). Viktor Dukhovni.
 
 20260510
 
@@ -31119,11 +31119,48 @@ Apologies for any names omitted.
        master/multi_server.c, master/single_server.c,
        src/master/trigger_server.c.
 
-TODO
 
-       Reorganize PTEST_LIB, PMOCK_LIB, TESTLIB, TESTLIBS, etc.
+20260513
+
+       Bitrot: builds with musl libc were using the obsolete
+       NO_SNPRINTF code path in vbuf_print.c. File: util/sys_defs.h.
+
+20260514
+
+       Bitrot: the obsolete NO_SNPRINTF code path in vbuf_print.c
+       wasn't updated for Claude Code findings. File: util/vbuf_print.c.
+
+       Feature: TLS protocol trace via SSL_trace, enabled with
+       "trace" in *_tls_loglevel or *_tls_loglevel_maps. smtp(8),
+       smtpd(8), and tlsproxy(8) write the transcript to a
+       per-connection file under $queue_directory/tlstrace/, capped
+       at *_tls_trace_size_limit bytes per file. posttls-finger(1)
+       writes to a file in the current directory; one file per
+       run, with separator lines between reconnects. The path is
+       logged via msg_info() when the trace begins. Files:
+       proto/postconf.proto, global/mail_params.h,
+       postscreen/postscreen.c, postscreen/postscreen_tls_conf.c,
+       posttls-finger/posttls-finger.c, smtp/lmtp_params.c,
+       smtp/smtp.c, smtp/smtp_params.c, smtp/smtp_proto.c,
+       smtpd/smtpd.c, tls/tls.h, tls/tls_client.c, tls/tls_misc.c,
+       tls/tls_proxy_attr.h, tls/tls_proxy_client_start_proto.[hc],
+       tls/tls_proxy_server_start_proto.[hc], tls/tls_server.c,
+       tlsproxy/tlsproxy.c, tlsproxy/tlsproxy_client.c,
+       tlsproxy/tlsproxy_server.c.
+
+       The above feature was implemented in three iterations. In
+       the first two, it was designed by Wietse and Viktor, with
+       preliminary implementations by Claude Code supervised by
+       Viktor. With minor changes, the Claude Code implementation
+       was finished by humans.
+
+       Feature: Postfix daemons create at most tls_trace_rate_limit
+       trace files (default: 1) per anvil_rate_time_unit interval
+       (default: 60s). This limit applies to the combined trace
+       file output from all Postfix daemon processes. Files:
+       anvil/anvil.c, global/anvil_clnt.[hc], proto/postconf.proto,
+       mantools/postlink.
 
-       Document TLS parameters in tlsproxy(8) and postscreen(8).
+TODO
 
-       Why are process_name and service_name implemented in different
-       ways?
+       Reorganize PTEST_LIB, PMOCK_LIB, TESTLIB, TESTLIBS, etc.
index 623dabf31f013a719453bfd461c8771162905803..649560d43ad5626257829c915f6751f636320167 100644 (file)
@@ -617,6 +617,14 @@ The following is an extensive list of names and values.
 ||-DNO_SNPRINTF                |default, Postfix uses snprintf() except on   |
 ||                             |ancient systems.                             |
 ||______________________________|_____________________________________________|
+||                             |Do not build with support for OpenSSL TLS    |
+||                             |traces. Some vendor OpenSSL runtime libraries|
+||                             |are built without support for tracing, and   |
+||-DNO_TLS_TRACE               |Postfix software built on a system with TLS  |
+||                             |trace support would not work when installed  |
+||                             |on one without. See smtp_tls_loglevel in the |
+||                             |postconf(5) manual.                          |
+||______________________________|_____________________________________________|
 |                              |Specifies a non-default compiler debugging   |
 |DEBUG=debug_level             |level. The default is "-g". Specify DEBUG= to|
 |                              |turn off debugging.                          |
index 956e0ea4ebe36bd92d91816629430dd7cfe3e91a..d11826fd991b53a32e05769bfb07370cdd7a4299 100644 (file)
@@ -617,6 +617,14 @@ The following is an extensive list of names and values.
 ||-DNO_SNPRINTF                 |default, Postfix uses snprintf() except on   |
 ||                              |ancient systems.                             |
 |_\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+||                              |Do not build with support for OpenSSL TLS    |
+||                              |traces. Some vendor OpenSSL runtime libraries|
+||                              |are built without support for tracing, and   |
+||-DNO_TLS_TRACE                |Postfix software built on a system with TLS  |
+||                              |trace support would not work when installed  |
+||                              |on one without. See smtp_tls_loglevel in the |
+||                              |postconf(5) manual.                          |
+|_\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
 |                               |Specifies a non-default compiler debugging   |
 |DEBUG=debug_level              |level. The default is "-g". Specify DEBUG= to|
 |                               |turn off debugging.                          |
index 91e6190564ccc9c0090a0f2cbd5cb7faf068b8d9..db94d64904b9e642ccbe3019eba80b3c484f266e 100644 (file)
@@ -26,6 +26,44 @@ now also distributed with the more recent Eclipse Public License
 license of their choice. Those who are more comfortable with the
 IPL can continue with that license.
 
+Major changes with snapshot 20260514
+====================================
+
+Support for per-session TLS traces with detailed TLS protocol
+information but without any plaintext SMTP content. This feature
+can be enabled by appending ",trace" to a TLS loglevel.
+
+Postfix daemons will record one trace per TLS session under
+$queue_directory/tlstrace. A trace file name is the concatenation
+of the application name ("smtpd", "smtp", etc.), a time stamp
+formatted as yyyymmddhhmmss, the microsecond portion of system time,
+the peer IP address, and a six-character unique string to avoid
+file name collisions.
+
+Safety measures: the size of each trace file is limited with {lmtp,
+postscreen, smtp_, smtpd}_tls_trace_size_limit (default: 102400),
+and all Postfix daemons combined will create no more than
+tls_trace_rate_limit trace files (default: 1) per anvil_rate_time_unit
+interval (default: 60s).
+
+The posttls-finger command will create trace files (using the same
+name format as daemons) in the current directory, for example:
+"posttls-finger -L 1,trace example.com". It is not subject to the
+tls_trace_rate_limit or trace file size constraints.
+
+This feature is based on a design by Wietse and Viktor, initially
+implemented by Claude Code, then simplified and completed by Wietse
+and Viktor.
+
+Incompatible changes with snapshot 20260514
+===========================================
+
+The internal protocol between tlsproxy(8) and its clients (smtp(8),
+postscreen(8), smtpd(8) in tlsproxy mode, and "posttls-finger -X")
+gained a new attribute. Run "postfix reload" after the upgrade. If
+this step is skipped, TLS sessions through tlsproxy(8) will fail,
+because the old and new processes disagree on the protocol shape.
+
 Incompatible changes with snapshot 20260312
 ===========================================
 
index 7db6b3c3babd691e4c856e3801ebb53bd08e541a..68412e6a7592bd4d1c5f10f169ca4830dc2d8f44 100644 (file)
@@ -65,6 +65,7 @@ $queue_directory/maildrop:d:$mail_owner:$setgid_group:730:uc
 $queue_directory/public:d:$mail_owner:$setgid_group:710:uc
 $queue_directory/pid:d:root:-:755:uc
 $queue_directory/saved:d:$mail_owner:-:700:ucr
+$queue_directory/tlstrace:d:$mail_owner:-:700:ucr
 $queue_directory/trace:d:$mail_owner:-:700:ucr
 # Update shared libraries and plugins before daemon or command-line programs.
 $shlib_directory/lib${LIB_PREFIX}util${LIB_SUFFIX}:f:root:-:755
index f207623611b755fdc506ccecaf2db238250717d7..c64f3bcffd3510ecdc290058774f5b777b80f710 100644 (file)
@@ -891,6 +891,12 @@ they are known to be available. </td> </tr>
 instead of <tt>snprintf()</tt>.  By default, Postfix uses
 <tt>snprintf()</tt> except on ancient systems. </td> </tr>
 
+<tr> <td> </td> <td> -DNO_TLS_TRACE </td> <td> Do not build with support
+for OpenSSL TLS traces.  Some vendor OpenSSL runtime libraries are built
+without support for tracing, and Postfix software built on a system with
+TLS trace support would not work when installed on one without.  See
+<tt><a href="postconf.5.html#smtp_tls_loglevel">smtp_tls_loglevel</a></tt> in the <a href="postconf.5.html">postconf(5)</a> manual. </td> </tr>
+
 <tr> <td colspan="2"> DEBUG=debug_level </td> <td> Specifies a
 non-default compiler debugging level. The default is "<tt>-g</tt>".
 Specify DEBUG= to turn off debugging. </td> </tr>
index 0647075d3d5b10a82817d3ec36bf6cd6e576a03c..d8a927d5e5f7c7ad6f76c600ec78f5f4789796bc 100644 (file)
@@ -120,6 +120,19 @@ ANVIL(8)                                                              ANVIL(8)
            <b>status=0</b>
            <b>rate=</b><i>number</i>
 
+<b><a name="tls_trace_rate_control">TLS TRACE RATE CONTROL</a></b>
+       To register a TLS  trace  event  send  the  following  request  to  the
+       <a href="anvil.8.html"><b>anvil</b>(8)</a> server:
+
+           <b>request=tlstr</b>
+           <b>ident=</b><i>string</i>
+
+       The  <a href="anvil.8.html"><b>anvil</b>(8)</a>  server answers with the number of TLS trace requests per
+       unit time for the (service, client) combination specified with <b>ident</b>:
+
+           <b>status=0</b>
+           <b>rate=</b><i>number</i>
+
 <b><a name="security">SECURITY</a></b>
        The <a href="anvil.8.html"><b>anvil</b>(8)</a> server does not talk to the network or to local users, and
        can run chrooted at fixed low privilege.
index 04e8ed84aae63c15af79c935853bcf461d545c25..97be3c227b2e15317a4b999a8f4d3d7dda05d3fc 100644 (file)
@@ -794,6 +794,16 @@ SMTP(8)                                                                SMTP(8)
               Optional TLS loglevel override that depends on the  remote  peer
               host name or IP address.
 
+       <b><a href="postconf.5.html#smtp_tls_trace_size_limit">smtp_tls_trace_size_limit</a> (102400)</b>
+              Size  limit,  in bytes, for the TLS protocol transcript that the
+              Postfix SMTP client writes when the "trace" keyword is  included
+              in   the   TLS   loglevel   for  a  peer  (<a href="postconf.5.html#smtp_tls_loglevel">smtp_tls_loglevel</a>  or
+              <a href="postconf.5.html#smtp_tls_loglevel_maps">smtp_tls_loglevel_maps</a>).
+
+       <b><a href="postconf.5.html#tls_trace_rate_limit">tls_trace_rate_limit</a> (1)</b>
+              The maximum number of TLS traces per  <a href="postconf.5.html#anvil_rate_time_unit">anvil_rate_time_unit</a>  that
+              all Postfix daemons combined will create.
+
 <b><a name="obsolete_tls_controls">OBSOLETE TLS CONTROLS</a></b>
        The  following  configuration  parameters  exist for compatibility with
        Postfix versions before 2.3. Support for these will  be  removed  in  a
index c5afd48f92f69cb4dc608c9964d8e1648b90263b..f9a3ba2e446f9af06436c745ccebc596b70d12a5 100644 (file)
@@ -131,33 +131,36 @@ MAKEDEFS(1)                                                        MAKEDEFS(1)
               <b>-DNO_STDBOOL</b>
                      Don't use &lt;stdbool.h&gt;. This is usually auto-detected.
 
+              <b>-DNO_TLS_TRACE</b>
+                     Build without OpenSSL 3 (and later) debug trace  support.
+
        <b>DEBUG=</b><i>debug</i><b>_</b><i>level</i>
-              Specifies a non-default debugging  level.  The  default  is  <b>-g</b>.
+              Specifies  a  non-default  debugging  level.  The default is <b>-g</b>.
               Specify <b>DEBUG=</b> to turn off debugging.
 
        <b>OPT=</b><i>optimization</i><b>_</b><i>level</i>
-              Specifies  a  non-default optimization level. The default is <b>-O</b>.
+              Specifies a non-default optimization level. The default  is  <b>-O</b>.
               Specify <b>OPT=</b> to turn off optimization.
 
        <b>POSTFIX_INSTALL_OPTS=</b><i>-option...</i>
-              Specifies options for the postfix-install command, separated  by
-              whitespace.    Currently,   the   only   supported   option   is
+              Specifies  options for the postfix-install command, separated by
+              whitespace.   Currently,   the   only   supported   option    is
               <b>-keep-build-mtime</b>.
 
        <b>SHLIB_CFLAGS=</b><i>flags</i>
-              Override the compiler flags  (typically,  "-fPIC")  for  Postfix
+              Override  the  compiler  flags  (typically, "-fPIC") for Postfix
               dynamically-linked libraries and database plugins.
 
               This feature was introduced with Postfix 3.0.
 
        <b>SHLIB_RPATH=</b><i>rpath</i>
-              Override  the  runpath  (typically, "'-Wl,-rpath,${SHLIB_DIR}'")
+              Override the  runpath  (typically,  "'-Wl,-rpath,${SHLIB_DIR}'")
               for Postfix dynamically-linked libraries.
 
               This feature was introduced with Postfix 3.0.
 
        <b>SHLIB_SUFFIX=</b><i>suffix</i>
-              Override the filename  suffix  (typically,  ".so")  for  Postfix
+              Override  the  filename  suffix  (typically,  ".so") for Postfix
               dynamically-linked libraries and database plugins.
 
               This feature was introduced with Postfix 3.0.
@@ -165,7 +168,7 @@ MAKEDEFS(1)                                                        MAKEDEFS(1)
        <b>shared=yes</b>
 
        <b>shared=no</b>
-              Enable   (disable)   Postfix   builds   with  dynamically-linked
+              Enable  (disable)   Postfix   builds   with   dynamically-linked
               libraries typically named $<a href="postconf.5.html#shlib_directory">shlib_directory</a>/libpostfix-*.so.*.
 
               This feature was introduced with Postfix 3.0.
@@ -173,39 +176,39 @@ MAKEDEFS(1)                                                        MAKEDEFS(1)
        <b>dynamicmaps=yes</b>
 
        <b>dynamicmaps=no</b>
-              Enable (disable) Postfix  builds  with  the  configuration  file
+              Enable  (disable)  Postfix  builds  with  the configuration file
               $<a href="postconf.5.html#meta_directory">meta_directory</a>/dynamicmaps.cf and dynamically-loadable database
-              plugins typically named  postfix-*.so.*.   The  setting  "dynam-
-              icmaps=yes"   implicitly   enables   Postfix  dynamically-linked
+              plugins  typically  named  postfix-*.so.*.   The setting "dynam-
+              icmaps=yes"  implicitly   enables   Postfix   dynamically-linked
               libraries.
 
               This feature was introduced with Postfix 3.0.
 
        <b>pie=yes</b>
 
-       <b>pie=no</b> Enable (disable) Postfix builds with  position-independent  exe-
+       <b>pie=no</b> Enable  (disable)  Postfix builds with position-independent exe-
               cutables, on platforms where this is supported.
 
               This feature was introduced with Postfix 3.0.
 
        <i>installation</i><b>_</b><i>parameter</i><b>=</b><i>value</i>...
-              Override  the compiled-in default value of the specified instal-
-              lation parameter(s). The following parameters are  supported  in
+              Override the compiled-in default value of the specified  instal-
+              lation  parameter(s).  The following parameters are supported in
               this context:
 
-              <a href="postconf.5.html#command_directory">command_directory</a>  <a href="postconf.5.html#config_directory">config_directory</a> <a href="postconf.5.html#daemon_directory">daemon_directory</a> <a href="postconf.5.html#data_directory">data_direc</a>-
-              <a href="postconf.5.html#data_directory">tory</a> <a href="postconf.5.html#default_cache_db_type">default_cache_db_type</a> <a href="postconf.5.html#default_database_type">default_database_type</a>  <a href="postconf.5.html#html_directory">html_directory</a>
+              <a href="postconf.5.html#command_directory">command_directory</a> <a href="postconf.5.html#config_directory">config_directory</a> <a href="postconf.5.html#daemon_directory">daemon_directory</a>  <a href="postconf.5.html#data_directory">data_direc</a>-
+              <a href="postconf.5.html#data_directory">tory</a>  <a href="postconf.5.html#default_cache_db_type">default_cache_db_type</a> <a href="postconf.5.html#default_database_type">default_database_type</a> <a href="postconf.5.html#html_directory">html_directory</a>
               <a href="postconf.5.html#mail_spool_directory">mail_spool_directory</a> <a href="postconf.5.html#mailq_path">mailq_path</a> <a href="postconf.5.html#manpage_directory">manpage_directory</a> <a href="postconf.5.html#meta_directory">meta_directory</a>
-              <a href="postconf.5.html#newaliases_path">newaliases_path</a> <a href="postconf.5.html#queue_directory">queue_directory</a>  <a href="postconf.5.html#readme_directory">readme_directory</a>  <a href="postconf.5.html#sendmail_path">sendmail_path</a>
+              <a href="postconf.5.html#newaliases_path">newaliases_path</a>  <a href="postconf.5.html#queue_directory">queue_directory</a>  <a href="postconf.5.html#readme_directory">readme_directory</a> <a href="postconf.5.html#sendmail_path">sendmail_path</a>
               <a href="postconf.5.html#shlib_directory">shlib_directory</a> <a href="postconf.5.html#openssl_path">openssl_path</a>
 
-              See  the  <a href="postconf.5.html">postconf(5)</a> manpage for a description of these parame-
+              See the <a href="postconf.5.html">postconf(5)</a> manpage for a description of  these  parame-
               ters.
 
               This feature was introduced with Postfix 3.0.
 
        <b>WARN=</b><i>warning</i><b>_</b><i>flags</i>
-              Specifies non-default gcc compiler warning options for use  when
+              Specifies  non-default gcc compiler warning options for use when
               "make" is invoked in a source subdirectory only.
 
 <b><a name="license">LICENSE</a></b>
index 7631a7cbc4f477ed475645295204e87171694604..c71d032601fc87cddfd783d21c583a2a1cf4e33a 100644 (file)
@@ -6130,6 +6130,16 @@ configuration parameter.  See there for details. </p>
 <p> This feature is available in Postfix 2.3 and later. </p>
 
 
+</DD>
+
+<DT><b><a name="lmtp_tls_trace_size_limit">lmtp_tls_trace_size_limit</a>
+(default: 102400)</b></DT><DD>
+
+<p> The <a href="lmtp.8.html">lmtp(8)</a> equivalent of <a href="postconf.5.html#smtp_tls_trace_size_limit">smtp_tls_trace_size_limit</a>. </p>
+
+<p> This feature is available in Postfix 3.12 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="lmtp_tls_trust_anchor_file">lmtp_tls_trust_anchor_file</a>
@@ -9912,6 +9922,18 @@ for details. </p>
 <p> This feature is available in Postfix 2.8 and later. </p>
 
 
+</DD>
+
+<DT><b><a name="postscreen_tls_trace_size_limit">postscreen_tls_trace_size_limit</a>
+(default: $<a href="postconf.5.html#smtpd_tls_trace_size_limit">smtpd_tls_trace_size_limit</a>)</b></DT><DD>
+
+<p> The <a href="postscreen.8.html">postscreen(8)</a> equivalent of <a href="postconf.5.html#smtpd_tls_trace_size_limit">smtpd_tls_trace_size_limit</a>.
+<a href="postscreen.8.html">postscreen(8)</a> generates the trace via <a href="tlsproxy.8.html">tlsproxy(8)</a>; the trace file
+name starts with "tlsproxy-".  </p>
+
+<p> This feature is available in Postfix 3.12 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="postscreen_upstream_proxy_protocol">postscreen_upstream_proxy_protocol</a>
@@ -15005,6 +15027,19 @@ transmission after STARTTLS. </dd>
 <p> Do not use "<a href="postconf.5.html#smtp_tls_loglevel">smtp_tls_loglevel</a> = 2" or higher except in case of
 problems. Use of loglevel 4 is strongly discouraged. </p>
 
+<p> With Postfix 3.12 and later, any of the levels above may be
+followed by ",trace" (for example "<a href="postconf.5.html#smtp_tls_loglevel">smtp_tls_loglevel</a> = 1,trace").
+The "trace" keyword writes a protocol message trace (this does not
+include the <b>content</b> of application data messages) of the TLS
+session to a per-connection file under $<a href="postconf.5.html#queue_directory">queue_directory</a>/tlstrace/,
+capped at <a href="postconf.5.html#smtp_tls_trace_size_limit">smtp_tls_trace_size_limit</a> bytes per file.  The path is
+written to the system log at the start of each trace.  The "trace"
+keyword is intended for occasional use via <a href="postconf.5.html#smtp_tls_loglevel_maps">smtp_tls_loglevel_maps</a>
+for a specific peer; setting it globally will produce a trace file
+for every TLS session.  Old trace files are not removed
+automatically; operators who enable the feature should arrange
+periodic cleanup (find(1), logrotate(8), or similar).  </p>
+
 <p> This feature is available in Postfix 2.2 and later.  </p>
 
 
@@ -16029,6 +16064,23 @@ The default time unit is s (seconds).  </p>
 <p> This feature is available in Postfix 2.2 and later.  </p>
 
 
+</DD>
+
+<DT><b><a name="smtp_tls_trace_size_limit">smtp_tls_trace_size_limit</a>
+(default: 102400)</b></DT><DD>
+
+<p> Size limit, in bytes, for the TLS protocol transcript that the
+Postfix SMTP client writes when the "trace" keyword is included in
+the TLS loglevel for a peer (<a href="postconf.5.html#smtp_tls_loglevel">smtp_tls_loglevel</a> or
+<a href="postconf.5.html#smtp_tls_loglevel_maps">smtp_tls_loglevel_maps</a>).  The transcript is written to a per-
+connection file under $<a href="postconf.5.html#queue_directory">queue_directory</a>/tlstrace/, named
+smtp-pid-time-peer.txt.  Once the limit is reached the trace is
+truncated with a one-line note.  A value of 0 disables tracing.
+</p>
+
+<p> This feature is available in Postfix 3.12 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="smtp_tls_trust_anchor_file">smtp_tls_trust_anchor_file</a>
@@ -20600,6 +20652,19 @@ transmission after STARTTLS. </dd>
 <p> Do not use "<a href="postconf.5.html#smtpd_tls_loglevel">smtpd_tls_loglevel</a> = 2" or higher except in case
 of problems. Use of loglevel 4 is strongly discouraged. </p>
 
+<p> With Postfix 3.12 and later, any of the levels above may be
+followed by ",trace" (for example "<a href="postconf.5.html#smtpd_tls_loglevel">smtpd_tls_loglevel</a> = 1,trace").
+The "trace" keyword writes a protocol message trace (this does not
+include the <b>content</b> of application data messages) of the TLS
+session to a per-connection file under $<a href="postconf.5.html#queue_directory">queue_directory</a>/tlstrace/,
+capped at <a href="postconf.5.html#smtpd_tls_trace_size_limit">smtpd_tls_trace_size_limit</a> bytes per file.  The path is
+written to the system log at the start of each trace.  The "trace"
+keyword is intended for occasional use via <a href="postconf.5.html#smtpd_tls_loglevel_maps">smtpd_tls_loglevel_maps</a>
+for a specific peer; setting it globally will produce a trace file
+for every TLS session.  Old trace files are not removed
+automatically; operators who enable the feature should arrange
+periodic cleanup (find(1), logrotate(8), or similar).  </p>
+
 <p> This feature is available in Postfix 2.2 and later.  </p>
 
 
@@ -20998,6 +21063,17 @@ The default time unit is s (seconds).  </p>
 for TLS session ticket support in Postfix 2.11. </p>
 
 
+</DD>
+
+<DT><b><a name="smtpd_tls_trace_size_limit">smtpd_tls_trace_size_limit</a>
+(default: 102400)</b></DT><DD>
+
+<p> The Postfix SMTP server equivalent of <a href="postconf.5.html#smtp_tls_trace_size_limit">smtp_tls_trace_size_limit</a>.
+File names start with "smtpd-" instead of "smtp-". </p>
+
+<p> This feature is available in Postfix 3.12 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="smtpd_tls_wrappermode">smtpd_tls_wrappermode</a>
@@ -22451,6 +22527,18 @@ SSL_CTX_set_options(3).</dd>
 <p> This feature is available in Postfix 2.11 and later.  </p>
 
 
+</DD>
+
+<DT><b><a name="tls_trace_rate_limit">tls_trace_rate_limit</a>
+(default: 1)</b></DT><DD>
+
+<p> The maximum number of TLS traces per <a href="postconf.5.html#anvil_rate_time_unit">anvil_rate_time_unit</a> that
+all Postfix daemons combined will create. Specify a value &le;0 to
+disable the limit. </p>
+
+<p> This feature is available in Postfix 3.12 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="tls_trust_server_ccerts">tls_trust_server_ccerts</a>
index 1f603e910daa966b13fcc3af59ea0cc8828a3967..034a7e506271d5d775f1ee23347642b05d2c5177 100644 (file)
@@ -459,6 +459,9 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
               Optional  TLS  loglevel override that depends on the remote peer
               host name or IP address.
 
+       <b><a href="postconf.5.html#postscreen_tls_trace_size_limit">postscreen_tls_trace_size_limit</a> ($<a href="postconf.5.html#smtpd_tls_trace_size_limit">smtpd_tls_trace_size_limit</a>)</b>
+              The <a href="postscreen.8.html"><b>postscreen</b>(8)</a> equivalent of <a href="postconf.5.html#smtpd_tls_trace_size_limit">smtpd_tls_trace_size_limit</a>.
+
        <b><a href="postconf.5.html#postscreen_tls_mandatory_ciphers">postscreen_tls_mandatory_ciphers</a> ($<a href="postconf.5.html#smtpd_tls_mandatory_ciphers">smtpd_tls_mandatory_ciphers</a>)</b>
               The <a href="postscreen.8.html"><b>postscreen</b>(8)</a> equivalent of <a href="postconf.5.html#smtpd_tls_mandatory_ciphers">smtpd_tls_mandatory_ciphers</a>.
 
@@ -476,12 +479,16 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
        <b><a href="postconf.5.html#postscreen_tls_req_ccert">postscreen_tls_req_ccert</a> ($<a href="postconf.5.html#smtpd_tls_req_ccert">smtpd_tls_req_ccert</a>)</b>
               The <a href="postscreen.8.html"><b>postscreen</b>(8)</a> equivalent of <a href="postconf.5.html#smtpd_tls_req_ccert">smtpd_tls_req_ccert</a>.
 
+       <b><a href="postconf.5.html#tls_trace_rate_limit">tls_trace_rate_limit</a> (1)</b>
+              The  maximum  number of TLS traces per <a href="postconf.5.html#anvil_rate_time_unit">anvil_rate_time_unit</a> that
+              all Postfix daemons combined will create.
+
 <b><a name="obsolete_starttls_support_controls">OBSOLETE STARTTLS SUPPORT CONTROLS</a></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#postscreen_use_tls">postscreen_use_tls</a> ($<a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a>)</b>
-              Opportunistic TLS: announce  STARTTLS  support  to  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#postscreen_enforce_tls">postscreen_enforce_tls</a> ($<a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a>)</b>
@@ -490,18 +497,18 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
 
 <b><a name="miscellaneous_controls">MISCELLANEOUS CONTROLS</a></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#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
-              The  maximal  number of digits after the decimal point when log-
+              The maximal number of digits after the decimal point  when  log-
               ging delay values.
 
        <b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
               The location of all postfix administrative commands.
 
        <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
-              The maximum amount of time that an idle Postfix  daemon  process
+              The  maximum  amount of time that an idle Postfix daemon process
               waits for an incoming connection before terminating voluntarily.
 
        <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
@@ -514,7 +521,7 @@ POSTSCREEN(8)                                                    POSTSCREEN(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:
@@ -525,7 +532,7 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
        Available in Postfix 3.5 and later:
 
        <b><a href="postconf.5.html#info_log_address_format">info_log_address_format</a> (external)</b>
-              The  email  address  form that will be used in non-debug logging
+              The email address form that will be used  in  non-debug  logging
               (info, warning, etc.).
 
 <b><a name="see_also">SEE ALSO</a></b>
@@ -544,7 +551,7 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
 <b><a name="history">HISTORY</a></b>
        This service was introduced with Postfix version 2.8.
 
-       Many  ideas  in  <a href="postscreen.8.html"><b>postscreen</b>(8)</a> were explored in earlier work by Michael
+       Many ideas in <a href="postscreen.8.html"><b>postscreen</b>(8)</a> were explored in earlier  work  by  Michael
        Tokarev, in OpenBSD spamd, and in MailChannels Traffic Control.
 
 <b>AUTHOR(S)</b>
index d52b306fb1cfe10e37d864d930c8b03b44cfc3b3..5c27d704f11c219b115f65e3baeaa62615997221 100644 (file)
@@ -20,7 +20,7 @@ POSTTLS-FINGER(1)                                            POSTTLS-FINGER(1)
        a  domainname;  with LMTP it is either a domainname prefixed with <b>inet:</b>
        or a pathname prefixed with <b>unix:</b>.  If Postfix  is  built  without  TLS
        support, the resulting <a href="posttls-finger.1.html"><b>posttls-finger</b>(1)</a> program has very limited func-
-       tionality, and only the <b>-a</b>, <b>-c</b>, <b>-h</b>, <b>-o</b>, <b>-S</b>, <b>-t</b>, <b>-T</b> and <b>-v</b>  options  are
+       tionality, and only the <b>-a</b>, <b>-c</b>, <b>-h</b>, <b>-S</b>,  <b>-t</b>,  <b>-T</b>  and  <b>-v</b>  options  are
        available.
 
        Note:  this is an unsupported test program. No attempt is made to main-
@@ -206,85 +206,98 @@ POSTTLS-FINGER(1)                                            POSTTLS-FINGER(1)
                      only  useful to those who can debug SSL protocol problems
                      from hex dumps.
 
+              <b>trace</b>  Available  with  Postfix  3.12   and   later.   Write   a
+                     human-readable  protocol transcript of the TLS session to
+                     a file in  the  current  directory.  The  file  is  named
+                     <i>process</i><b>_</b><i>name</i>-<i>date</i><b>_</b><i>time</i>.<i>usec</i>-<i>peer</i>-<i>XXXXXX</i>,  where <i>XXXXXX</i> is
+                     replaced with a unique  string  to  avoid  filename  con-
+                     flicts.  All  reconnect attempts in a single command-line
+                     run share the same trace file, separated  by  "===  post-
+                     tls-finger  reconnect  ==="  lines. When <b>-X</b> is in effect,
+                     <a href="tlsproxy.8.html">tlsproxy(8)</a> generates the trace file under  <i>$queue</i><b>_</b><i>direc-</i>
+                     <i>tory</i>/tlstrace/  instead.  The  keyword  is ignored with a
+                     warning if Postfix or OpenSSL was built without TLS trace
+                     support.
+
               <b>untrusted</b>
-                     Logs trust chain verification problems.  This  is  turned
-                     on  automatically  at security levels that use peer names
-                     signed by Certification Authorities to validate  certifi-
-                     cates.   So  while this setting is recognized, you should
+                     Logs  trust  chain verification problems.  This is turned
+                     on automatically at security levels that use  peer  names
+                     signed  by Certification Authorities to validate certifi-
+                     cates.  So while this setting is recognized,  you  should
                      never need to set it explicitly.
 
               <b>peercert</b>
-                     This logs a one line summary of the  remote  SMTP  server
+                     This  logs  a  one line summary of the remote SMTP server
                      certificate subject, issuer, and fingerprints.
 
               <b>certmatch</b>
-                     This  logs remote SMTP server certificate matching, show-
+                     This logs remote SMTP server certificate matching,  show-
                      ing  the  CN  and  each  subjectAltName  and  which  name
-                     matched.    With  DANE,  logs  matching  of  TLSA  record
+                     matched.   With  DANE,  logs  matching  of  TLSA   record
                      trust-anchor and end-entity certificates.
 
-              <b>cache</b>  This logs session cache operations, showing whether  ses-
-                     sion  caching  is  effective with the remote SMTP server.
-                     Automatically used when reconnecting with the <b>-r</b>  option;
+              <b>cache</b>  This  logs session cache operations, showing whether ses-
+                     sion caching is effective with the  remote  SMTP  server.
+                     Automatically  used when reconnecting with the <b>-r</b> option;
                      rarely needs to be set explicitly.
 
               <b>verbose</b>
                      Enables  verbose  logging  in  the  Postfix  TLS  driver;
                      includes all of peercert..cache and more.
 
-              The default is <b>routine,certmatch</b>. After a  reconnect,  <b>peercert</b>,
+              The  default  is <b>routine,certmatch</b>. After a reconnect, <b>peercert</b>,
               <b>certmatch</b> and <b>verbose</b> are automatically disabled while <b>cache</b> and
               <b>summary</b> are enabled.
 
        <b>-m</b> <i>count</i> (default: <b>5</b>)
-              When the <b>-r</b> <i>delay</i> option is specified, the <b>-m</b> option  determines
-              the  maximum  number  of reconnect attempts to use with a server
-              behind a load balancer, to see  whether  connection  caching  is
-              likely  to  be  effective for this destination.  Some MTAs don't
-              expose the underlying server identity in  their  EHLO  response;
-              with  these servers there will never be more than 1 reconnection
+              When  the <b>-r</b> <i>delay</i> option is specified, the <b>-m</b> option determines
+              the maximum number of reconnect attempts to use  with  a  server
+              behind  a  load  balancer,  to see whether connection caching is
+              likely to be effective for this destination.   Some  MTAs  don't
+              expose  the  underlying  server identity in their EHLO response;
+              with these servers there will never be more than 1  reconnection
               attempt.
 
        <b>-M</b> <i>insecure</i><b>_</b><i>mx</i><b>_</b><i>policy</i> (default: <b>dane</b>)
-              The TLS policy for MX hosts with "secure" TLSA records when  the
-              nexthop  destination  security  level is <b>dane</b>, but the MX record
+              The  TLS policy for MX hosts with "secure" TLSA records when the
+              nexthop destination security level is <b>dane</b>, but  the  MX  record
               was found via an "insecure" MX lookup.  See the <a href="postconf.5.html">main.cf</a> documen-
               tation for <a href="postconf.5.html#smtp_tls_dane_insecure_mx_policy">smtp_tls_dane_insecure_mx_policy</a> for details.
 
        <b>-o</b> <i>name=value</i>
-              Specify  zero or more times to override the value of the <a href="postconf.5.html">main.cf</a>
-              parameter <i>name</i> with <i>value</i>.  Possible use-cases include  overrid-
-              ing  the  values  of  TLS library parameters, or "<a href="postconf.5.html#myhostname">myhostname</a>" to
+              Specify zero or more times to override the value of the  <a href="postconf.5.html">main.cf</a>
+              parameter  <i>name</i> with <i>value</i>.  Possible use-cases include overrid-
+              ing the values of TLS library  parameters,  or  "<a href="postconf.5.html#myhostname">myhostname</a>"  to
               configure the SMTP EHLO name sent to the remote server.
 
        <b>-p</b> <i>protocols</i> (default: &gt;=TLSv1)
-              TLS protocols that <a href="posttls-finger.1.html"><b>posttls-finger</b>(1)</a> will  exclude  or  include.
+              TLS  protocols  that  <a href="posttls-finger.1.html"><b>posttls-finger</b>(1)</a> will exclude or include.
               See <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> for details.
 
        <b>-P</b> <i>CApath/</i> (default: none)
-              The  OpenSSL  CApath/  directory  (indexed  via c_rehash(1)) for
+              The OpenSSL CApath/  directory  (indexed  via  c_rehash(1))  for
               remote SMTP server certificate verification.  By default no CAp-
               ath is used and no public CAs are trusted.
 
        <b>-r</b> <i>delay</i>
-              With  a  cacheable  TLS  session, disconnect and reconnect after
+              With a cacheable TLS session,  disconnect  and  reconnect  after
               <i>delay</i> seconds. Report whether the session is re-used. Retry if a
-              new  server  is  encountered, up to 5 times or as specified with
-              the <b>-m</b> option.  By default reconnection is disabled,  specify  a
+              new server is encountered, up to 5 times or  as  specified  with
+              the  <b>-m</b>  option.  By default reconnection is disabled, specify a
               positive delay to enable this behavior.
 
        <b>-R</b>     Use SRV lookup instead of MX.
 
        <b>-s</b> <i>servername</i>
-              The  server  name  to  send  with the TLS Server Name Indication
-              (SNI) extension.  When the server has DANE  TLSA  records,  this
-              parameter  is  ignored and the TLSA base domain is used instead.
-              Otherwise, SNI is not used by default, but  can  be  enabled  by
+              The server name to send with  the  TLS  Server  Name  Indication
+              (SNI)  extension.   When  the server has DANE TLSA records, this
+              parameter is ignored and the TLSA base domain is  used  instead.
+              Otherwise,  SNI  is  not  used by default, but can be enabled by
               specifying the desired value with this option.
 
-       <b>-S</b>     Disable  SMTP;  that  is, connect to an LMTP server. The default
-              port for LMTP over TCP is 24.  Alternative ports  can  specified
-              by  appending "<i>:servicename</i>" or ":<i>portnumber</i>" to the destination
+       <b>-S</b>     Disable SMTP; that is, connect to an LMTP  server.  The  default
+              port  for  LMTP over TCP is 24.  Alternative ports can specified
+              by appending "<i>:servicename</i>" or ":<i>portnumber</i>" to the  destination
               argument.
 
        <b>-t</b> <i>timeout</i> (default: <b>30</b>)
@@ -292,41 +305,41 @@ POSTTLS-FINGER(1)                                            POSTTLS-FINGER(1)
               reading the remote server's 220 banner.
 
        <b>-T</b> <i>timeout</i> (default: <b>30</b>)
-              The  SMTP/LMTP command timeout for EHLO/LHLO, STARTTLS and QUIT.
+              The SMTP/LMTP command timeout for EHLO/LHLO, STARTTLS and  QUIT.
 
-       <b>-v</b>     Enable verbose Postfix  logging.   Specify  more  than  once  to
+       <b>-v</b>     Enable  verbose  Postfix  logging.   Specify  more  than once to
               increase the level of verbose logging.
 
-       <b>-w</b>     Enable  outgoing TLS wrapper mode, or SUBMISSIONS/SMTPS support.
-              This is typically provided on port 465 by servers that are  com-
-              patible  with the SMTP-in-SSL protocol, rather than the STARTTLS
-              protocol.  The destination <i>domain</i>:<i>port</i> must  of  course  provide
+       <b>-w</b>     Enable outgoing TLS wrapper mode, or SUBMISSIONS/SMTPS  support.
+              This  is typically provided on port 465 by servers that are com-
+              patible with the SMTP-in-SSL protocol, rather than the  STARTTLS
+              protocol.   The  destination  <i>domain</i>:<i>port</i> must of course provide
               such a service.
 
-       <b>-x</b>     Prefer  <a href="https://tools.ietf.org/html/rfc7250">RFC7250</a>  non-X.509  raw  public key (RPK) server creden-
-              tials.  By default only X.509 certificates are  accepted.   This
+       <b>-x</b>     Prefer <a href="https://tools.ietf.org/html/rfc7250">RFC7250</a> non-X.509 raw public  key  (RPK)  server  creden-
+              tials.   By  default only X.509 certificates are accepted.  This
               is analogous to setting <b><a href="postconf.5.html#smtp_tls_enable_rpk">smtp_tls_enable_rpk</a> = yes</b> in the <a href="smtp.8.html">smtp(8)</a>
               client.  At the fingerprint security level, when raw public keys
-              are  enabled, only public key (and not certificate) fingerprints
-              will be compared against the specified list of <i>match</i>  arguments.
-              Certificate  fingerprints  are  fragile when raw public keys are
-              solicited, the server may at some point in time start  returning
+              are enabled, only public key (and not certificate)  fingerprints
+              will  be compared against the specified list of <i>match</i> arguments.
+              Certificate fingerprints are fragile when raw  public  keys  are
+              solicited,  the server may at some point in time start returning
               only the public key.
 
-       <b>-X</b>     Enable  <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a>  mode. This is an unsupported mode, for pro-
+       <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  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-
+              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-
               able via <b>native</b> lookups).
 
        <b>unix:</b><i>pathname</i>
@@ -335,8 +348,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>
index 04e8ed84aae63c15af79c935853bcf461d545c25..97be3c227b2e15317a4b999a8f4d3d7dda05d3fc 100644 (file)
@@ -794,6 +794,16 @@ SMTP(8)                                                                SMTP(8)
               Optional TLS loglevel override that depends on the  remote  peer
               host name or IP address.
 
+       <b><a href="postconf.5.html#smtp_tls_trace_size_limit">smtp_tls_trace_size_limit</a> (102400)</b>
+              Size  limit,  in bytes, for the TLS protocol transcript that the
+              Postfix SMTP client writes when the "trace" keyword is  included
+              in   the   TLS   loglevel   for  a  peer  (<a href="postconf.5.html#smtp_tls_loglevel">smtp_tls_loglevel</a>  or
+              <a href="postconf.5.html#smtp_tls_loglevel_maps">smtp_tls_loglevel_maps</a>).
+
+       <b><a href="postconf.5.html#tls_trace_rate_limit">tls_trace_rate_limit</a> (1)</b>
+              The maximum number of TLS traces per  <a href="postconf.5.html#anvil_rate_time_unit">anvil_rate_time_unit</a>  that
+              all Postfix daemons combined will create.
+
 <b><a name="obsolete_tls_controls">OBSOLETE TLS CONTROLS</a></b>
        The  following  configuration  parameters  exist for compatibility with
        Postfix versions before 2.3. Support for these will  be  removed  in  a
index 75800d0e9e6a34052ba9a90b85e2dcd474ff45f9..34d70a154e6663ea9ff1f9564c20e2aa486da590 100644 (file)
@@ -678,6 +678,13 @@ SMTPD(8)                                                              SMTPD(8)
               Optional  TLS  loglevel override that depends on the remote peer
               host name or IP address.
 
+       <b><a href="postconf.5.html#smtpd_tls_trace_size_limit">smtpd_tls_trace_size_limit</a> (102400)</b>
+              The Postfix SMTP server equivalent of <a href="postconf.5.html#smtp_tls_trace_size_limit">smtp_tls_trace_size_limit</a>.
+
+       <b><a href="postconf.5.html#tls_trace_rate_limit">tls_trace_rate_limit</a> (1)</b>
+              The  maximum  number of TLS traces per <a href="postconf.5.html#anvil_rate_time_unit">anvil_rate_time_unit</a> that
+              all Postfix daemons combined will create.
+
 <b><a name="obsolete_tls_controls">OBSOLETE TLS CONTROLS</a></b>
        The following configuration parameters  exist  for  compatibility  with
        Postfix  versions  before  2.3.  Support for these will be removed in a
index d21749a23f0662eb44366a7caf6968bf1743cb13..2ec81ccc41de44c4d73f90bcb57107b200991e4e 100644 (file)
 #      uses snprintf() except on ancient systems.
 # .IP \fB-DNO_STDBOOL\fR
 #      Don't use <stdbool.h>. This is usually auto-detected.
+# .IP \fB-DNO_TLS_TRACE\fR
+#      Build without OpenSSL 3 (and later) debug trace support.
 # .RE
 # .IP \fBDEBUG=\fIdebug_level\fR
 #      Specifies a non-default debugging level. The default is \fB-g\fR.
@@ -885,7 +887,7 @@ CCARGS="$CCARGS -DSNAPSHOT"
 
 # Non-production: needs thorough testing, or major changes are still
 # needed before the code stabilizes.
-#CCARGS="$CCARGS -DNONPROD"
+#CCARGS="$CCARGS -DNONPROD='\"featurename-nonprod\"'"
 
 # Workaround: prepend Postfix include files before other include files.
 CCARGS="-I. -I../../include $CCARGS"
index d479e80a515d8590cfad50cea33f475a17f095ea..15e8a0b6fe069f237bdd2531baa6c5d0f1d12a45 100644 (file)
@@ -112,6 +112,8 @@ Use sprintf() instead of snprintf(). By default, Postfix
 uses snprintf() except on ancient systems.
 .IP \fB\-DNO_STDBOOL\fR
 Don't use <stdbool.h>. This is usually auto\-detected.
+.IP \fB\-DNO_TLS_TRACE\fR
+Build without OpenSSL 3 (and later) debug trace support.
 .RE
 .IP \fBDEBUG=\fIdebug_level\fR
 Specifies a non\-default debugging level. The default is \fB\-g\fR.
index ee8bd8a685db2665a9ef94994ec85607ee6da5f9..66cb9ea32596cc7ca5d9608ba63898895d1f1675 100644 (file)
@@ -20,7 +20,7 @@ destination is a domainname; with LMTP it is either a domainname
 prefixed with \fBinet:\fR or a pathname prefixed with \fBunix:\fR.  If
 Postfix is built without TLS support, the resulting \fBposttls\-finger\fR(1)
 program has very limited functionality, and only the \fB\-a\fR, \fB\-c\fR,
-\fB\-h\fR, \fB\-o\fR, \fB\-S\fR, \fB\-t\fR, \fB\-T\fR and \fB\-v\fR options
+\fB\-h\fR, \fB\-S\fR, \fB\-t\fR, \fB\-T\fR and \fB\-v\fR options
 are available.
 
 Note: this is an unsupported test program. No attempt is made
@@ -187,6 +187,19 @@ Log hexadecimal packet dumps of the SSL handshake; for experts only.
 .IP "\fBssl\-session\-packet\-dump\fR"
 Log hexadecimal packet dumps of the entire SSL session; only useful
 to those who can debug SSL protocol problems from hex dumps.
+.IP "\fBtrace\fR"
+Available with Postfix 3.12 and later. Write a human\-readable
+protocol transcript of the TLS session to a file in the current
+directory. The file is named
+\fIprocess_name\fR\-\fIdate_time\fR.\fIusec\fR\-\fIpeer\fR\-\fIXXXXXX\fR,
+where \fIXXXXXX\fR is replaced with a unique string to avoid
+filename conflicts. All reconnect attempts in a single
+command\-line run share the same trace file, separated by "===
+posttls\-finger reconnect ===" lines. When \fB\-X\fR is in effect,
+tlsproxy(8) generates the trace file under
+\fI$queue_directory\fR/tlstrace/ instead. The keyword is
+ignored with a warning if Postfix or OpenSSL was built without
+TLS trace support.
 .IP "\fBuntrusted\fR"
 Logs trust chain verification problems.  This is turned on
 automatically at security levels that use peer names signed
index fc5997b1922102b257a4888d8078b491a0563315..a5a7a28a4a41e5c64e68e7cf69bcbfaf760bd431 100644 (file)
@@ -3702,6 +3702,10 @@ The LMTP\-specific version of the smtp_tls_session_cache_timeout
 configuration parameter.  See there for details.
 .PP
 This feature is available in Postfix 2.3 and later.
+.SH lmtp_tls_trace_size_limit (default: 102400)
+The \fBlmtp\fR(8) equivalent of smtp_tls_trace_size_limit.
+.PP
+This feature is available in Postfix 3.12 and later.
 .SH lmtp_tls_trust_anchor_file (default: empty)
 The LMTP\-specific version of the smtp_tls_trust_anchor_file
 configuration parameter.  See there for details.
@@ -6143,6 +6147,12 @@ postscreen_use_tls and postscreen_enforce_tls. See smtpd_tls_security_level
 for details.
 .PP
 This feature is available in Postfix 2.8 and later.
+.SH postscreen_tls_trace_size_limit (default: $smtpd_tls_trace_size_limit)
+The \fBpostscreen\fR(8) equivalent of smtpd_tls_trace_size_limit.
+\fBpostscreen\fR(8) generates the trace via \fBtlsproxy\fR(8); the trace file
+name starts with "tlsproxy\-".
+.PP
+This feature is available in Postfix 3.12 and later.
 .SH postscreen_upstream_proxy_protocol (default: empty)
 The name of the proxy protocol used by an optional before\-postscreen
 proxy agent. When a proxy agent is used, this protocol conveys local
@@ -9894,6 +9904,19 @@ transmission after STARTTLS.
 Do not use "smtp_tls_loglevel = 2" or higher except in case of
 problems. Use of loglevel 4 is strongly discouraged.
 .PP
+With Postfix 3.12 and later, any of the levels above may be
+followed by ",trace" (for example "smtp_tls_loglevel = 1,trace").
+The "trace" keyword writes a protocol message trace (this does not
+include the \fBcontent\fR of application data messages) of the TLS
+session to a per\-connection file under $queue_directory/tlstrace/,
+capped at smtp_tls_trace_size_limit bytes per file.  The path is
+written to the system log at the start of each trace.  The "trace"
+keyword is intended for occasional use via smtp_tls_loglevel_maps
+for a specific peer; setting it globally will produce a trace file
+for every TLS session.  Old trace files are not removed
+automatically; operators who enable the feature should arrange
+periodic cleanup (\fBfind\fR(1), \fBlogrotate\fR(8), or similar).
+.PP
 This feature is available in Postfix 2.2 and later.
 .SH smtp_tls_loglevel_maps (default: empty)
 Optional TLS loglevel override that depends on the remote peer
@@ -10833,6 +10856,16 @@ one\-letter suffix that specifies the time unit).  Time units: s
 The default time unit is s (seconds).
 .PP
 This feature is available in Postfix 2.2 and later.
+.SH smtp_tls_trace_size_limit (default: 102400)
+Size limit, in bytes, for the TLS protocol transcript that the
+Postfix SMTP client writes when the "trace" keyword is included in
+the TLS loglevel for a peer (smtp_tls_loglevel or
+smtp_tls_loglevel_maps).  The transcript is written to a per\-
+connection file under $queue_directory/tlstrace/, named
+smtp\-pid\-time\-peer.txt.  Once the limit is reached the trace is
+truncated with a one\-line note.  A value of 0 disables tracing.
+.PP
+This feature is available in Postfix 3.12 and later.
 .SH smtp_tls_trust_anchor_file (default: empty)
 Zero or more PEM\-format files with trust\-anchor certificates
 and/or public keys.  If the parameter is not empty the root CAs in
@@ -14422,6 +14455,19 @@ transmission after STARTTLS.
 Do not use "smtpd_tls_loglevel = 2" or higher except in case
 of problems. Use of loglevel 4 is strongly discouraged.
 .PP
+With Postfix 3.12 and later, any of the levels above may be
+followed by ",trace" (for example "smtpd_tls_loglevel = 1,trace").
+The "trace" keyword writes a protocol message trace (this does not
+include the \fBcontent\fR of application data messages) of the TLS
+session to a per\-connection file under $queue_directory/tlstrace/,
+capped at smtpd_tls_trace_size_limit bytes per file.  The path is
+written to the system log at the start of each trace.  The "trace"
+keyword is intended for occasional use via smtpd_tls_loglevel_maps
+for a specific peer; setting it globally will produce a trace file
+for every TLS session.  Old trace files are not removed
+automatically; operators who enable the feature should arrange
+periodic cleanup (\fBfind\fR(1), \fBlogrotate\fR(8), or similar).
+.PP
 This feature is available in Postfix 2.2 and later.
 .SH smtpd_tls_loglevel_maps (default: empty)
 Optional TLS loglevel override that depends on the remote peer
@@ -14768,6 +14814,11 @@ The default time unit is s (seconds).
 .PP
 This feature is available in Postfix 2.2 and later, and updated
 for TLS session ticket support in Postfix 2.11.
+.SH smtpd_tls_trace_size_limit (default: 102400)
+The Postfix SMTP server equivalent of smtp_tls_trace_size_limit.
+File names start with "smtpd\-" instead of "smtp\-".
+.PP
+This feature is available in Postfix 3.12 and later.
 .SH smtpd_tls_wrappermode (default: no)
 Run the Postfix SMTP server in TLS "wrapper" mode,
 instead of using the STARTTLS command.
@@ -15894,6 +15945,12 @@ Postfix >= 3.4. See \fBSSL_CTX_set_options\fR(3).
 .br
 .PP
 This feature is available in Postfix 2.11 and later.
+.SH tls_trace_rate_limit (default: 1)
+The maximum number of TLS traces per anvil_rate_time_unit that
+all Postfix daemons combined will create. Specify a value <=0 to
+disable the limit.
+.PP
+This feature is available in Postfix 3.12 and later.
 .SH tls_trust_server_ccerts (default: no)
 Whether to trust client certificates whose extended key usage (EKU) lists
 only \fBserverAuth\fR and not \fBclientAuth\fR as valid TLS client
index 89ea9a6c393da4c9c491ac477cdba397def84fa6..a98503b42ac898eaac768e1b95a1b27e6f587398 100644 (file)
@@ -161,6 +161,27 @@ The \fBanvil\fR(8) server answers with the number of auth
 requests per unit time for the (service, client) combination
 specified with \fBident\fR:
 
+.nf
+    \fBstatus=0\fR
+    \fBrate=\fInumber\fR
+.fi
+.SH "TLS TRACE RATE CONTROL"
+.na
+.nf
+.ad
+.fi
+To register a TLS trace event send the following request
+to the \fBanvil\fR(8) server:
+
+.nf
+    \fBrequest=tlstr\fR
+    \fBident=\fIstring\fR
+.fi
+
+The \fBanvil\fR(8) server answers with the number of TLS trace
+requests per unit time for the (service, client) combination
+specified with \fBident\fR:
+
 .nf
     \fBstatus=0\fR
     \fBrate=\fInumber\fR
index 73a338e77a87f739bf831016bd14e6a6862febbb..0adf0c110f2568b76fa63011dd4e0055b91a37a6 100644 (file)
@@ -434,6 +434,8 @@ The \fBpostscreen\fR(8) equivalent of smtpd_tls_loglevel.
 .IP "\fBpostscreen_tls_loglevel_maps ($smtpd_tls_loglevel_maps)\fR"
 Optional TLS loglevel override that depends on the remote peer
 host name or IP address.
+.IP "\fBpostscreen_tls_trace_size_limit ($smtpd_tls_trace_size_limit)\fR"
+The \fBpostscreen\fR(8) equivalent of smtpd_tls_trace_size_limit.
 .IP "\fBpostscreen_tls_mandatory_ciphers ($smtpd_tls_mandatory_ciphers)\fR"
 The \fBpostscreen\fR(8) equivalent of smtpd_tls_mandatory_ciphers.
 .IP "\fBpostscreen_tls_mandatory_exclude_ciphers ($smtpd_tls_mandatory_exclude_ciphers)\fR"
@@ -444,6 +446,9 @@ The \fBpostscreen\fR(8) equivalent of smtpd_tls_mandatory_protocols.
 The \fBpostscreen\fR(8) equivalent of smtpd_tls_protocols.
 .IP "\fBpostscreen_tls_req_ccert ($smtpd_tls_req_ccert)\fR"
 The \fBpostscreen\fR(8) equivalent of smtpd_tls_req_ccert.
+.IP "\fBtls_trace_rate_limit (1)\fR"
+The maximum number of TLS traces per anvil_rate_time_unit that
+all Postfix daemons combined will create.
 .SH "OBSOLETE STARTTLS SUPPORT CONTROLS"
 .na
 .nf
index 11da44d31630973d47e5fcd790d54d04a62ddc9e..e8de6fdb940700b3932712ee59d04074c3d3c7df 100644 (file)
@@ -709,6 +709,14 @@ Available in Postfix version 3.12 and later:
 .IP "\fBsmtp_tls_loglevel_maps (empty)\fR"
 Optional TLS loglevel override that depends on the remote peer
 host name or IP address.
+.IP "\fBsmtp_tls_trace_size_limit (102400)\fR"
+Size limit, in bytes, for the TLS protocol transcript that the
+Postfix SMTP client writes when the "trace" keyword is included in
+the TLS loglevel for a peer (smtp_tls_loglevel or
+smtp_tls_loglevel_maps).
+.IP "\fBtls_trace_rate_limit (1)\fR"
+The maximum number of TLS traces per anvil_rate_time_unit that
+all Postfix daemons combined will create.
 .SH "OBSOLETE TLS CONTROLS"
 .na
 .nf
index f79feab31ea76e2974f3d820f75143c25c9e2e36..03c24b45b29e3c9385c604c92af72b7ed735ec9a 100644 (file)
@@ -596,6 +596,11 @@ Available in Postfix version 3.12 and later:
 .IP "\fBsmtpd_tls_loglevel_maps (empty)\fR"
 Optional TLS loglevel override that depends on the remote peer
 host name or IP address.
+.IP "\fBsmtpd_tls_trace_size_limit (102400)\fR"
+The Postfix SMTP server equivalent of smtp_tls_trace_size_limit.
+.IP "\fBtls_trace_rate_limit (1)\fR"
+The maximum number of TLS traces per anvil_rate_time_unit that
+all Postfix daemons combined will create.
 .SH "OBSOLETE TLS CONTROLS"
 .na
 .nf
index 159e05a125c96f4ef2592bfe1afa152238a62479..064684fa6895366e4d044d8bf03dd720a867e5f3 100755 (executable)
@@ -820,6 +820,12 @@ while (<>) {
     s;\btls_fast_shutdown_enable\b;<a href="postconf.5.html#tls_fast_shutdown_enable">$&</a>;g;
     s;\btls_trust_server_ccerts\b;<a href="postconf.5.html#tls_trust_server_ccerts">$&</a>;g;
 
+    s;\blmtp_tls_trace_size_limit\b;<a href="postconf.5.html#lmtp_tls_trace_size_limit">$&</a>;g;
+    s;\bpostscreen_tls_trace_size_limit\b;<a href="postconf.5.html#postscreen_tls_trace_size_limit">$&</a>;g;
+    s;\bsmtp_tls_trace_size_limit\b;<a href="postconf.5.html#smtp_tls_trace_size_limit">$&</a>;g;
+    s;\bsmtpd_tls_trace_size_limit\b;<a href="postconf.5.html#smtpd_tls_trace_size_limit">$&</a>;g;
+    s;\btls_trace_rate_limit\b;<a href="postconf.5.html#tls_trace_rate_limit">$&</a>;g;
+
     s;\bfrozen_delivered_to\b;<a href="postconf.5.html#frozen_delivered_to">$&</a>;g;
     s;\breset_owner_alias\b;<a href="postconf.5.html#reset_owner_alias">$&</a>;g;
     s;\benable_long_queue_ids\b;<a href="postconf.5.html#enable_long_queue_ids">$&</a>;g;
index 898d5298b43f27b175fe9270b15e62e6ec1139ab..cd61804700e670df3ed9a5688c224e5bef299890 100644 (file)
@@ -891,6 +891,12 @@ they are known to be available. </td> </tr>
 instead of <tt>snprintf()</tt>.  By default, Postfix uses
 <tt>snprintf()</tt> except on ancient systems. </td> </tr>
 
+<tr> <td> </td> <td> -DNO_TLS_TRACE </td> <td> Do not build with support
+for OpenSSL TLS traces.  Some vendor OpenSSL runtime libraries are built
+without support for tracing, and Postfix software built on a system with
+TLS trace support would not work when installed on one without.  See
+<tt>smtp_tls_loglevel</tt> in the postconf(5) manual. </td> </tr>
+
 <tr> <td colspan="2"> DEBUG=debug_level </td> <td> Specifies a
 non-default compiler debugging level. The default is "<tt>-g</tt>".
 Specify DEBUG= to turn off debugging. </td> </tr>
index 77683ff3960f5c0e39e1f0ba5ffec969490e0504..7dfaf484541ad7982893005022b5c620b18bd6ba 100644 (file)
@@ -10102,6 +10102,19 @@ transmission after STARTTLS. </dd>
 <p> Do not use "smtpd_tls_loglevel = 2" or higher except in case
 of problems. Use of loglevel 4 is strongly discouraged. </p>
 
+<p> With Postfix 3.12 and later, any of the levels above may be
+followed by ",trace" (for example "smtpd_tls_loglevel = 1,trace").
+The "trace" keyword writes a protocol message trace (this does not
+include the <b>content</b> of application data messages) of the TLS
+session to a per-connection file under $queue_directory/tlstrace/,
+capped at smtpd_tls_trace_size_limit bytes per file.  The path is
+written to the system log at the start of each trace.  The "trace"
+keyword is intended for occasional use via smtpd_tls_loglevel_maps
+for a specific peer; setting it globally will produce a trace file
+for every TLS session.  Old trace files are not removed
+automatically; operators who enable the feature should arrange
+periodic cleanup (find(1), logrotate(8), or similar).  </p>
+
 <p> This feature is available in Postfix 2.2 and later.  </p>
 
 %PARAM smtpd_tls_received_header no
@@ -10610,6 +10623,19 @@ transmission after STARTTLS. </dd>
 <p> Do not use "smtp_tls_loglevel = 2" or higher except in case of
 problems. Use of loglevel 4 is strongly discouraged. </p>
 
+<p> With Postfix 3.12 and later, any of the levels above may be
+followed by ",trace" (for example "smtp_tls_loglevel = 1,trace").
+The "trace" keyword writes a protocol message trace (this does not
+include the <b>content</b> of application data messages) of the TLS
+session to a per-connection file under $queue_directory/tlstrace/,
+capped at smtp_tls_trace_size_limit bytes per file.  The path is
+written to the system log at the start of each trace.  The "trace"
+keyword is intended for occasional use via smtp_tls_loglevel_maps
+for a specific peer; setting it globally will produce a trace file
+for every TLS session.  Old trace files are not removed
+automatically; operators who enable the feature should arrange
+periodic cleanup (find(1), logrotate(8), or similar).  </p>
+
 <p> This feature is available in Postfix 2.2 and later.  </p>
 
 %PARAM smtp_tls_session_cache_database
@@ -20956,3 +20982,45 @@ until a match is found or until all subnetworks have been tried.
 <p> The lmtp(8) equivalent of smtp_tls_loglevel_maps. </p>
 
 <p> This feature is available in Postfix 3.12 and later. </p>
+
+%PARAM smtp_tls_trace_size_limit 102400
+
+<p> Size limit, in bytes, for the TLS protocol transcript that the
+Postfix SMTP client writes when the "trace" keyword is included in
+the TLS loglevel for a peer (smtp_tls_loglevel or
+smtp_tls_loglevel_maps).  The transcript is written to a per-
+connection file under $queue_directory/tlstrace/, named
+smtp-pid-time-peer.txt.  Once the limit is reached the trace is
+truncated with a one-line note.  A value of 0 disables tracing.
+</p>
+
+<p> This feature is available in Postfix 3.12 and later. </p>
+
+%PARAM lmtp_tls_trace_size_limit 102400
+
+<p> The lmtp(8) equivalent of smtp_tls_trace_size_limit. </p>
+
+<p> This feature is available in Postfix 3.12 and later. </p>
+
+%PARAM smtpd_tls_trace_size_limit 102400
+
+<p> The Postfix SMTP server equivalent of smtp_tls_trace_size_limit.
+File names start with "smtpd-" instead of "smtp-". </p>
+
+<p> This feature is available in Postfix 3.12 and later. </p>
+
+%PARAM postscreen_tls_trace_size_limit $smtpd_tls_trace_size_limit
+
+<p> The postscreen(8) equivalent of smtpd_tls_trace_size_limit.
+postscreen(8) generates the trace via tlsproxy(8); the trace file
+name starts with "tlsproxy-".  </p>
+
+<p> This feature is available in Postfix 3.12 and later. </p>
+
+%PARAM tls_trace_rate_limit 1
+
+<p> The maximum number of TLS traces per anvil_rate_time_unit that
+all Postfix daemons combined will create. Specify a value &le;0 to
+disable the limit. </p>
+
+<p> This feature is available in Postfix 3.12 and later. </p>
index f1ed8411cd3c31e70d48494b532b9bc5b30edce0..e7e6efe2f69524a90774825d7284341993393bbb 100644 (file)
@@ -1718,3 +1718,5 @@ yana
 YANA
 substrings
 Substring
+tlstrace
+yyyymmddhhmmss
index 7b282060f0b397c4e20fea0cdefb8490e80e60a5..c463b4d8f7978a3923fffea90ff395b51b625d05 100644 (file)
@@ -254,3 +254,8 @@ proto  proto stop proto stop double cc
  postfix postfix c postmap postmap c postmulti postmulti c 
  stutter File postmulti postmulti c 
  with other command line tools File postlog postlog c 
+ auxiliary collate collate pl 
+ global mail_params h postscreen postscreen c 
+ smtpd smtpd c tls tls h tls tls_client c tls tls_misc c 
+ smtp smtp c smtp smtp_params c smtp smtp_proto c 
+ tlsproxy tlsproxy c tlsproxy tlsproxy_client c 
index 77f4e741718384d8779bcef8f8911c36919fa2ff..0fb87a2ca51cfaed3a707a19cfd5e3aa8c768e85 100644 (file)
@@ -1982,3 +1982,14 @@ openUTS
 xff
 nameN
 valueN
+XXXXXX
+cwd
+mkstemp
+tlstr
+tlstrace
+tlstrs
+yyyymmddhhmmss
+datetime
+getpeername
+overshift
+Sayre
index 884be28b950b4293ae5175f35e8962c5e263c6ae..c8abec76cd2f77ffb4c66460c180c7c624fcb555 100644 (file)
 /*         \fBstatus=0\fR
 /*         \fBrate=\fInumber\fR
 /* .fi
+/* TLS TRACE RATE CONTROL
+/* .ad
+/* .fi
+/*     To register a TLS trace event send the following request
+/*     to the \fBanvil\fR(8) server:
+/*
+/* .nf
+/*         \fBrequest=tlstr\fR
+/*         \fBident=\fIstring\fR
+/* .fi
+/*
+/*     The \fBanvil\fR(8) server answers with the number of TLS trace
+/*     requests per unit time for the (service, client) combination
+/*     specified with \fBident\fR:
+/*
+/* .nf
+/*         \fBstatus=0\fR
+/*         \fBrate=\fInumber\fR
+/* .fi
 /* SECURITY
 /* .ad
 /* .fi
@@ -318,6 +337,7 @@ typedef struct {
     int     rcpt;                      /* recipient rate */
     int     ntls;                      /* new TLS session rate */
     int     auth;                      /* AUTH request rate */
+    int     tlstr;                     /* TLS trace event rate */
     time_t  start;                     /* time of first rate sample */
 } ANVIL_REMOTE;
 
@@ -349,6 +369,7 @@ typedef struct {
        (remote)->rcpt = 0; \
        (remote)->ntls = 0; \
        (remote)->auth = 0; \
+       (remote)->tlstr = 0; \
        (remote)->start = event_time(); \
     } while(0)
 
@@ -369,6 +390,7 @@ typedef struct {
        (remote)->rcpt = 0; \
        (remote)->ntls = 0; \
        (remote)->auth = 0; \
+       (remote)->tlstr = 0; \
        (remote)->start = _start; \
     } while(0)
 
@@ -399,6 +421,8 @@ typedef struct {
 
 #define ANVIL_REMOTE_INCR_AUTH(remote) ANVIL_REMOTE_INCR_RATE((remote), auth)
 
+#define ANVIL_REMOTE_INCR_TLSTR(remote)        ANVIL_REMOTE_INCR_RATE((remote), tlstr)
+
 /* Drop connection from (service, client) state. */
 
 #define ANVIL_REMOTE_DROP_ONE(remote) \
@@ -476,6 +500,7 @@ static ANVIL_MAX max_mail_rate;             /* peak message rate */
 static ANVIL_MAX max_rcpt_rate;                /* peak recipient rate */
 static ANVIL_MAX max_ntls_rate;                /* peak new TLS session rate */
 static ANVIL_MAX max_auth_rate;                /* peak AUTH request rate */
+static ANVIL_MAX max_tlstr_rate;       /* peak TLS trace request rate */
 
 static int max_cache_size;             /* peak cache size */
 static time_t max_cache_time;          /* time of peak size */
@@ -584,6 +609,7 @@ static void anvil_remote_lookup(VSTREAM *client_stream, const char *ident)
                         SEND_ATTR_INT(ANVIL_ATTR_RCPT, anvil_remote->rcpt),
                         SEND_ATTR_INT(ANVIL_ATTR_NTLS, anvil_remote->ntls),
                         SEND_ATTR_INT(ANVIL_ATTR_AUTH, anvil_remote->auth),
+                        SEND_ATTR_INT(ANVIL_ATTR_AUTH, anvil_remote->tlstr),
                         ATTR_TYPE_END);
     }
 }
@@ -755,6 +781,35 @@ static void anvil_remote_auth(VSTREAM *client_stream, const char *ident)
        ANVIL_MAX_UPDATE(max_auth_rate, anvil_remote->auth, anvil_remote->ident);
 }
 
+/* anvil_remote_tlstr - register TLS trace request event */
+
+static void anvil_remote_tlstr(VSTREAM *client_stream, const char *ident)
+{
+    ANVIL_REMOTE *anvil_remote;
+
+    /*
+     * Be prepared for "postfix reload" after "connect".
+     */
+    if ((anvil_remote =
+        (ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) == 0)
+       anvil_remote = anvil_remote_conn_update(client_stream, ident);
+
+    /*
+     * Update TLS trace request rate and respond to requesting server.
+     */
+    ANVIL_REMOTE_INCR_TLSTR(anvil_remote);
+    attr_print_plain(client_stream, ATTR_FLAG_NONE,
+                    SEND_ATTR_INT(ANVIL_ATTR_STATUS, ANVIL_STAT_OK),
+                    SEND_ATTR_INT(ANVIL_ATTR_RATE, anvil_remote->tlstr),
+                    ATTR_TYPE_END);
+
+    /*
+     * Update peak statistics.
+     */
+    if (anvil_remote->tlstr > max_tlstr_rate.value)
+       ANVIL_MAX_UPDATE(max_tlstr_rate, anvil_remote->tlstr, anvil_remote->ident);
+}
+
 /* anvil_remote_newtls - register newtls event */
 
 static void anvil_remote_newtls(VSTREAM *client_stream, const char *ident)
@@ -893,6 +948,7 @@ static void anvil_status_dump(char *unused_name, char **unused_argv)
     ANVIL_MAX_RATE_REPORT(max_rcpt_rate, "recipient");
     ANVIL_MAX_RATE_REPORT(max_ntls_rate, "newtls");
     ANVIL_MAX_RATE_REPORT(max_auth_rate, "auth");
+    ANVIL_MAX_RATE_REPORT(max_tlstr_rate, "tlstrace");
 
     if (max_cache_size > 0) {
        msg_info("statistics: max cache size %d at %.15s",
@@ -923,6 +979,7 @@ static void anvil_service(VSTREAM *client_stream, char *unused_service, char **a
        ANVIL_REQ_DISC, anvil_remote_disconnect,
        ANVIL_REQ_NTLS_STAT, anvil_remote_newtls_stat,
        ANVIL_REQ_AUTH, anvil_remote_auth,
+       ANVIL_REQ_TLSTR, anvil_remote_tlstr,
        ANVIL_REQ_LOOKUP, anvil_remote_lookup,
        0, 0,
     };
index fff9ec7f44b5a8abb9b883957dd74d5c33180fac..e536c52d0417508f612adee022642664f2857a2a 100644 (file)
 /*     const char *addr;
 /*     int     *auths;
 /*
+/*     int     anvil_clnt_tlstr(anvil_clnt, service, addr, tlstrs)
+/*     ANVIL_CLNT *anvil_clnt;
+/*     const char *service;
+/*     const char *addr;
+/*     int     *tlstrs;
+/*
 /*     int     anvil_clnt_disconnect(anvil_clnt, service, addr)
 /*     ANVIL_CLNT *anvil_clnt;
 /*     const char *service;
 /*     const char *addr;
 /*
 /*     int     anvil_clnt_lookup(anvil_clnt, service, addr, count,
-/*                                     rate, msgs, rcpts, ntls, auths)
+/*                                     rate, msgs, rcpts, ntls, auths,
+/*                                     tlstrs)
 /*     ANVIL_CLNT *anvil_clnt;
 /*     const char *service;
 /*     const char *addr;
@@ -65,6 +72,7 @@
 /*     int     *rcpts;
 /*     int     *ntls;
 /*     int     *auths;
+/*     int     *tlstrs;
 /* DESCRIPTION
 /*     anvil_clnt_create() instantiates a local anvil service
 /*     client endpoint.
@@ -91,6 +99,9 @@
 /*     anvil_clnt_auth() registers an AUTH event and returns the
 /*     current AUTH event rate for the specified remote client.
 /*
+/*     anvil_clnt_tlstr() registers a TLS trace event and returns the
+/*     current TLS trace event rate for the specified service and peer.
+/*
 /*     anvil_clnt_disconnect() informs the anvil server that a remote
 /*     client has disconnected.
 /*
@@ -212,7 +223,8 @@ void    anvil_clnt_free(ANVIL_CLNT *anvil_clnt)
 
 int     anvil_clnt_lookup(ANVIL_CLNT *anvil_clnt, const char *service,
                                  const char *addr, int *count, int *rate,
-                            int *msgs, int *rcpts, int *newtls, int *auths)
+                                 int *msgs, int *rcpts, int *newtls,
+                                 int *auths, int *tlstrs)
 {
     char   *ident = ANVIL_IDENT(service, addr);
     int     status;
@@ -230,7 +242,8 @@ int     anvil_clnt_lookup(ANVIL_CLNT *anvil_clnt, const char *service,
                          RECV_ATTR_INT(ANVIL_ATTR_RCPT, rcpts),
                          RECV_ATTR_INT(ANVIL_ATTR_NTLS, newtls),
                          RECV_ATTR_INT(ANVIL_ATTR_AUTH, auths),
-                         ATTR_TYPE_END) != 7)
+                         RECV_ATTR_INT(ANVIL_ATTR_TLSTR, tlstrs),
+                         ATTR_TYPE_END) != 8)
        status = ANVIL_STAT_FAIL;
     else if (status != ANVIL_STAT_OK)
        status = ANVIL_STAT_FAIL;
@@ -383,6 +396,30 @@ int     anvil_clnt_auth(ANVIL_CLNT *anvil_clnt, const char *service,
     return (status);
 }
 
+/* anvil_clnt_tlstr - heads-up and status query */
+
+int     anvil_clnt_tlstr(ANVIL_CLNT *anvil_clnt, const char *service,
+                                const char *addr, int *tlstrs)
+{
+    char   *ident = ANVIL_IDENT(service, addr);
+    int     status;
+
+    if (attr_clnt_request((ATTR_CLNT *) anvil_clnt,
+                         ATTR_FLAG_NONE,       /* Query attributes. */
+                         SEND_ATTR_STR(ANVIL_ATTR_REQ, ANVIL_REQ_TLSTR),
+                         SEND_ATTR_STR(ANVIL_ATTR_IDENT, ident),
+                         ATTR_TYPE_END,
+                         ATTR_FLAG_MISSING,    /* Reply attributes. */
+                         RECV_ATTR_INT(ANVIL_ATTR_STATUS, &status),
+                         RECV_ATTR_INT(ANVIL_ATTR_RATE, tlstrs),
+                         ATTR_TYPE_END) != 2)
+       status = ANVIL_STAT_FAIL;
+    else if (status != ANVIL_STAT_OK)
+       status = ANVIL_STAT_FAIL;
+    myfree(ident);
+    return (status);
+}
+
 /* anvil_clnt_disconnect - heads-up only */
 
 int     anvil_clnt_disconnect(ANVIL_CLNT *anvil_clnt, const char *service,
index d060155a6e00ac1093b688e01c26e489234d4987..ca93812b924575bf26430e22a7dddeab294eb44d 100644 (file)
@@ -36,6 +36,7 @@
 #define ANVIL_REQ_NTLS_STAT    "newtls_status"
 #define ANVIL_REQ_AUTH         "auth"
 #define ANVIL_REQ_LOOKUP       "lookup"
+#define ANVIL_REQ_TLSTR                "tlstr"
 #define ANVIL_ATTR_IDENT       "ident"
 #define ANVIL_ATTR_COUNT       "count"
 #define ANVIL_ATTR_RATE                "rate"
@@ -43,6 +44,7 @@
 #define ANVIL_ATTR_RCPT                "rcpt"
 #define ANVIL_ATTR_NTLS                "newtls"
 #define ANVIL_ATTR_AUTH                "auth"
+#define ANVIL_ATTR_TLSTR       "tlstr"
 #define ANVIL_ATTR_STATUS      "status"
 
 #define ANVIL_STAT_OK          0
@@ -60,7 +62,8 @@ extern int anvil_clnt_rcpt(ANVIL_CLNT *, const char *, const char *, int *);
 extern int anvil_clnt_newtls(ANVIL_CLNT *, const char *, const char *, int *);
 extern int anvil_clnt_newtls_stat(ANVIL_CLNT *, const char *, const char *, int *);
 extern int anvil_clnt_auth(ANVIL_CLNT *, const char *, const char *, int *);
-extern int anvil_clnt_lookup(ANVIL_CLNT *, const char *, const char *, int *, int *, int *, int *, int *, int *);
+extern int anvil_clnt_tlstr(ANVIL_CLNT *, const char *, const char *, int *);
+extern int anvil_clnt_lookup(ANVIL_CLNT *, const char *, const char *, int *, int *, int *, int *, int *, int *, int *);
 extern int anvil_clnt_disconnect(ANVIL_CLNT *, const char *, const char *);
 extern void anvil_clnt_free(ANVIL_CLNT *);
 
index f35f81faaff536e495873fc7ef0d7904161dd951..ec934d4a14f94008fd1e7ce9aef912de992b3182 100644 (file)
@@ -1445,6 +1445,10 @@ extern char *var_smtpd_tls_loglevel;
 #define DEF_SMTPD_TLS_LOGLEVEL_MAPS    ""
 extern char *var_smtpd_tls_loglevel_maps;
 
+#define VAR_SMTPD_TLS_TRACE_SIZE_LIMIT "smtpd_tls_trace_size_limit"
+#define DEF_SMTPD_TLS_TRACE_SIZE_LIMIT 102400
+extern int var_smtpd_tls_trace_size_limit;
+
 #define VAR_SMTPD_TLS_RECHEAD  "smtpd_tls_received_header"
 #define DEF_SMTPD_TLS_RECHEAD  0
 extern bool var_smtpd_tls_received_header;
@@ -1626,6 +1630,12 @@ extern char *var_lmtp_tls_loglevel;      /* In tlsmgr(8) */
 extern char *var_smtp_tls_loglevel_maps;
 extern char *var_lmtp_tls_loglevel_maps;
 
+#define VAR_SMTP_TLS_TRACE_SIZE_LIMIT  "smtp_tls_trace_size_limit"
+#define DEF_SMTP_TLS_TRACE_SIZE_LIMIT  102400
+#define VAR_LMTP_TLS_TRACE_SIZE_LIMIT  "lmtp_tls_trace_size_limit"
+#define DEF_LMTP_TLS_TRACE_SIZE_LIMIT  102400
+extern int var_smtp_tls_trace_size_limit;
+
 #define VAR_SMTP_TLS_NOTEOFFER "smtp_tls_note_starttls_offer"
 #define DEF_SMTP_TLS_NOTEOFFER 0
 #define VAR_LMTP_TLS_NOTEOFFER "lmtp_tls_note_starttls_offer"
@@ -4757,6 +4767,10 @@ extern char *var_psc_tls_loglevel;
 #define DEF_PSC_TLS_LOGLEVEL_MAPS "$" VAR_SMTPD_TLS_LOGLEVEL_MAPS
 extern char *var_psc_tls_loglevel_maps;
 
+#define VAR_PSC_TLS_TRACE_SIZE_LIMIT "postscreen_tls_trace_size_limit"
+#define DEF_PSC_TLS_TRACE_SIZE_LIMIT "$" VAR_SMTPD_TLS_TRACE_SIZE_LIMIT
+extern int var_psc_tls_trace_size_limit;
+
 #define VAR_PSC_TLS_MAND_CIPH  "postscreen_tls_mandatory_ciphers"
 #define DEF_PSC_TLS_MAND_CIPH  "$" VAR_SMTPD_TLS_MAND_CIPH
 extern char *var_psc_tls_mand_ciph;
@@ -4781,6 +4795,13 @@ extern int var_psc_tls_ccert_vd;
 #define DEF_PSC_STARTTLS_TMOUT "$" VAR_SMTPD_STARTTLS_TMOUT
 extern int var_psc_starttls_tmout;
 
+ /*
+  * How many TLS traces per anvil(8) time unit.
+  */
+#define VAR_TLS_TRACE_ANVIL_RATE       "tls_trace_rate_limit"
+#define DEF_TLS_TRACE_ANVIL_RATE       1
+extern int var_tls_trace_anvil_rate;
+
 /* LICENSE
 /* .ad
 /* .fi
index 96e4ad8b9362f6f2d819a848bb9dd14344f7f7f6..a531444487e62c65523b050a60c5597ca67cd54e 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      "20260510"
+#define MAIL_RELEASE_DATE      "20260514"
 #define MAIL_VERSION_NUMBER    "3.12"
 
 #ifdef SNAPSHOT
@@ -30,7 +30,7 @@
 #endif
 
 #ifdef NONPROD
-#define MAIL_VERSION_PROD      "-nonprod"
+#define MAIL_VERSION_PROD      "-" NONPROD
 #else
 #define MAIL_VERSION_PROD      ""
 #endif
index 9614608dac3a8d461e5852a4b51e11f1df0d4e21..22ab219fd7e879adc338ec806881adca05a0adc9 100644 (file)
 /* .IP "\fBpostscreen_tls_loglevel_maps ($smtpd_tls_loglevel_maps)\fR"
 /*     Optional TLS loglevel override that depends on the remote peer
 /*     host name or IP address.
+/* .IP "\fBpostscreen_tls_trace_size_limit ($smtpd_tls_trace_size_limit)\fR"
+/*     The \fBpostscreen\fR(8) equivalent of smtpd_tls_trace_size_limit.
 /* .IP "\fBpostscreen_tls_mandatory_ciphers ($smtpd_tls_mandatory_ciphers)\fR"
 /*     The \fBpostscreen\fR(8) equivalent of smtpd_tls_mandatory_ciphers.
 /* .IP "\fBpostscreen_tls_mandatory_exclude_ciphers ($smtpd_tls_mandatory_exclude_ciphers)\fR"
 /*     The \fBpostscreen\fR(8) equivalent of smtpd_tls_protocols.
 /* .IP "\fBpostscreen_tls_req_ccert ($smtpd_tls_req_ccert)\fR"
 /*     The \fBpostscreen\fR(8) equivalent of smtpd_tls_req_ccert.
+/* .IP "\fBtls_trace_rate_limit (1)\fR"
+/*     The maximum number of TLS traces per anvil_rate_time_unit that
+/*     all Postfix daemons combined will create.
 /* OBSOLETE STARTTLS SUPPORT CONTROLS
 /* .ad
 /* .fi
@@ -646,6 +651,7 @@ char   *var_smtpd_tls_proto;
 
 int     var_smtpd_tls_ccert_vd;
 int     var_smtpd_starttls_tmout;
+int     var_smtpd_tls_trace_size_limit;
 
 bool    var_psc_tls_ask_ccert;
 bool    var_psc_tls_enable_rpk;
@@ -676,6 +682,7 @@ char   *var_psc_tls_proto;
 
 int     var_psc_tls_ccert_vd;
 int     var_psc_starttls_tmout;
+int     var_psc_tls_trace_size_limit;
 
  /*
   * Global variables.
@@ -1369,6 +1376,7 @@ int     main(int argc, char **argv)
        VAR_PSC_CMD_COUNT, DEF_PSC_CMD_COUNT, &var_psc_cmd_count, 1, 0,
        VAR_SMTPD_CCONN_LIMIT, DEF_SMTPD_CCONN_LIMIT, &var_smtpd_cconn_limit, 0, 0,
        VAR_SMTPD_TLS_CCERT_VD, DEF_SMTPD_TLS_CCERT_VD, &var_smtpd_tls_ccert_vd, 0, 0,
+       VAR_SMTPD_TLS_TRACE_SIZE_LIMIT, DEF_SMTPD_TLS_TRACE_SIZE_LIMIT, &var_smtpd_tls_trace_size_limit, 0, 0,
        0,
     };
     static const CONFIG_NINT_TABLE nint_table[] = {
@@ -1377,6 +1385,7 @@ int     main(int argc, char **argv)
        VAR_PSC_CCONN_LIMIT, DEF_PSC_CCONN_LIMIT, &var_psc_cconn_limit, 0, 0,
        VAR_PSC_DNSBL_ALTHRESH, DEF_PSC_DNSBL_ALTHRESH, &var_psc_dnsbl_althresh, 0, 0,
        VAR_PSC_TLS_CCERT_VD, DEF_PSC_TLS_CCERT_VD, &var_psc_tls_ccert_vd, 0, 0,
+       VAR_PSC_TLS_TRACE_SIZE_LIMIT, DEF_PSC_TLS_TRACE_SIZE_LIMIT, &var_psc_tls_trace_size_limit, 0, 0,
        0,
     };
     static const CONFIG_TIME_TABLE time_table[] = {
index 331d29826fe1be660c66028ba628a07a3ab24bfc..3ba6d0908302efe693ceb9290e2d6bccb15ea9ec 100644 (file)
@@ -310,7 +310,9 @@ bool    psc_tls_pre_start(const PSC_STATE *state,
                                 namaddr = state->smtp_client_addr_port,
                                 cipher_grade = cipher_grade,
                                 cipher_exclusions = STR(cipher_exclusions),
-                                mdalg = var_psc_tls_fpt_dgst);
+                                mdalg = var_psc_tls_fpt_dgst,
+                                trace_size_limit = var_psc_tls_trace_size_limit,
+                                trace_peer = state->smtp_client_addr);
     return (true);
 }
 
index da3cfe46968acd615c987abcf23df184c78b2e7c..690aedb401d9670595cd7bc3f19debed8972f853 100644 (file)
@@ -14,7 +14,7 @@
 /*     prefixed with \fBinet:\fR or a pathname prefixed with \fBunix:\fR.  If
 /*     Postfix is built without TLS support, the resulting \fBposttls-finger\fR(1)
 /*     program has very limited functionality, and only the \fB-a\fR, \fB-c\fR,
-/*     \fB-h\fR, \fB-o\fR, \fB-S\fR, \fB-t\fR, \fB-T\fR and \fB-v\fR options
+/*     \fB-h\fR, \fB-S\fR, \fB-t\fR, \fB-T\fR and \fB-v\fR options
 /*     are available.
 /*
 /*     Note: this is an unsupported test program. No attempt is made
 /* .IP "\fBssl-session-packet-dump\fR"
 /*     Log hexadecimal packet dumps of the entire SSL session; only useful
 /*     to those who can debug SSL protocol problems from hex dumps.
+/* .IP "\fBtrace\fR"
+/*     Available with Postfix 3.12 and later. Write a human-readable
+/*     protocol transcript of the TLS session to a file in the current
+/*     directory. The file is named
+/*     \fIprocess_name\fR-\fIdate_time\fR.\fIusec\fR-\fIpeer\fR-\fIXXXXXX\fR,
+/*     where \fIXXXXXX\fR is replaced with a unique string to avoid
+/*     filename conflicts. All reconnect attempts in a single
+/*     command-line run share the same trace file, separated by "===
+/*     posttls-finger reconnect ===" lines. When \fB-X\fR is in effect,
+/*     tlsproxy(8) generates the trace file under
+/*     \fI$queue_directory\fR/tlstrace/ instead. The keyword is
+/*     ignored with a warning if Postfix or OpenSSL was built without
+/*     TLS trace support.
 /* .IP "\fBuntrusted\fR"
 /*     Logs trust chain verification problems.  This is turned on
 /*     automatically at security levels that use peer names signed
 #include <signal.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <limits.h>                    /* INT_MAX */
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <netinet/in.h>
@@ -509,12 +523,18 @@ typedef struct STATE {
     char   *protocols;                 /* Protocol inclusion/exclusion */
     int     mxinsec_level;             /* DANE for insecure MX RRs? */
     int     tlsproxy_mode;
+    char   *trace_file;                        /* full path; built once per run */
+    int     trace_failed;              /* give up after first open failure */
 #endif
     OPTIONS options;                   /* JCL */
 } STATE;
 
 static DNS_RR *host_addr(STATE *, const char *);
 
+#if defined(USE_TLS) && defined(HAVE_SSL_TRACE)
+static BIO *posttls_trace_open(void *, const char *);
+#endif
+
 #define HNAME(addr) (addr->qname)
 
  /*
@@ -840,7 +860,9 @@ static int starttls(STATE *state)
                                     tlsrpt = 0,
                                     ffail_type = 0,
                                     dane = state->ddane ?
-                                    state->ddane : state->dane);
+                                    state->ddane : state->dane,
+                                    trace_size_limit = INT_MAX,
+                                    trace_peer = state->paddr);
 
 #define PROXY_OPEN_FLAGS \
        (TLS_PROXY_FLAG_ROLE_CLIENT | TLS_PROXY_FLAG_SEND_CONTEXT)
@@ -947,7 +969,15 @@ static int starttls(STATE *state)
                             mdalg = state->mdalg,
                             tlsrpt = 0,
                             ffail_type = 0,
-                         dane = state->ddane ? state->ddane : state->dane);
+                          dane = state->ddane ? state->ddane : state->dane,
+                            trace_size_limit = INT_MAX,
+#ifdef HAVE_SSL_TRACE
+                            trace_open = posttls_trace_open,
+#else
+                            trace_open = 0,
+#endif
+                            trace_arg = (void *) state,
+                            trace_peer = state->paddr);
     }                                          /* tlsproxy_mode */
     vstring_free(cipher_exclusions);
     if (state->helo) {
@@ -1831,6 +1861,8 @@ static void cleanup(STATE *state)
     myfree(state->certfile);
     myfree(state->keyfile);
     myfree(state->sni);
+    if (state->trace_file)
+       myfree(state->trace_file);
     if (state->options.level)
        myfree(state->options.level);
     myfree(state->options.logopts);
@@ -1873,20 +1905,66 @@ static void usage(void)
     exit(1);
 }
 
-#ifdef USE_TLS
-#ifndef OPENSSL_NO_SSL_TRACE
-static void ssl_trace(int write_p, int version, int content_type,
-                       const void *buf, size_t msglen, SSL *ssl, void *arg)
+#if defined(USE_TLS) && defined(HAVE_SSL_TRACE)
+
+/* posttls_trace_open - open or reopen the SSL_trace destination file */
+
+static BIO *posttls_trace_open(void *arg, const char *trace_peer)
 {
-    BIO    *out = (BIO *) arg;
+    STATE  *state = (STATE *) arg;
+    struct timeval tv;
+    FILE   *fp;
+    BIO    *bio;
+
+    /*
+     * If the destination became non-writable on a previous attempt, do not
+     * keep retrying: the resulting trace file would silently miss the
+     * earlier sessions.
+     */
+    if (state->trace_failed)
+       return (0);
+
+    /*
+     * Build the path lazily on the first connection of a posttls-finger run.
+     * All subsequent reconnects (-r/-m) reuse the same file, so one CLI
+     * invocation produces one trace file with each handshake's transcript
+     * appended after a separator line.
+     */
+    if (state->trace_file == 0) {
+       VSTRING *path = vstring_alloc(64);
+
+       bio = tls_trace_create_file(path, trace_peer);
+       state->trace_file = vstring_export(path);
+       if (bio == 0) {
+           /* Warning is already logged. */
+           state->trace_failed = 1;
+           return (0);
+       }
+       msg_info("TLS protocol trace saved to %s", state->trace_file);
+    }
 
-    /* Avoid mixing BIO and vstream/stdio buffers */
-    vstream_fflush(VSTREAM_OUT);
-    SSL_trace(write_p, version, content_type, buf, msglen, ssl, out);
-    (void) BIO_flush(out);
+    /*
+     * Truncate on the first connection so the file reflects only the current
+     * invocation; append on subsequent reconnects with a delimiter line in
+     * between.
+     */
+    else {
+       if ((fp = fopen(state->trace_file, "a")) == 0) {
+           msg_warn("TLS trace: cannot open %s: %m", state->trace_file);
+           state->trace_failed = 1;
+           return (0);
+       }
+       if ((bio = BIO_new_fp(fp, BIO_CLOSE)) == 0) {
+           msg_warn("TLS trace: BIO_new_fp() failed for %s", state->trace_file);
+           (void) fclose(fp);
+           state->trace_failed = 1;
+           return (0);
+       }
+       (void) fputs("\n=== posttls-finger reconnect ===\n\n", fp);
+    }
+    return (bio);
 }
 
-#endif
 #endif
 
 /* tls_init - initialize application TLS library context */
@@ -1916,13 +1994,6 @@ static void tls_init(STATE *state)
                        CAfile = state->CAfile,
                        CApath = state->CApath,
                        mdalg = state->mdalg);
-#ifndef OPENSSL_NO_SSL_TRACE
-    if (state->tls_ctx != 0
-       && (state->log_mask & TLS_LOG_DEBUG)) {
-       SSL_CTX_set_msg_callback(state->tls_ctx->ssl_ctx, ssl_trace);
-       SSL_CTX_set_msg_callback_arg(state->tls_ctx->ssl_ctx, state->tls_bio);
-    }
-#endif
 #endif
 }
 
@@ -1976,6 +2047,7 @@ static void parse_options(STATE *state, int argc, char *argv[])
     state->level = TLS_LEV_DANE;
     state->mxinsec_level = TLS_LEV_DANE;
     state->tlsproxy_mode = 0;
+    state->trace_file = 0;             /* lazily constructed at trace_open */
 #else
 #define TLSOPTS ""
     state->level = TLS_LEV_NONE;
index 7e76bf56b861e827a8b41e8c1a2c41cade5e3da8..5c7d9c8e9d60cbcb155c0a4ec67190dc330fd0b7 100644 (file)
        VAR_LMTP_REUSE_COUNT, DEF_LMTP_REUSE_COUNT, &var_smtp_reuse_count, 0, 0,
 #ifdef USE_TLS
        VAR_LMTP_TLS_SCERT_VD, DEF_LMTP_TLS_SCERT_VD, &var_smtp_tls_scert_vd, 0, 0,
+       VAR_LMTP_TLS_TRACE_SIZE_LIMIT, DEF_LMTP_TLS_TRACE_SIZE_LIMIT, &var_smtp_tls_trace_size_limit, 0, 0,
 #endif
        VAR_LMTP_MIN_DATA_RATE, DEF_LMTP_MIN_DATA_RATE, &var_smtp_min_data_rate, 1, 0,
        0,
index b2d38d4a9d9f64ae6bf6963d546d33750e84a4d6..5f9be87d4a19df929e686ac1c4530af865ec75bb 100644 (file)
 /* .IP "\fBsmtp_tls_loglevel_maps (empty)\fR"
 /*     Optional TLS loglevel override that depends on the remote peer
 /*     host name or IP address.
+/* .IP "\fBsmtp_tls_trace_size_limit (102400)\fR"
+/*     Size limit, in bytes, for the TLS protocol transcript that the
+/*     Postfix SMTP client writes when the "trace" keyword is included in
+/*     the TLS loglevel for a peer (smtp_tls_loglevel or
+/*     smtp_tls_loglevel_maps).
+/* .IP "\fBtls_trace_rate_limit (1)\fR"
+/*     The maximum number of TLS traces per anvil_rate_time_unit that
+/*     all Postfix daemons combined will create.
 /* OBSOLETE TLS CONTROLS
 /* .ad
 /* .fi
@@ -1143,6 +1151,7 @@ bool    var_smtp_tls_enforce_peername;
 char   *var_smtp_tls_key_file;
 char   *var_smtp_tls_loglevel;
 char   *var_smtp_tls_loglevel_maps;
+int     var_smtp_tls_trace_size_limit;
 bool    var_smtp_tls_note_starttls_offer;
 char   *var_smtp_tls_mand_proto;
 char   *var_smtp_tls_sec_cmatch;
index e206e4201e529500247e576d3c31eab429658273..a866fa94960393f892522ecd1febc71046263b2f 100644 (file)
        VAR_SMTP_REUSE_COUNT, DEF_SMTP_REUSE_COUNT, &var_smtp_reuse_count, 0, 0,
 #ifdef USE_TLS
        VAR_SMTP_TLS_SCERT_VD, DEF_SMTP_TLS_SCERT_VD, &var_smtp_tls_scert_vd, 0, 0,
+       VAR_SMTP_TLS_TRACE_SIZE_LIMIT, DEF_SMTP_TLS_TRACE_SIZE_LIMIT, &var_smtp_tls_trace_size_limit, 0, 0,
 #endif
        VAR_SMTP_MIN_DATA_RATE, DEF_SMTP_MIN_DATA_RATE, &var_smtp_min_data_rate, 1, 0,
        0,
index f673608820e661d948f36ff5b619905778a01942..1e7a7521eb3d457a18d981b86c5899f56d38669d 100644 (file)
@@ -1097,7 +1097,9 @@ static int smtp_start_tls(SMTP_STATE *state)
                                     tlsrpt = 0,
 #endif
                                     ffail_type = 0,
-                                    dane = state->tls->dane);
+                                    dane = state->tls->dane,
+                                    trace_size_limit = var_smtp_tls_trace_size_limit,
+                                    trace_peer = STR(iter->addr));
 
        /*
         * The tlsproxy(8) server enforces timeouts that are larger than
@@ -1228,7 +1230,11 @@ static int smtp_start_tls(SMTP_STATE *state)
                             tlsrpt = 0,
 #endif
                             ffail_type = state->tls->ext_policy_failure,
-                            dane = state->tls->dane);
+                            dane = state->tls->dane,
+                            trace_size_limit = var_smtp_tls_trace_size_limit,
+                            trace_open = 0,
+                            trace_arg = 0,
+                            trace_peer = STR(iter->addr));
 
        /*
         * At this point there must not be any pending data in the stream
index 4480eb9547abb523cf4232f091614db3afd3733e..091f0f549b7b76d07f02ef97429bb9fb19a9a2c1 100644 (file)
 /* .IP "\fBsmtpd_tls_loglevel_maps (empty)\fR"
 /*     Optional TLS loglevel override that depends on the remote peer
 /*     host name or IP address.
+/* .IP "\fBsmtpd_tls_trace_size_limit (102400)\fR"
+/*     The Postfix SMTP server equivalent of smtp_tls_trace_size_limit.
+/* .IP "\fBtls_trace_rate_limit (1)\fR"
+/*     The maximum number of TLS traces per anvil_rate_time_unit that
+/*     all Postfix daemons combined will create.
 /* OBSOLETE TLS CONTROLS
 /* .ad
 /* .fi
@@ -1529,6 +1534,7 @@ char   *var_smtpd_tls_dkey_file;
 char   *var_smtpd_tls_key_file;
 char   *var_smtpd_tls_loglevel;
 char   *var_smtpd_tls_loglevel_maps;
+int     var_smtpd_tls_trace_size_limit;
 char   *var_smtpd_tls_mand_proto;
 bool    var_smtpd_tls_received_header;
 bool    var_smtpd_tls_req_ccert;
@@ -5345,7 +5351,9 @@ static void smtpd_start_tls(SMTPD_STATE *state)
                                 namaddr = state->namaddr,
                                 cipher_grade = cipher_grade,
                                 cipher_exclusions = STR(cipher_exclusions),
-                                mdalg = var_smtpd_tls_fpt_dgst);
+                                mdalg = var_smtpd_tls_fpt_dgst,
+                                trace_size_limit = var_smtpd_tls_trace_size_limit,
+                                trace_peer = state->addr);
 
     /*
      * Note: state->tlsproxy is left open when smtp_flush() calls longjmp(),
@@ -5394,7 +5402,11 @@ static void smtpd_start_tls(SMTPD_STATE *state)
                         namaddr = state->namaddr,
                         cipher_grade = cipher_grade,
                         cipher_exclusions = STR(cipher_exclusions),
-                        mdalg = var_smtpd_tls_fpt_dgst);
+                        mdalg = var_smtpd_tls_fpt_dgst,
+                        trace_size_limit = var_smtpd_tls_trace_size_limit,
+                        trace_open = 0,
+                        trace_arg = 0,
+                        trace_peer = state->addr);
 
 #endif                                         /* USE_TLSPROXY */
 
@@ -6885,6 +6897,7 @@ int     main(int argc, char **argv)
        VAR_SMTPD_CIPV6_PREFIX, DEF_SMTPD_CIPV6_PREFIX, &var_smtpd_cipv6_prefix, 0, MAX_SMTPD_CIPV6_PREFIX,
 #ifdef USE_TLS
        VAR_SMTPD_TLS_CCERT_VD, DEF_SMTPD_TLS_CCERT_VD, &var_smtpd_tls_ccert_vd, 0, 0,
+       VAR_SMTPD_TLS_TRACE_SIZE_LIMIT, DEF_SMTPD_TLS_TRACE_SIZE_LIMIT, &var_smtpd_tls_trace_size_limit, 0, 0,
 #endif
        VAR_SMTPD_SASL_RESP_LIMIT, DEF_SMTPD_SASL_RESP_LIMIT, &var_smtpd_sasl_resp_limit, DEF_SMTPD_SASL_RESP_LIMIT, 0,
        VAR_SMTPD_POLICY_REQ_LIMIT, DEF_SMTPD_POLICY_REQ_LIMIT, &var_smtpd_policy_req_limit, 0, 0,
index aa11f78fdff393c78d3514742c506cb26c89bd08..d443c38320f3c7ac8e9aab6bbee89041fcee768b 100644 (file)
@@ -329,6 +329,7 @@ tls_mgr.o: tls_mgr.c
 tls_mgr.o: tls_mgr.h
 tls_mgr.o: tls_scache.h
 tls_misc.o: ../../include/argv.h
+tls_misc.o: ../../include/been_here.h
 tls_misc.o: ../../include/check_arg.h
 tls_misc.o: ../../include/dict.h
 tls_misc.o: ../../include/dns.h
index 8ce9c213cf5d02a873d7adbc6f4bb89f8d38a756..80f4bc57e6a1bd276f447f07b3182e5685410020 100644 (file)
@@ -141,6 +141,16 @@ extern const char *str_tls_level(int);
 #else
 #define TLS_ADD1_HOST   SSL_add1_host
 #define TLS_SET1_HOST   SSL_set1_host
+#endif
+
+ /*
+  * SSL_trace() is built into OpenSSL only when the library is configured
+  * with "enable-ssl-trace". This is the upstream default, but some
+  * distributions disable it. Postfix can also opt out at build time with
+  * CCARGS=-DNO_TLS_TRACE.
+  */
+#if !defined(OPENSSL_NO_SSL_TRACE) && !defined(NO_TLS_TRACE)
+#define HAVE_SSL_TRACE
 #endif
 
  /*
@@ -281,6 +291,9 @@ typedef struct {
     int     errorcode;                 /* First error at error depth */
     int     must_fail;                 /* Failed to load trust settings */
     char   *ffail_type;                        /* Forced verification failure */
+    /* SSL protocol trace; populated when log_mask has TLS_LOG_TRACE. */
+    BIO    *trace_bio;                 /* destination BIO, or NULL */
+    int     trace_size_limit;          /* size cap; <= 0 means "stop now" */
     /* End of Private members. */
 } TLS_SESS_STATE;
 
@@ -330,6 +343,7 @@ extern int tls_log_mask(const char *, const char *);
 #define TLS_LOG_TLSPKTS                        (1<<8)
 #define TLS_LOG_ALLPKTS                        (1<<9)
 #define TLS_LOG_DANE                   (1<<10)
+#define TLS_LOG_TRACE                  (1<<11)
 
  /*
   * Client and Server application contexts
@@ -517,6 +531,10 @@ typedef struct {
     const TLS_DANE *dane;              /* DANE TLSA verification */
     struct TLSRPT_WRAPPER *tlsrpt;     /* RFC 8460 reporting */
     char   *ffail_type;                        /* Forced verification failure */
+    int     trace_size_limit;          /* TLS protocol trace size limit */
+    BIO    *(*trace_open) (void *, const char *);      /* override dest */
+    void   *trace_arg;                 /* opaque trace_open argument */
+    char   *trace_peer;                        /* Printable peer IP address */
 } TLS_CLIENT_START_PROPS;
 
 extern TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *);
@@ -540,13 +558,15 @@ extern TLS_SESS_STATE *tls_client_post_connect(TLS_SESS_STATE *,
     a6, a7, a8, a9, a10, a11, a12, a13, a14))
 
 #define TLS_CLIENT_START(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \
-    a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22) \
+    a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, \
+    a23, a24, a25, a26) \
     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)->a16), ((props)->a17), ((props)->a18), ((props)->a19), \
-    ((props)->a20), ((props)->a21), ((props)->a22), (props)))
+    ((props)->a20), ((props)->a21), ((props)->a22), ((props)->a23), \
+    ((props)->a24), ((props)->a25), ((props)->a26), (props)))
 
  /*
   * tls_server.c
@@ -588,6 +608,10 @@ typedef struct {
     const char *cipher_grade;
     const char *cipher_exclusions;
     const char *mdalg;                 /* default message digest algorithm */
+    int     trace_size_limit;          /* TLS protocol trace size limit */
+    BIO    *(*trace_open) (void *, const char *); /* override dest */
+    void   *trace_arg;                 /* opaque trace_open argument */
+    char   *trace_peer;                        /* Printable peer IP address */
 } TLS_SERVER_START_PROPS;
 
 extern TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *);
@@ -612,11 +636,12 @@ extern TLS_SESS_STATE *tls_server_post_accept(TLS_SESS_STATE *);
     a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20))
 
 #define TLS_SERVER_START(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \
-    a10, a11, a12, a13) \
+    a10, a11, a12, a13, a14, a15, a16, a17) \
     tls_server_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)))
+    ((props)->a12), ((props)->a13), ((props)->a14), ((props)->a15), \
+    ((props)->a16), ((props)->a17), (props)))
 
  /*
   * tls_session.c
@@ -743,6 +768,28 @@ extern const EVP_MD *tls_validate_digest(const char *);
 extern void tls_enable_client_rpk(SSL_CTX *, SSL *);
 extern void tls_enable_server_rpk(SSL_CTX *, SSL *);
 
+#ifdef HAVE_SSL_TRACE
+extern void tls_msg_callback(int, int, int, const void *, size_t,
+                                    SSL *, void *);
+
+ /*
+  * Default trace destination: a file under tlstrace/. This is the default
+  * for daemon programs that do not supply start_props->trace_open. The real
+  * work is done in tls_trace_create_file().
+  */
+#define TLS_TRACE_QDIR "tlstrace"
+extern bool tls_trace_rate_ok(int);
+extern BIO *tls_trace_create_qfile(const char *);
+
+ /*
+  * Append <process_name>-<yyyymmddhhmmss>.<usec>-<peer>-XXXXXX to the path
+  * buffer, then create the named file with mkstemp() and wrap it in an
+  * OpenSSL file BIO.
+  */
+extern BIO *tls_trace_create_file(VSTRING *, const char *);
+
+#endif
+
  /*
   * tls_seed.c
   */
index 23e66964bf4bb3b74e3896a1db5b6fc8b923b6c8..fc33c5e34f3dec1865132b7a543d22f15be97aca 100644 (file)
@@ -1286,6 +1286,38 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
     if (log_mask & TLS_LOG_TLSPKTS)
        tls_set_bio_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb);
 
+#ifdef HAVE_SSL_TRACE
+
+    /*
+     * If "trace" is included in the TLS loglevel, open a destination BIO
+     * (either the application's override or the libtls default file under
+     * $queue_directory/tlstrace/) and install the SSL message callback.
+     * SSL_trace() writes records straight into the BIO; the budget is
+     * enforced via BIO_tell() in tls_msg_callback(). Enforce a global trace
+     * creation rate limit for requests from a daemon process.
+     */
+    if ((log_mask & TLS_LOG_TRACE) && props->trace_size_limit > 0) {
+       BIO    *bio;
+
+       if (props->trace_open != 0) {
+           bio = props->trace_open(props->trace_arg, props->trace_peer);
+       } else if (tls_trace_rate_ok(var_tls_trace_anvil_rate)) {
+           bio = tls_trace_create_qfile(props->trace_peer);
+       } else {
+           msg_info("skipping TLS trace output - rate limit (%d) exceeded",
+                    var_tls_trace_anvil_rate);
+           bio = 0;
+       }
+
+       if (bio != 0) {
+           TLScontext->trace_bio = bio;
+           TLScontext->trace_size_limit = props->trace_size_limit;
+           SSL_set_msg_callback(TLScontext->con, tls_msg_callback);
+           SSL_set_msg_callback_arg(TLScontext->con, TLScontext);
+       }
+    }
+#endif
+
     /*
      * An external (STS) policy signaled a failure. Prevent false (PKI)
      * certificate matches in tls_verify.c. TODO(wietse) how was this handled
index dad8cb54f99cdf940993cbb40fd2fb51f38baece..1c5a5a6aa877b0c8510b16ac4110c784c6b3458f 100644 (file)
 /*     void tls_enable_server_rpk(ctx, ssl)
 /*     SSL_CTX *ctx;
 /*     SSL     *ssl;
+/*
+/*     bool    tls_trace_rate_ok(int tls_trace_rate_limit)
+/*
+/*     BIO     *tls_trace_create_file(
+/*     VSTRING *path,
+/*     const char *trace_peer)
+/*
+/*     BIO     *tls_trace_create_qfile(const char *trace_peer)
 /* DESCRIPTION
 /*     This module implements public and internal routines that
 /*     support the TLS client and server.
 /*
 /*     tls_enable_server_rpk() enables the use of raw public keys in the
 /*     server to client direction, if supported by the OpenSSL library.
+/*
+/*     tls_trace_create_file() fills in a TLS trace file name template
+/*     <process_name>-<date_time>.<usec>-<trace_peer>-XXXXXX, appends
+/*     the result to the path argument, opens the named file with
+/*     mkstemp(), and returns it as a file BIO with BIO_CLOSE
+/*     enabled. The result value is null in case of failure; all errors
+/*     are logged.
+/*
+/*     tls_trace_rate_ok() queries the anvil(8) service and enforces the
+/*     tls_trace_rate_limit value.
+/*
+/*     tls_trace_create_qfile() creates a TLS trace file for a daemon
+/*     process. This function initializes a path buffer with "tlstrace/",
+/*     and delegates the remaining work to tls_trace_create_file().
 /* LICENSE
 /* .ad
 /* .fi
 #include <sys_defs.h>
 #include <ctype.h>
 #include <string.h>
+#include <fcntl.h>                     /* O_WRONLY etc. */
+#include <time.h>
 
 /* Utility library. */
 
  /*
   * Global library.
   */
+#include <anvil_clnt.h>
+#include <been_here.h>
 #include <mail_params.h>
 #include <mail_conf.h>
 #include <maps.h>
@@ -299,6 +325,7 @@ char   *var_tls_low_ignored;
 char   *var_tls_export_ignored;
 char   *var_tls_null_clist;
 int     var_tls_daemon_rand_bytes;
+int     var_tls_trace_anvil_rate;
 char   *var_tls_eecdh_auto;
 char   *var_tls_eecdh_strong;
 char   *var_tls_eecdh_ultra;
@@ -556,6 +583,7 @@ static const NAME_MASK tls_log_table[] = {
     "ssl-debug", TLS_LOG_DEBUG,                /* SSL library debug/verbose */
     "ssl-handshake-packet-dump", TLS_LOG_TLSPKTS,
     "ssl-session-packet-dump", TLS_LOG_TLSPKTS | TLS_LOG_ALLPKTS,
+    "trace", TLS_LOG_TRACE,            /* SSL_trace() to a file or email */
     0, 0,
 };
 
@@ -578,9 +606,144 @@ int     tls_log_mask(const char *log_param, const char *log_level)
 
     mask = name_mask_opt(log_param, tls_log_table, log_level,
                         NAME_MASK_ANY_CASE | NAME_MASK_RETURN);
+#ifndef HAVE_SSL_TRACE
+    if (mask & TLS_LOG_TRACE) {
+       static BH_TABLE *log_spam_filter;
+
+       if (log_spam_filter == 0)
+           log_spam_filter = been_here_init(BH_BOUND_NONE, BH_FLAG_NONE);
+       if (!been_here(log_spam_filter, "%s=%s", log_param, log_level)) {
+           msg_warn("%s: ignoring \"trace\" log level: "
+                    "SSL_trace() is not available in this build",
+                    log_param);
+           mask &= ~TLS_LOG_TRACE;
+       }
+    }
+#endif
     return (mask);
 }
 
+#ifdef HAVE_SSL_TRACE
+
+/* tls_msg_callback - SSL message callback for TLS_LOG_TRACE */
+
+void    tls_msg_callback(int write_p, int version, int content_type,
+                                const void *buf, size_t msglen,
+                                SSL *ssl, void *arg)
+{
+    TLS_SESS_STATE *TLScontext = (TLS_SESS_STATE *) arg;
+    BIO    *bio = TLScontext->trace_bio;
+
+    /*
+     * trace_size_limit <= 0 means either tracing is off (never started)
+     * or we already crossed the budget and emitted the truncation marker.
+     * Either way, do not write further.
+     */
+    if (bio == 0 || TLScontext->trace_size_limit <= 0)
+       return;
+
+    SSL_trace(write_p, version, content_type, buf, msglen, ssl, bio);
+
+    if (BIO_tell(bio) >= TLScontext->trace_size_limit) {
+       static const char trailer[] =
+       "\n[TLS trace truncated: size limit reached]\n";
+
+       (void) BIO_write(bio, trailer, sizeof(trailer) - 1);
+       TLScontext->trace_size_limit = -1;
+    }
+}
+
+/* tls_trace_rate_ok - enforce tls_trace_rate_limit */
+
+bool    tls_trace_rate_ok(int tls_trace_rate_limit)
+{
+    ANVIL_CLNT *client;
+    int     rate;
+    int     ret;
+
+    if (tls_trace_rate_limit > 0) {
+       client = anvil_clnt_create();
+       if (anvil_clnt_tlstr(client, "any", "any", &rate) == ANVIL_STAT_OK) {
+           ret = rate <= tls_trace_rate_limit;
+       } else {
+           ret = true;
+       }
+       anvil_clnt_free(client);
+    } else {
+       ret = true;
+    }
+    return (ret);
+} 
+
+/* tls_trace_create_qfile - default trace destination for daemons */
+
+BIO    *tls_trace_create_qfile(const char *trace_peer)
+{
+    VSTRING *path;
+    BIO    *bio;
+
+    /*
+     * Create the file under "tlstrace/". The cwd of every Postfix daemon is
+     * $queue_directory, so the relative path resolves correctly with or
+     * without chroot. The directory itself is expected to exist;
+     * postfix-script and postfix-files arrange for it, and most Postfix
+     * daemons would not have sufficient privileges to create it.
+     */
+    path = vstring_alloc(100);
+    vstring_strcpy(path, TLS_TRACE_QDIR "/");
+    bio = tls_trace_create_file(path, trace_peer);
+    msg_info("TLS protocol trace for %s saved to %s",
+            trace_peer, vstring_str(path));
+    vstring_free(path);
+    return (bio);
+}
+
+/* tls_trace_create_file - trace destination for CLI or daemon */
+
+BIO *tls_trace_create_file(VSTRING *path, const char *trace_peer)
+{
+    struct timeval tv;
+    struct tm *lt;
+    FILE   *fp;
+    BIO    *bio;
+
+    int     newfd;
+
+    /*
+     * Append "<app>-<yyyymmddhhmmss>.<usec>-<peer>-XXXXXX" to the path. Open
+     * with mkstemp() so that this will never clobber an existing file;
+     * fdopen(3) hands the descriptor to stdio, and BIO_new_fp() with
+     * BIO_CLOSE() wraps the stream so that BIO_free_all() at session
+     * teardown also fclose()s it.
+     */
+    vstring_sprintf_append(path, "%s-", var_procname);
+    GETTIMEOFDAY(&tv);
+    lt = localtime(&tv.tv_sec);
+    while (strftime(vstring_end(path), vstring_avail(path),
+                   "%Y%m%d%H%M%S", lt) == 0)
+       VSTRING_SPACE(path, vstring_avail(path) + 100);
+    VSTRING_SKIP(path);
+    vstring_sprintf_append(path, ".%06d-%s-XXXXXX",
+                          (int) tv.tv_usec, trace_peer);
+    if ((newfd = mkstemp(vstring_str(path))) < 0) {
+       msg_warn("TLS trace: cannot open %s: %m", vstring_str(path));
+       return (0);
+    }
+    if ((fp = fdopen(newfd, "w")) == 0) {
+       msg_warn("TLS trace: fdopen(%s) failed: %m", vstring_str(path));
+       (void) close(newfd);
+       return (0);
+    }
+    if ((bio = BIO_new_fp(fp, BIO_CLOSE)) == 0) {
+       msg_warn("TLS trace: BIO_new_fp() failed for %s", vstring_str(path));
+       (void) fclose(fp);
+       return (0);
+    }
+    return (bio);
+}
+
+#endif                                 /* HAVE_SSL_TRACE */
+
 /* tls_update_app_logmask - update log level after init */
 
 void    tls_update_app_logmask(TLS_APPL_STATE *app_ctx, int log_mask)
@@ -685,6 +848,7 @@ void    tls_param_init(void)
     /* If this changes, update TLS_*_PARAMS* in tls_*.h. */
     static const CONFIG_INT_TABLE int_table[] = {
        VAR_TLS_DAEMON_RAND_BYTES, DEF_TLS_DAEMON_RAND_BYTES, &var_tls_daemon_rand_bytes, 1, 0,
+       VAR_TLS_TRACE_ANVIL_RATE, DEF_TLS_TRACE_ANVIL_RATE, &var_tls_trace_anvil_rate, 0, 0,
        0,
     };
 
@@ -1372,6 +1536,8 @@ TLS_SESS_STATE *tls_alloc_sess_context(int log_mask, const char *namaddr)
     TLScontext->errorcert = 0;
     TLScontext->rpt_reported = 0;
     TLScontext->ffail_type = 0;
+    TLScontext->trace_bio = 0;
+    TLScontext->trace_size_limit = 0;
 
     return (TLScontext);
 }
@@ -1389,6 +1555,24 @@ void    tls_free_context(TLS_SESS_STATE *TLScontext)
     if (TLScontext->con != 0)
        SSL_free(TLScontext->con);
 
+    /*
+     * Release the protocol trace, if one was opened.  Order matters:
+     * SSL_free() above can still drive the message callback during
+     * teardown (close-notify processing in particular), so trace_bio
+     * must stay valid until after SSL_free() returns.  Closing it
+     * first would let tls_msg_callback() write through a freed BIO.
+     *
+     * Always BIO_flush() before close, so any stdio buffering inside
+     * BIO_new_fp() lands on disk before the FILE * is fclose()d.  An
+     * application override may release the BIO; otherwise BIO_free_all
+     * walks the chain and (with BIO_CLOSE) closes the underlying file.
+     */
+    if (TLScontext->trace_bio != 0) {
+       (void) BIO_flush(TLScontext->trace_bio);
+       BIO_free_all(TLScontext->trace_bio);
+       TLScontext->trace_bio = 0;
+    }
+
     if (TLScontext->namaddr)
        myfree(TLScontext->namaddr);
     if (TLScontext->serverid)
index f539de6a47e759cee07468c7fc3b5daf7af0ac71..1fd02fc5f7e0cde9e82bc4e43c39a04088493eda 100644 (file)
@@ -59,6 +59,7 @@
 #define TLS_ATTR_SRVR_SIG_DGST "srvr_signature_digest"
 #define TLS_ATTR_NAMADDR       "namaddr"
 #define TLS_ATTR_RPT_REPORTED  "rpt_reported"
+#define TLS_ATTR_TRACE_PEER    "trace_peer"
 
  /*
   * TLS_SERVER_INIT_PROPS attributes.
@@ -95,6 +96,7 @@
 #define TLS_ATTR_CIPHER_GRADE  "cipher_grade"
 #define TLS_ATTR_CIPHER_EXCLUSIONS "cipher_exclusions"
 #define TLS_ATTR_MDALG         "mdalg"
+#define TLS_ATTR_TRACE_PEER    "trace_peer"
 
  /*
   * TLS_CLIENT_INIT_PROPS attributes.
 #define TLS_ATTR_DANE          "dane"
 #define TLS_ATTR_TLSRPT                "tlsrpt"
 #define TLS_ATTR_FFAIL_TYPE    "forced_failure_type"
+#define TLS_ATTR_TRACE_SIZE_LIMIT "trace_size_limit"
+#define TLS_ATTR_TRACE_PEER    "trace_peer"
 
  /*
   * TLS_TLSA attributes.
index beae3a7c6a5523dfce88e8b5cc20733e25e912f8..b34264e0361b2f99f23ac8dbf9714ce881799791 100644 (file)
@@ -267,6 +267,9 @@ int     tls_proxy_client_start_print(ATTR_PRINT_COMMON_FN print_fn,
 #endif
                   SEND_ATTR_STR(TLS_ATTR_FFAIL_TYPE,
                                 STRING_OR_EMPTY(props->ffail_type)),
+                  SEND_ATTR_INT(TLS_ATTR_TRACE_SIZE_LIMIT,
+                                props->trace_size_limit),
+                  SEND_ATTR_STR(TLS_ATTR_TRACE_PEER, props->trace_peer),
                   ATTR_TYPE_END);
     /* Do not flush the stream. */
     if (msg_verbose)
@@ -289,6 +292,7 @@ void    tls_proxy_client_start_free(TLS_CLIENT_START_PROPS *props)
     myfree((void *) props->protocols);
     myfree((void *) props->cipher_grade);
     myfree((void *) props->cipher_exclusions);
+    myfree((void *) props->trace_peer);
     if (props->matchargv)
        argv_free((ARGV *) props->matchargv);
     myfree((void *) props->mdalg);
@@ -497,11 +501,12 @@ int     tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
     VSTRING *cipher_exclusions = vstring_alloc(25);
     VSTRING *mdalg = vstring_alloc(25);
     VSTRING *ffail_type = vstring_alloc(25);
+    VSTRING *trace_peer = vstring_alloc(25);
 
 #ifdef USE_TLSRPT
-#define EXPECT_START_SCAN_RETURN       19
+#define EXPECT_START_SCAN_RETURN       21
 #else
-#define EXPECT_START_SCAN_RETURN       18
+#define EXPECT_START_SCAN_RETURN       20
 #endif
 
     if (msg_verbose)
@@ -540,6 +545,9 @@ int     tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
                                 &props->tlsrpt),
 #endif
                  RECV_ATTR_STR(TLS_ATTR_FFAIL_TYPE, ffail_type),
+                 RECV_ATTR_INT(TLS_ATTR_TRACE_SIZE_LIMIT,
+                               &props->trace_size_limit),
+                 RECV_ATTR_STR(TLS_ATTR_TRACE_PEER, trace_peer),
                  ATTR_TYPE_END);
     /* Always construct a well-formed structure. */
     props->log_param = vstring_export(log_param);
@@ -555,6 +563,9 @@ int     tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
     props->cipher_exclusions = vstring_export(cipher_exclusions);
     props->mdalg = vstring_export(mdalg);
     EXPORT_OR_NULL(props->ffail_type, ffail_type);
+    props->trace_open = 0;
+    props->trace_arg = 0;
+    props->trace_peer = vstring_export(trace_peer);
     ret = (ret == EXPECT_START_SCAN_RETURN ? 1 : -1);
     if (ret != 1) {
        tls_proxy_client_start_free(props);
index f1859ff7d32c94caf5d6973ec35d1a8448b0a4e4..613180a0f006a38857230d56e6c415aeebb56bf6 100644 (file)
 #ifdef USE_TLS
 
 #define TLS_PROXY_CLIENT_START_PROPS(props, a1, a2, a3, a4, a5, a6, a7, a8, \
-    a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19) \
+    a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21) \
     (((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)->a16), ((props)->a17), ((props)->a18), ((props)->a19))
+    ((props)->a16), ((props)->a17), ((props)->a18), ((props)->a19), \
+    ((props)->a20), ((props)->a21))
 
 extern int tls_proxy_client_start_print(ATTR_PRINT_COMMON_FN, VSTREAM *, int, const void *);
 extern void tls_proxy_client_start_free(TLS_CLIENT_START_PROPS *);
index 808abbe73ecd64643d8f47e02a6e6220824f9c32..fb94673c85491c4f8cd014ba13ef38893b3925e3 100644 (file)
@@ -112,6 +112,8 @@ int     tls_proxy_context_print(ATTR_PRINT_COMMON_FN print_fn, VSTREAM *fp,
                                 STRING_OR_EMPTY(tp->namaddr)),
                   SEND_ATTR_INT(TLS_ATTR_RPT_REPORTED,
                                 tp->rpt_reported),
+                  SEND_ATTR_INT(TLS_ATTR_TRACE_SIZE_LIMIT,
+                                tp->trace_size_limit),
                   ATTR_TYPE_END);
     /* Do not flush the stream. */
     return (ret);
index fc23c528a8e4a3e9796574b59ff4885cad2da23b..949c90831d937380fe55bcacd38a8c5de55fc45c 100644 (file)
@@ -126,6 +126,8 @@ int     tls_proxy_context_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
                  RECV_ATTR_STR(TLS_ATTR_NAMADDR, namaddr),
                  RECV_ATTR_INT(TLS_ATTR_RPT_REPORTED,
                                &tls_context->rpt_reported),
+                 RECV_ATTR_INT(TLS_ATTR_TRACE_SIZE_LIMIT,
+                               &tls_context->trace_size_limit),
                  ATTR_TYPE_END);
     /* Always construct a well-formed structure. */
     tls_context->peer_CN = vstring_export(peer_CN);
@@ -143,7 +145,7 @@ int     tls_proxy_context_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
     tls_context->srvr_sig_curve = vstring_export(srvr_sig_curve);
     tls_context->srvr_sig_dgst = vstring_export(srvr_sig_dgst);
     tls_context->namaddr = vstring_export(namaddr);
-    ret = (ret == 25 ? 1 : -1);
+    ret = (ret == 26 ? 1 : -1);
     if (ret != 1) {
        tls_proxy_context_free(tls_context);
        tls_context = 0;
index db2f6c4cef7c42f0d0fa2cc72ec0075c24f91fa6..21ce1e079af880f920cf176bd98251ef347a6ed4 100644 (file)
@@ -118,6 +118,10 @@ int     tls_proxy_server_start_print(ATTR_PRINT_COMMON_FN print_fn, VSTREAM *fp,
                                 STRING_OR_EMPTY(props->cipher_exclusions)),
                   SEND_ATTR_STR(TLS_ATTR_MDALG,
                                 STRING_OR_EMPTY(props->mdalg)),
+                  SEND_ATTR_INT(TLS_ATTR_TRACE_SIZE_LIMIT,
+                                props->trace_size_limit),
+                  SEND_ATTR_STR(TLS_ATTR_TRACE_PEER,
+                                STRING_OR_EMPTY(props->trace_peer)),
                   ATTR_TYPE_END);
     /* Do not flush the stream. */
     return (ret);
@@ -138,6 +142,7 @@ int     tls_proxy_server_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
     VSTRING *cipher_grade = vstring_alloc(25);
     VSTRING *cipher_exclusions = vstring_alloc(25);
     VSTRING *mdalg = vstring_alloc(25);
+    VSTRING *trace_peer = vstring_alloc(25);
 
     /*
      * Note: memset() is not a portable way to initialize non-integer types.
@@ -158,6 +163,9 @@ int     tls_proxy_server_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
                  RECV_ATTR_STR(TLS_ATTR_CIPHER_EXCLUSIONS,
                                cipher_exclusions),
                  RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
+                 RECV_ATTR_INT(TLS_ATTR_TRACE_SIZE_LIMIT,
+                               &props->trace_size_limit),
+                 RECV_ATTR_STR(TLS_ATTR_TRACE_PEER, trace_peer),
                  ATTR_TYPE_END);
     /* Always construct a well-formed structure. */
     props->log_param = vstring_export(log_param);
@@ -167,7 +175,10 @@ int     tls_proxy_server_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
     props->cipher_grade = vstring_export(cipher_grade);
     props->cipher_exclusions = vstring_export(cipher_exclusions);
     props->mdalg = vstring_export(mdalg);
-    ret = (ret == 10 ? 1 : -1);
+    props->trace_open = 0;
+    props->trace_arg = 0;
+    props->trace_peer = vstring_export(trace_peer);
+    ret = (ret == 12 ? 1 : -1);
     if (ret != 1) {
        tls_proxy_server_start_free(props);
        props = 0;
@@ -188,6 +199,7 @@ void    tls_proxy_server_start_free(TLS_SERVER_START_PROPS *props)
     myfree((void *) props->cipher_grade);
     myfree((void *) props->cipher_exclusions);
     myfree((void *) props->mdalg);
+    myfree((void *) props->trace_peer);
     myfree((void *) props);
 }
 
index 2062d78fb3c67c1c4d14c475518e9b95a4a59809..fb3d8f6f974c357e0e62e8c4df2664b79413c425 100644 (file)
 #ifdef USE_TLS
 
 #define TLS_PROXY_SERVER_START_PROPS(props, a1, a2, a3, a4, a5, a6, a7, a8, \
-    a9, a10) \
+    a9, a10, a11, a12) \
     (((props)->a1), ((props)->a2), ((props)->a3), \
     ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
-    ((props)->a8), ((props)->a9), ((props)->a10))
+    ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \
+    ((props)->a12))
 
 extern int tls_proxy_server_start_print(ATTR_PRINT_COMMON_FN, VSTREAM *, int, const void *);
 extern void tls_proxy_server_start_free(TLS_SERVER_START_PROPS *);
index 122628501698217db09500801091427788b667e0..04066142c3fbd9ee0cb5e50803df01400cb31adc 100644 (file)
@@ -931,6 +931,38 @@ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props)
     if (log_mask & TLS_LOG_TLSPKTS)
        tls_set_bio_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb);
 
+#ifdef HAVE_SSL_TRACE
+
+    /*
+     * If "trace" is included in the TLS loglevel, open a destination BIO
+     * (either the application's override or the libtls default file under
+     * $queue_directory/tlstrace/) and install the SSL message callback.
+     * SSL_trace() writes records straight into the BIO; the budget is
+     * enforced via BIO_tell() in tls_msg_callback(). Enforce a global trace
+     * creation rate limit for requests from a daemon process.
+     */
+    if ((log_mask & TLS_LOG_TRACE) && props->trace_size_limit > 0) {
+       BIO    *bio;
+
+       if (props->trace_open != 0) {
+           bio = props->trace_open(props->trace_arg, props->trace_peer);
+       } else if (tls_trace_rate_ok(var_tls_trace_anvil_rate)) {
+           bio = tls_trace_create_qfile(props->trace_peer);
+       } else {
+           msg_info("skipping TLS trace output - rate limit (%d) exceeded",
+                    var_tls_trace_anvil_rate);
+           bio = 0;
+       }
+
+       if (bio != 0) {
+           TLScontext->trace_bio = bio;
+           TLScontext->trace_size_limit = props->trace_size_limit;
+           SSL_set_msg_callback(TLScontext->con, tls_msg_callback);
+           SSL_set_msg_callback_arg(TLScontext->con, TLScontext);
+       }
+    }
+#endif
+
     /*
      * If we don't trigger the handshake in the library, leave control over
      * SSL_accept/read/write/etc with the application.
index ebda90a69848a9fe926b7125ed995f2d325ab967..871e48c5e135cb2df027983038951644c85ef53a 100644 (file)
@@ -797,8 +797,6 @@ extern int initgroups(const char *, int);
 #if HAVE_GLIBC_API_VERSION_SUPPORT(2, 1)
 #define SOCKADDR_SIZE  socklen_t
 #define SOCKOPT_SIZE   socklen_t
-#else
-#define NO_SNPRINTF
 #endif
 #ifndef NO_IPV6
 #define HAS_IPV6
index 6e14cc0e906557f452252a8662ac704afe5384c4..368d0da747e65cd2cd36bc197f805ba2961fe651 100644 (file)
        VBUF_SKIP(bp); \
     } while (0)
 #else
-#define VBUF_SNPRINTF(bp, sz, fmt, arg) do { \
-       if (VBUF_SPACE((bp), (sz)) != 0) \
+#define VBUF_SNPRINTF(bp, width_or_prec, type_space, fmt, arg) do { \
+       if ((width_or_prec) > INT_MAX - (type_space)) \
+           msg_panic("vbuf_print: field width (%d + %lu) > INT_MAX", \
+               (width_or_prec), (unsigned long) (type_space)); \
+       if (VBUF_SPACE((bp), (width_or_prec) + (type_space)) != 0) \
            return (bp); \
        sprintf((char *) (bp)->ptr, (fmt), (arg)); \
        VBUF_SKIP(bp); \