2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-09-02 23:25:31 +00:00

postfix-3.8-20220421

This commit is contained in:
Wietse Venema
2022-04-21 00:00:00 -05:00
committed by Viktor Dukhovni
parent e3ead5dfac
commit 1b1cb925cd
3 changed files with 195 additions and 197 deletions

View File

@@ -26351,7 +26351,7 @@ Apologies for any names omitted.
setting to be ignored. It is now a non-fatal error. The setting to be ignored. It is now a non-fatal error. The
same client is used by many Postfix clients (smtpd_proxy, same client is used by many Postfix clients (smtpd_proxy,
dovecot auth, tcp_table, memcache, socketmap, and so on). dovecot auth, tcp_table, memcache, socketmap, and so on).
File: util/inet_connect.c. Problem reported by Christian Degenkolb. File: util/inet_connect.c.
20220407 20220407
@@ -26365,7 +26365,8 @@ Apologies for any names omitted.
Cleanup (problem introduced: Postfix 2.7): milter_header_checks Cleanup (problem introduced: Postfix 2.7): milter_header_checks
maps are now opened before the cleanup server enters the maps are now opened before the cleanup server enters the
chroot jail. Files: cleanup/cleanup.h, cleanup/cleanup_init.c, chroot jail. Problem reported by Jesper Dybdal. Files:
cleanup/cleanup.h, cleanup/cleanup_init.c,
cleanup/cleanup_milter.c, cleanup/cleanup_state.c. cleanup/cleanup_milter.c, cleanup/cleanup_state.c.
20220407 20220407
@@ -26384,7 +26385,8 @@ Apologies for any names omitted.
postfix-regexp package installed?" instead of "unsupported postfix-regexp package installed?" instead of "unsupported
map type for this operation". This happened with all built-in map type for this operation". This happened with all built-in
map types (static, cidr, etc.) that have no 'bulk create' map types (static, cidr, etc.) that have no 'bulk create'
support. File: global/dynamicmaps.c. support. Problem reported by Greg Klanderman. File:
global/dynamicmaps.c.
20220417 20220417
@@ -26393,3 +26395,13 @@ Apologies for any names omitted.
message will not be applied to a later email message that is message will not be applied to a later email message that is
handled by the same cleanup process. File: handled by the same cleanup process. File:
cleanup/cleanup_milter.c. cleanup/cleanup_milter.c.
20220421
Bugfix (introduced: Postfix 3.7): reverted an overly complex
change in the postscreen SMTP engine from 20211023, that
was segfaulting on malformed input, where the Postfix 3.6
implementation worked properly. The purpose of the change
was to prevent complaints about "malformed UTF8" from Postfix
lookup tables. Replaced the change with a trivial guard.
File: postscreen/postscreen_smtpd.c.

View File

@@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no * Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only. * patchlevel; they change the release date only.
*/ */
#define MAIL_RELEASE_DATE "20220417" #define MAIL_RELEASE_DATE "20220421"
#define MAIL_VERSION_NUMBER "3.8" #define MAIL_VERSION_NUMBER "3.8"
#ifdef SNAPSHOT #ifdef SNAPSHOT

View File

