Prereq: "3.4.27" diff -ur --new-file /var/tmp/postfix-3.4.27/src/global/mail_version.h ./src/global/mail_version.h --- /var/tmp/postfix-3.4.27/src/global/mail_version.h 2022-10-07 17:04:37.000000000 -0400 +++ ./src/global/mail_version.h 2023-01-21 15:31:24.000000000 -0500 @@ -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 "20221007" -#define MAIL_VERSION_NUMBER "3.4.27" +#define MAIL_RELEASE_DATE "20230121" +#define MAIL_VERSION_NUMBER "3.4.28" #ifdef SNAPSHOT #define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE diff -ur --new-file /var/tmp/postfix-3.4.27/HISTORY ./HISTORY --- /var/tmp/postfix-3.4.27/HISTORY 2022-10-07 17:00:18.000000000 -0400 +++ ./HISTORY 2023-01-21 15:34:23.000000000 -0500 @@ -24818,3 +24818,62 @@ Cleanup: Postfix 3.4.26 introduced a missing msg_panic() argument (in code that never executes). File: cleanup/cleanup_milter.c. + +20221128 + + Bugfix (introduced: Postfix 2.2): the smtpd_proxy_client + code mis-parsed the last XFORWARD attribute name in the + SMTP server's EHLO response. The result was that the + smtpd_proxy_client code failed to forward the IDENT attribute. + Fix by Andreas Weigel. File: smtpd/smtpd_proxy.c. + +20221201 + + Portability: LINUX6 support. Files: makedefs, util/sys_defs.h. + +20221207 + + Workaround: OpenSSL 3.x EVP_get_digestbyname() can return + lazily bound handles that may fail to work when one attempts + to use them, because no provider search happens until one + constructs an actual operation context. In sufficiently + hostile configurations, Postfix could mistakenly believe + that an algorithm is available, when in fact it is not. A + similar workaround may be needed for EVP_get_cipherbyname(). + Fix by Viktor Dukhovni. Files: tls/tls.h, tls/tls_dane.c, + tls/tls_fprint.c, tls/tls_misc.c. + + Bugfix (introduced: Postfix 2.11): the checkok() macro in + tls/tls_fprint.c evaluated its argument unconditionally; + it should evaluate the argument only if there was no prior + error. Found during code review. File: tls/tls_fprint.c. + +20221215 + + Foolproofing: postscreen segfault with postscreen_dnsbl_threshold + < 1. It should reject such input with a fatal error instead. + Discovered by Benny Pedersen. File: postscreen/postscreen.c. + +20230103 + + Bugfix (introduced: Postfix 2.7): the verify daemon logged + a garbled cache name when terminating a cache scan in + progress. Reported by Phil Biggs, fix by Viktor Dukhovni. + File: util/dict_cache.c. + + Bitrot: fixes for linker warnings from newer Darwin (MacOS) + versions. Viktor Dukhovni. File: makedefs. + +20230115 + + Workaround: STRREF() macro to shut up compiler warnings for + legitimate string comparison expressions. Back-ported from + Postfix 3.6 and later. Files: util/stringops.h, flush/flush.c. + + 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 + safe because the SMTP protocol implements application-level + 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. diff -ur --new-file /var/tmp/postfix-3.4.27/makedefs ./makedefs --- /var/tmp/postfix-3.4.27/makedefs 2021-01-16 18:36:30.000000000 -0500 +++ ./makedefs 2023-01-21 09:03:42.000000000 -0500 @@ -557,7 +557,7 @@ : ${SHLIB_ENV="LD_LIBRARY_PATH=`pwd`/lib"} : ${PLUGIN_LD="${CC-gcc} -shared"} ;; - Linux.[345].*) SYSTYPE=LINUX$RELEASE_MAJOR +Linux.[3456].*) SYSTYPE=LINUX$RELEASE_MAJOR case "$CCARGS" in *-DNO_DB*) ;; *-DHAS_DB*) ;; @@ -699,6 +699,12 @@ ?.*|10.*) ;; *) SYSLIBS="$SYSLIBS -lresolv";; esac + # Darwin 21 linker without additional coaxing complains about + # -Wl,-undefined,dynamic_lookup + case $RELEASE in + 2[1-9].*|[3-9]?.*) NOFIXUP="-Wl,-no_fixup_chains ";; + *) NOFIXUP="";; + esac # kqueue and/or poll are broken in MacOS X 10.5 (Darwin 9). # kqueue works in Mac OS X 10.8 (Darwin 12). case $RELEASE in @@ -706,12 +712,12 @@ esac : ${SHLIB_CFLAGS=-fPIC} : ${SHLIB_SUFFIX=.dylib} - : ${SHLIB_LD='cc -shared -Wl,-flat_namespace -Wl,-undefined,dynamic_lookup -Wl,-install_name,@rpath/${LIB}'} + : ${SHLIB_LD="cc -shared -Wl,-flat_namespace ${NOFIXUP}-Wl,-undefined,dynamic_lookup "'-Wl,-install_name,@rpath/${LIB}'} : ${SHLIB_RPATH='-Wl,-rpath,${SHLIB_DIR}'} # In MacOS/X 10.11.x /bin/sh unsets DYLD_LIBRARY_PATH, so we # have export it into postfix-install indirectly! : ${SHLIB_ENV="DYLD_LIBRARY_PATH=`pwd`/lib SHLIB_ENV_VAR=DYLD_LIBRARY_PATH SHLIB_ENV_VAL=`pwd`/lib"} - : ${PLUGIN_LD='cc -shared -Wl,-flat_namespace -Wl,-undefined,dynamic_lookup'} + : ${PLUGIN_LD="cc -shared -Wl,-flat_namespace ${NOFIXUP}-Wl,-undefined,dynamic_lookup"} ;; dcosx.1*) SYSTYPE=DCOSX1 RANLIB=echo diff -ur --new-file /var/tmp/postfix-3.4.27/src/flush/flush.c ./src/flush/flush.c --- /var/tmp/postfix-3.4.27/src/flush/flush.c 2019-02-03 13:52:36.000000000 -0500 +++ ./src/flush/flush.c 2023-01-15 17:31:40.000000000 -0500 @@ -229,7 +229,7 @@ * Silly little macros. */ #define STR(x) vstring_str(x) -#define STREQ(x,y) ((x) == (y) || strcmp(x,y) == 0) +#define STREQ(x,y) (STRREF(x) == STRREF(y) || strcmp(x,y) == 0) /* * Forward declarations resulting from breaking up routines according to diff -ur --new-file /var/tmp/postfix-3.4.27/src/postscreen/postscreen.c ./src/postscreen/postscreen.c --- /var/tmp/postfix-3.4.27/src/postscreen/postscreen.c 2019-02-03 14:01:19.000000000 -0500 +++ ./src/postscreen/postscreen.c 2023-01-21 09:02:19.000000000 -0500 @@ -1136,7 +1136,7 @@ 0, }; static const CONFIG_INT_TABLE int_table[] = { - VAR_PSC_DNSBL_THRESH, DEF_PSC_DNSBL_THRESH, &var_psc_dnsbl_thresh, 0, 0, + VAR_PSC_DNSBL_THRESH, DEF_PSC_DNSBL_THRESH, &var_psc_dnsbl_thresh, 1, 0, VAR_PSC_DNSBL_WTHRESH, DEF_PSC_DNSBL_WTHRESH, &var_psc_dnsbl_wthresh, 0, 0, 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, diff -ur --new-file /var/tmp/postfix-3.4.27/src/smtpd/smtpd_proxy.c ./src/smtpd/smtpd_proxy.c --- /var/tmp/postfix-3.4.27/src/smtpd/smtpd_proxy.c 2015-01-29 08:40:49.000000000 -0500 +++ ./src/smtpd/smtpd_proxy.c 2022-12-11 16:49:17.000000000 -0500 @@ -388,7 +388,7 @@ */ server_xforward_features = 0; lines = STR(proxy->reply); - while ((words = mystrtok(&lines, "\n")) != 0) { + while ((words = mystrtok(&lines, "\r\n")) != 0) { if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t")) != 0) { if (strcasecmp(word, XFORWARD_CMD) == 0) while ((word = mystrtok(&words, " \t")) != 0) diff -ur --new-file /var/tmp/postfix-3.4.27/src/tls/tls.h ./src/tls/tls.h --- /var/tmp/postfix-3.4.27/src/tls/tls.h 2019-02-18 18:03:54.000000000 -0500 +++ ./src/tls/tls.h 2023-01-21 16:00:03.000000000 -0500 @@ -415,6 +415,13 @@ #define SSL_OP_NO_TLSv1_3 0L /* Noop */ #endif +/* + * Always used when defined, SMTP has no truncation attacks. + */ +#ifndef SSL_OP_IGNORE_UNEXPECTED_EOF +#define SSL_OP_IGNORE_UNEXPECTED_EOF 0L +#endif + #define TLS_KNOWN_PROTOCOLS \ ( TLS_PROTOCOL_SSLv2 | TLS_PROTOCOL_SSLv3 | TLS_PROTOCOL_TLSv1 \ | TLS_PROTOCOL_TLSv1_1 | TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3 ) @@ -431,7 +438,8 @@ * just exposed via hex codes or named elements of tls_ssl_options. */ #define TLS_SSL_OP_MANAGED_BITS \ - (SSL_OP_CIPHER_SERVER_PREFERENCE | TLS_SSL_OP_PROTOMASK(~0)) + (SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_IGNORE_UNEXPECTED_EOF | \ + TLS_SSL_OP_PROTOMASK(~0)) extern int tls_protocol_mask(const char *); @@ -679,6 +687,7 @@ /* * tls_fprint.c */ +extern const EVP_MD *tls_digest_byname(const char *, EVP_MD_CTX **); extern char *tls_digest_encode(const unsigned char *, int); extern char *tls_data_fprint(const char *, int, const char *); extern char *tls_cert_fprint(X509 *, const char *); diff -ur --new-file /var/tmp/postfix-3.4.27/src/tls/tls_client.c ./src/tls/tls_client.c --- /var/tmp/postfix-3.4.27/src/tls/tls_client.c 2020-07-24 19:47:04.000000000 -0400 +++ ./src/tls/tls_client.c 2023-01-21 16:00:03.000000000 -0500 @@ -403,6 +403,15 @@ SSL_CTX_set_verify_depth(client_ctx, props->verifydepth + 1); /* + * Presently we use TLS only with SMTP where truncation attacks are not + * possible as a result of application framing. If we ever use TLS in + * some other application protocol where truncation could be relevant, + * we'd need to disable truncation detection conditionally, or explicitly + * clear the option in that code path. + */ + off |= SSL_OP_IGNORE_UNEXPECTED_EOF; + + /* * Protocol selection is destination dependent, so we delay the protocol * selection options to the per-session SSL object. */ diff -ur --new-file /var/tmp/postfix-3.4.27/src/tls/tls_dane.c ./src/tls/tls_dane.c --- /var/tmp/postfix-3.4.27/src/tls/tls_dane.c 2019-03-10 15:26:20.000000000 -0400 +++ ./src/tls/tls_dane.c 2023-01-21 09:00:10.000000000 -0500 @@ -344,7 +344,7 @@ } if (*dane_mdalg - && ((md = EVP_get_digestbyname(dane_mdalg)) == 0 + && ((md = tls_digest_byname(dane_mdalg, NULL)) == 0 || (mdlen = EVP_MD_size(md)) <= 0 || mdlen > EVP_MAX_MD_SIZE)) { msg_warn("Unimplemented digest algorithm in %s: %s%s%s", diff -ur --new-file /var/tmp/postfix-3.4.27/src/tls/tls_fprint.c ./src/tls/tls_fprint.c --- /var/tmp/postfix-3.4.27/src/tls/tls_fprint.c 2015-10-31 20:24:04.000000000 -0400 +++ ./src/tls/tls_fprint.c 2023-01-21 09:00:46.000000000 -0500 @@ -6,6 +6,10 @@ /* SYNOPSIS /* #include /* +/* EVP_MD *tls_digest_byname(const char *mdalg, EVP_MD_CTX **mdctxPtr) +/* const char *mdalg; +/* EVP_MD_CTX **mdctxPtr; +/* /* char *tls_serverid_digest(props, protomask, ciphers) /* const TLS_CLIENT_START_PROPS *props; /* long protomask; @@ -28,6 +32,13 @@ /* X509 *peercert; /* const char *mdalg; /* DESCRIPTION +/* tls_digest_byname() constructs, and optionally returns, an EVP_MD_CTX +/* handle for performing digest operations with the algorithm named by the +/* mdalg parameter. The return value is non-null on success, and holds a +/* digest algorithm handle. If the mdctxPtr argument is non-null the +/* created context is returned to the caller, who is then responsible for +/* deleting it by calling EVP_MD_ctx_free() once it is no longer needed. +/* /* tls_digest_encode() converts a binary message digest to a hex ASCII /* format with ':' separators between each pair of hex digits. /* The return value is dynamically allocated with mymalloc(), @@ -61,6 +72,8 @@ /* and the caller must eventually free it with myfree(). /* /* Arguments: +/* .IP mdalg +/* A digest algorithm name, such as "sha256". /* .IP peercert /* Server or client X.509 certificate. /* .IP md_buf @@ -71,6 +84,9 @@ /* Name of a message digest algorithm suitable for computing secure /* (1st pre-image resistant) message digests of certificates. For now, /* md5, sha1, or member of SHA-2 family if supported by OpenSSL. +/* .IP mdctxPtr +/* Pointer to an (EVP_MD_CTX *) handle, or NULL if only probing for +/* algorithm support without immediate use in mind. /* .IP buf /* Input data for the message digest algorithm mdalg. /* .IP len @@ -125,7 +141,7 @@ static const char hexcodes[] = "0123456789ABCDEF"; -#define checkok(ret) (ok &= ((ret) ? 1 : 0)) +#define checkok(stillok) (ok = ok && (stillok)) #define digest_data(p, l) checkok(EVP_DigestUpdate(mdctx, (char *)(p), (l))) #define digest_object(p) digest_data((p), sizeof(*(p))) #define digest_string(s) digest_data((s), strlen(s)+1) @@ -159,13 +175,50 @@ return (ok); } +/* tls_digest_byname - test availability or prepare to use digest */ + +const EVP_MD *tls_digest_byname(const char *mdalg, EVP_MD_CTX **mdctxPtr) +{ + const EVP_MD *md; + EVP_MD_CTX *mdctx = NULL; + int ok = 1; + + /* + * In OpenSSL 3.0, because of dynamically variable algorithm providers, + * there is a time-of-check/time-of-use issue that means that abstract + * algorithm handles returned by EVP_get_digestbyname() can (and not + * infrequently do) return ultimately unusable algorithms, to check for + * actual availability, one needs to use the new EVP_MD_fetch() API, or + * indirectly check usability by creating a concrete context. We take the + * latter approach here (works for 1.1.1 without #ifdef). + * + * Note that EVP_MD_CTX_{create,destroy} were renamed to, respectively, + * EVP_MD_CTX_{new,free} in OpenSSL 1.1.0. + */ + checkok(md = EVP_get_digestbyname(mdalg)); + + /* + * Sanity check: Newer shared libraries could (hypothetical ABI break) + * allow larger digests, we avoid such poison algorithms. + */ + checkok(EVP_MD_size(md) <= EVP_MAX_MD_SIZE); + checkok(mdctx = EVP_MD_CTX_new()); + checkok(EVP_DigestInit_ex(mdctx, md, NULL)); + + + if (ok && mdctxPtr != 0) + *mdctxPtr = mdctx; + else + EVP_MD_CTX_free(mdctx); + return (ok ? md : 0); +} + /* tls_serverid_digest - suffix props->serverid with parameter digest */ char *tls_serverid_digest(const TLS_CLIENT_START_PROPS *props, long protomask, const char *ciphers) { EVP_MD_CTX *mdctx; - const EVP_MD *md; const char *mdalg; unsigned char md_buf[EVP_MAX_MD_SIZE]; unsigned int md_len; @@ -181,17 +234,17 @@ * default digest, but DANE requires sha256 and sha512, so if we must * fall back to our default digest, DANE support won't be available. We * panic if the fallback algorithm is not available, as it was verified - * available in tls_client_init() and must not simply vanish. + * available in tls_client_init() and must not simply vanish. Our + * provider set is not expected to change once the OpenSSL library is + * initialized. */ - if ((md = EVP_get_digestbyname(mdalg = "sha256")) == 0 - && (md = EVP_get_digestbyname(mdalg = props->mdalg)) == 0) - msg_panic("digest algorithm \"%s\" not found", mdalg); + if (tls_digest_byname(mdalg = LN_sha256, &mdctx) == 0 + && tls_digest_byname(mdalg = props->mdalg, &mdctx) == 0) + msg_panic("digest algorithm \"%s\" not found", props->mdalg); /* Salt the session lookup key with the OpenSSL runtime version. */ sslversion = OpenSSL_version_num(); - mdctx = EVP_MD_CTX_create(); - checkok(EVP_DigestInit_ex(mdctx, md, NULL)); digest_string(props->helo ? props->helo : ""); digest_object(&sslversion); digest_object(&protomask); @@ -284,18 +337,15 @@ char *tls_data_fprint(const char *buf, int len, const char *mdalg) { - EVP_MD_CTX *mdctx; - const EVP_MD *md; + EVP_MD_CTX *mdctx = NULL; unsigned char md_buf[EVP_MAX_MD_SIZE]; unsigned int md_len; int ok = 1; /* Previously available in "init" routine. */ - if ((md = EVP_get_digestbyname(mdalg)) == 0) + if (tls_digest_byname(mdalg, &mdctx) == 0) msg_panic("digest algorithm \"%s\" not found", mdalg); - mdctx = EVP_MD_CTX_create(); - checkok(EVP_DigestInit_ex(mdctx, md, NULL)); digest_data(buf, len); checkok(EVP_DigestFinal_ex(mdctx, md_buf, &md_len)); EVP_MD_CTX_destroy(mdctx); diff -ur --new-file /var/tmp/postfix-3.4.27/src/tls/tls_misc.c ./src/tls/tls_misc.c --- /var/tmp/postfix-3.4.27/src/tls/tls_misc.c 2021-08-11 15:09:56.000000000 -0400 +++ ./src/tls/tls_misc.c 2023-01-21 09:00:10.000000000 -0500 @@ -1516,7 +1516,6 @@ int tls_validate_digest(const char *dgst) { const EVP_MD *md_alg; - unsigned int md_len; /* * Register SHA-2 digests, if implemented and not already registered. @@ -1524,15 +1523,15 @@ * deploy SHA-2 certificates. Also facilitates DANE and TA support. */ #if defined(LN_sha256) && defined(NID_sha256) && !defined(OPENSSL_NO_SHA256) - if (!EVP_get_digestbyname(LN_sha224)) + if (!tls_digest_byname(LN_sha224, NULL)) EVP_add_digest(EVP_sha224()); - if (!EVP_get_digestbyname(LN_sha256)) + if (!tls_digest_byname(LN_sha256, NULL)) EVP_add_digest(EVP_sha256()); #endif #if defined(LN_sha512) && defined(NID_sha512) && !defined(OPENSSL_NO_SHA512) - if (!EVP_get_digestbyname(LN_sha384)) + if (!tls_digest_byname(LN_sha384, NULL)) EVP_add_digest(EVP_sha384()); - if (!EVP_get_digestbyname(LN_sha512)) + if (!tls_digest_byname(LN_sha512, NULL)) EVP_add_digest(EVP_sha512()); #endif @@ -1540,19 +1539,10 @@ * If the administrator specifies an unsupported digest algorithm, fail * now, rather than in the middle of a TLS handshake. */ - if ((md_alg = EVP_get_digestbyname(dgst)) == 0) { + if ((md_alg = tls_digest_byname(dgst, NULL)) == 0) { msg_warn("Digest algorithm \"%s\" not found", dgst); return (0); } - - /* - * Sanity check: Newer shared libraries may use larger digests. - */ - if ((md_len = EVP_MD_size(md_alg)) > EVP_MAX_MD_SIZE) { - msg_warn("Digest algorithm \"%s\" output size %u too large", - dgst, md_len); - return (0); - } return (1); } diff -ur --new-file /var/tmp/postfix-3.4.27/src/tls/tls_server.c ./src/tls/tls_server.c --- /var/tmp/postfix-3.4.27/src/tls/tls_server.c 2022-10-07 16:58:44.000000000 -0400 +++ ./src/tls/tls_server.c 2023-01-21 16:00:03.000000000 -0500 @@ -478,6 +478,15 @@ cachable = 0; /* + * Presently we use TLS only with SMTP where truncation attacks are not + * possible as a result of application framing. If we ever use TLS in + * some other application protocol where truncation could be relevant, + * we'd need to disable truncation detection conditionally, or explicitly + * clear the option in that code path. + */ + off |= SSL_OP_IGNORE_UNEXPECTED_EOF; + + /* * Protocol work-arounds, OpenSSL version dependent. */ off |= tls_bug_bits(); diff -ur --new-file /var/tmp/postfix-3.4.27/src/util/dict_cache.c ./src/util/dict_cache.c --- /var/tmp/postfix-3.4.27/src/util/dict_cache.c 2014-12-25 11:47:17.000000000 -0500 +++ ./src/util/dict_cache.c 2023-01-03 08:09:55.000000000 -0500 @@ -659,8 +659,8 @@ /* * Destroy the DICT_CACHE object. */ - myfree(cp->name); dict_cache_control(cp, DICT_CACHE_CTL_INTERVAL, 0, DICT_CACHE_CTL_END); + myfree(cp->name); dict_close(cp->db); if (cp->saved_curr_key) myfree(cp->saved_curr_key); diff -ur --new-file /var/tmp/postfix-3.4.27/src/util/stringops.h ./src/util/stringops.h --- /var/tmp/postfix-3.4.27/src/util/stringops.h 2019-04-10 17:23:22.000000000 -0400 +++ ./src/util/stringops.h 2023-01-15 17:29:12.000000000 -0500 @@ -80,6 +80,12 @@ #define strncasecmp_utf8(s1, s2, l) \ strncasecmp_utf8x(util_utf8_enable ? CASEF_FLAG_UTF8 : 0, (s1), (s2), (l)) + /* + * Use STRREF(x) instead of x, to shut up compiler warnings when the operand + * is a string literal. + */ +#define STRREF(x) (&x[0]) + /* LICENSE /* .ad /* .fi diff -ur --new-file /var/tmp/postfix-3.4.27/src/util/sys_defs.h ./src/util/sys_defs.h --- /var/tmp/postfix-3.4.27/src/util/sys_defs.h 2022-01-30 18:24:18.000000000 -0500 +++ ./src/util/sys_defs.h 2022-12-01 19:31:47.000000000 -0500 @@ -749,7 +749,8 @@ /* * LINUX. */ -#if defined(LINUX2) || defined(LINUX3) || defined(LINUX4) || defined(LINUX5) +#if defined(LINUX2) || defined(LINUX3) || defined(LINUX4) || defined(LINUX5) \ + || defined(LINUX6) #define SUPPORTED #define UINT32_TYPE unsigned int #define UINT16_TYPE unsigned short