]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.12-20260805 master
authorWietse Z Venema <wietse@porcupine.org>
Wed, 5 Aug 2026 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <ietf-dane@dukhovni.org>
Thu, 6 Aug 2026 06:30:36 +0000 (16:30 +1000)
postfix/HISTORY
postfix/html/postconf.5.html
postfix/man/man5/postconf.5
postfix/proto/postconf.proto
postfix/proto/stop
postfix/proto/stop.double-history
postfix/proto/stop.spell-cc
postfix/src/global/dict_mysql.c
postfix/src/global/mail_version.h
postfix/src/smtpd/smtpd.c
postfix/src/tls/tls_server.c

index f30d0ad8e5d2a066075999a9f926c31aa7f23d8d..8d9cfd50b6b143b4bfe2bb5c351ec9a411cb8b1f 100644 (file)
@@ -31865,6 +31865,24 @@ Apologies for any names omitted.
        client remained in the "accept this message" state, skipping
        Milter policy enforcement for the second message.
 
        client remained in the "accept this message" state, skipping
        Milter policy enforcement for the second message.
 
+20260805
+
+       Isolation: stamp Postfix SMTP server TLS session tickets
+       with their master.cf service name. With this, an SMTP server
+       defined in master.cf will no longer accept tickets issued
+       by a different SMTP server defined in the same master.cf
+       file. Fix by OpenAI security. File: tls_server.c.
+
+       Bug (defect introduced: Postfix 3.4, date: 20180805): SMTP
+       server command history memory exhaustion with a large number
+       of very small BDAT requests. Reported by OpenAI security.
+       File: smtpd.c.
+
+       Bug (defect introduced: Postfix 3.4, date: 20180303): the
+       MySQL client setting "tls_verify_cert = yes" had no effect
+       with Oracle MySQL 8 and later. Report and fix by OpenAI
+       Security. File: dict_mysql.c.
+
 TODO
 
        Reorganize PTEST_LIB, PMOCK_LIB, TESTLIB, TESTLIBS, etc.
 TODO
 
        Reorganize PTEST_LIB, PMOCK_LIB, TESTLIB, TESTLIBS, etc.
index 7fc52ce1c97aa39c165d2e17dc0272d26afa9d0f..5b06a6a199d2e321ed30d38f7086bed62e1ddbbc 100644 (file)
@@ -18037,7 +18037,11 @@ requirements. </p>
 
 <p>
 The maximal number of lines in the Postfix SMTP server command history
 
 <p>
 The maximal number of lines in the Postfix SMTP server command history
-before it is flushed upon receipt of EHLO, RSET, or end of DATA.
+before it is flushed upon receipt of EHLO, RSET, or end of DATA. With
+Postfix &ge; 3.4 releases after 20260805, the history is flushed
+whenever it reaches the threshold. The <a href="postconf.5.html#notify_classes">notify_classes</a> parameter
+controls what command history may be reported in postmaster
+notification email.
 </p>
 
 
 </p>
 
 
index 6ccde017c47042bd5656822eedbe940a5c44906a..e82fa36f4340045f06bd0c57c6c6278638c0b744 100644 (file)
@@ -12373,7 +12373,11 @@ requirements.
 This feature is available in Postfix >= 3.10.
 .SH smtpd_history_flush_threshold (default: 100)
 The maximal number of lines in the Postfix SMTP server command history
 This feature is available in Postfix >= 3.10.
 .SH smtpd_history_flush_threshold (default: 100)
 The maximal number of lines in the Postfix SMTP server command history
-before it is flushed upon receipt of EHLO, RSET, or end of DATA.
+before it is flushed upon receipt of EHLO, RSET, or end of DATA. With
+Postfix >= 3.4 releases after 20260805, the history is flushed
+whenever it reaches the threshold. The notify_classes parameter
+controls what command history may be reported in postmaster
+notification email.
 .SH smtpd_junk_command_limit (default: normal: 100, overload: 1)
 The number of junk commands (NOOP, VRFY, ETRN or RSET) that a remote
 SMTP client can send before the Postfix SMTP server starts to
 .SH smtpd_junk_command_limit (default: normal: 100, overload: 1)
 The number of junk commands (NOOP, VRFY, ETRN or RSET) that a remote
 SMTP client can send before the Postfix SMTP server starts to
