was comparing memory addresses instead of queue file names.
It now properly compares strings. Reported by Mehmet Avcioglu.
File: global/record.c.
+
+20210811
+
+ Bitrot: OpenSSL 3.x requires const. File: tls/tls_misc.c.
+
+20210925
+
+ Bugfix (bug introduced: Postfix 2.10): postconf -x produced
+ incorrect output, because different functions were implicitly
+ sharing a buffer for intermediate results. Reported
+ by raf, root cause analysis by Viktor Dukhovni. File:
+ postconf/postconf_builtin.c.
+
+20211030
+
+ Bugfix (problem introduced: Postfix 2.11): check_ccert_access
+ worked as expected, but produced a spurious warning when
+ Postfix was built without SASL support. Fix by Brad Barden.
+ File: smtpd/smtpd_check.c.
+
+20211105
+
+ Bugfix (introduced: Postfix 2.4): queue file corruption
+ after a Milter (for example, MIMEDefang) made a request to
+ replace the message body with a copy of that message body
+ plus additional text (for example, a SpamAssassin report).
+
+ The most likely impacts were a) the queue manager reporting
+ a fatal error resulting in email delivery delays, or b) the
+ queue manager reporting the corruption and moving the message
+ to the corrupt queue for damaged messages.
+
+ However, a determined adversary could craft an email message
+ that would trigger the bug, and insert a content filter
+ destination or a redirect email address into its queue file.
+ Postfix would then deliver the message headers there, in
+ most cases without delivering the message body. With enough
+ experimentation, an attacker could make Postfix deliver
+ both the message headers and body.
+
+ The details of a successful attack depend on the Milter
+ implementation, and on the Postfix and Milter configuration
+ details; these can be determined remotely through
+ experimentation. Failed experiments may be detected when
+ the queue manager terminates with a fatal error, or when
+ the queue manager moves damaged files to the "corrupt" queue
+ as evidence.
+
+ Technical details: when Postfix executes a "replace body"
+ Milter request it will reuse queue file storage that was
+ used by the existing email message body. If the new body
+ is larger, Postfix will append body content to the end of
+ the queue file. The corruption happened when a Milter (for
+ example, MIMEDefang) made a request to replace the body of
+ a message with a new body that contained a copy of the
+ original body plus some new text, and the original body
+ contained a line longer than $line_length_limit bytes (for
+ example, an image encoded in base64 without hard or soft
+ line breaks). In queue files, Postfix stores a long text
+ line as multiple records with up to $line_length_limit bytes
+ each. Unfortunately, Postfix's "replace body" support did
+ not account for the additional queue file space needed to
+ store the second etc. record headers. And thus, the last
+ record(s) of a long text line could overwrite one or more
+ queue file records immediately after the space that was
+ previously occupied by the original message body.
+
+ Problem report by BenoƮt Panizzon.
/*
* Finally, output the queue file record.
*/
- CLEANUP_OUT_BUF(state, REC_TYPE_NORM, buf);
+ CLEANUP_OUT_BUF(state, rec_type, buf);
curr_rp->write_offs = vstream_ftell(state->dst);
return (0);
/* cleanup_repl_body - replace message body */
-static const char *cleanup_repl_body(void *context, int cmd, VSTRING *buf)
+static const char *cleanup_repl_body(void *context, int cmd, int rec_type,
+ VSTRING *buf)
{
const char *myname = "cleanup_repl_body";
CLEANUP_STATE *state = (CLEANUP_STATE *) context;
*/
switch (cmd) {
case MILTER_BODY_LINE:
- if (cleanup_body_edit_write(state, REC_TYPE_NORM, buf) < 0)
+ if (cleanup_body_edit_write(state, rec_type, buf) < 0)
return (cleanup_milter_error(state, errno));
break;
case MILTER_BODY_START:
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20210724"
-#define MAIL_VERSION_NUMBER "3.3.19"
+#define MAIL_RELEASE_DATE "20211107"
+#define MAIL_VERSION_NUMBER "3.3.20"
#ifdef SNAPSHOT
#define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE
typedef const char *(*MILTER_EDIT_FROM_FN) (void *, const char *, const char *);
typedef const char *(*MILTER_EDIT_RCPT_FN) (void *, const char *);
typedef const char *(*MILTER_EDIT_RCPT_PAR_FN) (void *, const char *, const char *);
-typedef const char *(*MILTER_EDIT_BODY_FN) (void *, int, VSTRING *);
+typedef const char *(*MILTER_EDIT_BODY_FN) (void *, int, int, VSTRING *);
typedef struct MILTERS {
MILTER *milter_list; /* linked list of Milters */
if (edit_resp == 0 && LEN(body_line_buf) > 0)
edit_resp = parent->repl_body(parent->chg_context,
MILTER_BODY_LINE,
+ REC_TYPE_NORM,
body_line_buf);
if (edit_resp == 0)
edit_resp = parent->repl_body(parent->chg_context,
MILTER_BODY_END,
+ /* unused*/ 0,
(VSTRING *) 0);
body_edit_lockout = 1;
vstring_free(body_line_buf);
body_line_buf = vstring_alloc(var_line_limit);
edit_resp = parent->repl_body(parent->chg_context,
MILTER_BODY_START,
+ /* unused */ 0,
(VSTRING *) 0);
}
/* Extract lines from the on-the-wire CRLF format. */
LEN(body_line_buf) - 1);
edit_resp = parent->repl_body(parent->chg_context,
MILTER_BODY_LINE,
+ REC_TYPE_NORM,
body_line_buf);
VSTRING_RESET(body_line_buf);
} else {
+ /* Preserves \r if not followed by \n. */
+ if (LEN(body_line_buf) == var_line_limit) {
+ edit_resp = parent->repl_body(parent->chg_context,
+ MILTER_BODY_LINE,
+ REC_TYPE_CONT,
+ body_line_buf);
+ VSTRING_RESET(body_line_buf);
+ }
VSTRING_ADDCH(body_line_buf, ch);
}
}
static const char *pcf_mynetworks(void)
{
static const char *networks;
+ VSTRING *exp_buf;
const char *junk;
/*
if (networks)
return (networks);
+ exp_buf = vstring_alloc(100);
+
if (var_inet_interfaces == 0) {
if ((pcf_cmd_mode & PCF_SHOW_DEFS)
|| (junk = mail_conf_lookup_eval(VAR_INET_INTERFACES)) == 0)
- junk = pcf_expand_parameter_value((VSTRING *) 0, pcf_cmd_mode,
+ junk = pcf_expand_parameter_value(exp_buf, pcf_cmd_mode,
DEF_INET_INTERFACES,
(PCF_MASTER_ENT *) 0);
var_inet_interfaces = mystrdup(junk);
if (var_mynetworks_style == 0) {
if ((pcf_cmd_mode & PCF_SHOW_DEFS)
|| (junk = mail_conf_lookup_eval(VAR_MYNETWORKS_STYLE)) == 0)
- junk = pcf_expand_parameter_value((VSTRING *) 0, pcf_cmd_mode,
+ junk = pcf_expand_parameter_value(exp_buf, pcf_cmd_mode,
DEF_MYNETWORKS_STYLE,
(PCF_MASTER_ENT *) 0);
var_mynetworks_style = mystrdup(junk);
if (var_inet_protocols == 0) {
if ((pcf_cmd_mode & PCF_SHOW_DEFS)
|| (junk = mail_conf_lookup_eval(VAR_INET_PROTOCOLS)) == 0)
- junk = pcf_expand_parameter_value((VSTRING *) 0, pcf_cmd_mode,
+ junk = pcf_expand_parameter_value(exp_buf, pcf_cmd_mode,
DEF_INET_PROTOCOLS,
(PCF_MASTER_ENT *) 0);
var_inet_protocols = mystrdup(junk);
(void) inet_proto_init(VAR_INET_PROTOCOLS, var_inet_protocols);
}
+ vstring_free(exp_buf);
return (networks = mystrdup(mynetworks()));
}
}
} else if (is_map_command(state, name, CHECK_CCERT_ACL, &cpp)) {
status = check_ccert_access(state, *cpp, def_acl);
-#ifdef USE_SASL_AUTH
} else if (is_map_command(state, name, CHECK_SASL_ACL, &cpp)) {
+#ifdef USE_SASL_AUTH
if (var_smtpd_sasl_enable) {
if (state->sasl_username && state->sasl_username[0])
status = check_sasl_access(state, *cpp, def_acl);
EVP_PKEY *pkey = 0;
#ifndef OPENSSL_NO_EC
- EC_KEY *eckey;
+ const EC_KEY *eckey;
#endif