Do nothing. When TLS security enforcement is required but
fails, a TLSRPT summary message will be delayed
until the problem is addressed, or until the message expires
diff --git a/postfix/proto/stop.double-history b/postfix/proto/stop.double-history
index 0f36085d5..ef83bc3c8 100644
--- a/postfix/proto/stop.double-history
+++ b/postfix/proto/stop.double-history
@@ -158,3 +158,4 @@ proto proto socketmap_table
pickup pickup c qmgr qmgr h qmgr qmgr_active c
qmgr qmgr_deliver c qmgr qmgr_message c qmqpd qmqpd c
smtp smtp_proto c smtpd smtpd c verify verify c
+ operations Files cleanup cleanup h cleanup cleanup_message c
diff --git a/postfix/proto/stop.spell-history b/postfix/proto/stop.spell-history
index 8a8540985..74e0858b7 100644
--- a/postfix/proto/stop.spell-history
+++ b/postfix/proto/stop.spell-history
@@ -98,3 +98,4 @@ diffs
CLOSEFROM
Roessner
bitflags
+Schulze
diff --git a/postfix/src/cleanup/Makefile.in b/postfix/src/cleanup/Makefile.in
index adf21aa21..306d3b537 100644
--- a/postfix/src/cleanup/Makefile.in
+++ b/postfix/src/cleanup/Makefile.in
@@ -959,6 +959,42 @@ cleanup_envelope.o: ../../include/vstream.h
cleanup_envelope.o: ../../include/vstring.h
cleanup_envelope.o: cleanup.h
cleanup_envelope.o: cleanup_envelope.c
+cleanup_envelope_test.o: ../../include/argv.h
+cleanup_envelope_test.o: ../../include/attr.h
+cleanup_envelope_test.o: ../../include/been_here.h
+cleanup_envelope_test.o: ../../include/check_arg.h
+cleanup_envelope_test.o: ../../include/cleanup_user.h
+cleanup_envelope_test.o: ../../include/dict.h
+cleanup_envelope_test.o: ../../include/dsn_mask.h
+cleanup_envelope_test.o: ../../include/header_body_checks.h
+cleanup_envelope_test.o: ../../include/header_opts.h
+cleanup_envelope_test.o: ../../include/htable.h
+cleanup_envelope_test.o: ../../include/mail_conf.h
+cleanup_envelope_test.o: ../../include/mail_params.h
+cleanup_envelope_test.o: ../../include/mail_stream.h
+cleanup_envelope_test.o: ../../include/maps.h
+cleanup_envelope_test.o: ../../include/match_list.h
+cleanup_envelope_test.o: ../../include/milter.h
+cleanup_envelope_test.o: ../../include/mime_state.h
+cleanup_envelope_test.o: ../../include/msg.h
+cleanup_envelope_test.o: ../../include/msg_vstream.h
+cleanup_envelope_test.o: ../../include/myflock.h
+cleanup_envelope_test.o: ../../include/mymalloc.h
+cleanup_envelope_test.o: ../../include/nvtable.h
+cleanup_envelope_test.o: ../../include/rec_type.h
+cleanup_envelope_test.o: ../../include/record.h
+cleanup_envelope_test.o: ../../include/resolve_clnt.h
+cleanup_envelope_test.o: ../../include/sendopts.h
+cleanup_envelope_test.o: ../../include/smtputf8.h
+cleanup_envelope_test.o: ../../include/string_list.h
+cleanup_envelope_test.o: ../../include/stringops.h
+cleanup_envelope_test.o: ../../include/sys_defs.h
+cleanup_envelope_test.o: ../../include/tok822.h
+cleanup_envelope_test.o: ../../include/vbuf.h
+cleanup_envelope_test.o: ../../include/vstream.h
+cleanup_envelope_test.o: ../../include/vstring.h
+cleanup_envelope_test.o: cleanup.h
+cleanup_envelope_test.o: cleanup_envelope_test.c
cleanup_extracted.o: ../../include/argv.h
cleanup_extracted.o: ../../include/attr.h
cleanup_extracted.o: ../../include/been_here.h
@@ -1172,6 +1208,7 @@ cleanup_message.o: ../../include/ascii_header_text.h
cleanup_message.o: ../../include/attr.h
cleanup_message.o: ../../include/been_here.h
cleanup_message.o: ../../include/check_arg.h
+cleanup_message.o: ../../include/clean_ascii_cntrl_space.h
cleanup_message.o: ../../include/cleanup_user.h
cleanup_message.o: ../../include/conv_time.h
cleanup_message.o: ../../include/dict.h
@@ -1206,12 +1243,12 @@ cleanup_message.o: ../../include/rec_type.h
cleanup_message.o: ../../include/record.h
cleanup_message.o: ../../include/resolve_clnt.h
cleanup_message.o: ../../include/rfc2047_code.h
+cleanup_message.o: ../../include/sendopts.h
cleanup_message.o: ../../include/split_at.h
cleanup_message.o: ../../include/string_list.h
cleanup_message.o: ../../include/stringops.h
cleanup_message.o: ../../include/sys_defs.h
cleanup_message.o: ../../include/tok822.h
-cleanup_message.o: ../../include/clean_ascii_cntrl_space.h
cleanup_message.o: ../../include/vbuf.h
cleanup_message.o: ../../include/vstream.h
cleanup_message.o: ../../include/vstring.h
diff --git a/postfix/src/cleanup/cleanup.h b/postfix/src/cleanup/cleanup.h
index 3565b6f16..82bd482ef 100644
--- a/postfix/src/cleanup/cleanup.h
+++ b/postfix/src/cleanup/cleanup.h
@@ -12,6 +12,7 @@
* System library.
*/
#include
+#include /* C99 uint64_t */
/*
* Utility library.
@@ -69,7 +70,7 @@ typedef struct CLEANUP_STATE {
int qmgr_opts; /* qmgr processing options */
int errs; /* any badness experienced */
int err_mask; /* allowed badness */
- int headers_seen; /* which headers were seen */
+ uint64_t headers_seen; /* which headers were seen */
int hop_count; /* count of received: headers */
char *resent; /* any resent- header seen */
BH_TABLE *dups; /* recipient dup filter */
@@ -141,6 +142,11 @@ typedef struct CLEANUP_STATE {
#define CLEANUP_FLAG_WARN_SEEN (1<<17) /* REC_TYPE_WARN record seen */
#define CLEANUP_FLAG_END_SEEN (1<<18) /* REC_TYPE_END record seen */
+ /*
+ * Bit mask for the CLEANUP_STATE.headers_seen member.
+ */
+#define HDRS_SEEN_MASK(hval) ((uint64_t) 1 << (hval))
+
/*
* Mappings.
*/
diff --git a/postfix/src/cleanup/cleanup_envelope_test.c b/postfix/src/cleanup/cleanup_envelope_test.c
index cc0a098b1..2fa168961 100644
--- a/postfix/src/cleanup/cleanup_envelope_test.c
+++ b/postfix/src/cleanup/cleanup_envelope_test.c
@@ -132,8 +132,8 @@ static int overrides_size_fields(const TEST_CASE *tp)
CLEANUP_STATE saved_state = *state;
/*
- * Process the test SIZE record payload and write an place-holder SIZE
- * record that will be overwritten later with final information.
+ * Process the test SIZE record payload, clear some bits from the
+ * sendopts field, and write an all-zeroes preliminary SIZE record.
*/
VSTRING *output_stream_buf = vstring_alloc(100);
@@ -153,7 +153,8 @@ static int overrides_size_fields(const TEST_CASE *tp)
input_buf = 0;
/*
- * Write an updated SIZE record to the output stream.
+ * Overwrite the SIZE record with an updated version that includes the
+ * modified sendopts field.
*/
cleanup_final(state);
if (state->errs != CLEANUP_STAT_OK) {
@@ -166,7 +167,8 @@ static int overrides_size_fields(const TEST_CASE *tp)
state->dst = 0;
/*
- * Compare the stored record content against the expected content.
+ * Read the final SIZE record content. This normally happens in the queue
+ * manager, and in the pickup daemon after a message is re-queued.
*/
VSTREAM *fp;
@@ -185,6 +187,13 @@ static int overrides_size_fields(const TEST_CASE *tp)
(void) vstream_fclose(fp);
vstring_free(output_stream_buf);
+ /*
+ * Compare the stored SIZE record content against the expected content.
+ * We expect that the fields for data_size, data_offset, rcpt_count,
+ * qmgr_opts, and cont_length, are consistent with the saved
+ * CLEANUP_STATE, and we expect to see a specific value for the sendopts
+ * field that was made by cleanup_envelope().
+ */
int got_conv;
long data_size, data_offset, cont_length;
int rcpt_count, qmgr_opts, sendopts;
diff --git a/postfix/src/cleanup/cleanup_message.c b/postfix/src/cleanup/cleanup_message.c
index 21d94431d..b9a7e9360 100644
--- a/postfix/src/cleanup/cleanup_message.c
+++ b/postfix/src/cleanup/cleanup_message.c
@@ -96,6 +96,7 @@
#include
#include
#include
+#include
/* Application-specific. */
@@ -631,7 +632,7 @@ static void cleanup_header_callback(void *context, int header_class,
* MAY remove Return-path headers before adding their own.
*/
else {
- state->headers_seen |= (1 << hdr_opts->type);
+ state->headers_seen |= HDRS_SEEN_MASK(hdr_opts->type);
if (hdr_opts->type == HDR_MESSAGE_ID) {
ssize_t len;
@@ -652,6 +653,17 @@ static void cleanup_header_callback(void *context, int header_class,
if (state->hop_count == 1)
argv_add(state->auto_hdrs, vstring_str(header_buf), ARGV_END);
}
+ if (hdr_opts->type == HDR_TLS_REQUIRED) {
+ char *cp = vstring_str(header_buf) + strlen(hdr_opts->name) + 1;
+
+ while (ISSPACE(*cp))
+ cp++;
+ if (strcasecmp(cp, "no") == 0)
+ state->sendopts |= SOPT_REQUIRETLS_HEADER;
+ else
+ msg_warn("ignoring malformed header: '%.100s'",
+ vstring_str(header_buf));
+ }
if (CLEANUP_OUT_OK(state)) {
if (hdr_opts->flags & HDR_OPT_RR)
state->resent = "Resent-";
@@ -758,8 +770,8 @@ static void cleanup_header_done_callback(void *context)
* complicate future code that wants to log more name=value attributes.
*/
if ((state->hdr_rewrite_context || var_always_add_hdrs)
- && (state->headers_seen & (1 << (state->resent[0] ?
- HDR_RESENT_MESSAGE_ID : HDR_MESSAGE_ID))) == 0) {
+ && (state->headers_seen & HDRS_SEEN_MASK(state->resent[0] ?
+ HDR_RESENT_MESSAGE_ID : HDR_MESSAGE_ID)) == 0) {
if (var_long_queue_ids) {
vstring_sprintf(state->temp1, "%s@%s",
state->queue_id, var_myhostname);
@@ -776,14 +788,14 @@ static void cleanup_header_done_callback(void *context)
msg_info("%s: %smessage-id=<%s>",
state->queue_id, *state->resent ? "resent-" : "",
vstring_str(state->temp1));
- state->headers_seen |= (1 << (state->resent[0] ?
- HDR_RESENT_MESSAGE_ID : HDR_MESSAGE_ID));
+ state->headers_seen |= HDRS_SEEN_MASK(state->resent[0] ?
+ HDR_RESENT_MESSAGE_ID : HDR_MESSAGE_ID);
if (state->resent[0] == 0 && state->message_id == 0)
state->message_id = concatenate("<", vstring_str(state->temp1),
">", (char *) 0);
}
- if ((state->headers_seen & (1 << HDR_MESSAGE_ID)) == 0)
+ if ((state->headers_seen & HDRS_SEEN_MASK(HDR_MESSAGE_ID)) == 0)
msg_info("%s: message-id=<>", state->queue_id);
/*
@@ -791,8 +803,8 @@ static void cleanup_header_done_callback(void *context)
* with the GMT offset at the end.
*/
if ((state->hdr_rewrite_context || var_always_add_hdrs)
- && (state->headers_seen & (1 << (state->resent[0] ?
- HDR_RESENT_DATE : HDR_DATE))) == 0) {
+ && (state->headers_seen & HDRS_SEEN_MASK(state->resent[0] ?
+ HDR_RESENT_DATE : HDR_DATE)) == 0) {
vstring_sprintf(state->temp2, "%sDate: %s",
state->resent, mail_date(state->arrival_time.tv_sec));
cleanup_out_header(state, state->temp2);
@@ -802,8 +814,8 @@ static void cleanup_header_done_callback(void *context)
* Add a missing (Resent-)From: header.
*/
if ((state->hdr_rewrite_context || var_always_add_hdrs)
- && (state->headers_seen & (1 << (state->resent[0] ?
- HDR_RESENT_FROM : HDR_FROM))) == 0) {
+ && (state->headers_seen & HDRS_SEEN_MASK(state->resent[0] ?
+ HDR_RESENT_FROM : HDR_FROM)) == 0) {
char *fullname;
quote_822_local(state->temp1, *state->sender ?
@@ -869,8 +881,10 @@ static void cleanup_header_done_callback(void *context)
/*
* Add a missing destination header.
*/
-#define VISIBLE_RCPT ((1 << HDR_TO) | (1 << HDR_RESENT_TO) \
- | (1 << HDR_CC) | (1 << HDR_RESENT_CC))
+#define VISIBLE_RCPT (HDRS_SEEN_MASK(HDR_TO) \
+ | HDRS_SEEN_MASK(HDR_RESENT_TO) \
+ | HDRS_SEEN_MASK(HDR_CC) \
+ | HDRS_SEEN_MASK(HDR_RESENT_CC))
if ((state->hdr_rewrite_context || var_always_add_hdrs)
&& (state->headers_seen & VISIBLE_RCPT) == 0 && *var_rcpt_witheld) {
diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in
index 84f10c40b..67520c7e2 100644
--- a/postfix/src/global/Makefile.in
+++ b/postfix/src/global/Makefile.in
@@ -131,7 +131,7 @@ TESTPROG= domain_list dot_lockfile mail_addr_crunch mail_addr_find \
fold_addr smtp_reply_footer mail_addr_map normalize_mailhost_addr \
haproxy_srvr map_search delivered_hdr login_sender_match \
compat_level config_known_tcp_ports hfrom_format rfc2047_code \
- ascii_header_text sendopts
+ ascii_header_text sendopts_test
LIBS = ../../lib/lib$(LIB_PREFIX)util$(LIB_SUFFIX)
LIB_DIR = ../../lib
@@ -405,7 +405,7 @@ rfc2047_code: rfc2047_code.c $(LIB) $(LIBS)
ascii_header_text: ascii_header_text.c $(LIB) $(LIBS)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
-sendopts: sendopts.c $(LIB) $(LIBS)
+sendopts_test: sendopts_test.c $(LIB) $(LIBS)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
config_known_tcp_ports: config_known_tcp_ports.c $(LIB) $(LIBS)
@@ -421,7 +421,7 @@ tests: tok822_test mime_tests strip_addr_test tok822_limit_test \
normalize_mailhost_addr_test haproxy_srvr_test map_search_test \
delivered_hdr_test login_sender_match_test compat_level_test \
config_known_tcp_ports_test hfrom_format_test rfc2047_code_test \
- ascii_header_text_test sendopts_test
+ ascii_header_text_test test_sendopts
mime_tests: mime_test mime_nest mime_8bit mime_dom mime_trunc mime_cvt \
mime_cvt2 mime_cvt3 mime_garb1 mime_garb2 mime_garb3 mime_garb4
@@ -793,8 +793,8 @@ rfc2047_code_test: update rfc2047_code
ascii_header_text_test: update ascii_header_text
$(SHLIB_ENV) $(VALGRIND) ./ascii_header_text
-sendopts_test: update sendopts
- -$(SHLIB_ENV) $(VALGRIND) ./sendopts
+test_sendopts: update sendopts_test
+ -$(SHLIB_ENV) $(VALGRIND) ./sendopts_test
clean:
rm -f *.o $(LIB) *core $(TESTPROG) junk $(MAPS)
@@ -2679,6 +2679,24 @@ scache_single.o: ../../include/vbuf.h
scache_single.o: ../../include/vstring.h
scache_single.o: scache.h
scache_single.o: scache_single.c
+sendopts.o: ../../include/check_arg.h
+sendopts.o: ../../include/msg.h
+sendopts.o: ../../include/name_mask.h
+sendopts.o: ../../include/sys_defs.h
+sendopts.o: ../../include/vbuf.h
+sendopts.o: ../../include/vstring.h
+sendopts.o: sendopts.c
+sendopts.o: sendopts.h
+sendopts_test.o: ../../include/check_arg.h
+sendopts_test.o: ../../include/msg.h
+sendopts_test.o: ../../include/msg_vstream.h
+sendopts_test.o: ../../include/stringops.h
+sendopts_test.o: ../../include/sys_defs.h
+sendopts_test.o: ../../include/vbuf.h
+sendopts_test.o: ../../include/vstream.h
+sendopts_test.o: ../../include/vstring.h
+sendopts_test.o: sendopts.h
+sendopts_test.o: sendopts_test.c
sent.o: ../../include/attr.h
sent.o: ../../include/check_arg.h
sent.o: ../../include/htable.h
diff --git a/postfix/src/global/header_opts.c b/postfix/src/global/header_opts.c
index c0c4d5ceb..1be71a4ed 100644
--- a/postfix/src/global/header_opts.c
+++ b/postfix/src/global/header_opts.c
@@ -26,6 +26,9 @@
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* porcupine.org
/*--*/
/* System library. */
@@ -87,6 +90,7 @@ static HEADER_OPTS header_opts[] = {
"Return-Receipt-To", HDR_RETURN_RECEIPT_TO, HDR_OPT_SENDER,
"Sender", HDR_SENDER, HDR_OPT_SENDER,
"To", HDR_TO, HDR_OPT_XRECIP,
+ "TLS-Required", HDR_TLS_REQUIRED, 0,
};
#define HEADER_OPTS_SIZE (sizeof(header_opts) / sizeof(header_opts[0]))
diff --git a/postfix/src/global/header_opts.h b/postfix/src/global/header_opts.h
index b03cc5d87..1af23b22c 100644
--- a/postfix/src/global/header_opts.h
+++ b/postfix/src/global/header_opts.h
@@ -20,8 +20,7 @@ typedef struct {
} HEADER_OPTS;
/*
- * Header types. If we reach 31, we must group the headers we need to
- * remember at the beginning, or we should use fd_set bit sets.
+ * Header types.
*/
#define HDR_OTHER 0
#define HDR_APPARENTLY_TO 1
@@ -55,6 +54,7 @@ typedef struct {
#define HDR_CONTENT_ID 29
#define HDR_MIME_VERSION 30
#define HDR_DISP_NOTIFICATION 31
+#define HDR_TLS_REQUIRED 32 /* RFC 8689 */
/*
* Header flags.
@@ -79,6 +79,9 @@ extern const HEADER_OPTS *header_opts_find(const char *);
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* porcupine.org
/*--*/
#endif
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index d77292240..0d155f8e2 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 "20250116"
+#define MAIL_RELEASE_DATE "20250117"
#define MAIL_VERSION_NUMBER "3.10"
#ifdef SNAPSHOT
diff --git a/postfix/src/global/sendopts.c b/postfix/src/global/sendopts.c
index 0dc3ddc15..f8570db27 100644
--- a/postfix/src/global/sendopts.c
+++ b/postfix/src/global/sendopts.c
@@ -6,8 +6,9 @@
/* SYNOPSIS
/* #include
/*
-/* const char *sendopts_strflags(code)
-/* int code;
+/* const char *sendopts_strflags(
+/* int flags,
+/* int delim)
/* DESCRIPTION
/* Postfix queue files and IPC messages contain a sendopts field
/* with flags that control SMTPUTF8, REQUIRETLS, etc. support. The
@@ -18,6 +19,14 @@
/*
/* sendopts_strflags() maps a sendopts flag value to printable
/* string. The result is overwritten upon each call.
+/*
+/* Arguments:
+/* .IP flags
+/* A bitmask that is to be converted to text.
+/* .IP delim
+/* The character to separate output words with: one of ' ,|'.
+/* DIAGNOSTICS
+/* Panic: invalid delimiter. Fatal error: invalid flag.
/* LICENSE
/* .ad
/* .fi
@@ -30,6 +39,7 @@
/* System library. */
#include
+#include
/*
* Utility library.
@@ -44,7 +54,7 @@
#include
/*
- * Mapping from flags code to printable string.
+ * Mapping from flags to printable string.
*/
static NAME_MASK sendopts_flag_map[] = {
"smtputf8_requested", SOPT_SMTPUTF8_REQUESTED,
@@ -58,9 +68,13 @@ static NAME_MASK sendopts_flag_map[] = {
/* sendopts_strflags - map flags code to printable string */
-const char *sendopts_strflags(unsigned flags)
+const char *sendopts_strflags(unsigned flags, int delim)
{
+ const char myname[] = "sendopts_strflags";
+ static const char delims[] = " ,|";
+ static const int dflags[] = {0, NAME_MASK_COMMA, NAME_MASK_PIPE};
static VSTRING *result;
+ const char *cp;
if (flags == 0)
return ("none");
@@ -70,92 +84,10 @@ const char *sendopts_strflags(unsigned flags)
else
VSTRING_RESET(result);
+ if ((cp = strchr(delims, delim)) == 0)
+ msg_panic("%s: bad delimiter: '%c'", myname, delim);
+
return (str_name_mask_opt(result, "sendopts_strflags", sendopts_flag_map,
- flags, NAME_MASK_FATAL));
+ flags, NAME_MASK_FATAL | dflags[cp - delims]));
}
-#ifdef TEST
-#include
-#include
-#include
-#include
-
- /*
- * Tests and test cases.
- */
-typedef struct TEST_CASE {
- const char *label; /* identifies test case */
- int mask;
- const char *want;
-} TEST_CASE;
-
-static const TEST_CASE test_cases[] = {
- {"SOPT_SMTPUTF8_ALL",
- SOPT_SMTPUTF8_ALL,
- "smtputf8_requested smtputf8_header smtputf8_sender smtputf8_recipient"
- },
- {"SOPT_SMTPUTF8_DERIVED",
- SOPT_SMTPUTF8_DERIVED,
- "smtputf8_header smtputf8_sender smtputf8_recipient"
- },
- {"SOPT_SMTPUTF8_REQUESTED",
- SOPT_SMTPUTF8_REQUESTED,
- "smtputf8_requested"
- },
- {"SOPT_SMTPUTF8_HEADER",
- SOPT_SMTPUTF8_HEADER,
- "smtputf8_header"
- },
- {"SOPT_SMTPUTF8_SENDER",
- SOPT_SMTPUTF8_SENDER,
- "smtputf8_sender"
- },
- {"SOPT_SMTPUTF8_RECIPIENT",
- SOPT_SMTPUTF8_RECIPIENT,
- "smtputf8_recipient"
- },
- {"SOPT_REQUIRETLS_ALL",
- SOPT_REQUIRETLS_ALL,
- "requiretls_header requiretls_esmtp"
- },
- {"SOPT_REQUIRETLS_DERIVED",
- SOPT_REQUIRETLS_DERIVED,
- "requiretls_header"
- },
- {"SOPT_REQUIRETLS_HEADER",
- SOPT_REQUIRETLS_HEADER,
- "requiretls_header"
- },
- {"SOPT_REQUIRETLS_ESMTP",
- SOPT_REQUIRETLS_ESMTP,
- "requiretls_esmtp"
- },
- {0},
-};
-
-int main(int argc, char **argv)
-{
- const TEST_CASE *tp;
- int pass = 0;
- int fail = 0;
- const char *got;
-
- msg_vstream_init(sane_basename((VSTRING *) 0, argv[0]), VSTREAM_ERR);
-
- for (tp = test_cases; tp->label != 0; tp++) {
- msg_info("RUN %s", tp->label);
- got = sendopts_strflags(tp->mask);
- if (strcmp(got, tp->want) != 0) {
- msg_warn("got result '%s', want: '%s'", got, tp->want);
- fail++;
- msg_info("FAIL %s", tp->label);
- } else {
- msg_info("PASS %s", tp->label);
- pass++;
- }
- }
- msg_info("PASS=%d FAIL=%d", pass, fail);
- exit(fail != 0);
-}
-
-#endif
diff --git a/postfix/src/global/sendopts.h b/postfix/src/global/sendopts.h
index c80ea5a33..bcc54809b 100644
--- a/postfix/src/global/sendopts.h
+++ b/postfix/src/global/sendopts.h
@@ -44,7 +44,7 @@
/*
* Debug helper.
*/
-extern const char *sendopts_strflags(unsigned flags);
+extern const char *sendopts_strflags(unsigned flags, int delim);
/* LICENSE
/* .ad
diff --git a/postfix/src/global/sendopts_test.c b/postfix/src/global/sendopts_test.c
new file mode 100644
index 000000000..e2df6b774
--- /dev/null
+++ b/postfix/src/global/sendopts_test.c
@@ -0,0 +1,108 @@
+ /*
+ * System library.
+ */
+#include
+#include
+#include
+#include
+
+ /*
+ * Utility library.
+ */
+#include
+#include
+#include
+#include
+
+ /*
+ * Global library.
+ */
+#include
+
+ /*
+ * Tests and test cases.
+ */
+typedef struct TEST_CASE {
+ const char *label; /* identifies test case */
+ int mask;
+ const char *want;
+} TEST_CASE;
+
+static const TEST_CASE test_cases[] = {
+ {"SOPT_SMTPUTF8_ALL",
+ SOPT_SMTPUTF8_ALL,
+ "smtputf8_requested smtputf8_header smtputf8_sender smtputf8_recipient"
+ },
+ {"SOPT_SMTPUTF8_DERIVED",
+ SOPT_SMTPUTF8_DERIVED,
+ "smtputf8_header smtputf8_sender smtputf8_recipient"
+ },
+ {"SOPT_SMTPUTF8_REQUESTED",
+ SOPT_SMTPUTF8_REQUESTED,
+ "smtputf8_requested"
+ },
+ {"SOPT_SMTPUTF8_HEADER",
+ SOPT_SMTPUTF8_HEADER,
+ "smtputf8_header"
+ },
+ {"SOPT_SMTPUTF8_SENDER",
+ SOPT_SMTPUTF8_SENDER,
+ "smtputf8_sender"
+ },
+ {"SOPT_SMTPUTF8_RECIPIENT",
+ SOPT_SMTPUTF8_RECIPIENT,
+ "smtputf8_recipient"
+ },
+ {"SOPT_REQUIRETLS_ALL",
+ SOPT_REQUIRETLS_ALL,
+ "requiretls_header requiretls_esmtp"
+ },
+ {"SOPT_REQUIRETLS_DERIVED",
+ SOPT_REQUIRETLS_DERIVED,
+ "requiretls_header"
+ },
+ {"SOPT_REQUIRETLS_HEADER",
+ SOPT_REQUIRETLS_HEADER,
+ "requiretls_header"
+ },
+ {"SOPT_REQUIRETLS_ESMTP",
+ SOPT_REQUIRETLS_ESMTP,
+ "requiretls_esmtp"
+ },
+ {"SOPT_FLAG_ALL",
+ SOPT_FLAG_ALL,
+ "smtputf8_requested smtputf8_header smtputf8_sender smtputf8_recipient"
+ " requiretls_header requiretls_esmtp"
+ },
+ {"SOPT_FLAG_DERIVED",
+ SOPT_FLAG_DERIVED,
+ "smtputf8_header smtputf8_sender smtputf8_recipient"
+ " requiretls_header"
+ },
+ {0},
+};
+
+int main(int argc, char **argv)
+{
+ const TEST_CASE *tp;
+ int pass = 0;
+ int fail = 0;
+ const char *got;
+
+ msg_vstream_init(sane_basename((VSTRING *) 0, argv[0]), VSTREAM_ERR);
+
+ for (tp = test_cases; tp->label != 0; tp++) {
+ msg_info("RUN %s", tp->label);
+ got = sendopts_strflags(tp->mask, ' ');
+ if (strcmp(got, tp->want) != 0) {
+ msg_warn("got result '%s', want: '%s'", got, tp->want);
+ fail++;
+ msg_info("FAIL %s", tp->label);
+ } else {
+ msg_info("PASS %s", tp->label);
+ pass++;
+ }
+ }
+ msg_info("PASS=%d FAIL=%d", pass, fail);
+ exit(fail != 0);
+}
diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in
index f416b071a..44add46b2 100644
--- a/postfix/src/smtp/Makefile.in
+++ b/postfix/src/smtp/Makefile.in
@@ -259,6 +259,7 @@ smtp_connect.o: ../../include/recipient_list.h
smtp_connect.o: ../../include/resolve_clnt.h
smtp_connect.o: ../../include/sane_connect.h
smtp_connect.o: ../../include/scache.h
+smtp_connect.o: ../../include/sendopts.h
smtp_connect.o: ../../include/sock_addr.h
smtp_connect.o: ../../include/split_at.h
smtp_connect.o: ../../include/string_list.h
@@ -804,7 +805,6 @@ smtp_tlsrpt.o: ../../include/header_body_checks.h
smtp_tlsrpt.o: ../../include/header_opts.h
smtp_tlsrpt.o: ../../include/hex_code.h
smtp_tlsrpt.o: ../../include/htable.h
-smtp_tlsrpt.o: ../../include/inet_proto.h
smtp_tlsrpt.o: ../../include/mail_params.h
smtp_tlsrpt.o: ../../include/maps.h
smtp_tlsrpt.o: ../../include/match_list.h
diff --git a/postfix/src/smtp/smtp_connect.c b/postfix/src/smtp/smtp_connect.c
index e60450f21..88ea18eb0 100644
--- a/postfix/src/smtp/smtp_connect.c
+++ b/postfix/src/smtp/smtp_connect.c
@@ -105,6 +105,7 @@
#include
#include
#include
+#include
/* DNS library. */
@@ -497,6 +498,51 @@ static void smtp_cache_policy(SMTP_STATE *state, const char *dest)
}
}
+/* smtp_get_effective_tls_level - get the effective TLS security level */
+
+static int smtp_get_effective_tls_level(DSN_BUF *why, SMTP_STATE *state)
+{
+ SMTP_ITERATOR *iter = state->iterator;
+ SMTP_TLS_POLICY *tls = state->tls;
+
+ /*
+ * Determine the TLS level for this destination.
+ */
+ if (!smtp_tls_policy_cache_query(why, tls, iter)) {
+ return (0);
+ }
+
+ /*
+ * If the sender requires verified TLS, the TLS level must enforce a
+ * server certificate match.
+ */
+#if 0
+ else if ((state->request->sendopts & SOPT_REQUIRETLS_ESMTP)) {
+ if (TLS_MUST_MATCH(tls->level) == 0) {
+ dsb_simple(why, "5.7.10", "Sender requires verified TLS, "
+ " but my configured TLS security level is '%s %s'",
+ var_mail_name, str_tls_level(tls->level));
+ return (0);
+ }
+ }
+#endif
+
+ /*
+ * Otherwise, if the TLS level is not TLS_LEV_NONE or some non-level, and
+ * the message contains a "TLS-Required: no" header, limit the level to
+ * TLS_LEV_MAY.
+ */
+ else if (tls->level > TLS_LEV_NONE
+ && (state->request->sendopts & SOPT_REQUIRETLS_HEADER)) {
+ tls->level = TLS_LEV_MAY;
+ }
+
+ /*
+ * Success.
+ */
+ return (1);
+}
+
/* smtp_connect_local - connect to local server */
static void smtp_connect_local(SMTP_STATE *state, const char *path)
@@ -552,7 +598,7 @@ static void smtp_connect_local(SMTP_STATE *state, const char *path)
* of SASL-unauthenticated connections.
*/
#ifdef USE_TLS
- if (!smtp_tls_policy_cache_query(why, state->tls, iter)) {
+ if (!smtp_get_effective_tls_level(why, state)) {
msg_warn("TLS policy lookup error for %s/%s: %s",
STR(iter->host), STR(iter->addr), STR(why->reason));
return;
@@ -777,7 +823,7 @@ static int smtp_reuse_session(SMTP_STATE *state, DNS_RR **addr_list,
}
SMTP_ITER_UPDATE_HOST(iter, SMTP_HNAME(addr), hostaddr.buf, addr);
#ifdef USE_TLS
- if (!smtp_tls_policy_cache_query(why, state->tls, iter)) {
+ if (!smtp_get_effective_tls_level(why, state)) {
msg_warn("TLS policy lookup error for %s/%s: %s",
STR(iter->dest), STR(iter->host), STR(why->reason));
continue;
@@ -1065,7 +1111,7 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
}
SMTP_ITER_UPDATE_HOST(iter, SMTP_HNAME(addr), hostaddr.buf, addr);
#ifdef USE_TLS
- if (!smtp_tls_policy_cache_query(why, state->tls, iter)) {
+ if (!smtp_get_effective_tls_level(why, state)) {
msg_warn("TLS policy lookup for %s/%s: %s",
STR(iter->dest), STR(iter->host), STR(why->reason));
continue;
diff --git a/postfix/src/util/argv.c b/postfix/src/util/argv.c
index 0816430bc..555a35ef9 100644
--- a/postfix/src/util/argv.c
+++ b/postfix/src/util/argv.c
@@ -807,7 +807,7 @@ int main(int argc, char **argv)
argvp = argv_alloc(1);
if (setjmp(test_panic_jbuf) == 0)
- tp->populate_fn(tp, argvp);
+ argvp = tp->populate_fn(tp, argvp);
test_failed = test_argv_verify(tp, argvp);
if (test_failed) {
msg_info("%s: FAIL", tp->label);
diff --git a/postfix/src/util/hex_code.c b/postfix/src/util/hex_code.c
index feed9f1cd..07d224895 100644
--- a/postfix/src/util/hex_code.c
+++ b/postfix/src/util/hex_code.c
@@ -296,6 +296,7 @@ int main(int unused_argc, char **unused_argv)
fail++;
}
}
+ vstring_free(buf);
msg_info("PASS=%d FAIL=%d", pass, fail);
return (fail > 0);
}