mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-22 09:57:34 +00:00
postfix-3.11-20250803
This commit is contained in:
parent
e3e5fbac8c
commit
1c43ccaf44
@ -29530,3 +29530,21 @@ Apologies for any names omitted.
|
||||
change did not have space between POSTLOG_HOSTNAME and
|
||||
XDG_RUNTIME_DIR, breaking maillog_file support and graphical
|
||||
debugging. File: global/mail_params.h.
|
||||
|
||||
20250801
|
||||
|
||||
Feature: smtpd_reject_filter_maps can selectively replace a
|
||||
reject response from the Postfix SMTP server, or from a
|
||||
program that replies through the Postfix SMTP server. Files:
|
||||
smtpd/smtpd.c, smtpd/smtpd_chat.c, global/mail_params.h,
|
||||
proto/postconf.proto, mantools/postlink.
|
||||
|
||||
20250803
|
||||
|
||||
Cleanup: when "tls_required_enable = yes" and a message
|
||||
contains a "TLS-Required: no" header", the Postfix SMTP
|
||||
client now also ignores the recipient-side TLSRPT policy,
|
||||
in addition to the already ignored recipient-side MTA-STS
|
||||
and DANE policies. This prevents TLSRPT notifications for
|
||||
all SMTP deliveries that do not require TLS. File:
|
||||
smtp/smtp_connect.c.
|
||||
|
@ -17393,6 +17393,58 @@ Example:
|
||||
</pre>
|
||||
|
||||
|
||||
</DD>
|
||||
|
||||
<DT><b><a name="smtpd_reject_filter_maps">smtpd_reject_filter_maps</a>
|
||||
(default: empty)</b></DT><DD>
|
||||
|
||||
<p> An optional filter that can replace a reject response from the
|
||||
Postfix SMTP server itself, or from a program that replies through
|
||||
the Postfix SMTP server. The filter is applied before the optional
|
||||
reject footers are appended. Typically, the filter will be a <a href="regexp_table.5.html">regexp</a>:
|
||||
or <a href="pcre_table.5.html">pcre</a>: table, where the left-hand side specifies a pattern, and
|
||||
the right-hand side specifies replacement text. </p>
|
||||
|
||||
<p> The input is a server response that starts with a 4XX or 5XX
|
||||
reply code (see <a href="https://tools.ietf.org/html/rfc5321">RFC 5321</a>), usually followed by an enhanced status
|
||||
code (see <a href="https://tools.ietf.org/html/rfc3463">RFC 3463</a>) and text. The filter returns replacement text
|
||||
or indicates that there was no match. This feature cannot be used
|
||||
to change a reject reply into a non-reject one or vice versa. </p>
|
||||
|
||||
<p> LIMITATION: <a href="postconf.5.html#smtpd_reject_filter_maps">smtpd_reject_filter_maps</a> will not replace text that
|
||||
was already logged before the Postfix SMTP server replies to the
|
||||
remote SMTP client. To help with logfile analysis, the Postfix SMTP
|
||||
server logs both the unmodified reply (logged below as "reject
|
||||
filter in") and the replacement reply (logged below as "reject
|
||||
filter out").
|
||||
|
||||
<p> Example: </p>
|
||||
|
||||
<pre>
|
||||
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
|
||||
<a href="postconf.5.html#smtpd_reject_filter_maps">smtpd_reject_filter_maps</a> = <a href="regexp_table.5.html">regexp</a>:/etc/postfix/smtpd_reject_filter
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
/etc/postfix/smtpd_reject_filter:
|
||||
# Replace soft reject with hard reject.
|
||||
/^451 4(\.6\.0 Alias expansion error)/ 550 5${1}
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
# Silly rule for demo purposes.
|
||||
/^(4.+[^.])\.*$/ $1. See you later.
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
/var/log/maillog:
|
||||
NOQUEUE: reject filter in: 451 4.6.0 Alias expansion error
|
||||
NOQUEUE: reject filter out: 550 5.6.0 Alias expansion error
|
||||
</pre>
|
||||
|
||||
<p> This feature is available in Postfix ≥ 3.11. </p>
|
||||
|
||||
|
||||
</DD>
|
||||
|
||||
<DT><b><a name="smtpd_reject_footer">smtpd_reject_footer</a>
|
||||
|
@ -1437,6 +1437,13 @@ SMTPD(8) SMTPD(8)
|
||||
Do not include SMTP client session information in the Postfix
|
||||
SMTP server's Received: message header.
|
||||
|
||||
Available in Postfix version 3.11 and later:
|
||||
|
||||
<b><a href="postconf.5.html#smtpd_reject_filter_maps">smtpd_reject_filter_maps</a> (empty)</b>
|
||||
An optional filter that can replace a reject response from the
|
||||
Postfix SMTP server itself, or from a program that replies
|
||||
through the Postfix SMTP server.
|
||||
|
||||
<b><a name="see_also">SEE ALSO</a></b>
|
||||
<a href="anvil.8.html">anvil(8)</a>, connection/rate limiting
|
||||
<a href="cleanup.8.html">cleanup(8)</a>, message canonicalization
|
||||
|
@ -11815,6 +11815,60 @@ Example:
|
||||
smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination
|
||||
.fi
|
||||
.ad
|
||||
.SH smtpd_reject_filter_maps (default: empty)
|
||||
An optional filter that can replace a reject response from the
|
||||
Postfix SMTP server itself, or from a program that replies through
|
||||
the Postfix SMTP server. The filter is applied before the optional
|
||||
reject footers are appended. Typically, the filter will be a regexp:
|
||||
or pcre: table, where the left\-hand side specifies a pattern, and
|
||||
the right\-hand side specifies replacement text.
|
||||
.PP
|
||||
The input is a server response that starts with a 4XX or 5XX
|
||||
reply code (see RFC 5321), usually followed by an enhanced status
|
||||
code (see RFC 3463) and text. The filter returns replacement text
|
||||
or indicates that there was no match. This feature cannot be used
|
||||
to change a reject reply into a non\-reject one or vice versa.
|
||||
.PP
|
||||
LIMITATION: smtpd_reject_filter_maps will not replace text that
|
||||
was already logged before the Postfix SMTP server replies to the
|
||||
remote SMTP client. To help with logfile analysis, the Postfix SMTP
|
||||
server logs both the unmodified reply (logged below as "reject
|
||||
filter in") and the replacement reply (logged below as "reject
|
||||
filter out").
|
||||
.PP
|
||||
Example:
|
||||
.PP
|
||||
.nf
|
||||
.na
|
||||
/etc/postfix/main.cf:
|
||||
smtpd_reject_filter_maps = regexp:/etc/postfix/smtpd_reject_filter
|
||||
.fi
|
||||
.ad
|
||||
.PP
|
||||
.nf
|
||||
.na
|
||||
/etc/postfix/smtpd_reject_filter:
|
||||
# Replace soft reject with hard reject.
|
||||
/^451 4(\e.6\e.0 Alias expansion error)/ 550 5${1}
|
||||
.fi
|
||||
.ad
|
||||
.PP
|
||||
.nf
|
||||
.na
|
||||
# Silly rule for demo purposes.
|
||||
/^(4.+[^.])\e.*$/ $1. See you later.
|
||||
.fi
|
||||
.ad
|
||||
.PP
|
||||
.nf
|
||||
.na
|
||||
/var/log/maillog:
|
||||
NOQUEUE: reject filter in: 451 4.6.0 Alias expansion error
|
||||
NOQUEUE: reject filter out: 550 5.6.0 Alias expansion error
|
||||
.fi
|
||||
.ad
|
||||
.PP
|
||||
This feature is available in Postfix >= 3.11.
|
||||
.SH smtpd_reject_footer (default: empty)
|
||||
Optional information that is appended after each Postfix SMTP
|
||||
server
|
||||
|
@ -1237,6 +1237,12 @@ Available in Postfix 3.10 and later:
|
||||
.IP "\fBsmtpd_hide_client_session (no)\fR"
|
||||
Do not include SMTP client session information in the Postfix
|
||||
SMTP server's Received: message header.
|
||||
.PP
|
||||
Available in Postfix version 3.11 and later:
|
||||
.IP "\fBsmtpd_reject_filter_maps (empty)\fR"
|
||||
An optional filter that can replace a reject response from the
|
||||
Postfix SMTP server itself, or from a program that replies through
|
||||
the Postfix SMTP server.
|
||||
.SH "SEE ALSO"
|
||||
.na
|
||||
.nf
|
||||
|
@ -770,6 +770,7 @@ while (<>) {
|
||||
s;\bsmtpd_use_tls\b;<a href="postconf.5.html#smtpd_use_tls">$&</a>;g;
|
||||
s;\bsmtpd_reject_footer\b;<a href="postconf.5.html#smtpd_reject_footer">$&</a>;g;
|
||||
s;\bsmtpd_reject_footer_maps\b;<a href="postconf.5.html#smtpd_reject_footer_maps">$&</a>;g;
|
||||
s;\bsmtpd_reject_filter_maps\b;<a href="postconf.5.html#smtpd_reject_filter_maps">$&</a>;g;
|
||||
s;\bsmtpd_per_record_deadline\b;<a href="postconf.5.html#smtpd_per_record_deadline">$&</a>;g;
|
||||
s;\bsmtpd_per_request_deadline\b;<a href="postconf.5.html#smtpd_per_request_deadline">$&</a>;g;
|
||||
s;\bsmtpd_min_data_rate\b;<a href="postconf.5.html#smtpd_min_data_rate">$&</a>;g;
|
||||
|
@ -19661,3 +19661,51 @@ and therefore it does not need to provide the information required by
|
||||
RFC 5321. The form does still meet RFC 5322 requirements. </p>
|
||||
|
||||
<p> This feature is available in Postfix ≥ 3.10. </p>
|
||||
|
||||
%PARAM smtpd_reject_filter_maps
|
||||
|
||||
<p> An optional filter that can replace a reject response from the
|
||||
Postfix SMTP server itself, or from a program that replies through
|
||||
the Postfix SMTP server. The filter is applied before the optional
|
||||
reject footers are appended. Typically, the filter will be a regexp:
|
||||
or pcre: table, where the left-hand side specifies a pattern, and
|
||||
the right-hand side specifies replacement text. </p>
|
||||
|
||||
<p> The input is a server response that starts with a 4XX or 5XX
|
||||
reply code (see RFC 5321), usually followed by an enhanced status
|
||||
code (see RFC 3463) and text. The filter returns replacement text
|
||||
or indicates that there was no match. This feature cannot be used
|
||||
to change a reject reply into a non-reject one or vice versa. </p>
|
||||
|
||||
<p> LIMITATION: smtpd_reject_filter_maps will not replace text that
|
||||
was already logged before the Postfix SMTP server replies to the
|
||||
remote SMTP client. To help with logfile analysis, the Postfix SMTP
|
||||
server logs both the unmodified reply (logged below as "reject
|
||||
filter in") and the replacement reply (logged below as "reject
|
||||
filter out").
|
||||
|
||||
<p> Example: </p>
|
||||
|
||||
<pre>
|
||||
/etc/postfix/main.cf:
|
||||
smtpd_reject_filter_maps = regexp:/etc/postfix/smtpd_reject_filter
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
/etc/postfix/smtpd_reject_filter:
|
||||
# Replace soft reject with hard reject.
|
||||
/^451 4(\.6\.0 Alias expansion error)/ 550 5${1}
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
# Silly rule for demo purposes.
|
||||
/^(4.+[^.])\.*$/ $1. See you later.
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
/var/log/maillog:
|
||||
NOQUEUE: reject filter in: 451 4.6.0 Alias expansion error
|
||||
NOQUEUE: reject filter out: 550 5.6.0 Alias expansion error
|
||||
</pre>
|
||||
|
||||
<p> This feature is available in Postfix ≥ 3.11. </p>
|
||||
|
@ -194,3 +194,4 @@ proto proto COMPATIBILITY_README html
|
||||
src global config_known_tcp_ports c postmulti postmulti c
|
||||
virtual virtual c
|
||||
request Reported by John Doe File tlsproxy tlsproxy c
|
||||
smtpd smtpd c smtpd smtpd_chat c global mail_params h
|
||||
|
@ -1867,3 +1867,4 @@ ossl
|
||||
deduplicates
|
||||
intmax
|
||||
lflag
|
||||
REPLYCODE
|
||||
|
@ -2568,7 +2568,8 @@ extern int var_local_rcpt_code;
|
||||
" $" VAR_SMTP_BODY_CHKS \
|
||||
" $" VAR_SMTP_HEAD_CHKS \
|
||||
" $" VAR_SMTP_MIME_CHKS \
|
||||
" $" VAR_SMTP_NEST_CHKS
|
||||
" $" VAR_SMTP_NEST_CHKS \
|
||||
" $" VAR_SMTPD_REJECT_FILTER_MAPS
|
||||
extern char *var_proxy_read_maps;
|
||||
|
||||
#define VAR_PROXY_WRITE_MAPS "proxy_write_maps"
|
||||
@ -4534,6 +4535,13 @@ extern int var_sockmap_max_reply;
|
||||
#define DEF_SMTPD_HIDE_CLIENT_SESSION "no"
|
||||
extern int var_smtpd_hide_client_session;
|
||||
|
||||
/*
|
||||
* SMTP server reject response filter.
|
||||
*/
|
||||
#define VAR_SMTPD_REJECT_FILTER_MAPS "smtpd_reject_filter_maps"
|
||||
#define DEF_SMTPD_REJECT_FILTER_MAPS ""
|
||||
extern char *var_smtpd_reject_filter_maps;
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
|
@ -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 "20250801"
|
||||
#define MAIL_RELEASE_DATE "20250803"
|
||||
#define MAIL_VERSION_NUMBER "3.11"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
|
@ -507,24 +507,6 @@ static int smtp_get_effective_tls_level(DSN_BUF *why, SMTP_STATE *state)
|
||||
SMTP_ITERATOR *iter = state->iterator;
|
||||
SMTP_TLS_POLICY *tls = state->tls;
|
||||
|
||||
/*
|
||||
* If the message contains a "TLS-Required: no" header, update the
|
||||
* iterator to limit the policy at TLS_LEV_MAY.
|
||||
*
|
||||
* We must do this early to avoid possible failure if TLSA record lookups
|
||||
* fail, or if TLSA records are found, but can't be activated because the
|
||||
* security level has been reset to "may".
|
||||
*
|
||||
* Note that the REQUIRETLS verb in ESMTP overrides the "TLS-Required: no"
|
||||
* header.
|
||||
*/
|
||||
#ifdef USE_TLS
|
||||
if (var_tls_required_enable
|
||||
&& (state->request->sendopts & SOPT_REQUIRETLS_HEADER)) {
|
||||
iter->tlsreqno = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Determine the TLS level for this destination.
|
||||
*/
|
||||
@ -970,15 +952,40 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
|
||||
|
||||
SMTP_ITER_INIT(iter, dest, NO_HOST, NO_ADDR, port, state);
|
||||
|
||||
/*
|
||||
* If a "TLS-Required: no" header is in effect, update the iterator
|
||||
* to override TLS policy selection and to limit the security level
|
||||
* to "may". Do not reset the security level after policy selection,
|
||||
* as that would result in errors. For example, when TLSA records are
|
||||
* looked up for security level "dane", and then the security level
|
||||
* is reset to "may", the activation of those TLSA records will fail.
|
||||
*
|
||||
* Note that the REQUIRETLS verb in ESMTP overrides the "TLS-Required:
|
||||
* no" header.
|
||||
*/
|
||||
#ifdef USE_TLS
|
||||
if (var_tls_required_enable
|
||||
&& (state->request->sendopts & SOPT_REQUIRETLS_HEADER)) {
|
||||
iter->tlsreqno = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TODO(wietse) If the domain publishes a TLSRPT policy, they expect
|
||||
* that clients use SMTP over TLS. Should we upgrade a TLS security
|
||||
* level of "may" to "encrypt"? This would disable falling back to
|
||||
* plaintext, and could break interoperability with receivers that
|
||||
* crank up security up to 11.
|
||||
*
|
||||
* As of change 20250803, with "TLS-Required: no", the SMTP client also
|
||||
* ignores the recipient-side policy mechanism TLSRPT, in addition to
|
||||
* the already ignored DANE and MTA-STS mechanisms. This prevents
|
||||
* TLSRPT notifications for all SMTP deliveries that do not require
|
||||
* TLS.
|
||||
*/
|
||||
#ifdef USE_TLSRPT
|
||||
if (smtp_mode && var_smtp_tlsrpt_enable
|
||||
&& iter->tlsreqno == 0
|
||||
&& tls_level_lookup(var_smtp_tls_level) > TLS_LEV_NONE
|
||||
&& !valid_hostaddr(domain, DONT_GRIPE))
|
||||
smtp_tlsrpt_create_wrapper(state, domain);
|
||||
|
@ -1179,6 +1179,12 @@
|
||||
/* .IP "\fBsmtpd_hide_client_session (no)\fR"
|
||||
/* Do not include SMTP client session information in the Postfix
|
||||
/* SMTP server's Received: message header.
|
||||
/* .PP
|
||||
/* Available in Postfix version 3.11 and later:
|
||||
/* .IP "\fBsmtpd_reject_filter_maps (empty)\fR"
|
||||
/* An optional filter that can replace a reject response from the
|
||||
/* Postfix SMTP server itself, or from a program that replies through
|
||||
/* the Postfix SMTP server.
|
||||
/* SEE ALSO
|
||||
/* anvil(8), connection/rate limiting
|
||||
/* cleanup(8), message canonicalization
|
||||
@ -1478,6 +1484,7 @@ bool var_smtpd_tls_auth_only;
|
||||
char *var_smtpd_cmd_filter;
|
||||
char *var_smtpd_rej_footer;
|
||||
char *var_smtpd_rej_ftr_maps;
|
||||
char *var_smtpd_reject_filter_maps;
|
||||
char *var_smtpd_acl_perm_log;
|
||||
char *var_smtpd_dns_re_filter;
|
||||
|
||||
@ -6635,9 +6642,9 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
|
||||
var_smtpd_dns_re_filter);
|
||||
|
||||
/*
|
||||
* Reject footer.
|
||||
* Reject filter and footer.
|
||||
*/
|
||||
if (*var_smtpd_rej_ftr_maps)
|
||||
if (*var_smtpd_rej_ftr_maps || *var_smtpd_reject_filter_maps)
|
||||
smtpd_chat_pre_jail_init();
|
||||
}
|
||||
|
||||
@ -6911,6 +6918,7 @@ int main(int argc, char **argv)
|
||||
VAR_SMTPD_POLICY_CONTEXT, DEF_SMTPD_POLICY_CONTEXT, &var_smtpd_policy_context, 0, 0,
|
||||
VAR_SMTPD_DNS_RE_FILTER, DEF_SMTPD_DNS_RE_FILTER, &var_smtpd_dns_re_filter, 0, 0,
|
||||
VAR_SMTPD_REJ_FTR_MAPS, DEF_SMTPD_REJ_FTR_MAPS, &var_smtpd_rej_ftr_maps, 0, 0,
|
||||
VAR_SMTPD_REJECT_FILTER_MAPS, DEF_SMTPD_REJECT_FILTER_MAPS, &var_smtpd_reject_filter_maps, 0, 0,
|
||||
VAR_HFROM_FORMAT, DEF_HFROM_FORMAT, &var_hfrom_format, 1, 0,
|
||||
VAR_SMTPD_FORBID_BARE_LF_EXCL, DEF_SMTPD_FORBID_BARE_LF_EXCL, &var_smtpd_forbid_bare_lf_excl, 0, 0,
|
||||
VAR_SMTPD_FORBID_BARE_LF, DEF_SMTPD_FORBID_BARE_LF, &var_smtpd_forbid_bare_lf, 1, 0,
|
||||
|
@ -112,8 +112,9 @@
|
||||
#include "smtpd_chat.h"
|
||||
|
||||
/*
|
||||
* Reject footer.
|
||||
* Reject filter and footer maps.
|
||||
*/
|
||||
static MAPS *smtpd_reject_filter_maps;
|
||||
static MAPS *smtpd_rej_ftr_maps;
|
||||
|
||||
#define STR vstring_str
|
||||
@ -128,6 +129,14 @@ void smtpd_chat_pre_jail_init(void)
|
||||
if (init_count++ != 0)
|
||||
msg_panic("smtpd_chat_pre_jail_init: multiple calls");
|
||||
|
||||
/*
|
||||
* SMTP server reject filter.
|
||||
*/
|
||||
if (*var_smtpd_reject_filter_maps)
|
||||
smtpd_reject_filter_maps = maps_create(VAR_SMTPD_REJECT_FILTER_MAPS,
|
||||
var_smtpd_reject_filter_maps,
|
||||
DICT_FLAG_LOCK);
|
||||
|
||||
/*
|
||||
* SMTP server reject footer.
|
||||
*/
|
||||
@ -206,6 +215,7 @@ void vsmtpd_chat_reply(SMTPD_STATE *state, const char *format, va_list ap)
|
||||
char *cp;
|
||||
char *next;
|
||||
char *end;
|
||||
const char *alt_reply;
|
||||
const char *footer;
|
||||
|
||||
/*
|
||||
@ -215,8 +225,30 @@ void vsmtpd_chat_reply(SMTPD_STATE *state, const char *format, va_list ap)
|
||||
if (state->error_count >= var_smtpd_soft_erlim)
|
||||
sleep(delay = var_smtpd_err_sleep);
|
||||
|
||||
/*
|
||||
* Postfix generates single-line reject responses, but Milters may
|
||||
* generate multi-line rejects with the SMFIR_REPLYCODE request.
|
||||
*/
|
||||
vstring_vsprintf(state->buffer, format, ap);
|
||||
cp = STR(state->buffer);
|
||||
if ((*cp == '4' || *cp == '5')
|
||||
&& smtpd_reject_filter_maps != 0
|
||||
&& (alt_reply = maps_find(smtpd_reject_filter_maps, cp, 0)) != 0) {
|
||||
const char *queue_id = state->queue_id ? state->queue_id : "NOQUEUE";
|
||||
|
||||
/* XXX Enforce this for each line of a multi-line reply. */
|
||||
if ((alt_reply[0] != '4' && alt_reply[0] != '5')
|
||||
|| !ISDIGIT(alt_reply[1]) || !ISDIGIT(alt_reply[2])
|
||||
|| (alt_reply[3] != ' ' && alt_reply[3] != '-')
|
||||
|| (ISDIGIT(alt_reply[4]) && (alt_reply[4] != alt_reply[0]))) {
|
||||
msg_warn("%s: ignoring invalid reject filter result: %s",
|
||||
queue_id, alt_reply);
|
||||
} else {
|
||||
msg_info("%s: reply filter in: %s", queue_id, cp);
|
||||
msg_info("%s: reply filter out: %s", queue_id, alt_reply);
|
||||
vstring_strcpy(state->buffer, alt_reply);
|
||||
}
|
||||
}
|
||||
if ((*(cp = STR(state->buffer)) == '4' || *cp == '5')
|
||||
&& ((smtpd_rej_ftr_maps != 0
|
||||
&& (footer = maps_find(smtpd_rej_ftr_maps, cp, 0)) != 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user