]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.8-20230128
authorWietse Venema <wietse@porcupine.org>
Sat, 28 Jan 2023 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Sun, 29 Jan 2023 03:42:28 +0000 (22:42 -0500)
postfix/HISTORY
postfix/README_FILES/MILTER_README
postfix/html/MILTER_README.html
postfix/postfix-env.sh
postfix/proto/MILTER_README.html
postfix/src/global/mail_version.h
postfix/src/posttls-finger/posttls-finger.c
postfix/src/tls/tls_server.c

index b93da842b96b8128f3d2afa95c8c4b91ef7747c6..d1545c53a4203c08284a8e1c2c0444fc45c901ee 100644 (file)
@@ -26779,6 +26779,7 @@ Apologies for any names omitted.
        warning message tls.tls_dh.c.
 
 20230115
+
        Workaround for a breaking change in OpenSSL 3: always turn
        on SSL_OP_IGNORE_UNEXPECTED_EOF, to avoid warning messages
        and missed opportunities for TLS session reuse. This is
@@ -26786,3 +26787,24 @@ Apologies for any names omitted.
        framing, and is therefore not affected by TLS truncation
        attacks. Fix by Viktor Dukhovni. Files: tls/tls.h, tls_client.c,
        tls/tls_server.c.
+
+20230121
+
+       Documentation: describe when Postfix and Milters inspect
+       SMTP commands or header/body content. File:
+       proto/MILTER_README.html.
+
+20230127
+
+       Bugfix (introduced: Postfix 3.4): the posttls-finger command
+       failed to detect that a connection was resumed in the case
+       that a server did not return a certificate. Viktor Dukhovni.
+       File: posttls-finger/posttls-finger.c.
+
+       Workaround: OpenSSL 3.x EVP_get_cipherbyname() can return
+       lazily-bound handles. Postfix now checks that the expected
+       functionality will be available instead of failing later.
+       Fix by Viktor Dukhovni. File: tls/tls_server.c.
+
+       Portability: MacOS support for the postfix-env.sh test
+       script.
index fc52c6e8d9eb1ec0d96bc611dc1628839d270f05..4ace868216403a9f5f58a80b859b28f0bd26c722 100644 (file)
@@ -24,6 +24,7 @@ implementations.
 This document provides information on the following topics:
 
   * How Milter applications plug into Postfix
+  * When Postfix and Milters inspect an SMTP session
   * Building Milter applications
   * Running Milter applications
   * Configuring Postfix
@@ -80,6 +81,41 @@ Postfix architecture).
 
     Local   -> sendmail(1)
 
+W\bWh\bhe\ben\bn P\bPo\bos\bst\btf\bfi\bix\bx a\ban\bnd\bd M\bMi\bil\blt\bte\ber\brs\bs i\bin\bns\bsp\bpe\bec\bct\bt a\ban\bn S\bSM\bMT\bTP\bP s\bse\bes\bss\bsi\bio\bon\bn
+
+Generally, Postfix inspects information first, then the first configured
+Milter, the second configured Milter, and so on.
+
+  * With most SMTP commands: Postfix reviews one SMTP command, and if Postfix
+    does not reject it, Postfix passes the command to the first configured
+    Milter. If the first Milter does not reject the command, Postfix passes it
+    to the second configured Milter, and so on. This includes commands with an
+    envelope sender (MAIL FROM) or envelope recipient (RCPT TO). Postfix stores
+    the same envelope records in a queue file as when no Milters are
+    configured, including rewritten envelope addresses, expanded virtual
+    aliases, BCC addresses from sender/recipient_bcc_maps, and so on.
+
+  * With header/body content: Postfix may rewrite or reject header/body content
+    before it stores that content in the queue file; Postfix stores the same
+    header/body content as when no Milters are configured. If Postfix does not
+    reject the header/body content, Postfix passes it to the first configured
+    Milter which may modify or reject that content or may modify the stored
+    envelope. If the first Milter does not reject the header/body content,
+    Postfix passes it to the second configured Milter, and so on.
+
+Details:
+
+  * Postfix hides its own Postfix-prepended Received: header, for compatibility
+    with Sendmail. Postfix does not hide other headers that Postfix or Milters
+    added or modified.
+
+  * When the Postfix SMTP server receives a sequence of one or more valid BDAT
+    commands, it generates one DATA command for the Milters.
+
+  * The Milter API does not support inspection of SMTP commands such as QUIT,
+    NOOP, or VRFY; the API supports only commands that are needed for email
+    delivery.
+
 B\bBu\bui\bil\bld\bdi\bin\bng\bg M\bMi\bil\blt\bte\ber\br a\bap\bpp\bpl\bli\bic\bca\bat\bti\bio\bon\bns\bs
 
 Milter applications have been written in C, Haskell, Java, Perl, Python, Rust,