index bdb60a9231c99d5d3d7c002e9b30e9cc321f9651..9659b335afc07393570897b978f88f343b7a259a 100644 (file)
@@ -6270,7 +6270,11 @@ smtpd_helo_restrictions = permit_mynetworks, reject_unknown_helo_hostname
 
 <p>
 The maximal number of lines in the Postfix SMTP server command history
 
 <p>
 The maximal number of lines in the Postfix SMTP server command history
-before it is flushed upon receipt of EHLO, RSET, or end of DATA.
+before it is flushed upon receipt of EHLO, RSET, or end of DATA. With
+Postfix &ge; 3.4 releases after 20260805, the history is flushed
+whenever it reaches the threshold. The notify_classes parameter
+controls what command history may be reported in postmaster
+notification email.
 </p>
 
 %PARAM smtpd_noop_commands 
 </p>
 
 %PARAM smtpd_noop_commands 
index 671e3d6d2134026e919dc5f76147e69ec6e1a938..8fc534cc46e5e3f0f2c8784031ed85f5eaf2cddd 100644 (file)
@@ -1733,3 +1733,5 @@ optimizers
 resloop
 tokenized
 fortra
 resloop
 tokenized
 fortra
+OpenAI
+stateful
index a42ef13ec04e3817628a0223d92fbe267cacfc29..81e5e74c60432804b7d84a2779bb3640799d0b21 100644 (file)
@@ -267,3 +267,5 @@ proto  proto stop proto stop double cc
  support File smtpd smtpd c 
  sendmail sendmail c 
  postqueue postqueue c 
  support File smtpd smtpd c 
  sendmail sendmail c 
  postqueue postqueue c 
+ OpenAI Security File smtpd smtpd c 
+ by OpenAI Security File smtpd smtpd c 
index b6e5f5a8c8b68ac51e9e32d71b5d0796b84147aa..bee6c3842ce0488c2a239dc7b293b59654a05660 100644 (file)
@@ -1997,3 +1997,5 @@ jk
 unitext
 esmtpargs
 uncoded
 unitext
 esmtpargs
 uncoded
+desynchronization
+xffffffff
index 482e6180d178e0ae9624fa03c1cae0cc88899289..10cd35ed897b4ef38458b353d904cffea2d14be7 100644 (file)
 #if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50023
 #define DICT_MYSQL_SSL_VERIFY_SERVER_CERT MYSQL_OPT_SSL_VERIFY_SERVER_CERT
 #elif MYSQL_VERSION_ID >= 80000
 #if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50023
 #define DICT_MYSQL_SSL_VERIFY_SERVER_CERT MYSQL_OPT_SSL_VERIFY_SERVER_CERT
 #elif MYSQL_VERSION_ID >= 80000
-#define DICT_MYSQL_SSL_VERIFY_SERVER_CERT MYSQL_OPT_SSL_MODE
+/* 202607 OpenAI: MYSQL_OPT_SSL_MODE is an enum, not a bool. */
+#define DICT_MYSQL_SSL_MODE MYSQL_OPT_SSL_MODE
 #endif
 
  /*
 #endif
 
  /*
@@ -172,7 +173,7 @@ typedef struct {
     char   *tls_CAfile;
     char   *tls_CApath;
     char   *tls_ciphers;
     char   *tls_CAfile;
     char   *tls_CApath;
     char   *tls_ciphers;
-#if defined(DICT_MYSQL_SSL_VERIFY_SERVER_CERT)
+#if defined(DICT_MYSQL_SSL_VERIFY_SERVER_CERT) || defined(DICT_MYSQL_SSL_MODE)
     int     tls_verify_cert;
 #endif
     int     require_result_set;
     int     tls_verify_cert;
 #endif
     int     require_result_set;
@@ -602,6 +603,11 @@ static int plmysql_query(DICT_MYSQL *dict_mysql,
  */
 static void plmysql_connect_single(DICT_MYSQL *dict_mysql, HOST *host)
 {
  */
 static void plmysql_connect_single(DICT_MYSQL *dict_mysql, HOST *host)
 {
+#if defined(DICT_MYSQL_SSL_MODE)
+    enum mysql_ssl_mode ssl_mode;
+
+#endif
+
     if ((host->db = mysql_init(NULL)) == NULL)
        msg_fatal("dict_mysql: insufficient memory");
     if (dict_mysql->option_file)
     if ((host->db = mysql_init(NULL)) == NULL)
        msg_fatal("dict_mysql: insufficient memory");
     if (dict_mysql->option_file)
@@ -629,7 +635,19 @@ static void plmysql_connect_single(DICT_MYSQL *dict_mysql, HOST *host)
                      dict_mysql->tls_CAfile, dict_mysql->tls_CApath,
                      dict_mysql->tls_ciphers);
 #endif
                      dict_mysql->tls_CAfile, dict_mysql->tls_CApath,
                      dict_mysql->tls_ciphers);
 #endif
-#if defined(DICT_MYSQL_SSL_VERIFY_SERVER_CERT)
+#if defined(DICT_MYSQL_SSL_MODE)
+    if (dict_mysql->tls_verify_cert != -1) {
+       /* MYSQL_OPT_SSL_MODE enum values are not Boolean values. */
+       ssl_mode = dict_mysql->tls_verify_cert ? SSL_MODE_VERIFY_IDENTITY :
+           SSL_MODE_PREFERRED;
+       if (mysql_options(host->db, DICT_MYSQL_SSL_MODE, &ssl_mode) != 0) {
+           msg_warn("dict_mysql: could not set TLS mode for host %s: %s",
+                    host->hostname, mysql_error(host->db));
+           plmysql_down_host(host, dict_mysql->retry_interval);
+           return;
+       }
+    }
+#elif defined(DICT_MYSQL_SSL_VERIFY_SERVER_CERT)
     if (dict_mysql->tls_verify_cert != -1)
        mysql_options(host->db, DICT_MYSQL_SSL_VERIFY_SERVER_CERT,
                      &dict_mysql->tls_verify_cert);
     if (dict_mysql->tls_verify_cert != -1)
        mysql_options(host->db, DICT_MYSQL_SSL_VERIFY_SERVER_CERT,
                      &dict_mysql->tls_verify_cert);
@@ -705,7 +723,7 @@ static void mysql_parse_config(DICT_MYSQL *dict_mysql, const char *mysqlcf)
     dict_mysql->tls_CAfile = cfg_get_str(p, "tls_CAfile", NULL, 0, 0);
     dict_mysql->tls_CApath = cfg_get_str(p, "tls_CApath", NULL, 0, 0);
     dict_mysql->tls_ciphers = cfg_get_str(p, "tls_ciphers", NULL, 0, 0);
     dict_mysql->tls_CAfile = cfg_get_str(p, "tls_CAfile", NULL, 0, 0);
     dict_mysql->tls_CApath = cfg_get_str(p, "tls_CApath", NULL, 0, 0);
     dict_mysql->tls_ciphers = cfg_get_str(p, "tls_ciphers", NULL, 0, 0);
-#if defined(DICT_MYSQL_SSL_VERIFY_SERVER_CERT)
+#if defined(DICT_MYSQL_SSL_VERIFY_SERVER_CERT) || defined(DICT_MYSQL_SSL_MODE)
     dict_mysql->tls_verify_cert = cfg_get_bool(p, "tls_verify_cert", -1);
 #endif
     dict_mysql->require_result_set = cfg_get_bool(p, "require_result_set", 1);
     dict_mysql->tls_verify_cert = cfg_get_bool(p, "tls_verify_cert", -1);
 #endif
     dict_mysql->require_result_set = cfg_get_bool(p, "require_result_set", 1);
