Description: Security smtpd_forbid_bare_newline Author: genie Origin: https://www.postfix.org/smtp-smuggling.html --- This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ Index: postfix-3.3.0/src/global/mail_params.h =================================================================== --- postfix-3.3.0.orig/src/global/mail_params.h +++ postfix-3.3.0/src/global/mail_params.h @@ -4009,6 +4009,15 @@ extern char *var_smtp_dns_re_filter; extern char *var_smtpd_dns_re_filter; /* + * Backwards compatibility. + */ +#define VAR_SMTPD_FORBID_BARE_LF "smtpd_forbid_bare_newline" +#define DEF_SMTPD_FORBID_BARE_LF 0 + +#define VAR_SMTPD_FORBID_BARE_LF_EXCL "smtpd_forbid_bare_newline_exclusions" +#define DEF_SMTPD_FORBID_BARE_LF_EXCL "$" VAR_MYNETWORKS + + /* * Location of shared-library files. * * If the files will be installed into a known directory, such as a directory Index: postfix-3.3.0/src/global/smtp_stream.c =================================================================== --- postfix-3.3.0.orig/src/global/smtp_stream.c +++ postfix-3.3.0/src/global/smtp_stream.c @@ -169,6 +169,8 @@ #include "smtp_stream.h" +int smtp_forbid_bare_lf; + /* smtp_timeout_reset - reset per-stream error flags, restart deadline timer */ static void smtp_timeout_reset(VSTREAM *stream) @@ -345,6 +347,9 @@ int smtp_get(VSTRING *vp, VSTREAM *s */ case '\n': vstring_truncate(vp, VSTRING_LEN(vp) - 1); + if (smtp_forbid_bare_lf + && (VSTRING_LEN(vp) == 0 || vstring_end(vp)[-1] != '\r')) + vstream_longjmp(stream, SMTP_ERR_LF); while (VSTRING_LEN(vp) > 0 && vstring_end(vp)[-1] == '\r') vstring_truncate(vp, VSTRING_LEN(vp) - 1); VSTRING_TERMINATE(vp); Index: postfix-3.3.0/src/global/smtp_stream.h =================================================================== --- postfix-3.3.0.orig/src/global/smtp_stream.h +++ postfix-3.3.0/src/global/smtp_stream.h @@ -32,6 +32,7 @@ #define SMTP_ERR_QUIET 3 /* silent cleanup (application) */ #define SMTP_ERR_NONE 4 /* non-error case */ #define SMTP_ERR_DATA 5 /* application data error */ +#define SMTP_ERR_LF 6 /* bare protocol error */ extern void smtp_stream_setup(VSTREAM *, int, int); extern void PRINTFLIKE(2, 3) smtp_printf(VSTREAM *, const char *,...); @@ -41,6 +42,7 @@ extern int smtp_get(VSTRING *, VSTREAM * extern void smtp_fputs(const char *, ssize_t len, VSTREAM *); extern void smtp_fwrite(const char *, ssize_t len, VSTREAM *); extern void smtp_fputc(int, VSTREAM *); +extern int smtp_forbid_bare_lf; extern void smtp_vprintf(VSTREAM *, const char *, va_list); Index: postfix-3.3.0/src/smtpd/smtpd.c =================================================================== --- postfix-3.3.0.orig/src/smtpd/smtpd.c +++ postfix-3.3.0/src/smtpd/smtpd.c @@ -1416,6 +1416,10 @@ char *var_tlsproxy_service; char *var_smtpd_uproxy_proto; int var_smtpd_uproxy_tmout; +bool var_smtpd_forbid_bare_lf; +char *var_smtpd_forbid_bare_lf_excl; +static NAMADR_LIST *bare_lf_excl; + /* * Silly little macros. */ @@ -1490,6 +1494,7 @@ static void tls_reset(SMTPD_STATE *); #define REASON_TIMEOUT "timeout" #define REASON_LOST_CONNECTION "lost connection" #define REASON_ERROR_LIMIT "too many errors" +#define REASON_BARE_LF "bare received" #ifdef USE_TLS @@ -4156,6 +4161,9 @@ static int xclient_cmd(SMTPD_STATE *stat */ xclient_allowed = namadr_list_match(xclient_hosts, state->name, state->addr); + smtp_forbid_bare_lf = SMTPD_STAND_ALONE((state)) == 0 + && var_smtpd_forbid_bare_lf + && !namadr_list_match(bare_lf_excl, state->name, state->addr); /* NOT: tls_reset() */ if (got_helo == 0) helo_reset(state); @@ -4936,6 +4944,13 @@ static void smtpd_proto(SMTPD_STATE *sta var_myhostname); break; + case SMTP_ERR_LF: + state->reason = REASON_BARE_LF; + if (vstream_setjmp(state->client) == 0) + smtpd_chat_reply(state, "521 5.5.2 %s Error: bare received", + var_myhostname); + break; + case 0: /* @@ -5461,6 +5476,13 @@ static void smtpd_service(VSTREAM *strea namadr_list_match(xforward_hosts, state.name, state.addr); /* + * Enforce strict SMTP line endings, with compatibility exclusions. + */ + smtp_forbid_bare_lf = SMTPD_STAND_ALONE((&state)) == 0 + && var_smtpd_forbid_bare_lf + && !namadr_list_match(bare_lf_excl, state.name, state.addr); + + /* * See if we need to turn on verbose logging for this client. */ debug_peer_check(state.name, state.addr); @@ -5522,10 +5544,14 @@ static void pre_jail_init(char *unused_n hogger_list = namadr_list_init(VAR_SMTPD_HOGGERS, MATCH_FLAG_RETURN | match_parent_style(VAR_SMTPD_HOGGERS), var_smtpd_hoggers); + bare_lf_excl = namadr_list_init(VAR_SMTPD_FORBID_BARE_LF_EXCL, + MATCH_FLAG_RETURN + | match_parent_style(VAR_MYNETWORKS), + var_smtpd_forbid_bare_lf_excl); /* * Open maps before dropping privileges so we can read passwords etc. - * + * * XXX We should not do this in stand-alone (sendmail -bs) mode, but we * can't use SMTPD_STAND_ALONE(state) here. This means "sendmail -bs" * will try to connect to proxymap when invoked by root for mail @@ -5850,6 +5876,7 @@ int main(int argc, char **argv) VAR_SMTPD_PEERNAME_LOOKUP, DEF_SMTPD_PEERNAME_LOOKUP, &var_smtpd_peername_lookup, VAR_SMTPD_DELAY_OPEN, DEF_SMTPD_DELAY_OPEN, &var_smtpd_delay_open, VAR_SMTPD_CLIENT_PORT_LOG, DEF_SMTPD_CLIENT_PORT_LOG, &var_smtpd_client_port_log, + VAR_SMTPD_FORBID_BARE_LF, DEF_SMTPD_FORBID_BARE_LF, &var_smtpd_forbid_bare_lf, 0, }; static const CONFIG_NBOOL_TABLE nbool_table[] = { @@ -5960,6 +5987,7 @@ int main(int argc, char **argv) VAR_SMTPD_POLICY_DEF_ACTION, DEF_SMTPD_POLICY_DEF_ACTION, &var_smtpd_policy_def_action, 1, 0, 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_FORBID_BARE_LF_EXCL, DEF_SMTPD_FORBID_BARE_LF_EXCL, &var_smtpd_forbid_bare_lf_excl, 0, 0, 0, }; static const CONFIG_RAW_TABLE raw_table[] = {