index 2f8c994125721ff7cf6e1aeae746dd852cb58ede..bcef3b947317395869a9239cdf89608dbbaa78d6 100644 (file)
@@ -48,6 +48,9 @@ document for differences between Postfix and Sendmail implementations.
 
 <li><a href="#plumbing">How Milter applications plug into Postfix </a>
 
+<li><a href="#when-inspect">When Postfix and Milters inspect an
+SMTP session </a>
+
 <li><a href="#building">Building Milter applications</a>
 
 <li><a href="#running">Running Milter applications</a>
@@ -192,6 +195,54 @@ href="QSHAPE_README.html#incoming_queue"> incoming </a> </td>
 
 </blockquote>
 
+<h2><a name="when-inspect">When Postfix and Milters inspect an SMTP
+session </a></h2>
+
+<p> Generally, Postfix inspects information first, then the first
+configured Milter, the second configured Milter, and so on. </p>
+
+<ul>
+
+<li><p> With most SMTP commands: Postfix reviews one SMTP command,
+and if Postfix does not reject it, Postfix passes the command to
+the first configured Milter. If the first Milter does not reject
+the command, Postfix passes it to the second configured Milter, and
+so on. This includes commands with an envelope sender (MAIL FROM)
+or envelope recipient (RCPT TO). Postfix stores the same envelope
+records in a queue file as when no Milters are configured, including
+rewritten envelope addresses, expanded virtual aliases, BCC addresses
+from sender/recipient_bcc_maps, and so on. </p>
+
+<li><p> With header/body content: Postfix may rewrite or reject
+header/body content before it stores that content in the queue file;
+Postfix stores the same header/body content as when no Milters are
+configured.  If Postfix does not reject the header/body content,
+Postfix passes it to the first configured Milter which may modify
+or reject that content or may modify the stored envelope. If the
+first Milter does not reject the header/body content, Postfix passes
+it to the second configured Milter, and so on. </p>
+
+</ul>
+
+<p> Details: </p>
+
+<ul>
+
+<li><p> Postfix hides its own Postfix-prepended Received: header, for
+compatibility with Sendmail. Postfix does not hide other headers that
+Postfix or Milters added or modified. </p>
+
+
+<li><p> When the Postfix SMTP server receives a sequence of one or
+more valid BDAT commands, it generates one DATA command for the
+Milters.  </p>
+
+<li><p> The Milter API does not support inspection of SMTP commands
+such as QUIT, NOOP, or VRFY; the API supports only commands that are
+needed for email delivery. <p>
+
+</ul>
+
 <h2><a name="building">Building Milter applications</a></h2>
 
 <p> Milter applications have been written in C, Haskell, Java, Perl,
index 9c0fe44cf20e2005745877ead267097fab40c41e..35f317534664b28e46b471f4c370309291c3390b 100644 (file)
@@ -2,4 +2,4 @@
 
 # Run a program with the new shared libraries instead of the installed ones.
 
