Prereq: "3.7.16" diff -ur --new-file /var/tmp/postfix-3.7.16/src/global/mail_version.h ./src/global/mail_version.h --- /var/tmp/postfix-3.7.16/src/global/mail_version.h 2025-08-18 16:52:22.000000000 -0400 +++ ./src/global/mail_version.h 2025-10-26 18:27:03.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 "20250818" -#define MAIL_VERSION_NUMBER "3.7.16" +#define MAIL_RELEASE_DATE "20251026" +#define MAIL_VERSION_NUMBER "3.7.17" #ifdef SNAPSHOT #define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE diff -ur --new-file /var/tmp/postfix-3.7.16/HISTORY ./HISTORY --- /var/tmp/postfix-3.7.16/HISTORY 2025-08-18 16:52:49.000000000 -0400 +++ ./HISTORY 2025-10-23 20:05:33.000000000 -0400 @@ -26962,3 +26962,54 @@ role disabled by configuration, the tlsproxy daemon dereferenced a null pointer while handling a tlsproxy client request. Reported by John Doe. File: tlsproxy/tlsproxy.c. + +20250816 + + Bugfix (defect introduced: Postfix 3.0, date 20140731): the + smtpd 'disconnect' command counts did not count malformed + commands with "bad syntax" and "bad UTF-8 syntax" errors. + File: smtpd/smtpd.c. + +20250819 + + Bugfix: the 20250717 workaround broke DBM library support + which is still needed on Solaris. File: util/dict_dbm.c. + +20250829 + + Postfix 3.11 forward compatibility: allow a partial 'size' + record in maildrop queue files created with Postfix 3.11 + or later, instead of logging an ugly warning. Files: + showq/showq.c, postcat/postcat.c. + +20250911 + + Bugfix (defect introduced: Postfix 3.0): the Postfix SMTP + client's connection reuse logic did not distinguish between + sessions that require SMTPUTF8 support, and sessions that + do not. The solution is to store sessions with different + SMTPUTF8 requirements under distinct connection cache storage + keys, and to preserve the availability of SMTPUTF8 support + in the connection cache, so that a reused connection will + be stored under the same keys as it was looked up with. + Finally, do not cache a connection when SMTPUTF8 is + required but the server does not support that feature. + Files: smtp/smtp.h, smtp/smtp_key.c, smtp/smtp_proto.c. + +20250919 + + Bugfix (defect introduced: Postfix 3.8, date 20220128): the + 'postconf -e' output order for new main.cf entries was no + longer deterministic. Problem reported by Oleksandr Natalenko, + diagnosis by Eray Aslan. File: postconf/postconf_edit.c. + + Add missing meta_directory and shlib_directory settings to + the stock main.cf file. Problem diagnosed by Eray Aslan. + File: conf/main.cf. + +20251021 + + Cleanup: the change at 20250717 could result in warnings + with "database X is older than source file Y". Files: + util/dict.c, util/dict_db.c, util/dict_dbm.c, util/dict_lmdb.c, + util/dict_sdbm.c. diff -ur --new-file /var/tmp/postfix-3.7.16/conf/main.cf ./conf/main.cf --- /var/tmp/postfix-3.7.16/conf/main.cf 2021-12-22 17:49:37.000000000 -0500 +++ ./conf/main.cf 2025-10-23 20:04:12.000000000 -0400 @@ -683,3 +683,5 @@ # readme_directory = inet_protocols = ipv4 +shlib_directory = /usr/lib/postfix/${mail_version} +meta_directory = /etc/postfix diff -ur --new-file /var/tmp/postfix-3.7.16/src/postcat/postcat.c ./src/postcat/postcat.c --- /var/tmp/postfix-3.7.16/src/postcat/postcat.c 2021-11-27 12:12:31.000000000 -0500 +++ ./src/postcat/postcat.c 2025-10-23 20:04:12.000000000 -0400 @@ -339,6 +339,10 @@ /* Optional output (here before we update the state machine). */ if (do_print) PRINT_RECORD(flags, offset, rec_type, STR(buffer)); + /* Postfix 3.11 maildrop files may have preliminary SIZE record. */ + if (strncmp(VSTREAM_PATH(fp), MAIL_QUEUE_MAILDROP "/", + sizeof(MAIL_QUEUE_MAILDROP)) == 0) + continue; /* Read the message size/offset for the state machine optimizer. */ if (data_size >= 0 || data_offset >= 0) { msg_warn("file contains multiple size records"); diff -ur --new-file /var/tmp/postfix-3.7.16/src/postconf/postconf_edit.c ./src/postconf/postconf_edit.c --- /var/tmp/postfix-3.7.16/src/postconf/postconf_edit.c 2025-04-22 11:00:40.000000000 -0400 +++ ./src/postconf/postconf_edit.c 2025-10-23 20:04:12.000000000 -0400 @@ -66,6 +66,7 @@ /* System library. */ #include +#include #include #include @@ -148,6 +149,16 @@ } } +/* pcf_cmp_ht_key - qsort helper for ht_info pointer array */ + +static int pcf_cmp_ht_key(const void *a, const void *b) +{ + HTABLE_INFO **ap = (HTABLE_INFO **) a; + HTABLE_INFO **bp = (HTABLE_INFO **) b; + + return (strcmp(ap[0]->key, bp[0]->key)); +} + /* pcf_edit_main - edit main.cf file */ void pcf_edit_main(int mode, int argc, char **argv) @@ -263,7 +274,9 @@ * Generate new entries for parameters that were not found. */ if (mode & PCF_EDIT_CONF) { - for (ht_info = ht = htable_list(table); *ht; ht++) { + ht_info = htable_list(table); + qsort((void *) ht_info, table->used, sizeof(*ht_info), pcf_cmp_ht_key); + for (ht = ht_info; *ht; ht++) { cvalue = (struct cvalue *) ht[0]->value; if (cvalue->found == 0) vstream_fprintf(dst, "%s = %s\n", ht[0]->key, cvalue->value); diff -ur --new-file /var/tmp/postfix-3.7.16/src/showq/showq.c ./src/showq/showq.c --- /var/tmp/postfix-3.7.16/src/showq/showq.c 2020-09-19 17:40:12.000000000 -0400 +++ ./src/showq/showq.c 2025-10-23 20:04:12.000000000 -0400 @@ -213,7 +213,8 @@ arrival_time = atol(start); break; case REC_TYPE_SIZE: - if (msg_size_ok == 0) { + /* Postfix 3.11 maildrop files may have preliminary SIZE record. */ + if (msg_size_ok == 0 && strcmp(queue, MAIL_QUEUE_MAILDROP) != 0) { msg_size_ok = (start[strspn(start, "0123456789 ")] == 0 && (msg_size = atol(start)) >= 0); if (msg_size_ok == 0) { diff -ur --new-file /var/tmp/postfix-3.7.16/src/smtp/smtp.h ./src/smtp/smtp.h --- /var/tmp/postfix-3.7.16/src/smtp/smtp.h 2023-09-01 09:01:13.000000000 -0400 +++ ./src/smtp/smtp.h 2025-10-23 20:04:12.000000000 -0400 @@ -642,12 +642,14 @@ #define SMTP_KEY_FLAG_ADDR (1<<5) /* remote address */ #define SMTP_KEY_FLAG_PORT (1<<6) /* remote port */ #define SMTP_KEY_FLAG_TLS_LEVEL (1<<7) /* requested TLS level */ +#define SMTP_KEY_FLAG_REQ_SMTPUTF8 (1<<8) /* SMTPUTF8 is required */ #define SMTP_KEY_MASK_ALL \ (SMTP_KEY_FLAG_SERVICE | SMTP_KEY_FLAG_SENDER | \ SMTP_KEY_FLAG_REQ_NEXTHOP | \ SMTP_KEY_FLAG_CUR_NEXTHOP | SMTP_KEY_FLAG_HOSTNAME | \ - SMTP_KEY_FLAG_ADDR | SMTP_KEY_FLAG_PORT | SMTP_KEY_FLAG_TLS_LEVEL) + SMTP_KEY_FLAG_ADDR | SMTP_KEY_FLAG_PORT | SMTP_KEY_FLAG_TLS_LEVEL | \ + SMTP_KEY_FLAG_REQ_SMTPUTF8) /* * Conditional lookup-key flags for cached connections that may be @@ -686,7 +688,8 @@ */ #define SMTP_KEY_MASK_SCACHE_DEST_LABEL \ (SMTP_KEY_FLAG_SERVICE | COND_SASL_SMTP_KEY_FLAG_SENDER \ - | SMTP_KEY_FLAG_REQ_NEXTHOP) + | SMTP_KEY_FLAG_REQ_NEXTHOP | SMTP_KEY_FLAG_TLS_LEVEL \ + | SMTP_KEY_FLAG_REQ_SMTPUTF8) /* * Connection-cache endpoint lookup key. The SENDER, CUR_NEXTHOP, HOSTNAME, @@ -701,7 +704,8 @@ | COND_SASL_SMTP_KEY_FLAG_CUR_NEXTHOP \ | COND_SASL_SMTP_KEY_FLAG_HOSTNAME \ | COND_TLS_SMTP_KEY_FLAG_CUR_NEXTHOP | SMTP_KEY_FLAG_ADDR | \ - SMTP_KEY_FLAG_PORT | SMTP_KEY_FLAG_TLS_LEVEL) + SMTP_KEY_FLAG_PORT | SMTP_KEY_FLAG_TLS_LEVEL \ + | SMTP_KEY_FLAG_REQ_SMTPUTF8) /* * Silly little macros. diff -ur --new-file /var/tmp/postfix-3.7.16/src/smtp/smtp_key.c ./src/smtp/smtp_key.c --- /var/tmp/postfix-3.7.16/src/smtp/smtp_key.c 2018-11-20 07:25:40.000000000 -0500 +++ ./src/smtp/smtp_key.c 2025-10-24 10:04:32.000000000 -0400 @@ -65,6 +65,10 @@ /* The current iterator's remote address. /* .IP SMTP_KEY_FLAG_PORT /* The current iterator's remote port. +/* .IP SMTP_KEY_FLAG_TLS_LEVEL +/* The requested TLS security level. +/* .IP SMTP_KEY_FLAG_REQ_SMTPUTF8 +/* Whether SMTPUTF8 support is required. /* .RE /* DIAGNOSTICS /* Panic: undefined flag or zero flags. Fatal: out of memory. @@ -103,12 +107,18 @@ * Global library. */ #include +#include /* * Application-specific. */ #include + /* Duplicated to minimze patch footprint. */ +#define DELIVERY_REQUIRES_SMTPUTF8(request) \ + ((request->smtputf8 & SMTPUTF8_FLAG_REQUESTED) \ + && (request->smtputf8 & ~SMTPUTF8_FLAG_REQUESTED)) + /* * We use a configurable field terminator and optional place holder for data * that is unavailable or inapplicable. We base64-encode content that @@ -209,6 +219,20 @@ smtp_key_append_na(buffer, delim_na); #endif + /* + * Require SMTPUTF8 support, if applicable. TODO(wietse) if a delivery + * request does not need SMTPUTF8, should we also search the connection + * cache for a connection that is known to support it? No, because the + * connection would be saved back under a key that does not require + * SMTPUTF8 support. + */ + if (flags & SMTP_KEY_FLAG_REQ_SMTPUTF8) + smtp_key_append_uint(buffer, + DELIVERY_REQUIRES_SMTPUTF8(state->request), + delim_na); + else + smtp_key_append_na(buffer, delim_na); + VSTRING_TERMINATE(buffer); return STR(buffer); diff -ur --new-file /var/tmp/postfix-3.7.16/src/smtp/smtp_proto.c ./src/smtp/smtp_proto.c --- /var/tmp/postfix-3.7.16/src/smtp/smtp_proto.c 2022-01-20 10:17:28.000000000 -0500 +++ ./src/smtp/smtp_proto.c 2025-10-23 20:04:12.000000000 -0400 @@ -643,14 +643,19 @@ * SMTPUTF8. * * Fix 20140706: moved this before negotiating TLS, AUTH, and so on. + * + * Fix 20250911: do not cache this session because it does not satisfy the + * requirement expressed in the cache storage key. */ if ((session->features & SMTP_FEATURE_SMTPUTF8) == 0 - && DELIVERY_REQUIRES_SMTPUTF8) + && DELIVERY_REQUIRES_SMTPUTF8) { + DONT_CACHE_THIS_SESSION; return (smtp_mesg_fail(state, DSN_BY_LOCAL_MTA, SMTP_RESP_FAKE(&fake, "5.6.7"), "SMTPUTF8 is required, " "but was not offered by host %s", session->namaddr)); + } /* * Fix 20140706: don't do silly things when the remote server announces diff -ur --new-file /var/tmp/postfix-3.7.16/src/smtpd/smtpd.c ./src/smtpd/smtpd.c --- /var/tmp/postfix-3.7.16/src/smtpd/smtpd.c 2024-02-27 12:22:29.000000000 -0500 +++ ./src/smtpd/smtpd.c 2025-10-23 20:04:12.000000000 -0400 @@ -5525,6 +5525,13 @@ {0,}, }; + /* + * In addition to counting unknown commands, the last table element also + * counts malformed commands (which aren't looked up in the command table). + */ +#define LAST_TABLE_PTR(table) ((table) + sizeof(table)/sizeof(*(table)) - 1) +static SMTPD_CMD *smtpd_cmdp_unknown = LAST_TABLE_PTR(smtpd_cmd_table); + static STRING_LIST *smtpd_noop_cmds; static STRING_LIST *smtpd_forbid_cmds; @@ -5859,6 +5866,8 @@ state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "500 5.5.2 Error: bad UTF-8 syntax"); state->error_count++; + state->where = SMTPD_CMD_UNKNOWN; + smtpd_cmdp_unknown->total_count += 1; continue; } /* Move into smtpd_chat_query() and update session transcript. */ @@ -5880,6 +5889,8 @@ state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "500 5.5.2 Error: bad syntax"); state->error_count++; + state->where = SMTPD_CMD_UNKNOWN; + smtpd_cmdp_unknown->total_count += 1; continue; } /* Ignore smtpd_noop_cmds lookup errors. Non-critical feature. */ @@ -5888,6 +5899,7 @@ smtpd_chat_reply(state, "250 2.0.0 Ok"); if (state->junk_cmds++ > var_smtpd_junk_cmd_limit) state->error_count++; + /* XXX We can't count these. */ continue; } for (cmdp = smtpd_cmd_table; cmdp->name != 0; cmdp++) diff -ur --new-file /var/tmp/postfix-3.7.16/src/util/dict_db.c ./src/util/dict_db.c --- /var/tmp/postfix-3.7.16/src/util/dict_db.c 2025-08-18 16:51:30.000000000 -0400 +++ ./src/util/dict_db.c 2025-10-23 20:04:12.000000000 -0400 @@ -799,6 +799,7 @@ * the source file changed only seconds ago. */ if ((dict_flags & DICT_FLAG_LOCK) != 0 + && open_flags == O_RDONLY && stat(path, &st) == 0 && st.st_mtime > dict_db->dict.mtime && st.st_mtime < time((time_t *) 0) - 100) diff -ur --new-file /var/tmp/postfix-3.7.16/src/util/dict_dbm.c ./src/util/dict_dbm.c --- /var/tmp/postfix-3.7.16/src/util/dict_dbm.c 2025-08-18 16:51:30.000000000 -0400 +++ ./src/util/dict_dbm.c 2025-10-23 20:04:12.000000000 -0400 @@ -472,7 +472,7 @@ msg_fatal("open database %s: cannot support GDBM", path); if (fstat(dict_dbm->dict.stat_fd, &st) < 0) msg_fatal("dict_dbm_open: fstat: %m"); - if (open_mode == O_RDONLY) + if (open_flags == O_RDONLY) dict_dbm->dict.mtime = st.st_mtime; dict_dbm->dict.owner.uid = st.st_uid; dict_dbm->dict.owner.status = (st.st_uid != 0); @@ -482,6 +482,7 @@ * the source file changed only seconds ago. */ if ((dict_flags & DICT_FLAG_LOCK) != 0 + && open_flags == O_RDONLY && stat(path, &st) == 0 && st.st_mtime > dict_dbm->dict.mtime && st.st_mtime < time((time_t *) 0) - 100) diff -ur --new-file /var/tmp/postfix-3.7.16/src/util/dict_lmdb.c ./src/util/dict_lmdb.c --- /var/tmp/postfix-3.7.16/src/util/dict_lmdb.c 2025-08-18 16:51:30.000000000 -0400 +++ ./src/util/dict_lmdb.c 2025-10-23 20:04:12.000000000 -0400 @@ -666,6 +666,7 @@ * the source file changed only seconds ago. */ if ((dict_flags & DICT_FLAG_LOCK) != 0 + && open_flags == O_RDONLY && stat(path, &st) == 0 && st.st_mtime > dict_lmdb->dict.mtime && st.st_mtime < time((time_t *) 0) - 100) diff -ur --new-file /var/tmp/postfix-3.7.16/src/util/dict_sdbm.c ./src/util/dict_sdbm.c --- /var/tmp/postfix-3.7.16/src/util/dict_sdbm.c 2025-08-18 16:51:30.000000000 -0400 +++ ./src/util/dict_sdbm.c 2025-10-23 20:04:12.000000000 -0400 @@ -459,6 +459,7 @@ * the source file changed only seconds ago. */ if ((dict_flags & DICT_FLAG_LOCK) != 0 + && open_flags == O_RDONLY && stat(path, &st) == 0 && st.st_mtime > dict_sdbm->dict.mtime && st.st_mtime < time((time_t *) 0) - 100)