From: Wietse Z Venema Date: Tue, 2 Jun 2026 05:00:00 +0000 (-0500) Subject: postfix-3.12-20260602 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c7aa6f6941e68bbb4b8c82d2c7ebdeb2687760c5;p=thirdparty%2Fpostfix.git postfix-3.12-20260602 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index 1906d84fd..abaa94ec5 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -31242,6 +31242,18 @@ Apologies for any names omitted. panic() while parsing a TLSA record with length 3. Found during code maintenance. File: tls/tls_dane.c. +20260602 + + Incompatibility: the Postfix SMTP server now rejects ENVID + and ORCPT parameters with an encoded null (+00) sequence. + Problem introduced: Postfix 2.3, date: 20050507; reported + by Michael Wollner. File: smtpd/smtpd.c. + + Incompatibility: the Postfix SMTP server now rejects ORCPT + parameters with encoded characters that are not printable + or whitespace. Files: smtpd/smtpd.c, util/allprint.c, + util/allprint_test.c. + TODO Reorganize PTEST_LIB, PMOCK_LIB, TESTLIB, TESTLIBS, etc. diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index e619ac82e..eb4924c97 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20260601" +#define MAIL_RELEASE_DATE "20260602" #define MAIL_VERSION_NUMBER "3.12" #ifdef SNAPSHOT diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index cf9da72a4..1f1c785aa 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -2790,7 +2790,8 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) } if (dsn_envid || xtext_unquote(state->dsn_buf, arg + 6) == 0 - || !allprint(STR(state->dsn_buf))) { + || !all_isprint_tab(STR(state->dsn_buf)) + || strlen(STR(state->dsn_buf)) != LEN(state->dsn_buf)) { state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "501 5.5.4 Bad ENVID parameter syntax"); return (-1); @@ -3137,7 +3138,9 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) || *(dsn_orcpt_type = STR(state->dsn_orcpt_buf)) == 0 || (strcasecmp(dsn_orcpt_type, "utf-8") == 0 ? uxtext_unquote(state->dsn_buf, coded_addr) == 0 : - xtext_unquote(state->dsn_buf, coded_addr) == 0)) { + xtext_unquote(state->dsn_buf, coded_addr) == 0) + || !all_isprint_tab(STR(state->dsn_buf)) + || strlen(STR(state->dsn_buf)) != LEN(state->dsn_buf)) { state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "501 5.5.4 Error: Bad ORCPT parameter syntax"); diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index 9720b7da5..754dff0bc 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -139,7 +139,7 @@ TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ dict_stream_test.c dict_cli.c dict_union_test.c \ find_inet_service_test.c hash_fnv_test.c known_tcp_ports_test.c \ msg_output_test.c myaddrinfo_test.c mymalloc_test.c mystrtok_test.c \ - unescape_test.c + unescape_test.c allprint_test.c DEFS = -I. -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) FILES = Makefile $(SRCS) $(HDRS) @@ -163,7 +163,7 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \ dict_union_test dict_pipe_test myaddrinfo_test \ clean_env inet_prefix_top printable readlline quote_for_json \ normalize_ws valid_uri_scheme clean_ascii_cntrl_space \ - normalize_v4mapped_addr_test ossl_digest_test + normalize_v4mapped_addr_test ossl_digest_test allprint_test PLUGIN_MAP_SO = $(LIB_PREFIX)pcre$(LIB_SUFFIX) $(LIB_PREFIX)lmdb$(LIB_SUFFIX) \ $(LIB_PREFIX)cdb$(LIB_SUFFIX) $(LIB_PREFIX)sdbm$(LIB_SUFFIX) \ $(LIB_PREFIX)db$(LIB_SUFFIX) @@ -462,6 +462,9 @@ binhash: $(LIB) hash_fnv_test: $(LIB) $(TESTLIBS) update $(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(TESTLIBS) $(SYSLIBS) +allprint_test: $(LIB) $(TESTLIBS) update + $(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(TESTLIBS) $(SYSLIBS) + unix_recv_fd: $(LIB) mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) @@ -662,7 +665,7 @@ tests: update valid_hostname_test mac_expand_test dict_test test_unescape \ valid_utf8_string_test readlline_test quote_for_json_test \ normalize_ws_test valid_uri_scheme_test clean_ascii_cntrl_space_test \ test_normalize_v4mapped_addr test_ossl_digest test_dict_pipe \ - test_dict_union test_hash_fnv + test_dict_union test_hash_fnv test_allprint dict_tests: dict_test \ dict_pcre_tests dict_cidr_test dict_thash_test dict_static_test \ @@ -837,6 +840,9 @@ binhash_test: binhash /usr/share/dict/words test_hash_fnv: hash_fnv_test $(SHLIB_ENV) ${VALGRIND} ./hash_fnv_test +test_allprint: allprint_test + $(SHLIB_ENV) ${VALGRIND} ./allprint_test + hex_code_test: hex_code $(SHLIB_ENV) ${VALGRIND} ./hex_code @@ -1195,6 +1201,22 @@ allprint.o: stringops.h allprint.o: sys_defs.h allprint.o: vbuf.h allprint.o: vstring.h +allprint_test.o: ../../include/msg_jmp.h +allprint_test.o: ../../include/pmock_expect.h +allprint_test.o: ../../include/ptest.h +allprint_test.o: ../../include/ptest_main.h +allprint_test.o: allprint_test.c +allprint_test.o: argv.h +allprint_test.o: check_arg.h +allprint_test.o: msg.h +allprint_test.o: msg_output.h +allprint_test.o: msg_vstream.h +allprint_test.o: myrand.h +allprint_test.o: stringops.h +allprint_test.o: sys_defs.h +allprint_test.o: vbuf.h +allprint_test.o: vstream.h +allprint_test.o: vstring.h allspace.o: allspace.c allspace.o: check_arg.h allspace.o: stringops.h diff --git a/postfix/src/util/allprint.c b/postfix/src/util/allprint.c index 6e9c519ad..4f44c2030 100644 --- a/postfix/src/util/allprint.c +++ b/postfix/src/util/allprint.c @@ -6,10 +6,24 @@ /* SYNOPSIS /* #include /* +/* int all_isprint(buffer) +/* const char *buffer; +/* +/* int all_isprint_tab(buffer) +/* const char *buffer; +/* LEGACY API /* int allprint(buffer) /* const char *buffer; /* DESCRIPTION -/* allprint() determines if its argument is an all-printable string. +/* all_isprint() determines if its argument contains only isprint() +/* characters (letters, digits, punctuation, space). +/* +/* all_isprint_tab() determines if its argument contains only +/* isprint() or TAB characters. This function follows the "white +/* space" specification in RFC 5322 section 2.2.1. +/* +/* allprint() implements ABI backwards compatibility. For new +/* programs, allprint is an alias for all_isprint. /* /* Arguments: /* .IP buffer @@ -23,6 +37,9 @@ /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA +/* +/* Wietse Venema +/* porcupine.org /*--*/ /* System library. */ @@ -34,9 +51,18 @@ #include "stringops.h" -/* allprint - return true if string is all printable */ +/* allprint - ABI compatibility */ + +#undef allprint int allprint(const char *string) +{ + return (all_isprint(string)); +} + +/* all_isprint - return true if string contains only isprint() characters */ + +int all_isprint(const char *string) { const char *cp; int ch; @@ -48,3 +74,18 @@ int allprint(const char *string) return (0); return (1); } + +/* all_isprint_tab - return true with only isprint() or TAB characters */ + +int all_isprint_tab(const char *string) +{ + const char *cp; + int ch; + + if (*string == 0) + return (0); + for (cp = string; (ch = *(unsigned char *) cp) != 0; cp++) + if (!ISASCII(ch) || (!ISPRINT(ch) && ch != '\t')) + return (0); + return (1); +} diff --git a/postfix/src/util/allprint_test.c b/postfix/src/util/allprint_test.c new file mode 100644 index 000000000..6f880a146 --- /dev/null +++ b/postfix/src/util/allprint_test.c @@ -0,0 +1,90 @@ + /* + * Test program to exercise allprint.c. See PTEST_README for documentation. + */ + + /* + * System library. + */ +#include +#include + + /* + * Utility library. + */ +#include + + /* + * Test library. + */ +#include + +typedef struct PTEST_CASE { + const char *testname; /* identifies test case */ + void (*action) (PTEST_CTX *t, const struct PTEST_CASE *tp); +} PTEST_CASE; + +static void test_allprint(PTEST_CTX *t, const PTEST_CASE *tp) +{ + if (allprint != all_isprint) + ptest_error(t, "allprint %p != all_isprint %p", + (void *) allprint, (void *) all_isprint); +} + +static void test_all_isprint(PTEST_CTX *t, const PTEST_CASE *tp) +{ + unsigned char long_buf[256]; + int code; + int pos; + + for (pos = 0, code = 1; code < 256; code++) { + unsigned char short_buf[] = {code, 0}; + + if (ISPRINT(code)) { + long_buf[pos++] = code; + if (!all_isprint((char *) short_buf)) + ptest_error(t, "all_isprint(\"\\x%x\"): got 0, want 1", code); + } else { + if (all_isprint((char *) short_buf)) + ptest_error(t, "all_isprint(\"\\x%x\"): got 1, want 0", code); + } + } + long_buf[pos] = 0; + if (!all_isprint((char *) long_buf)) + ptest_error(t, "all_isprint(t, \"%s\"): got 0, want 1", long_buf); +} + +static void test_all_isprint_tab(PTEST_CTX *t, const PTEST_CASE *tp) +{ + unsigned char long_buf[256]; + int code; + int pos; + + for (pos = 0, code = 1; code < 256; code++) { + unsigned char short_buf[] = {code, 0}; + + if (ISPRINT(code) || code == '\t') { + long_buf[pos++] = code; + if (!all_isprint_tab((char *) short_buf)) + ptest_error(t, "all_isprint_tab(\"\\x%x\"): got 0, want 1", + code); + } else { + if (all_isprint_tab((char *) short_buf)) + ptest_error(t, "all_isprint_tab(\"\\x%x\"): got 1, want 0", + code); + } + } + long_buf[pos] = 0; + if (!all_isprint_tab((char *) long_buf)) + ptest_error(t, "all_isprint(t, \"%s\"): got 0, want 1", long_buf); +} + + /* + * The test cases. + */ +static const PTEST_CASE ptestcases[] = { + {.testname = "test allprint",.action = test_allprint,}, + {.testname = "test all_isprint",.action = test_all_isprint,}, + {.testname = "test all_isprint_tab",.action = test_all_isprint_tab,}, +}; + +#include diff --git a/postfix/src/util/stringops.h b/postfix/src/util/stringops.h index 3cf2d117b..38efd6cba 100644 --- a/postfix/src/util/stringops.h +++ b/postfix/src/util/stringops.h @@ -56,6 +56,8 @@ extern int alldig(const char *); extern int allalnum(const char *); extern int allalnumus(const char *); extern int allprint(const char *); +extern int all_isprint(const char *); +extern int all_isprint_tab(const char *); extern int allspace(const char *); extern int allascii_len(const char *, ssize_t); extern const char *WARN_UNUSED_RESULT split_nameval(char *, char **, char **); @@ -97,6 +99,11 @@ extern char *normalize_ws(char *); #define strncasecmp_utf8(s1, s2, l) \ strncasecmp_utf8x(util_utf8_enable ? CASEF_FLAG_UTF8 : 0, (s1), (s2), (l)) + /* + * API compatibility wrappers. + */ +#define allprint all_isprint + /* * Use STRREF(x) instead of x, to shut up compiler warnings when the operand * is a string literal.