-LD_LIBRARY_PATH=`pwd`/lib exec "$@"
+LD_LIBRARY_PATH=`pwd`/lib DYLD_LIBRARY_PATH=`pwd`/lib exec "$@"
index 1f2868d271c175b47c68662a17255e41e15d0b69..e5ec60e5ab696a08d65c84ed08daee5969aafafe 100644 (file)
@@ -48,6 +48,9 @@ document for differences between Postfix and Sendmail implementations.
 
 <li><a href="#plumbing">How Milter applications plug into Postfix </a>
 
+<li><a href="#when-inspect">When Postfix and Milters inspect an
+SMTP session </a>
+
 <li><a href="#building">Building Milter applications</a>
 
 <li><a href="#running">Running Milter applications</a>
@@ -192,6 +195,54 @@ href="QSHAPE_README.html#incoming_queue"> incoming </a> </td>
 
 </blockquote>
 
+<h2><a name="when-inspect">When Postfix and Milters inspect an SMTP
+session </a></h2>
+
+<p> Generally, Postfix inspects information first, then the first
+configured Milter, the second configured Milter, and so on. </p>
+
+<ul>
+
+<li><p> With most SMTP commands: Postfix reviews one SMTP command,
+and if Postfix does not reject it, Postfix passes the command to
+the first configured Milter. If the first Milter does not reject
+the command, Postfix passes it to the second configured Milter, and
+so on. This includes commands with an envelope sender (MAIL FROM)
+or envelope recipient (RCPT TO). Postfix stores the same envelope
+records in a queue file as when no Milters are configured, including
+rewritten envelope addresses, expanded virtual aliases, BCC addresses
+from sender/recipient_bcc_maps, and so on. </p>
+
+<li><p> With header/body content: Postfix may rewrite or reject
+header/body content before it stores that content in the queue file;
+Postfix stores the same header/body content as when no Milters are
+configured.  If Postfix does not reject the header/body content,
+Postfix passes it to the first configured Milter which may modify
+or reject that content or may modify the stored envelope. If the
+first Milter does not reject the header/body content, Postfix passes
+it to the second configured Milter, and so on. </p>
+
+</ul>
+
+<p> Details: </p>
+
+<ul>
+
+<li><p> Postfix hides its own Postfix-prepended Received: header, for
+compatibility with Sendmail. Postfix does not hide other headers that
+Postfix or Milters added or modified. </p>
+
+
+<li><p> When the Postfix SMTP server receives a sequence of one or
+more valid BDAT commands, it generates one DATA command for the
+Milters.  </p>
+
+<li><p> The Milter API does not support inspection of SMTP commands
+such as QUIT, NOOP, or VRFY; the API supports only commands that are
+needed for email delivery. <p>
+
+</ul>
+
 <h2><a name="building">Building Milter applications</a></h2>
 
 <p> Milter applications have been written in C, Haskell, Java, Perl,
index 07663c44aace64a8b72f95c9807a4e11b0c9e752..fcf78608ee7a8d313d7a1b573d48c9ed67e13903 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      "20230121"
+#define MAIL_RELEASE_DATE      "20230128"
 #define MAIL_VERSION_NUMBER    "3.8"
 
 #ifdef SNAPSHOT
index cdb0b4f9edabc7111e689fdeb060663f9d2d7cf7..5526c408d1f06c1d70a0faa9d756b68e58a8baff 100644 (file)
@@ -942,9 +942,9 @@ static int starttls(STATE *state)
                print_trust_info(state);
            state->log_mask &= ~(TLS_LOG_CERTMATCH | TLS_LOG_PEERCERT |
                                 TLS_LOG_VERBOSE | TLS_LOG_UNTRUSTED);
-           state->log_mask |= TLS_LOG_CACHE | TLS_LOG_SUMMARY;
-           tls_update_app_logmask(state->tls_ctx, state->log_mask);
        }
+       state->log_mask |= TLS_LOG_CACHE | TLS_LOG_SUMMARY;
+       tls_update_app_logmask(state->tls_ctx, state->log_mask);
     }
     return (0);
 }
