2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-31 14:17:41 +00:00

postfix-3.8-20230128

This commit is contained in:
Wietse Venema
2023-01-28 00:00:00 -05:00
committed by Viktor Dukhovni
parent 6876e42027
commit 3241579998
8 changed files with 187 additions and 23 deletions

View 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.

View 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)
WWhheenn PPoossttffiixx aanndd MMiilltteerrss iinnssppeecctt aann SSMMTTPP sseessssiioonn
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.
BBuuiillddiinngg MMiilltteerr aapppplliiccaattiioonnss
Milter applications have been written in C, Haskell, Java, Perl, Python, Rust,

View 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,

View 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 "$@"

View 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,

View 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

View File

@@ -942,10 +942,10 @@ 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);
}
}
return (0);
}

View File

@@ -167,6 +167,13 @@
*/
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);