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:
parent
8a4eed134b
commit
43c618e67f
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -98,3 +98,4 @@ diffs
|
||||
CLOSEFROM
|
||||
Roessner
|
||||
bitflags
|
||||
Schulze
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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]))
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -44,7 +44,7 @@
|
||||
/*
|
||||
* Debug helper.
|
||||
*/
|
||||
extern const char *sendopts_strflags(unsigned flags);
|
||||
extern const char *sendopts_strflags(unsigned flags, int delim);
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
|
108
postfix/src/global/sendopts_test.c
Normal file
108
postfix/src/global/sendopts_test.c
Normal 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);
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user