@@ -794,7 +794,6 @@ static void psc_smtpd_read_event(int event, void *context)
char *command; char *command;
const PSC_SMTPD_COMMAND *cmdp; const PSC_SMTPD_COMMAND *cmdp;
int write_stat; int write_stat;
int skip_command_processing;
if (msg_verbose > 1) if (msg_verbose > 1)
msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s", msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s",
@@ -930,39 +929,31 @@ static void psc_smtpd_read_event(int event, void *context)
} }
/* /*
* As in smtpd(8), reject malformed UTF-8 when "smtputf8_enable = * Avoid complaints from Postfix maps about malformed content.
* yes". This also avoids noisy "non-UTF-8 key" warnings from
* dict_utf8 infrastructure.
*
* Caution: do not skip all code in the remainder of this loop.
*/ */
if ((skip_command_processing = (var_smtputf8_enable #define PSC_BAD_UTF8(str, len) \
&& !valid_utf8_string(STR(state->cmd_buffer), (var_smtputf8_enable && !valid_utf8_string((str), (len)))
LEN(state->cmd_buffer))))) {
write_stat = PSC_SEND_REPLY(state,
"500 5.5.2 Error: bad UTF-8 syntax");
} else {
/* /*
* Terminate the command buffer, and apply the last-resort * Terminate the command buffer, and apply the last-resort command
* command editing workaround. * editing workaround.
*/ */
VSTRING_TERMINATE(state->cmd_buffer); VSTRING_TERMINATE(state->cmd_buffer);
if (psc_cmd_filter != 0) { if (psc_cmd_filter != 0 && !PSC_BAD_UTF8(STR(state->cmd_buffer),
const char *cp; LEN(state->cmd_buffer))) {
const char *cp;
for (cp = STR(state->cmd_buffer); *cp && IS_SPACE_TAB(*cp); cp++) for (cp = STR(state->cmd_buffer); *cp && IS_SPACE_TAB(*cp); cp++)
/* void */ ; /* void */ ;
if ((cp = psc_dict_get(psc_cmd_filter, cp)) != 0) { if ((cp = psc_dict_get(psc_cmd_filter, cp)) != 0) {
msg_info("[%s]:%s: replacing command \"%.100s\" with \"%.100s\"", msg_info("[%s]:%s: replacing command \"%.100s\" with \"%.100s\"",
state->smtp_client_addr, state->smtp_client_port, state->smtp_client_addr, state->smtp_client_port,
STR(state->cmd_buffer), cp); STR(state->cmd_buffer), cp);
vstring_strcpy(state->cmd_buffer, cp); vstring_strcpy(state->cmd_buffer, cp);
} else if (psc_cmd_filter->error != 0) { } else if (psc_cmd_filter->error != 0) {
msg_fatal("%s:%s lookup error for \"%.100s\"", msg_fatal("%s:%s lookup error for \"%.100s\"",
psc_cmd_filter->type, psc_cmd_filter->name, psc_cmd_filter->type, psc_cmd_filter->name,
STR(state->cmd_buffer)); STR(state->cmd_buffer));
}
} }
} }
@@ -975,180 +966,175 @@ static void psc_smtpd_read_event(int event, void *context)
state->read_state = PSC_SMTPD_CMD_ST_ANY; state->read_state = PSC_SMTPD_CMD_ST_ANY;
VSTRING_RESET(state->cmd_buffer); VSTRING_RESET(state->cmd_buffer);
if (skip_command_processing == 0) { /*
* Process the command line.
*
* Caution: some command handlers terminate the session and destroy the
* session state structure. When this happens we must leave the SMTP
* engine to avoid a dangling pointer problem.
*/
cmd_buffer_ptr = STR(state->cmd_buffer);
if (msg_verbose)
msg_info("< [%s]:%s: %s", state->smtp_client_addr,
state->smtp_client_port, cmd_buffer_ptr);
/* /* Parse the command name. */
* Process the command line. if ((command = PSC_SMTPD_NEXT_TOKEN(cmd_buffer_ptr)) == 0)
* command = "";
* Caution: some command handlers terminate the session and destroy
* the session state structure. When this happens we must leave
* the SMTP engine to avoid a dangling pointer problem.
*/
cmd_buffer_ptr = STR(state->cmd_buffer);
if (msg_verbose)
msg_info("< [%s]:%s: %s", state->smtp_client_addr,
state->smtp_client_port, cmd_buffer_ptr);
/* Parse the command name. */ /*
if ((command = PSC_SMTPD_NEXT_TOKEN(cmd_buffer_ptr)) == 0) * The non-SMTP, PIPELINING and command COUNT tests depend on the
command = ""; * client command handler.
*
/* * Caution: cmdp->name and cmdp->action may be null on loop exit.
* The non-SMTP, PIPELINING and command COUNT tests depend on the */
* client command handler. saved_where = state->where;
* state->where = PSC_SMTPD_CMD_UNIMPL;
* Caution: cmdp->name and cmdp->action may be null on loop exit. for (cmdp = command_table; cmdp->name != 0; cmdp++) {
*/ if (strcasecmp(command, cmdp->name) == 0) {
saved_where = state->where; state->where = cmdp->name;
state->where = PSC_SMTPD_CMD_UNIMPL; break;
for (cmdp = command_table; cmdp->name != 0; cmdp++) {
if (strcasecmp(command, cmdp->name) == 0) {
state->where = cmdp->name;
break;
}
} }
}
if ((state->flags & PSC_STATE_FLAG_SMTPD_X21) if ((state->flags & PSC_STATE_FLAG_SMTPD_X21)
&& cmdp->action != psc_quit_cmd) { && cmdp->action != psc_quit_cmd) {
PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event, PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event,
state->final_reply); state->final_reply);
return;
}
/* Non-SMTP command test. */
if ((state->flags & PSC_STATE_MASK_NSMTP_TODO_SKIP)
== PSC_STATE_FLAG_NSMTP_TODO && cmdp->name == 0
&& (is_header(command)
|| PSC_BAD_UTF8(command, strlen(command))
/* Ignore forbid_cmds lookup errors. Non-critical feature. */
|| (*var_psc_forbid_cmds
&& string_list_match(psc_forbid_cmds, command)))) {
printable(command, '?');
PSC_SMTPD_ESCAPE_TEXT(psc_temp, cmd_buffer_ptr,
strlen(cmd_buffer_ptr), 100);
msg_info("NON-SMTP COMMAND from [%s]:%s after %s: %.100s %s",
PSC_CLIENT_ADDR_PORT(state), saved_where,
command, STR(psc_temp));
PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_NSMTP_FAIL);
PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_NSMTP_PASS);
expire_time[PSC_TINDX_NSMTP] = PSC_TIME_STAMP_DISABLED; /* XXX */
/* Skip this test for the remainder of this SMTP session. */
PSC_SKIP_SESSION_STATE(state, "non-smtp test",
PSC_STATE_FLAG_NSMTP_SKIP);
switch (psc_nsmtp_action) {
case PSC_ACT_DROP:
PSC_CLEAR_EVENT_DROP_SESSION_STATE(state,
psc_smtpd_time_event,
"521 5.7.0 Error: I can break rules, too. Goodbye.\r\n");
return; return;
case PSC_ACT_ENFORCE:
PSC_ENFORCE_SESSION_STATE(state,
"550 5.5.1 Protocol error\r\n");
break;
case PSC_ACT_IGNORE:
PSC_UNFAIL_SESSION_STATE(state,
PSC_STATE_FLAG_NSMTP_FAIL);
/* Temporarily allowlist until something else expires. */
PSC_PASS_SESSION_STATE(state, "non-smtp test",
PSC_STATE_FLAG_NSMTP_PASS);
expire_time[PSC_TINDX_NSMTP] = event_time() + psc_min_ttl;
break;
default:
msg_panic("%s: unknown non_smtp_command action value %d",
myname, psc_nsmtp_action);
} }
/* Non-SMTP command test. */ }
if ((state->flags & PSC_STATE_MASK_NSMTP_TODO_SKIP) /* Command PIPELINING test. */
== PSC_STATE_FLAG_NSMTP_TODO && cmdp->name == 0 if ((cmdp->flags & PSC_SMTPD_CMD_FLAG_HAS_PAYLOAD) == 0
&& (is_header(command) && (state->flags & PSC_STATE_MASK_PIPEL_TODO_SKIP)
/* Ignore forbid_cmds lookup errors. Non-critical feature. */
|| (*var_psc_forbid_cmds
&& string_list_match(psc_forbid_cmds, command)))) {
printable(command, '?');
PSC_SMTPD_ESCAPE_TEXT(psc_temp, cmd_buffer_ptr,
strlen(cmd_buffer_ptr), 100);
msg_info("NON-SMTP COMMAND from [%s]:%s after %s: %.100s %s",
PSC_CLIENT_ADDR_PORT(state), saved_where,
command, STR(psc_temp));
PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_NSMTP_FAIL);
PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_NSMTP_PASS);
expire_time[PSC_TINDX_NSMTP] = PSC_TIME_STAMP_DISABLED; /* XXX */
/* Skip this test for the remainder of this SMTP session. */
PSC_SKIP_SESSION_STATE(state, "non-smtp test",
PSC_STATE_FLAG_NSMTP_SKIP);
switch (psc_nsmtp_action) {
case PSC_ACT_DROP:
PSC_CLEAR_EVENT_DROP_SESSION_STATE(state,
psc_smtpd_time_event,
"521 5.7.0 Error: I can break rules, too. Goodbye.\r\n");
return;
case PSC_ACT_ENFORCE:
PSC_ENFORCE_SESSION_STATE(state,
"550 5.5.1 Protocol error\r\n");
break;
case PSC_ACT_IGNORE:
PSC_UNFAIL_SESSION_STATE(state,
PSC_STATE_FLAG_NSMTP_FAIL);
/* Temporarily allowlist until something else expires. */
PSC_PASS_SESSION_STATE(state, "non-smtp test",
PSC_STATE_FLAG_NSMTP_PASS);
expire_time[PSC_TINDX_NSMTP] = event_time() + psc_min_ttl;
break;
default:
msg_panic("%s: unknown non_smtp_command action value %d",
myname, psc_nsmtp_action);
}
}
/* Command PIPELINING test. */
if ((cmdp->flags & PSC_SMTPD_CMD_FLAG_HAS_PAYLOAD) == 0
&& (state->flags & PSC_STATE_MASK_PIPEL_TODO_SKIP)
== PSC_STATE_FLAG_PIPEL_TODO && !PSC_SMTPD_BUFFER_EMPTY(state)) { == PSC_STATE_FLAG_PIPEL_TODO && !PSC_SMTPD_BUFFER_EMPTY(state)) {
printable(command, '?'); printable(command, '?');
PSC_SMTPD_ESCAPE_TEXT(psc_temp, PSC_SMTPD_PEEK_DATA(state), PSC_SMTPD_ESCAPE_TEXT(psc_temp, PSC_SMTPD_PEEK_DATA(state),
PSC_SMTPD_PEEK_LEN(state), 100); PSC_SMTPD_PEEK_LEN(state), 100);
msg_info("COMMAND PIPELINING from [%s]:%s after %.100s: %s", msg_info("COMMAND PIPELINING from [%s]:%s after %.100s: %s",
PSC_CLIENT_ADDR_PORT(state), command, STR(psc_temp)); PSC_CLIENT_ADDR_PORT(state), command, STR(psc_temp));
PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_PIPEL_FAIL); PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_PIPEL_FAIL);
PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_PIPEL_PASS); PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_PIPEL_PASS);
expire_time[PSC_TINDX_PIPEL] = PSC_TIME_STAMP_DISABLED; /* XXX */ expire_time[PSC_TINDX_PIPEL] = PSC_TIME_STAMP_DISABLED; /* XXX */
/* Skip this test for the remainder of this SMTP session. */ /* Skip this test for the remainder of this SMTP session. */
PSC_SKIP_SESSION_STATE(state, "pipelining test", PSC_SKIP_SESSION_STATE(state, "pipelining test",
PSC_STATE_FLAG_PIPEL_SKIP); PSC_STATE_FLAG_PIPEL_SKIP);
switch (psc_pipel_action) { switch (psc_pipel_action) {
case PSC_ACT_DROP: case PSC_ACT_DROP:
PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, PSC_CLEAR_EVENT_DROP_SESSION_STATE(state,
psc_smtpd_time_event, psc_smtpd_time_event,
"521 5.5.1 Protocol error\r\n"); "521 5.5.1 Protocol error\r\n");
return;
case PSC_ACT_ENFORCE:
PSC_ENFORCE_SESSION_STATE(state,
"550 5.5.1 Protocol error\r\n");
break;
case PSC_ACT_IGNORE:
PSC_UNFAIL_SESSION_STATE(state,
PSC_STATE_FLAG_PIPEL_FAIL);
/* Temporarily allowlist until something else expires. */
PSC_PASS_SESSION_STATE(state, "pipelining test",
PSC_STATE_FLAG_PIPEL_PASS);
expire_time[PSC_TINDX_PIPEL] = event_time() + psc_min_ttl;
break;
default:
msg_panic("%s: unknown pipelining action value %d",
myname, psc_pipel_action);
}
}
/*
* The following tests don't pass until the client gets all the
* way to the RCPT TO command. However, the client can still fail
* these tests with some later command.
*/
if (cmdp->action == psc_rcpt_cmd) {
if ((state->flags & PSC_STATE_MASK_BARLF_TODO_PASS_FAIL)
== PSC_STATE_FLAG_BARLF_TODO) {
PSC_PASS_SESSION_STATE(state, "bare newline test",
PSC_STATE_FLAG_BARLF_PASS);
/* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */
expire_time[PSC_TINDX_BARLF] = event_time()
+ var_psc_barlf_ttl;
}
if ((state->flags & PSC_STATE_MASK_NSMTP_TODO_PASS_FAIL)
== PSC_STATE_FLAG_NSMTP_TODO) {
PSC_PASS_SESSION_STATE(state, "non-smtp test",
PSC_STATE_FLAG_NSMTP_PASS);
/* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */
expire_time[PSC_TINDX_NSMTP] = event_time()
+ var_psc_nsmtp_ttl;
}
if ((state->flags & PSC_STATE_MASK_PIPEL_TODO_PASS_FAIL)
== PSC_STATE_FLAG_PIPEL_TODO) {
PSC_PASS_SESSION_STATE(state, "pipelining test",
PSC_STATE_FLAG_PIPEL_PASS);
/* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */
expire_time[PSC_TINDX_PIPEL] = event_time()
+ var_psc_pipel_ttl;
}
}
/* Command COUNT limit test. */
if (++state->command_count > var_psc_cmd_count
&& cmdp->action != psc_quit_cmd) {
msg_info("COMMAND COUNT LIMIT from [%s]:%s after %s",
PSC_CLIENT_ADDR_PORT(state), saved_where);
PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event,
psc_smtpd_421_reply);
return; return;
case PSC_ACT_ENFORCE:
PSC_ENFORCE_SESSION_STATE(state,
"550 5.5.1 Protocol error\r\n");
break;
case PSC_ACT_IGNORE:
PSC_UNFAIL_SESSION_STATE(state,
PSC_STATE_FLAG_PIPEL_FAIL);
/* Temporarily allowlist until something else expires. */
PSC_PASS_SESSION_STATE(state, "pipelining test",
PSC_STATE_FLAG_PIPEL_PASS);
expire_time[PSC_TINDX_PIPEL] = event_time() + psc_min_ttl;
break;
default:
msg_panic("%s: unknown pipelining action value %d",
myname, psc_pipel_action);
} }
/* Finally, execute the command. */ }
if (cmdp->name == 0 || (cmdp->flags & PSC_SMTPD_CMD_FLAG_ENABLE) == 0) {
write_stat = PSC_SEND_REPLY(state, /*
* The following tests don't pass until the client gets all the way
* to the RCPT TO command. However, the client can still fail these
* tests with some later command.
*/
if (cmdp->action == psc_rcpt_cmd) {
if ((state->flags & PSC_STATE_MASK_BARLF_TODO_PASS_FAIL)
== PSC_STATE_FLAG_BARLF_TODO) {
PSC_PASS_SESSION_STATE(state, "bare newline test",
PSC_STATE_FLAG_BARLF_PASS);
/* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */
expire_time[PSC_TINDX_BARLF] = event_time() + var_psc_barlf_ttl;
}
if ((state->flags & PSC_STATE_MASK_NSMTP_TODO_PASS_FAIL)
== PSC_STATE_FLAG_NSMTP_TODO) {
PSC_PASS_SESSION_STATE(state, "non-smtp test",
PSC_STATE_FLAG_NSMTP_PASS);
/* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */
expire_time[PSC_TINDX_NSMTP] = event_time() + var_psc_nsmtp_ttl;
}
if ((state->flags & PSC_STATE_MASK_PIPEL_TODO_PASS_FAIL)
== PSC_STATE_FLAG_PIPEL_TODO) {
PSC_PASS_SESSION_STATE(state, "pipelining test",
PSC_STATE_FLAG_PIPEL_PASS);
/* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */
expire_time[PSC_TINDX_PIPEL] = event_time() + var_psc_pipel_ttl;
}
}
/* Command COUNT limit test. */
if (++state->command_count > var_psc_cmd_count
&& cmdp->action != psc_quit_cmd) {
msg_info("COMMAND COUNT LIMIT from [%s]:%s after %s",
PSC_CLIENT_ADDR_PORT(state), saved_where);
PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event,
psc_smtpd_421_reply);
return;
}
/* Finally, execute the command. */
if (cmdp->name == 0 || (cmdp->flags & PSC_SMTPD_CMD_FLAG_ENABLE) == 0) {
write_stat = PSC_SEND_REPLY(state,
"502 5.5.2 Error: command not recognized\r\n"); "502 5.5.2 Error: command not recognized\r\n");
} else if (var_psc_enforce_tls } else if (var_psc_enforce_tls
&& (state->flags & PSC_STATE_FLAG_USING_TLS) == 0 && (state->flags & PSC_STATE_FLAG_USING_TLS) == 0
&& (cmdp->flags & PSC_SMTPD_CMD_FLAG_PRE_TLS) == 0) { && (cmdp->flags & PSC_SMTPD_CMD_FLAG_PRE_TLS) == 0) {
write_stat = PSC_SEND_REPLY(state, write_stat = PSC_SEND_REPLY(state,
"530 5.7.0 Must issue a STARTTLS command first\r\n"); "530 5.7.0 Must issue a STARTTLS command first\r\n");
} else { } else {
write_stat = cmdp->action(state, cmd_buffer_ptr); write_stat = cmdp->action(state, cmd_buffer_ptr);
if (cmdp->flags & PSC_SMTPD_CMD_FLAG_DESTROY) if (cmdp->flags & PSC_SMTPD_CMD_FLAG_DESTROY)
return; return;
}
} }
/* /*