]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.7.17 v3.7.17
authorWietse Z Venema <wietse@porcupine.org>
Sun, 26 Oct 2025 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <ietf-dane@dukhovni.org>
Mon, 27 Oct 2025 01:29:53 +0000 (12:29 +1100)
14 files changed:
postfix/HISTORY
postfix/conf/main.cf
postfix/src/global/mail_version.h
postfix/src/postcat/postcat.c
postfix/src/postconf/postconf_edit.c
postfix/src/showq/showq.c
postfix/src/smtp/smtp.h
postfix/src/smtp/smtp_key.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtpd/smtpd.c
postfix/src/util/dict_db.c
postfix/src/util/dict_dbm.c
postfix/src/util/dict_lmdb.c
postfix/src/util/dict_sdbm.c

index 3eff094b0e36a78a50a2a64a3327b540896b1f11..e23a4da4f5d445ab161481e5f70d70980c7249bc 100644 (file)
@@ -26962,3 +26962,54 @@ Apologies for any names omitted.
        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.
index 47de434638ddb338867d480353177314b89c4b08..69323b51aa41fbb771fbf9489f2537c9f133d906 100644 (file)
@@ -683,3 +683,5 @@ sample_directory =
 #
 readme_directory =
 inet_protocols = ipv4
+shlib_directory = /usr/lib/postfix/${mail_version}
+meta_directory = /etc/postfix
index 00a5371000e7ec309239c30bfb96d00a893c7ebb..4faf469fb0a8bf06050966b743704a30fb71446c 100644 (file)
@@ -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
index 36f27404a7157ee1dd7ddbf6a83c1e2487c12070..619f3d221d132247c99643643613cb5c8034bbbe 100644 (file)
@@ -339,6 +339,10 @@ static void postcat(VSTREAM *fp, VSTRING *buffer, int flags)
            /* 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");
index 83899281dd5509fd2f385d6db5c5eb0f653c9d13..c64e44c5759ea0cc59611f6e8e23533a817e8ef2 100644 (file)
@@ -66,6 +66,7 @@
 /* System library. */
 
 #include <sys_defs.h>
+#include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
 
@@ -148,6 +149,16 @@ static void pcf_gobble_cf_line(VSTRING *full_entry_buf, VSTRING *line_buf,
     }
 }
 
+/* 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 @@ 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);
index b8dd7e9948089252da5d3adad630db41aeaeceb7..febf08b316b4c2d91cb32b5f680429033696105e 100644 (file)
@@ -213,7 +213,8 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
                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) {
index 0d5c80a7ebbc82aadd174d9b0f2c825db5154c0e..5b09b3d69a9fbdf27f0ce9d8d273c67bd9ee939b 100644 (file)
@@ -642,12 +642,14 @@ char   *smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int);
 #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 @@ char   *smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int);
   */
 #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 @@ char   *smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int);
        | 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.
index 643f4db7e61d978e4c35d1efd453cd12df2b9667..d1d1edb0792328ee02279b3fc768e105c12605e8 100644 (file)
 /*     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
@@ -209,6 +219,20 @@ char   *smtp_key_prefix(VSTRING *buffer, const char *delim_na,
        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);
index 2ceb0f35c1d709e98605d85732b99c2969a369a5..4278bfb508c0d4c6bee020f14116ee28f8981bca 100644 (file)
@@ -643,14 +643,19 @@ int     smtp_helo(SMTP_STATE *state)
      * 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
index c2aa428ab0de22ade59f0963b36b8c87625d0ae7..0d07d18a91ddcd520e4b6ad86f96d2228977fee4 100644 (file)
@@ -5525,6 +5525,13 @@ static SMTPD_CMD smtpd_cmd_table[] = {
     {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 @@ static void smtpd_proto(SMTPD_STATE *state)
                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 @@ static void smtpd_proto(SMTPD_STATE *state)
                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 @@ static void smtpd_proto(SMTPD_STATE *state)
                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++)
index 0a760c6b9963cd075dfd4abf38a87c49567a69cc..053db3c1edcc1cedda51131a6c2bf7617da3e342 100644 (file)
@@ -799,6 +799,7 @@ static DICT *dict_db_open(const char *class, const char *path, int open_flags,
      * 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)
index b3bbe8510adbb5111b8cd1bc014f275fd22420e8..45fa71295535e8f64dd7f00a7262113b21ca009a 100644 (file)
@@ -472,7 +472,7 @@ DICT   *dict_dbm_open(const char *path, int open_flags, int dict_flags)
        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 @@ DICT   *dict_dbm_open(const char *path, int open_flags, int dict_flags)
      * 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)
index 6f4f276ca529648b2e3bf9b68887e036ed33545a..f672e1c055cdbc2af8d5c7c5f49172a721af3b88 100644 (file)
@@ -666,6 +666,7 @@ DICT   *dict_lmdb_open(const char *path, int open_flags, int dict_flags)
      * 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)
index fcb2556e8c09bc7534afe443e3e6d190968d2fc5..6cba5a2ec2644ad09c250460f8a4b8ab1a331527 100644 (file)
@@ -459,6 +459,7 @@ DICT   *dict_sdbm_open(const char *path, int open_flags, int dict_flags)
      * 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)