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.
+
+20250823
+
+ Bugfix (defect introduced: Postfix 3.9, date 20230517):
+ posttls-finger logged a zero port number. Viktor Dukhovni.
+ File: posttls-finger/posttls-finger.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.
#
readme_directory =
inet_protocols = ipv4
+shlib_directory = /usr/lib/postfix/${mail_version}
+meta_directory = /etc/postfix
* 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.8.11"
+#define MAIL_RELEASE_DATE "20251026"
+#define MAIL_VERSION_NUMBER "3.8.12"
#ifdef SNAPSHOT
#define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE
/* 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");
/* System library. */
#include <sys_defs.h>
+#include <stdlib.h>
#include <string.h>
#include <ctype.h>
}
}
+/* 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)
* 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);
if (level == TLS_LEV_INVALID
|| (state->stream = connect_addr(state, addr)) == 0) {
msg_info("Failed to establish session to %s via %s:%u: %s",
- dest, HNAME(addr), addr->port,
+ dest, HNAME(addr), ntohs(state->port),
vstring_str(state->why->reason));
continue;
}
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) {
#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
*/
#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,
| 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.
/* 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.
* Global library.
*/
#include <mail_params.h>
+#include <smtputf8.h>
/*
* Application-specific.
*/
#include <smtp.h>
+ /* 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
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);
* 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
{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;
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. */
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. */
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++)
* 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)
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);
* 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)
* 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)
* 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)