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.
* 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
}
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);
|| *(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");
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)
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)
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)
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 \
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
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
/* SYNOPSIS
/* #include <stringops.h>
/*
+/* 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
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* porcupine.org
/*--*/
/* System library. */
#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;
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);
+}
--- /dev/null
+ /*
+ * Test program to exercise allprint.c. See PTEST_README for documentation.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <ctype.h>
+
+ /*
+ * Utility library.
+ */
+#include <stringops.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+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 <ptest_main.h>
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 **);
#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.