2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-22 18:07:41 +00:00

postfix-3.10-20250117

This commit is contained in:
Wietse Z Venema 2025-01-17 00:00:00 -05:00 committed by Viktor Dukhovni
parent 8a4eed134b
commit 43c618e67f
22 changed files with 355 additions and 122 deletions

View File

@ -28854,3 +28854,27 @@ Apologies for any names omitted.
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,
20250117
Cleanup: factored out the sendopts.c unit test code, and
added two missing tests. File: global/sendopts_test.c.
Cleanup: increased the capacity to remember which types of
message headers have been seen, and encapsulated some set
operations. Files: cleanup/cleanup.h, cleanup/cleanup_message.c.
Feature: support for the RFC 8689 "TLS-Required: no" message
header. This limits the Postfix SMTP client TLS security
level to "smtp_tls_security = may", which does not authenticate
remote SMTP server TLS certificates, and which allows falling
back to plaintext. This is needed for the delivery of
messages such as TLSRPT summaries, which should be sent
even when the preferred TLS security policy cannot be
enforced. Support for the REQUIRETLS ESMTP extension remains
future work. Files: cleanup/cleanup_message.c,
global/header_opts.c, global/header_opts.h, smtp/smtp_connect.c,
proto/TLSRPT_README.html.
Cleanup: memory leaks in test code. Files: util/hex_code.c,
util/argv.c.

View File

@ -181,6 +181,12 @@ request that TLS enforcement will be disabled when submitting an email message.
Options:
* Specify the "TTLLSS--RReeqquuiirreedd:: nnoo" message header, defined in RFC 8689, to
reduce the TLS security level to "mmaayy" (that is, do not verify remote SMTP
server certificates, and fall back to plaintext if TLS is unavailable).
This feature is available in Postfix 3.10 and later.
* 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 in the mail queue. Keep in mind that TLSRPT is not a

View File

@ -26,6 +26,17 @@ now also distributed with the more recent Eclipse Public License
license of their choice. Those who are more comfortable with the
IPL can continue with that license.
[Feature 20250117]
Support for the RFC 8689 "TLS-Required: no" message header to request
delivery of messages such as TLSRPT summaries even if the preferred
TLS security policy cannot be enforced. This limits the Postfix
SMTP client to "smtp_tls_security_level = may" which does not
authenticate server certificates and which allows falling back to
plaintext.
Support for the REQUIRETLS SMTP service extension remains future work.
[Incompat 20250116]
Postfix needs "postfix reload" after upgrade, because of a change in

View File

@ -276,6 +276,12 @@ when submitting an email message. </p>
<ul>
<li> <p> Specify the "<b>TLS-Required: no</b>" message header,
defined in <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a>, to reduce the TLS security level to "<b>may</b>"
(that is, do not verify remote SMTP server certificates, and fall
back to plaintext if TLS is unavailable). <br> <br> This feature
is available in Postfix 3.10 and later. </p>
<li> <p> 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

View File

@ -276,6 +276,12 @@ when submitting an email message. </p>
<ul>
<li> <p> Specify the "<b>TLS-Required: no</b>" message header,
defined in RFC 8689, to reduce the TLS security level to "<b>may</b>"
(that is, do not verify remote SMTP server certificates, and fall
back to plaintext if TLS is unavailable). <br> <br> This feature
is available in Postfix 3.10 and later. </p>
<li> <p> 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

View File

@ -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

View File

@ -98,3 +98,4 @@ diffs
CLOSEFROM
Roessner
bitflags
Schulze

View File

@ -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

View File

@ -12,6 +12,7 @@
* System library.
*/
#include <sys/time.h>
#include <stdint.h> /* 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.
*/

View File

@ -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;

View File

@ -96,6 +96,7 @@
#include <info_log_addr_form.h>
#include <hfrom_format.h>
#include <rfc2047_code.h>
#include <sendopts.h>
/* 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) {

View File

@ -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

View File

@ -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]))

View File

@ -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

View File

@ -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

View File

@ -6,8 +6,9 @@
/* SYNOPSIS
/* #include <sendopts.h>
/*
/* 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 <sys_defs.h>
#include <string.h>
/*
* Utility library.
@ -44,7 +54,7 @@
#include <sendopts.h>
/*
* 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 <stdlib.h>
#include <string.h>
#include <stringops.h>
#include <msg_vstream.h>
/*
* 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

View File

@ -44,7 +44,7 @@
/*
* Debug helper.
*/
extern const char *sendopts_strflags(unsigned flags);
extern const char *sendopts_strflags(unsigned flags, int delim);
/* LICENSE
/* .ad

View File

@ -0,0 +1,108 @@
/*
* System library.
*/
#include <sys_defs.h>
#include <stdlib.h>
#include <string.h>
#include <stringops.h>
/*
* Utility library.
*/
#include <msg.h>
#include <msg_vstream.h>
#include <vstream.h>
#include <vstring.h>
/*
* Global library.
*/
#include <sendopts.h>
/*
* 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);
}

View File

@ -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

View File

@ -105,6 +105,7 @@
#include <dsn_buf.h>
#include <mail_addr.h>
#include <valid_hostname.h>
#include <sendopts.h>
/* 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;

View File

@ -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);

View File

@ -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);
}