On Thu, Aug 23, 2018 at 11:14:57AM -0400, Wietse Venema wrote: > > It looks like Postfix is not prepared to receive large tokens: > > > > 316 smtpd_chat_query(state); > > > > We need to replace smtpd_chat_query() with a sasl-specific function > > that calls smtp_get_line() one or more times as necessary to read > > and combine any partial lines to yield a complete client token, up > > to a limit of 12288 or more bytes (9K bytes before base64 encoding). > > Fine as long as it does not introduce a memory exhaustion vulnerability, > and as long as it handles time limits and EOF consistent with other SMTP > server inputs. > > If the response has a length indication perhaps one could benefit > from the brand-new smtp_fread() call (added for BDAT support).
Sadly no length indication. Two patches attached, the firsrt fixes a compiler type mismatch warning for a no-longer-used argument to psc_get_footer(). The second is the new SASL line limit. -- Viktor.
>From 4bf50040948b42396ed173f60dc17788847c7040 Mon Sep 17 00:00:00 2001 From: Viktor Dukhovni <postfix-us...@dukhovni.org> Date: Thu, 23 Aug 2018 12:26:19 -0400 Subject: [PATCH 1/2] Drop unused psc_get_footer parameter --- src/postscreen/postscreen_send.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/postscreen/postscreen_send.c b/src/postscreen/postscreen_send.c index b0615528..0e7af46b 100644 --- a/src/postscreen/postscreen_send.c +++ b/src/postscreen/postscreen_send.c @@ -108,8 +108,7 @@ void pcs_send_pre_jail_init(void) /* psc_get_footer - find that footer */ -static const char *psc_get_footer(PSC_STATE *state, const char *text, - ssize_t text_len) +static const char *psc_get_footer(const char *text, ssize_t text_len) { static VSTRING *footer_buf = 0; @@ -157,7 +156,7 @@ int psc_send_reply(PSC_STATE *state, const char *text) */ if ((*text == '4' || *text == '5') && ((psc_rej_ftr_maps != 0 - && (footer = psc_get_footer(psc_rej_ftr_maps, text, text_len)) != 0) + && (footer = psc_get_footer(text, text_len)) != 0) || *(footer = var_psc_rej_footer) != 0)) smtp_reply_footer(state->send_buf, start, footer, STR(psc_expand_filter), psc_expand_lookup, -- 2.15.2 (Apple Git-101.1)
>From 08e5eeece424c8fcdc77771a28ed6bb69bf1213f Mon Sep 17 00:00:00 2001 From: Viktor Dukhovni <postfix-us...@dukhovni.org> Date: Thu, 23 Aug 2018 12:26:48 -0400 Subject: [PATCH 2/2] Implement new SASL response line limit --- man/man8/smtpd.8 | 4 ++++ proto/postconf.proto | 16 ++++++++++++++++ src/global/mail_params.h | 12 ++++++++++++ src/smtpd/smtpd.c | 8 ++++++++ src/smtpd/smtpd_chat.c | 23 ++++++++++++++++++++--- src/smtpd/smtpd_chat.h | 1 + src/smtpd/smtpd_sasl_glue.c | 9 ++++----- 7 files changed, 65 insertions(+), 8 deletions(-) diff --git a/man/man8/smtpd.8 b/man/man8/smtpd.8 index c51f8ab0..ae173756 100644 --- a/man/man8/smtpd.8 +++ b/man/man8/smtpd.8 @@ -370,6 +370,10 @@ Available in Postfix version 2.11 and later: .IP "\fBsmtpd_sasl_service (smtp)\fR" The service name that is passed to the SASL plug\-in that is selected with \fBsmtpd_sasl_type\fR and \fBsmtpd_sasl_path\fR. +.PP +Available in Postfix version 3.4 and later: +.IP "\fBsmtpd_sasl_response_limit (12288)\fR" +The maximum length of a SASL client's response to a server challenge. .SH "STARTTLS SUPPORT CONTROLS" .na .nf diff --git a/proto/postconf.proto b/proto/postconf.proto index 271c701e..7e169b6b 100644 --- a/proto/postconf.proto +++ b/proto/postconf.proto @@ -10779,6 +10779,22 @@ selected with <b>smtpd_sasl_type</b> and <b>smtpd_sasl_path</b>. <p> This feature is available in Postfix 2.11 and later. Prior versions behave as if "<b>smtp</b>" is specified. </p> +%PARAM smtpd_sasl_response_limit 12288 + +<p> The maximum length of a SASL client's response to a server challenge. +When the client's "initial response" is longer than the normal limit for +SMTP commands, the client must omit its initial response, and wait for an +empty server challenge; it can then send what would have been its "initial +response" as a response to the empty server challenge. RFC4954 requires the +server to accept client responses up to at least 12288 octets of +base64-encoded text. The default value is therefore also the minimum value +accepted for this parameter.</p> + +<p> This feature is available in Postfix 3.4 and later. Prior versions use +"line_length_limit", which may need to be raised to accomodate larger client +responses, as may be needed with GSSAPI authenticaiton of Windows AD users +who are members of many groups. </p> + %PARAM cyrus_sasl_config_path <p> Search path for Cyrus SASL application configuration files, diff --git a/src/global/mail_params.h b/src/global/mail_params.h index 5b92c1c6..0e1dc306 100644 --- a/src/global/mail_params.h +++ b/src/global/mail_params.h @@ -1664,6 +1664,18 @@ extern char *var_smtpd_snd_auth_maps; #define REJECT_UNAUTH_SENDER_LOGIN_MISMATCH \ "reject_unauthenticated_sender_login_mismatch" +/*- + * https://tools.ietf.org/html/rfc4954#page-5 + * (At the time of writing of this document, 12288 octets is considered to be a + * sufficient line length limit for handling of deployed authentication + * mechanisms.) + * + * The default value is also the minimum permissible value for this parameter. + */ +#define VAR_SASL_RESPONSE_LIMIT "smtpd_sasl_response_limit" +#define DEF_SASL_RESPONSE_LIMIT 12288 +extern int var_sasl_response_limit; + /* * SASL authentication support, SMTP client side. */ diff --git a/src/smtpd/smtpd.c b/src/smtpd/smtpd.c index 99284b3b..59da6a94 100644 --- a/src/smtpd/smtpd.c +++ b/src/smtpd/smtpd.c @@ -338,6 +338,10 @@ /* .IP "\fBsmtpd_sasl_service (smtp)\fR" /* The service name that is passed to the SASL plug-in that is /* selected with \fBsmtpd_sasl_type\fR and \fBsmtpd_sasl_path\fR. +/* .PP +/* Available in Postfix version 3.4 and later: +/* .IP "\fBsmtpd_sasl_response_limit (12288)\fR" +/* The maximum length of a SASL client's response to a server challenge. /* STARTTLS SUPPORT CONTROLS /* .ad /* .fi @@ -1283,6 +1287,7 @@ char *var_smtpd_sasl_path; char *var_smtpd_sasl_service; char *var_cyrus_conf_path; char *var_smtpd_sasl_realm; +int var_sasl_response_limit; char *var_smtpd_sasl_exceptions_networks; char *var_smtpd_sasl_type; char *var_filter_xport; @@ -5819,6 +5824,9 @@ int main(int argc, char **argv) VAR_SMTPD_CAUTH_LIMIT, DEF_SMTPD_CAUTH_LIMIT, &var_smtpd_cauth_limit, 0, 0, #ifdef USE_TLS VAR_SMTPD_TLS_CCERT_VD, DEF_SMTPD_TLS_CCERT_VD, &var_smtpd_tls_ccert_vd, 0, 0, +#endif +#ifdef USE_SASL_AUTH + VAR_SASL_RESPONSE_LIMIT, DEF_SASL_RESPONSE_LIMIT, &var_sasl_response_limit, DEF_SASL_RESPONSE_LIMIT, 0, #endif VAR_SMTPD_POLICY_REQ_LIMIT, DEF_SMTPD_POLICY_REQ_LIMIT, &var_smtpd_policy_req_limit, 0, 0, VAR_SMTPD_POLICY_TRY_LIMIT, DEF_SMTPD_POLICY_TRY_LIMIT, &var_smtpd_policy_try_limit, 1, 0, diff --git a/src/smtpd/smtpd_chat.c b/src/smtpd/smtpd_chat.c index bd768133..dba2408b 100644 --- a/src/smtpd/smtpd_chat.c +++ b/src/smtpd/smtpd_chat.c @@ -9,6 +9,10 @@ /* /* void smtpd_chat_pre_jail_init(void) /* +/* int smtpd_chat_query_limit(state, limit) +/* SMTPD_STATE *state; +/* int limit; +/* /* void smtpd_chat_query(state) /* SMTPD_STATE *state; /* @@ -27,6 +31,11 @@ /* /* smtpd_chat_pre_jail_init() performs one-time initialization. /* +/* smtpd_chat_query_limit() reads a line from the client that is +/* at most "limit" bytes long. A copy is appended to the SMTP +/* transaction log. The return value is non-zero for a complete +/* line or else zero if the length limit was exceeded. +/* /* smtpd_chat_query() receives a client request and appends a copy /* to the SMTP transaction log. /* @@ -151,7 +160,7 @@ static void smtp_chat_append(SMTPD_STATE *state, char *direction, /* smtpd_chat_query - receive and record an SMTP request */ -void smtpd_chat_query(SMTPD_STATE *state) +int smtpd_chat_query_limit(SMTPD_STATE *state, int limit) { int last_char; @@ -159,16 +168,24 @@ void smtpd_chat_query(SMTPD_STATE *state) * We can't parse or store input that exceeds var_line_limit, so we skip * over it to avoid loss of synchronization. */ - last_char = smtp_get(state->buffer, state->client, var_line_limit, + last_char = smtp_get(state->buffer, state->client, limit, SMTP_GET_FLAG_SKIP); smtp_chat_append(state, "In: ", STR(state->buffer)); if (last_char != '\n') msg_warn("%s: request longer than %d: %.30s...", - state->namaddr, var_line_limit, + state->namaddr, limit, printable(STR(state->buffer), '?')); if (msg_verbose) msg_info("< %s: %s", state->namaddr, STR(state->buffer)); + return (last_char == '\n'); +} + +/* smtpd_chat_query - receive and record an SMTP request */ + +void smtpd_chat_query(SMTPD_STATE *state) +{ + (void) smtpd_chat_query_limit(state, var_line_limit); } /* smtpd_chat_reply - format, send and record an SMTP response */ diff --git a/src/smtpd/smtpd_chat.h b/src/smtpd/smtpd_chat.h index e64b1c92..6f222e30 100644 --- a/src/smtpd/smtpd_chat.h +++ b/src/smtpd/smtpd_chat.h @@ -14,6 +14,7 @@ */ extern void smtpd_chat_pre_jail_init(void); extern void smtpd_chat_reset(SMTPD_STATE *); +extern int smtpd_chat_query_limit(SMTPD_STATE *, int); extern void smtpd_chat_query(SMTPD_STATE *); extern void PRINTFLIKE(2, 3) smtpd_chat_reply(SMTPD_STATE *, const char *,...); extern void smtpd_chat_notify(SMTPD_STATE *); diff --git a/src/smtpd/smtpd_sasl_glue.c b/src/smtpd/smtpd_sasl_glue.c index 3a0782dc..e50c97ba 100644 --- a/src/smtpd/smtpd_sasl_glue.c +++ b/src/smtpd/smtpd_sasl_glue.c @@ -308,12 +308,11 @@ int smtpd_sasl_authenticate(SMTPD_STATE *state, /* * Receive the client response. "*" means that the client gives up. - * XXX For now we ignore the fact that an excessively long response - * will be chopped into multiple responses. To handle such responses, - * we need to change smtpd_chat_query() so that it returns an error - * indication. */ - smtpd_chat_query(state); + if (!smtpd_chat_query_limit(state, var_sasl_response_limit)) { + smtpd_chat_reply(state, "500 5.5.6 SASL response limit exceeded"); + return (-1); + } if (strcmp(STR(state->buffer), "*") == 0) { msg_warn("%s: SASL %s authentication aborted", state->namaddr, sasl_method); -- 2.15.2 (Apple Git-101.1)