index 3267bc3b98487e82c11736668642dfe991e6a668..585b82df62b993123ce24ef40e60a2a44bb58ef6 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20260804"
+#define MAIL_RELEASE_DATE      "20260805"
 #define MAIL_VERSION_NUMBER    "3.12"
 
 #ifdef SNAPSHOT
 #define MAIL_VERSION_NUMBER    "3.12"
 
 #ifdef SNAPSHOT
index 56b947e9f342bb93391581098e906b7fbac2db52..c8519a72baa5729423363a26b4547731273268f6 100644 (file)
@@ -6116,6 +6116,8 @@ static void smtpd_proto(SMTPD_STATE *state)
        for (;;) {
            if (state->flags & SMTPD_FLAG_HANGUP)
                break;
        for (;;) {
            if (state->flags & SMTPD_FLAG_HANGUP)
                break;
+           /* Flush the command history if it becomes large. */
+           chat_reset(state, var_smtpd_hist_thrsh);
            smtp_stream_setup(state->client, var_smtpd_tmout,
                              var_smtpd_req_deadline, 0);
            if (state->error_count >= var_smtpd_hard_erlim) {
            smtp_stream_setup(state->client, var_smtpd_tmout,
                              var_smtpd_req_deadline, 0);
            if (state->error_count >= var_smtpd_hard_erlim) {
index 30b7ddfb01acdef4538ec099817657828310d781..e4c1d3c6db3b466bd6be02f3923b0008986256c3 100644 (file)
@@ -819,6 +819,11 @@ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props)
     const char *cipher_list;
     TLS_APPL_STATE *app_ctx = props->ctx;
     int     log_mask;
     const char *cipher_list;
     TLS_APPL_STATE *app_ctx = props->ctx;
     int     log_mask;
+    /* 202607 OpenAI: isolate session tickets by master.cf service name. */ 
+    EVP_MD_CTX *sessid_ctx_md = 0;
+    unsigned char sessid_ctx[EVP_MAX_MD_SIZE];
+    unsigned int sessid_ctx_len;
+    static const char sessid_ctx_label[] = "Postfix/TLS serverid";
 
     /*
      * Convert user loglevel to internal logmask.
 
     /*
      * Convert user loglevel to internal logmask.
@@ -876,6 +881,29 @@ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props)
     TLScontext->stream = props->stream;
     TLScontext->mdalg = props->mdalg;
 
     TLScontext->stream = props->stream;
     TLScontext->mdalg = props->mdalg;
 
+    /*
+     * The serverid already partitions stateful sessions in the tlsmgr
+     * session cache. Apply the same partition to stateless sessions; all
+     * services in one Postfix instance share the tlsmgr ticket keys.
+     */
+    if (tls_digest_byname(LN_sha256, &sessid_ctx_md) == 0
+       || EVP_DigestUpdate(sessid_ctx_md, sessid_ctx_label,
+                           sizeof(sessid_ctx_label)) != 1
+       || EVP_DigestUpdate(sessid_ctx_md, props->serverid,
+                           strlen(props->serverid) + 1) != 1
+       || EVP_DigestFinal_ex(sessid_ctx_md, sessid_ctx, &sessid_ctx_len) != 1
+       || sessid_ctx_len > SSL_MAX_SID_CTX_LENGTH
+       || SSL_set_session_id_context(TLScontext->con, sessid_ctx,
+                                     sessid_ctx_len) != 1) {
+       msg_warn("Could not set TLS session ID context");
+       tls_print_errors();
+       if (sessid_ctx_md)
+           EVP_MD_CTX_destroy(sessid_ctx_md);
+       tls_free_context(TLScontext);
+       return (0);
+    }
+    EVP_MD_CTX_destroy(sessid_ctx_md);
+
     if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
        msg_warn("Could not set application data for 'TLScontext->con'");
        tls_print_errors();
     if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
        msg_warn("Could not set application data for 'TLScontext->con'");
        tls_print_errors();