index b76cfbc700ff76d0b46c99928f0c79ddbb225d9d..dcf232e84a86db55d09abba700b98eca8274f753 100644 (file)
   */
 static const char server_session_id_context[] = "Postfix/TLS";
 
+#ifndef OPENSSL_NO_TLSEXT
+ /*
+  * We retain the cipher handle for the lifetime of the process.
+  */
+static const EVP_CIPHER *tkt_cipher;
+#endif
+
 #define GET_SID(s, v, lptr)    ((v) = SSL_SESSION_get_id((s), (lptr)))
 
 typedef const unsigned char *session_id_t;
@@ -293,7 +300,7 @@ static int new_server_session_cb(SSL *ssl, SSL_SESSION *session)
 #define TLS_TKT_ACCEPT 1               /* Ticket decryptable and re-usable */
 #define TLS_TKT_REISSUE        2               /* Ticket decryptable, not re-usable */
 
-#if defined(SSL_OP_NO_TICKET) && !defined(OPENSSL_NO_TLSEXT)
+#if !defined(OPENSSL_NO_TLSEXT)
 
 #if OPENSSL_VERSION_PREREQ(3,0)
 
@@ -303,13 +310,11 @@ static int ticket_cb(SSL *con, unsigned char name[], unsigned char iv[],
                         EVP_CIPHER_CTX *ctx, EVP_MAC_CTX *hctx, int create)
 {
     OSSL_PARAM params[3];
-    static const EVP_CIPHER *ciph;
     TLS_TICKET_KEY *key;
     TLS_SESS_STATE *TLScontext = SSL_get_ex_data(con, TLScontext_index);
     int     timeout = ((int) SSL_CTX_get_timeout(SSL_get_SSL_CTX(con))) / 2;
 
-    if ((!ciph && (ciph = EVP_get_cipherbyname(var_tls_tkt_cipher)) == 0)
-       || (key = tls_mgr_key(create ? 0 : name, timeout)) == 0
+    if ((key = tls_mgr_key(create ? 0 : name, timeout)) == 0
        || (create && RAND_bytes(iv, TLS_TICKET_IVLEN) <= 0))
        return (create ? TLS_TKT_NOKEYS : TLS_TKT_STALE);
 
@@ -323,13 +328,13 @@ static int ticket_cb(SSL *con, unsigned char name[], unsigned char iv[],
        return (create ? TLS_TKT_NOKEYS : TLS_TKT_STALE);
 
     if (create) {
-       EVP_EncryptInit_ex(ctx, ciph, NOENGINE, key->bits, iv);
+       EVP_EncryptInit_ex(ctx, tkt_cipher, NOENGINE, key->bits, iv);
        memcpy((void *) name, (void *) key->name, TLS_TICKET_NAMELEN);
        if (TLScontext->log_mask & TLS_LOG_CACHE)
            msg_info("%s: Issuing session ticket, key expiration: %ld",
                     TLScontext->namaddr, (long) key->tout);
     } else {
-       EVP_DecryptInit_ex(ctx, ciph, NOENGINE, key->bits, iv);
+       EVP_DecryptInit_ex(ctx, tkt_cipher, NOENGINE, key->bits, iv);
        if (TLScontext->log_mask & TLS_LOG_CACHE)
            msg_info("%s: Decrypting session ticket, key expiration: %ld",
                     TLScontext->namaddr, (long) key->tout);
@@ -346,13 +351,11 @@ static int ticket_cb(SSL *con, unsigned char name[], unsigned char iv[],
                             EVP_CIPHER_CTX *ctx, HMAC_CTX *hctx, int create)
 {
     static const EVP_MD *sha256;
-    static const EVP_CIPHER *ciph;
     TLS_TICKET_KEY *key;
     TLS_SESS_STATE *TLScontext = SSL_get_ex_data(con, TLScontext_index);
     int     timeout = ((int) SSL_CTX_get_timeout(SSL_get_SSL_CTX(con))) / 2;
 
     if ((!sha256 && (sha256 = EVP_sha256()) == 0)
-       || (!ciph && (ciph = EVP_get_cipherbyname(var_tls_tkt_cipher)) == 0)
        || (key = tls_mgr_key(create ? 0 : name, timeout)) == 0
        || (create && RAND_bytes(iv, TLS_TICKET_IVLEN) <= 0))
        return (create ? TLS_TKT_NOKEYS : TLS_TKT_STALE);
@@ -360,13 +363,13 @@ static int ticket_cb(SSL *con, unsigned char name[], unsigned char iv[],
     HMAC_Init_ex(hctx, key->hmac, TLS_TICKET_MACLEN, sha256, NOENGINE);
 
     if (create) {
-       EVP_EncryptInit_ex(ctx, ciph, NOENGINE, key->bits, iv);
+       EVP_EncryptInit_ex(ctx, tkt_cipher, NOENGINE, key->bits, iv);
        memcpy((void *) name, (void *) key->name, TLS_TICKET_NAMELEN);
        if (TLScontext->log_mask & TLS_LOG_CACHE)
            msg_info("%s: Issuing session ticket, key expiration: %ld",
                     TLScontext->namaddr, (long) key->tout);
     } else {
-       EVP_DecryptInit_ex(ctx, ciph, NOENGINE, key->bits, iv);
+       EVP_DecryptInit_ex(ctx, tkt_cipher, NOENGINE, key->bits, iv);
        if (TLScontext->log_mask & TLS_LOG_CACHE)
            msg_info("%s: Decrypting session ticket, key expiration: %ld",
                     TLScontext->namaddr, (long) key->tout);
@@ -530,18 +533,20 @@ TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props)
      * Add SSL_OP_NO_TICKET when the timeout is zero or library support is
      * incomplete.
      */
-#ifdef SSL_OP_NO_TICKET
 #ifndef OPENSSL_NO_TLSEXT
     ticketable = (*var_tls_tkt_cipher && scache_timeout > 0
                  && !(off & SSL_OP_NO_TICKET));
     if (ticketable) {
-       const EVP_CIPHER *ciph;
-
-       if ((ciph = EVP_get_cipherbyname(var_tls_tkt_cipher)) == 0
-           || EVP_CIPHER_mode(ciph) != EVP_CIPH_CBC_MODE
-           || EVP_CIPHER_iv_length(ciph) != TLS_TICKET_IVLEN
-           || EVP_CIPHER_key_length(ciph) < TLS_TICKET_IVLEN
-           || EVP_CIPHER_key_length(ciph) > TLS_TICKET_KEYLEN) {
+#if OPENSSL_VERSION_PREREQ(3,0)
+       tkt_cipher = EVP_CIPHER_fetch(NULL, var_tls_tkt_cipher, NULL);
+#else
+       tkt_cipher = EVP_get_cipherbyname(var_tls_tkt_cipher);
+#endif
+       if (tkt_cipher == 0
+           || EVP_CIPHER_mode(tkt_cipher) != EVP_CIPH_CBC_MODE
+           || EVP_CIPHER_iv_length(tkt_cipher) != TLS_TICKET_IVLEN
+           || EVP_CIPHER_key_length(tkt_cipher) < TLS_TICKET_IVLEN
+           || EVP_CIPHER_key_length(tkt_cipher) > TLS_TICKET_KEYLEN) {
            msg_warn("%s: invalid value: %s; session tickets disabled",
                     VAR_TLS_TKT_CIPHER, var_tls_tkt_cipher);
            ticketable = 0;
@@ -571,7 +576,6 @@ TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props)
 #endif
     if (!ticketable)
        off |= SSL_OP_NO_TICKET;
-#endif
 
     SSL_CTX_set_options(server_ctx, off);