2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-28 20:57:56 +00:00

postfix-3.7-20211023

This commit is contained in:
Wietse Venema 2021-10-23 00:00:00 -05:00 committed by Viktor Dukhovni
parent 6b8941f03e
commit a677a91e79
6 changed files with 209 additions and 176 deletions

View File

@ -25815,3 +25815,14 @@ Apologies for any names omitted.
config_known_tcp_ports.c, mail_params.c, config_known_tcp_ports.c, mail_params.c,
posttls-finger/posttls-finger.c, smtp/smtp_connect.c, posttls-finger/posttls-finger.c, smtp/smtp_connect.c,
util/find_inet.c, util/myaddrinfo.c. util/find_inet.c, util/myaddrinfo.c.
20211023
Documentation: fixed a jq example in the postsuper manpage, to
delete the quotes around a queue ID. File: postsuper/postsuper.c.
Cleanup: with "smtputf8_nable = yes" (the default), the
postscreen(8) dummy SMTP engine will no longer log a "non-UTF-8
key" warning when a remote SMTP client sends garbage. Instead,
postscreen(8) will reject the command with the same server
repsonse as smtpd(8). File: postscreen/p[ostscreen_smtpd.c.

View File

@ -49,7 +49,7 @@ POSTSUPER(1) POSTSUPER(1)
select(.recipients[0].address == "user@example.com") select(.recipients[0].address == "user@example.com")
| select(.recipients[1].address == null) | select(.recipients[1].address == null)
| .queue_id | .queue_id
' | postsuper -d - ' | tr -d '"' | postsuper -d -
Or the historical form: Or the historical form:

View File

@ -51,7 +51,7 @@ postqueue \-j | jq '
select(.recipients[0].address == "user@example.com") select(.recipients[0].address == "user@example.com")
| select(.recipients[1].address == null) | select(.recipients[1].address == null)
| .queue_id | .queue_id
' | postsuper \-d \- ' | tr \-d '"' | postsuper \-d \-
.fi .fi
.sp .sp
Or the historical form: Or the historical form:

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 "20211022" #define MAIL_RELEASE_DATE "20211023"
#define MAIL_VERSION_NUMBER "3.7" #define MAIL_VERSION_NUMBER "3.7"
#ifdef SNAPSHOT #ifdef SNAPSHOT

View File

@ -794,6 +794,7 @@ 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",
@ -929,24 +930,39 @@ static void psc_smtpd_read_event(int event, void *context)
} }
/* /*
* Terminate the command buffer, and apply the last-resort command * As in smtpd(8), reject malformed UTF-8 when "smtputf8_enable =
* editing workaround. * 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.
*/ */
VSTRING_TERMINATE(state->cmd_buffer); if ((skip_command_processing = (var_smtputf8_enable
if (psc_cmd_filter != 0) { && !valid_utf8_string(STR(state->cmd_buffer),
const char *cp; LEN(state->cmd_buffer))))) {
write_stat = PSC_SEND_REPLY(state,
"500 5.5.2 Error: bad UTF-8 syntax");
} else {
for (cp = STR(state->cmd_buffer); *cp && IS_SPACE_TAB(*cp); cp++) /*
/* void */ ; * Terminate the command buffer, and apply the last-resort
if ((cp = psc_dict_get(psc_cmd_filter, cp)) != 0) { * command editing workaround.
msg_info("[%s]:%s: replacing command \"%.100s\" with \"%.100s\"", */
state->smtp_client_addr, state->smtp_client_port, VSTRING_TERMINATE(state->cmd_buffer);
STR(state->cmd_buffer), cp); if (psc_cmd_filter != 0) {
vstring_strcpy(state->cmd_buffer, cp); const char *cp;
} else if (psc_cmd_filter->error != 0) {
msg_fatal("%s:%s lookup error for \"%.100s\"", for (cp = STR(state->cmd_buffer); *cp && IS_SPACE_TAB(*cp); cp++)
psc_cmd_filter->type, psc_cmd_filter->name, /* void */ ;
STR(state->cmd_buffer)); if ((cp = psc_dict_get(psc_cmd_filter, cp)) != 0) {
msg_info("[%s]:%s: replacing command \"%.100s\" with \"%.100s\"",
state->smtp_client_addr, state->smtp_client_port,
STR(state->cmd_buffer), cp);
vstring_strcpy(state->cmd_buffer, cp);
} else if (psc_cmd_filter->error != 0) {
msg_fatal("%s:%s lookup error for \"%.100s\"",
psc_cmd_filter->type, psc_cmd_filter->name,
STR(state->cmd_buffer));
}
} }
} }
@ -959,174 +975,180 @@ 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. */ /*
if ((command = PSC_SMTPD_NEXT_TOKEN(cmd_buffer_ptr)) == 0) * Process the command line.
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. */
* The non-SMTP, PIPELINING and command COUNT tests depend on the if ((command = PSC_SMTPD_NEXT_TOKEN(cmd_buffer_ptr)) == 0)
* client command handler. command = "";
*
* Caution: cmdp->name and cmdp->action may be null on loop exit. /*
*/ * The non-SMTP, PIPELINING and command COUNT tests depend on the
saved_where = state->where; * client command handler.
state->where = PSC_SMTPD_CMD_UNIMPL; *
for (cmdp = command_table; cmdp->name != 0; cmdp++) { * Caution: cmdp->name and cmdp->action may be null on loop exit.
if (strcasecmp(command, cmdp->name) == 0) { */
state->where = cmdp->name; saved_where = state->where;
break; state->where = PSC_SMTPD_CMD_UNIMPL;
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)
/* 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. */
/* Command PIPELINING test. */ if ((state->flags & PSC_STATE_MASK_NSMTP_TODO_SKIP)
if ((cmdp->flags & PSC_SMTPD_CMD_FLAG_HAS_PAYLOAD) == 0 == PSC_STATE_FLAG_NSMTP_TODO && cmdp->name == 0
&& (state->flags & PSC_STATE_MASK_PIPEL_TODO_SKIP) && (is_header(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;
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; return;
case PSC_ACT_ENFORCE: case PSC_ACT_ENFORCE:
PSC_ENFORCE_SESSION_STATE(state, PSC_ENFORCE_SESSION_STATE(state,
"550 5.5.1 Protocol error\r\n"); "550 5.5.1 Protocol error\r\n");
break; break;
case PSC_ACT_IGNORE: case PSC_ACT_IGNORE:
PSC_UNFAIL_SESSION_STATE(state, PSC_UNFAIL_SESSION_STATE(state,
PSC_STATE_FLAG_PIPEL_FAIL); PSC_STATE_FLAG_PIPEL_FAIL);
/* Temporarily allowlist until something else expires. */ /* Temporarily allowlist until something else expires. */
PSC_PASS_SESSION_STATE(state, "pipelining test", PSC_PASS_SESSION_STATE(state, "pipelining test",
PSC_STATE_FLAG_PIPEL_PASS); PSC_STATE_FLAG_PIPEL_PASS);
expire_time[PSC_TINDX_PIPEL] = event_time() + psc_min_ttl; expire_time[PSC_TINDX_PIPEL] = event_time() + psc_min_ttl;
break; break;
default: default:
msg_panic("%s: unknown pipelining action value %d", msg_panic("%s: unknown pipelining action value %d",
myname, psc_pipel_action); myname, psc_pipel_action);
}
} }
}
/* /*
* The following tests don't pass until the client gets all the way * The following tests don't pass until the client gets all the
* to the RCPT TO command. However, the client can still fail these * way to the RCPT TO command. However, the client can still fail
* tests with some later command. * these tests with some later command.
*/ */
if (cmdp->action == psc_rcpt_cmd) { if (cmdp->action == psc_rcpt_cmd) {
if ((state->flags & PSC_STATE_MASK_BARLF_TODO_PASS_FAIL) if ((state->flags & PSC_STATE_MASK_BARLF_TODO_PASS_FAIL)
== PSC_STATE_FLAG_BARLF_TODO) { == PSC_STATE_FLAG_BARLF_TODO) {
PSC_PASS_SESSION_STATE(state, "bare newline test", PSC_PASS_SESSION_STATE(state, "bare newline test",
PSC_STATE_FLAG_BARLF_PASS); PSC_STATE_FLAG_BARLF_PASS);
/* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */ /* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */
expire_time[PSC_TINDX_BARLF] = event_time() + var_psc_barlf_ttl; 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;
}
} }
if ((state->flags & PSC_STATE_MASK_NSMTP_TODO_PASS_FAIL) /* Command COUNT limit test. */
== PSC_STATE_FLAG_NSMTP_TODO) { if (++state->command_count > var_psc_cmd_count
PSC_PASS_SESSION_STATE(state, "non-smtp test", && cmdp->action != psc_quit_cmd) {
PSC_STATE_FLAG_NSMTP_PASS); msg_info("COMMAND COUNT LIMIT from [%s]:%s after %s",
/* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */ PSC_CLIENT_ADDR_PORT(state), saved_where);
expire_time[PSC_TINDX_NSMTP] = event_time() + var_psc_nsmtp_ttl; PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event,
} psc_smtpd_421_reply);
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");
} else if (var_psc_enforce_tls
&& (state->flags & PSC_STATE_FLAG_USING_TLS) == 0
&& (cmdp->flags & PSC_SMTPD_CMD_FLAG_PRE_TLS) == 0) {
write_stat = PSC_SEND_REPLY(state,
"530 5.7.0 Must issue a STARTTLS command first\r\n");
} else {
write_stat = cmdp->action(state, cmd_buffer_ptr);
if (cmdp->flags & PSC_SMTPD_CMD_FLAG_DESTROY)
return; 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");
} else if (var_psc_enforce_tls
&& (state->flags & PSC_STATE_FLAG_USING_TLS) == 0
&& (cmdp->flags & PSC_SMTPD_CMD_FLAG_PRE_TLS) == 0) {
write_stat = PSC_SEND_REPLY(state,
"530 5.7.0 Must issue a STARTTLS command first\r\n");
} else {
write_stat = cmdp->action(state, cmd_buffer_ptr);
if (cmdp->flags & PSC_SMTPD_CMD_FLAG_DESTROY)
return;
}
} }
/* /*

View File

@ -45,7 +45,7 @@
/* select(.recipients[0].address == "user@example.com") /* select(.recipients[0].address == "user@example.com")
/* | select(.recipients[1].address == null) /* | select(.recipients[1].address == null)
/* | .queue_id /* | .queue_id
/* ' | postsuper -d - /* ' | tr -d '"' | postsuper -d -
/* .fi /* .fi
/* .sp /* .sp
/* Or the historical form: /* Or the historical form: