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)

Reply via email to