Prereq: "3.7.4" diff -ur --new-file /var/tmp/postfix-3.7.4/src/global/mail_version.h ./src/global/mail_version.h --- /var/tmp/postfix-3.7.4/src/global/mail_version.h 2023-01-21 16:15:12.000000000 -0500 +++ ./src/global/mail_version.h 2023-04-17 18:42:51.000000000 -0400 @@ -20,8 +20,8 @@ * 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_VERSION_NUMBER "3.7.4" +#define MAIL_RELEASE_DATE "20230418" +#define MAIL_VERSION_NUMBER "3.7.5" #ifdef SNAPSHOT #define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE diff -ur --new-file /var/tmp/postfix-3.7.4/HISTORY ./HISTORY --- /var/tmp/postfix-3.7.4/HISTORY 2023-01-21 16:05:10.000000000 -0500 +++ ./HISTORY 2023-04-18 15:42:17.000000000 -0400 @@ -26468,3 +26468,42 @@ 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. + +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. + +20230314 + + Bugfix (introduced: Postfix 3.5): check_ccert_access did + not parse inline map specifications. Report and fix by Sean + Gallagher. File: global/map_search.c. + +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. diff -ur --new-file /var/tmp/postfix-3.7.4/postfix-env.sh ./postfix-env.sh --- /var/tmp/postfix-3.7.4/postfix-env.sh 2014-06-25 12:58:34.000000000 -0400 +++ ./postfix-env.sh 2023-01-28 10:55:58.000000000 -0500 @@ -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 "$@" diff -ur --new-file /var/tmp/postfix-3.7.4/src/global/dict_mysql.c ./src/global/dict_mysql.c --- /var/tmp/postfix-3.7.4/src/global/dict_mysql.c 2018-08-25 19:10:33.000000000 -0400 +++ ./src/global/dict_mysql.c 2023-04-18 15:38:40.000000000 -0400 @@ -528,7 +528,7 @@ { HOST *host; MYSQL_RES *first_result = 0; - int query_error; + int query_error = 1; /* * Helper to avoid spamming the log with warnings. diff -ur --new-file /var/tmp/postfix-3.7.4/src/global/map_search.c ./src/global/map_search.c --- /var/tmp/postfix-3.7.4/src/global/map_search.c 2022-10-07 14:17:09.000000000 -0400 +++ ./src/global/map_search.c 2023-03-14 19:41:45.000000000 -0400 @@ -158,7 +158,8 @@ if ((heap_err = extpar(&bp, CHARS_BRACE, EXTPAR_FLAG_STRIP)) != 0) { msg_warn("malformed map specification: '%s'", heap_err); MAP_SEARCH_CREATE_RETURN(0); - } else if ((map_type_name = mystrtok(&bp, CHARS_COMMA_SP)) == 0) { + } else if ((map_type_name = mystrtokq(&bp, CHARS_COMMA_SP, + CHARS_BRACE)) == 0) { msg_warn("empty map specification: '%s'", map_spec); MAP_SEARCH_CREATE_RETURN(0); } @@ -308,6 +309,7 @@ {"{type:name {search_order=one, two}}", 1, "type:name", "\01\02"}, {"{type:name {search_order=one, two, bad}}", 0, 0, 0}, {"{inline:{a=b} {search_order=one, two}}", 1, "inline:{a=b}", "\01\02"}, + {"{inline:{a=b, c=d} {search_order=one, two}}", 1, "inline:{a=b, c=d}", "\01\02"}, {0}, }; TEST_CASE *test_case; diff -ur --new-file /var/tmp/postfix-3.7.4/src/posttls-finger/posttls-finger.c ./src/posttls-finger/posttls-finger.c --- /var/tmp/postfix-3.7.4/src/posttls-finger/posttls-finger.c 2021-12-20 17:11:22.000000000 -0500 +++ ./src/posttls-finger/posttls-finger.c 2023-01-27 15:55:23.000000000 -0500 @@ -941,9 +941,9 @@ 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); } diff -ur --new-file /var/tmp/postfix-3.7.4/src/tls/tls_server.c ./src/tls/tls_server.c --- /var/tmp/postfix-3.7.4/src/tls/tls_server.c 2023-01-21 16:00:03.000000000 -0500 +++ ./src/tls/tls_server.c 2023-01-27 17:01:19.000000000 -0500 @@ -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 @@ #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 @@ 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 @@ 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 @@ 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 @@ 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 @@ * 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 @@ #endif if (!ticketable) off |= SSL_OP_NO_TICKET; -#endif SSL_CTX_set_options(server_ctx, off); diff -ur --new-file /var/tmp/postfix-3.7.4/src/util/clean_env.c ./src/util/clean_env.c --- /var/tmp/postfix-3.7.4/src/util/clean_env.c 2017-12-27 17:29:45.000000000 -0500 +++ ./src/util/clean_env.c 2023-04-17 15:45:56.000000000 -0400 @@ -50,9 +50,11 @@ /* Utility library. */ #include +#include #include #include #include +#include /* clean_env - clean up the environment */ @@ -62,20 +64,27 @@ ARGV *save_list; char *value; char **cpp; - char *eq; + char *copy; + char *key; + char *val; + const char *err; /* * Preserve or specify selected environment variables. */ -#define STRING_AND_LENGTH(x, y) (x), (ssize_t) (y) - save_list = argv_alloc(10); - for (cpp = preserve_list; *cpp; cpp++) - if ((eq = strchr(*cpp, '=')) != 0) - argv_addn(save_list, STRING_AND_LENGTH(*cpp, eq - *cpp), - STRING_AND_LENGTH(eq + 1, strlen(eq + 1)), (char *) 0); - else if ((value = safe_getenv(*cpp)) != 0) + for (cpp = preserve_list; *cpp; cpp++) { + if (strchr(*cpp, '=') != 0) { + copy = mystrdup(*cpp); + err = split_nameval(copy, &key, &val); + 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); + } + } /* * Truncate the process environment, if available. On some systems @@ -103,16 +112,25 @@ { char **cpp; ARGV *save_list; - char *eq; + char *copy; + char *key; + char *val; + const char *err; /* * Extract name=value settings. */ save_list = argv_alloc(10); - for (cpp = preserve_list; *cpp; cpp++) - if ((eq = strchr(*cpp, '=')) != 0) - argv_addn(save_list, STRING_AND_LENGTH(*cpp, eq - *cpp), - STRING_AND_LENGTH(eq + 1, strlen(eq + 1)), (char *) 0); + for (cpp = preserve_list; *cpp; cpp++) { + if (strchr(*cpp, '=') != 0) { + copy = mystrdup(*cpp); + 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. diff -ur --new-file /var/tmp/postfix-3.7.4/src/util/split_nameval.c ./src/util/split_nameval.c --- /var/tmp/postfix-3.7.4/src/util/split_nameval.c 2013-11-07 17:06:23.000000000 -0500 +++ ./src/util/split_nameval.c 2023-04-17 15:45:56.000000000 -0400 @@ -81,7 +81,7 @@ } while (0) SKIP(buf, np, ISSPACE(*np)); /* find name begin */ - if (*np == 0) + if (*np == 0 || *np == '=') return ("missing attribute name"); SKIP(np, ep, !ISSPACE(*ep) && *ep != '='); /* find name end */ SKIP(ep, cp, ISSPACE(*cp)); /* skip blanks before '=' */