Prereq: "3.6.2" diff -ur --new-file /var/tmp/postfix-3.6.2/src/global/mail_version.h ./src/global/mail_version.h --- /var/tmp/postfix-3.6.2/src/global/mail_version.h 2021-07-24 19:16:27.000000000 -0400 +++ ./src/global/mail_version.h 2021-11-07 17:32:00.000000000 -0500 @@ -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 "20210724" -#define MAIL_VERSION_NUMBER "3.6.2" +#define MAIL_RELEASE_DATE "20211107" +#define MAIL_VERSION_NUMBER "3.6.3" #ifdef SNAPSHOT #define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE diff -ur --new-file /var/tmp/postfix-3.6.2/HISTORY ./HISTORY --- /var/tmp/postfix-3.6.2/HISTORY 2021-07-24 18:41:41.000000000 -0400 +++ ./HISTORY 2021-11-07 18:12:28.000000000 -0500 @@ -25612,3 +25612,85 @@ 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. + +20211022 + + Bugfix (introduced: Postfix 3.6): the known_tcp_ports setting + had no effect. Reported by Peter. The feature wasn't fully + implemented. Files: config_known_tcp_ports.c, mail_params.c, + posttls-finger/posttls-finger.c, smtp/smtp_connect.c, + util/find_inet.c, util/myaddrinfo.c. + +20211025 + + Bugfix (introduced: Postfix 3.6): mangled warning where a + hostname and warning message run together. Viktor Dukhovni. + File: tls/tls_dane.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. diff -ur --new-file /var/tmp/postfix-3.6.2/src/cleanup/cleanup_body_edit.c ./src/cleanup/cleanup_body_edit.c --- /var/tmp/postfix-3.6.2/src/cleanup/cleanup_body_edit.c 2017-12-27 17:29:44.000000000 -0500 +++ ./src/cleanup/cleanup_body_edit.c 2021-11-05 18:29:08.000000000 -0400 @@ -207,7 +207,7 @@ /* * 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); diff -ur --new-file /var/tmp/postfix-3.6.2/src/cleanup/cleanup_milter.c ./src/cleanup/cleanup_milter.c --- /var/tmp/postfix-3.6.2/src/cleanup/cleanup_milter.c 2020-09-25 16:11:17.000000000 -0400 +++ ./src/cleanup/cleanup_milter.c 2021-11-05 18:29:08.000000000 -0400 @@ -1836,7 +1836,8 @@ /* 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; @@ -1848,7 +1849,7 @@ */ 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: diff -ur --new-file /var/tmp/postfix-3.6.2/src/global/config_known_tcp_ports.c ./src/global/config_known_tcp_ports.c --- /var/tmp/postfix-3.6.2/src/global/config_known_tcp_ports.c 2021-04-19 14:56:10.000000000 -0400 +++ ./src/global/config_known_tcp_ports.c 2021-11-06 20:09:01.000000000 -0400 @@ -58,6 +58,8 @@ ARGV *association; char **cpp; + clear_known_tcp_ports(); + /* * The settings is in the form of associations separated by comma. Split * it into separate associations. diff -ur --new-file /var/tmp/postfix-3.6.2/src/global/mail_params.c ./src/global/mail_params.c --- /var/tmp/postfix-3.6.2/src/global/mail_params.c 2021-04-18 17:10:45.000000000 -0400 +++ ./src/global/mail_params.c 2021-11-06 20:20:40.000000000 -0400 @@ -237,6 +237,7 @@ #include #include #include +#include /* * Special configuration variables. @@ -923,6 +924,11 @@ util_utf8_enable = var_smtputf8_enable; /* + * Configure the known TCP port mappings. + */ + config_known_tcp_ports(VAR_KNOWN_TCP_PORTS, var_known_tcp_ports); + + /* * What protocols should we attempt to support? The result is stored in * the global inet_proto_table variable. */ diff -ur --new-file /var/tmp/postfix-3.6.2/src/milter/milter.h ./src/milter/milter.h --- /var/tmp/postfix-3.6.2/src/milter/milter.h 2020-06-08 12:34:32.000000000 -0400 +++ ./src/milter/milter.h 2021-11-05 18:29:08.000000000 -0400 @@ -100,7 +100,7 @@ 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 */ diff -ur --new-file /var/tmp/postfix-3.6.2/src/milter/milter8.c ./src/milter/milter8.c --- /var/tmp/postfix-3.6.2/src/milter/milter8.c 2020-02-02 15:49:15.000000000 -0500 +++ ./src/milter/milter8.c 2021-11-05 18:29:08.000000000 -0400 @@ -1147,10 +1147,12 @@ 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); @@ -1546,6 +1548,7 @@ 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. */ @@ -1559,9 +1562,18 @@ 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); } } diff -ur --new-file /var/tmp/postfix-3.6.2/src/postconf/postconf_builtin.c ./src/postconf/postconf_builtin.c --- /var/tmp/postfix-3.6.2/src/postconf/postconf_builtin.c 2021-02-18 14:44:05.000000000 -0500 +++ ./src/postconf/postconf_builtin.c 2021-09-25 19:01:35.000000000 -0400 @@ -247,6 +247,7 @@ static const char *pcf_mynetworks(void) { static const char *networks; + VSTRING *exp_buf; const char *junk; /* @@ -255,10 +256,12 @@ 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); @@ -266,7 +269,7 @@ 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); @@ -274,12 +277,13 @@ 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())); } diff -ur --new-file /var/tmp/postfix-3.6.2/src/posttls-finger/posttls-finger.c ./src/posttls-finger/posttls-finger.c --- /var/tmp/postfix-3.6.2/src/posttls-finger/posttls-finger.c 2021-04-18 16:44:01.000000000 -0400 +++ ./src/posttls-finger/posttls-finger.c 2021-11-06 20:09:01.000000000 -0400 @@ -1488,12 +1488,14 @@ /* * Convert service to port number, network byte order. */ + service = (char *) filter_known_tcp_port(service); if (alldig(service)) { if ((port = atoi(service)) >= 65536 || port == 0) - msg_fatal("bad network port in destination: %s", destination); + msg_fatal("bad network port: %s for destination: %s", + service, destination); *portp = htons(port); } else { - if ((sp = getservbyname(filter_known_tcp_port(service), protocol)) != 0) + if ((sp = getservbyname(service, protocol)) != 0) *portp = sp->s_port; else if (strcmp(service, "smtp") == 0) *portp = htons(25); diff -ur --new-file /var/tmp/postfix-3.6.2/src/smtp/smtp_connect.c ./src/smtp/smtp_connect.c --- /var/tmp/postfix-3.6.2/src/smtp/smtp_connect.c 2021-04-18 16:42:40.000000000 -0400 +++ ./src/smtp/smtp_connect.c 2021-11-06 20:09:01.000000000 -0400 @@ -356,12 +356,14 @@ /* * Convert service to port number, network byte order. */ + service = (char *) filter_known_tcp_port(service); if (alldig(service)) { if ((port = atoi(service)) >= 65536 || port == 0) - msg_fatal("bad network port in destination: %s", destination); + msg_fatal("bad network port: %s for destination: %s", + service, destination); *portp = htons(port); } else { - if ((sp = getservbyname(filter_known_tcp_port(service), protocol)) == 0) + if ((sp = getservbyname(service, protocol)) == 0) msg_fatal("unknown service: %s/%s", service, protocol); *portp = sp->s_port; } diff -ur --new-file /var/tmp/postfix-3.6.2/src/smtpd/smtpd_check.c ./src/smtpd/smtpd_check.c --- /var/tmp/postfix-3.6.2/src/smtpd/smtpd_check.c 2021-04-04 11:54:29.000000000 -0400 +++ ./src/smtpd/smtpd_check.c 2021-11-06 19:43:54.000000000 -0400 @@ -4374,8 +4374,8 @@ } } 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); diff -ur --new-file /var/tmp/postfix-3.6.2/src/tls/tls_dane.c ./src/tls/tls_dane.c --- /var/tmp/postfix-3.6.2/src/tls/tls_dane.c 2020-07-19 12:18:48.000000000 -0400 +++ ./src/tls/tls_dane.c 2021-10-25 09:35:37.000000000 -0400 @@ -392,7 +392,7 @@ vstring_sprintf(top, "..."); } - msg_warn("%s%s%s%s: %u %u %u %s%s%s", s1, s2, s3, s4, u, s, m, STR(top), + msg_warn("%s%s%s %s: %u %u %u %s%s%s", s1, s2, s3, s4, u, s, m, STR(top), dlen > MAX_DUMP_BYTES ? "..." : "", dlen > MAX_DUMP_BYTES ? STR(bot) : ""); } @@ -807,13 +807,13 @@ continue; } if (ret == 0) { - tlsa_carp(TLScontext->namaddr, ": ", "", "unusable TLSA RR", + tlsa_carp(TLScontext->namaddr, ":", "", "unusable TLSA RR", tp->usage, tp->selector, tp->mtype, tp->data, tp->length); continue; } /* Internal problem in OpenSSL */ - tlsa_carp(TLScontext->namaddr, ": ", "", "error loading trust settings", + tlsa_carp(TLScontext->namaddr, ":", "", "error loading trust settings", tp->usage, tp->selector, tp->mtype, tp->data, tp->length); tls_print_errors(); return (-1); diff -ur --new-file /var/tmp/postfix-3.6.2/src/tls/tls_misc.c ./src/tls/tls_misc.c --- /var/tmp/postfix-3.6.2/src/tls/tls_misc.c 2020-07-26 17:27:35.000000000 -0400 +++ ./src/tls/tls_misc.c 2021-08-11 15:10:08.000000000 -0400 @@ -883,7 +883,7 @@ EVP_PKEY *peer_pkey = 0; #ifndef OPENSSL_NO_EC - EC_KEY *eckey; + const EC_KEY *eckey; #endif diff -ur --new-file /var/tmp/postfix-3.6.2/src/util/find_inet.c ./src/util/find_inet.c --- /var/tmp/postfix-3.6.2/src/util/find_inet.c 2021-04-18 16:05:04.000000000 -0400 +++ ./src/util/find_inet.c 2021-11-06 20:29:34.000000000 -0400 @@ -85,12 +85,13 @@ struct servent *sp; int port; + service = filter_known_tcp_port(service); if (alldig(service) && (port = atoi(service)) != 0) { if (port < 0 || port > 65535) msg_fatal("bad port number: %s", service); return (htons(port)); } else { - if ((sp = getservbyname(filter_known_tcp_port(service), protocol)) == 0) + if ((sp = getservbyname(service, protocol)) == 0) msg_fatal("unknown service: %s/%s", service, protocol); return (sp->s_port); } diff -ur --new-file /var/tmp/postfix-3.6.2/src/util/myaddrinfo.c ./src/util/myaddrinfo.c --- /var/tmp/postfix-3.6.2/src/util/myaddrinfo.c 2021-04-18 16:03:51.000000000 -0400 +++ ./src/util/myaddrinfo.c 2021-11-06 20:09:01.000000000 -0400 @@ -271,6 +271,7 @@ const char *proto; unsigned port; + service = filter_known_tcp_port(service); if (alldig(service)) { port = atoi(service); return (port < 65536 ? htons(port) : -1); @@ -282,7 +283,7 @@ } else { return (-1); } - if ((sp = getservbyname(filter_known_tcp_port(service), proto)) != 0) { + if ((sp = getservbyname(service, proto)) != 0) { return (sp->s_port); } else { return (-1); @@ -445,7 +446,12 @@ } #endif } - err = getaddrinfo(hostname, filter_known_tcp_port(service), &hints, res); + if (service) { + service = filter_known_tcp_port(service); + if (alldig(service)) + hints.ai_flags |= AI_NUMERICSERV; + } + err = getaddrinfo(hostname, service, &hints, res); #if defined(BROKEN_AI_NULL_SERVICE) if (service == 0 && err == 0) { struct addrinfo *r; @@ -561,7 +567,12 @@ } #endif } - err = getaddrinfo(hostaddr, filter_known_tcp_port(service), &hints, res); + if (service) { + service = filter_known_tcp_port(service); + if (alldig(service)) + hints.ai_flags |= AI_NUMERICSERV; + } + err = getaddrinfo(hostaddr, service, &hints, res); #if defined(BROKEN_AI_NULL_SERVICE) if (service == 0 && err == 0) { struct addrinfo *r;