mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-31 22:25:24 +00:00
postfix-3.4.29
This commit is contained in:
committed by
Viktor Dukhovni
parent
29302a2b8c
commit
4c7a731f08
@@ -24877,3 +24877,41 @@ Apologies for any names omitted.
|
|||||||
framing, and is therefore not affected by TLS truncation
|
framing, and is therefore not affected by TLS truncation
|
||||||
attacks. Fix by Viktor Dukhovni. Files: tls/tls.h, tls_client.c,
|
attacks. Fix by Viktor Dukhovni. Files: tls/tls.h, tls_client.c,
|
||||||
tls/tls_server.c.
|
tls/tls_server.c.
|
||||||
|
|
||||||
|
20230125
|
||||||
|
|
||||||
|
Portability: the EVP_get_digestbyname change broke OpenSSL
|
||||||
|
1.0.2 support. File: tls/tls.h.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
20230330
|
||||||
|
|
||||||
|
Safety: the long form "{ name = value }" in import_environment
|
||||||
|
or export_environment is not documented, but accepted, and
|
||||||
|
it was stored in the process environment as the invalid
|
||||||
|
form "name = value", thus not setting or overriding an entry
|
||||||
|
for "name". This form is now stored as the expected
|
||||||
|
"name=value". Found during code maintenance. Also refined
|
||||||
|
the "missing attribute name" detection. Files: clean_env.c,
|
||||||
|
split_nameval.c.
|
||||||
|
|
||||||
|
20230418
|
||||||
|
|
||||||
|
Bugfix (introduced: Postfix 3.2): the MySQL client could
|
||||||
|
return "not found" instead of "error" during the time that
|
||||||
|
all MySQL server connections were turned down after error.
|
||||||
|
Found during code maintenance. File: global/dict_mysql.c.
|
||||||
|
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
# Run a program with the new shared libraries instead of the installed ones.
|
# 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 "$@"
|
||||||
|
@@ -528,7 +528,7 @@ static int plmysql_query(DICT_MYSQL *dict_mysql,
|
|||||||
{
|
{
|
||||||
HOST *host;
|
HOST *host;
|
||||||
MYSQL_RES *first_result = 0;
|
MYSQL_RES *first_result = 0;
|
||||||
int query_error;
|
int query_error = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper to avoid spamming the log with warnings.
|
* Helper to avoid spamming the log with warnings.
|
||||||
|
@@ -20,8 +20,8 @@
|
|||||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||||
* patchlevel; they change the release date only.
|
* patchlevel; they change the release date only.
|
||||||
*/
|
*/
|
||||||
#define MAIL_RELEASE_DATE "20230121"
|
#define MAIL_RELEASE_DATE "20230418"
|
||||||
#define MAIL_VERSION_NUMBER "3.4.28"
|
#define MAIL_VERSION_NUMBER "3.4.29"
|
||||||
|
|
||||||
#ifdef SNAPSHOT
|
#ifdef SNAPSHOT
|
||||||
#define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE
|
#define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE
|
||||||
|
@@ -933,9 +933,9 @@ static int starttls(STATE *state)
|
|||||||
print_trust_info(state);
|
print_trust_info(state);
|
||||||
state->log_mask &= ~(TLS_LOG_CERTMATCH | TLS_LOG_PEERCERT |
|
state->log_mask &= ~(TLS_LOG_CERTMATCH | TLS_LOG_PEERCERT |
|
||||||
TLS_LOG_VERBOSE | TLS_LOG_UNTRUSTED);
|
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);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@@ -84,6 +84,16 @@ extern const char *str_tls_level(int);
|
|||||||
#define ssl_cipher_stack_t STACK_OF(SSL_CIPHER)
|
#define ssl_cipher_stack_t STACK_OF(SSL_CIPHER)
|
||||||
#define ssl_comp_stack_t STACK_OF(SSL_COMP)
|
#define ssl_comp_stack_t STACK_OF(SSL_COMP)
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Official way to check minimum OpenSSL API version from 3.0 onward.
|
||||||
|
* We simply define it false for all prior versions, where we typically also
|
||||||
|
* need the patch level to determine API compatibility.
|
||||||
|
*/
|
||||||
|
#ifndef OPENSSL_VERSION_PREREQ
|
||||||
|
#define OPENSSL_VERSION_PREREQ(m,n) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if (OPENSSL_VERSION_NUMBER < 0x1000200fUL)
|
#if (OPENSSL_VERSION_NUMBER < 0x1000200fUL)
|
||||||
#error "OpenSSL releases prior to 1.0.2 are no longer supported"
|
#error "OpenSSL releases prior to 1.0.2 are no longer supported"
|
||||||
#endif
|
#endif
|
||||||
@@ -109,6 +119,8 @@ extern const char *str_tls_level(int);
|
|||||||
#define TLS_method SSLv23_method
|
#define TLS_method SSLv23_method
|
||||||
#define TLS_client_method SSLv23_client_method
|
#define TLS_client_method SSLv23_client_method
|
||||||
#define TLS_server_method SSLv23_server_method
|
#define TLS_server_method SSLv23_server_method
|
||||||
|
#define EVP_MD_CTX_new EVP_MD_CTX_create
|
||||||
|
#define EVP_MD_CTX_free EVP_MD_CTX_destroy
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Backwards compatibility with OpenSSL < 1.1.1 */
|
/* Backwards compatibility with OpenSSL < 1.1.1 */
|
||||||
|
@@ -164,6 +164,13 @@
|
|||||||
*/
|
*/
|
||||||
static const char server_session_id_context[] = "Postfix/TLS";
|
static const char server_session_id_context[] = "Postfix/TLS";
|
||||||
|
|
||||||
|
#ifndef OPENSSL_NO_TLSEXT
|
||||||
|
/*
|
||||||
|
* We retain the cipher handle for lifetime of the process, it is not freed.
|
||||||
|
*/
|
||||||
|
static const EVP_CIPHER *tkt_cipher;
|
||||||
|
#endif
|
||||||
|
|
||||||
#define GET_SID(s, v, lptr) ((v) = SSL_SESSION_get_id((s), (lptr)))
|
#define GET_SID(s, v, lptr) ((v) = SSL_SESSION_get_id((s), (lptr)))
|
||||||
|
|
||||||
/* OpenSSL 1.1.0 bitrot */
|
/* OpenSSL 1.1.0 bitrot */
|
||||||
@@ -299,19 +306,17 @@ static int new_server_session_cb(SSL *ssl, SSL_SESSION *session)
|
|||||||
|
|
||||||
/* ticket_cb - configure tls session ticket encrypt/decrypt context */
|
/* ticket_cb - configure tls session ticket encrypt/decrypt context */
|
||||||
|
|
||||||
#if defined(SSL_OP_NO_TICKET) && !defined(OPENSSL_NO_TLSEXT)
|
#if !defined(OPENSSL_NO_TLSEXT)
|
||||||
|
|
||||||
static int ticket_cb(SSL *con, unsigned char name[], unsigned char iv[],
|
static int ticket_cb(SSL *con, unsigned char name[], unsigned char iv[],
|
||||||
EVP_CIPHER_CTX * ctx, HMAC_CTX * hctx, int create)
|
EVP_CIPHER_CTX * ctx, HMAC_CTX * hctx, int create)
|
||||||
{
|
{
|
||||||
static const EVP_MD *sha256;
|
static const EVP_MD *sha256;
|
||||||
static const EVP_CIPHER *ciph;
|
|
||||||
TLS_TICKET_KEY *key;
|
TLS_TICKET_KEY *key;
|
||||||
TLS_SESS_STATE *TLScontext = SSL_get_ex_data(con, TLScontext_index);
|
TLS_SESS_STATE *TLScontext = SSL_get_ex_data(con, TLScontext_index);
|
||||||
int timeout = ((int) SSL_CTX_get_timeout(SSL_get_SSL_CTX(con))) / 2;
|
int timeout = ((int) SSL_CTX_get_timeout(SSL_get_SSL_CTX(con))) / 2;
|
||||||
|
|
||||||
if ((!sha256 && (sha256 = EVP_sha256()) == 0)
|
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
|
|| (key = tls_mgr_key(create ? 0 : name, timeout)) == 0
|
||||||
|| (create && RAND_bytes(iv, TLS_TICKET_IVLEN) <= 0))
|
|| (create && RAND_bytes(iv, TLS_TICKET_IVLEN) <= 0))
|
||||||
return (create ? TLS_TKT_NOKEYS : TLS_TKT_STALE);
|
return (create ? TLS_TKT_NOKEYS : TLS_TKT_STALE);
|
||||||
@@ -319,13 +324,13 @@ static int ticket_cb(SSL *con, unsigned char name[], unsigned char iv[],
|
|||||||
HMAC_Init_ex(hctx, key->hmac, TLS_TICKET_MACLEN, sha256, NOENGINE);
|
HMAC_Init_ex(hctx, key->hmac, TLS_TICKET_MACLEN, sha256, NOENGINE);
|
||||||
|
|
||||||
if (create) {
|
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);
|
memcpy((void *) name, (void *) key->name, TLS_TICKET_NAMELEN);
|
||||||
if (TLScontext->log_mask & TLS_LOG_CACHE)
|
if (TLScontext->log_mask & TLS_LOG_CACHE)
|
||||||
msg_info("%s: Issuing session ticket, key expiration: %ld",
|
msg_info("%s: Issuing session ticket, key expiration: %ld",
|
||||||
TLScontext->namaddr, (long) key->tout);
|
TLScontext->namaddr, (long) key->tout);
|
||||||
} else {
|
} 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)
|
if (TLScontext->log_mask & TLS_LOG_CACHE)
|
||||||
msg_info("%s: Decrypting session ticket, key expiration: %ld",
|
msg_info("%s: Decrypting session ticket, key expiration: %ld",
|
||||||
TLScontext->namaddr, (long) key->tout);
|
TLScontext->namaddr, (long) key->tout);
|
||||||
@@ -495,18 +500,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
|
* Add SSL_OP_NO_TICKET when the timeout is zero or library support is
|
||||||
* incomplete.
|
* incomplete.
|
||||||
*/
|
*/
|
||||||
#ifdef SSL_OP_NO_TICKET
|
|
||||||
#ifndef OPENSSL_NO_TLSEXT
|
#ifndef OPENSSL_NO_TLSEXT
|
||||||
ticketable = (*var_tls_tkt_cipher && scache_timeout > 0
|
ticketable = (*var_tls_tkt_cipher && scache_timeout > 0
|
||||||
&& !(off & SSL_OP_NO_TICKET));
|
&& !(off & SSL_OP_NO_TICKET));
|
||||||
if (ticketable) {
|
if (ticketable) {
|
||||||
const EVP_CIPHER *ciph;
|
#if OPENSSL_VERSION_PREREQ(3,0)
|
||||||
|
tkt_cipher = EVP_CIPHER_fetch(NULL, var_tls_tkt_cipher, NULL);
|
||||||
if ((ciph = EVP_get_cipherbyname(var_tls_tkt_cipher)) == 0
|
#else
|
||||||
|| EVP_CIPHER_mode(ciph) != EVP_CIPH_CBC_MODE
|
tkt_cipher = EVP_get_cipherbyname(var_tls_tkt_cipher);
|
||||||
|| EVP_CIPHER_iv_length(ciph) != TLS_TICKET_IVLEN
|
#endif
|
||||||
|| EVP_CIPHER_key_length(ciph) < TLS_TICKET_IVLEN
|
if (tkt_cipher == 0
|
||||||
|| EVP_CIPHER_key_length(ciph) > TLS_TICKET_KEYLEN) {
|
|| 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",
|
msg_warn("%s: invalid value: %s; session tickets disabled",
|
||||||
VAR_TLS_TKT_CIPHER, var_tls_tkt_cipher);
|
VAR_TLS_TKT_CIPHER, var_tls_tkt_cipher);
|
||||||
ticketable = 0;
|
ticketable = 0;
|
||||||
@@ -532,7 +539,6 @@ TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props)
|
|||||||
#endif
|
#endif
|
||||||
if (!ticketable)
|
if (!ticketable)
|
||||||
off |= SSL_OP_NO_TICKET;
|
off |= SSL_OP_NO_TICKET;
|
||||||
#endif
|
|
||||||
|
|
||||||
SSL_CTX_set_options(server_ctx, off);
|
SSL_CTX_set_options(server_ctx, off);
|
||||||
|
|
||||||
|
@@ -50,9 +50,11 @@
|
|||||||
/* Utility library. */
|
/* Utility library. */
|
||||||
|
|
||||||
#include <msg.h>
|
#include <msg.h>
|
||||||
|
#include <mymalloc.h>
|
||||||
#include <argv.h>
|
#include <argv.h>
|
||||||
#include <safe.h>
|
#include <safe.h>
|
||||||
#include <clean_env.h>
|
#include <clean_env.h>
|
||||||
|
#include <stringops.h>
|
||||||
|
|
||||||
/* clean_env - clean up the environment */
|
/* clean_env - clean up the environment */
|
||||||
|
|
||||||
@@ -62,20 +64,27 @@ void clean_env(char **preserve_list)
|
|||||||
ARGV *save_list;
|
ARGV *save_list;
|
||||||
char *value;
|
char *value;
|
||||||
char **cpp;
|
char **cpp;
|
||||||
char *eq;
|
char *copy;
|
||||||
|
char *key;
|
||||||
|
char *val;
|
||||||
|
const char *err;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Preserve or specify selected environment variables.
|
* Preserve or specify selected environment variables.
|
||||||
*/
|
*/
|
||||||
#define STRING_AND_LENGTH(x, y) (x), (ssize_t) (y)
|
|
||||||
|
|
||||||
save_list = argv_alloc(10);
|
save_list = argv_alloc(10);
|
||||||
for (cpp = preserve_list; *cpp; cpp++)
|
for (cpp = preserve_list; *cpp; cpp++) {
|
||||||
if ((eq = strchr(*cpp, '=')) != 0)
|
if (strchr(*cpp, '=') != 0) {
|
||||||
argv_addn(save_list, STRING_AND_LENGTH(*cpp, eq - *cpp),
|
copy = mystrdup(*cpp);
|
||||||
STRING_AND_LENGTH(eq + 1, strlen(eq + 1)), (char *) 0);
|
err = split_nameval(copy, &key, &val);
|
||||||
else if ((value = safe_getenv(*cpp)) != 0)
|
if (err != 0)
|
||||||
|
msg_fatal("clean_env: %s in: %s", err, *cpp);
|
||||||
|
argv_add(save_list, key, val, (char *) 0);
|
||||||
|
myfree(copy);
|
||||||
|
} else if ((value = safe_getenv(*cpp)) != 0) {
|
||||||
argv_add(save_list, *cpp, value, (char *) 0);
|
argv_add(save_list, *cpp, value, (char *) 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Truncate the process environment, if available. On some systems
|
* Truncate the process environment, if available. On some systems
|
||||||
@@ -103,16 +112,25 @@ void update_env(char **preserve_list)
|
|||||||
{
|
{
|
||||||
char **cpp;
|
char **cpp;
|
||||||
ARGV *save_list;
|
ARGV *save_list;
|
||||||
char *eq;
|
char *copy;
|
||||||
|
char *key;
|
||||||
|
char *val;
|
||||||
|
const char *err;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extract name=value settings.
|
* Extract name=value settings.
|
||||||
*/
|
*/
|
||||||
save_list = argv_alloc(10);
|
save_list = argv_alloc(10);
|
||||||
for (cpp = preserve_list; *cpp; cpp++)
|
for (cpp = preserve_list; *cpp; cpp++) {
|
||||||
if ((eq = strchr(*cpp, '=')) != 0)
|
if (strchr(*cpp, '=') != 0) {
|
||||||
argv_addn(save_list, STRING_AND_LENGTH(*cpp, eq - *cpp),
|
copy = mystrdup(*cpp);
|
||||||
STRING_AND_LENGTH(eq + 1, strlen(eq + 1)), (char *) 0);
|
err = split_nameval(copy, &key, &val);
|
||||||
|
if (err != 0)
|
||||||
|
msg_fatal("update_env: %s in: %s", err, *cpp);
|
||||||
|
argv_add(save_list, key, val, (char *) 0);
|
||||||
|
myfree(copy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Apply name=value settings.
|
* Apply name=value settings.
|
||||||
|
@@ -81,7 +81,7 @@ const char *split_nameval(char *buf, char **name, char **value)
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
SKIP(buf, np, ISSPACE(*np)); /* find name begin */
|
SKIP(buf, np, ISSPACE(*np)); /* find name begin */
|
||||||
if (*np == 0)
|
if (*np == 0 || *np == '=')
|
||||||
return ("missing attribute name");
|
return ("missing attribute name");
|
||||||
SKIP(np, ep, !ISSPACE(*ep) && *ep != '='); /* find name end */
|
SKIP(np, ep, !ISSPACE(*ep) && *ep != '='); /* find name end */
|
||||||
SKIP(ep, cp, ISSPACE(*cp)); /* skip blanks before '=' */
|
SKIP(ep, cp, ISSPACE(*cp)); /* skip blanks before '=' */
|
||||||
|
Reference in New Issue
Block a user