@@ -1835,20 +1835,33 @@
return true;
}
-static bool
+/**
+ * Read a string that is encoded as a 2 byte header with the length from the
+ * buffer \c buf. Will return the non-negative value if reading was successful.
+ * The returned value will include the trailing 0 byte.
+ *
+ * If the message is over the capacity or could not be read
+ * it will return the negative length that was in the
+ * header and try to skip the string. If the string cannot be skipped, the
+ * buf will stay at the current position or position + 2
+ */
+static int
read_string(struct buffer *buf, char *str, const unsigned int capacity)
{
const int len = buf_read_u16(buf);
if (len < 1 || len > (int)capacity)
{
- return false;
+ buf_advance(buf, len);
+
+ /* will also return 0 for a no string being present */
+ return -len;
}
if (!buf_read(buf, str, len))
{
- return false;
+ return -len;
}
str[len-1] = '\0';
- return true;
+ return len;
}
static char *
@@ -2218,8 +2231,6 @@
{
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- bool username_status, password_status;
-
struct gc_arena gc = gc_new();
char *options;
struct user_pass *up = NULL;
@@ -2253,7 +2264,7 @@
}
/* get options */
- if (!read_string(buf, options, TLS_OPTIONS_LEN))
+ if (read_string(buf, options, TLS_OPTIONS_LEN) < 0)
{
msg(D_TLS_ERRORS, "TLS Error: Failed to read required OCC options string");
goto error;
@@ -2266,8 +2277,8 @@
* peer_info data which follows behind
*/
ALLOC_OBJ_CLEAR_GC(up, struct user_pass, &gc);
- username_status = read_string(buf, up->username, USER_PASS_LEN);
- password_status = read_string(buf, up->password, USER_PASS_LEN);
+ int username_len = read_string(buf, up->username, USER_PASS_LEN);
+ int password_len = read_string(buf, up->password, USER_PASS_LEN);
/* get peer info from control channel */
free(multi->peer_info);
@@ -2290,10 +2301,21 @@
multi->remote_ciphername = string_alloc("none", NULL);
}
- if (tls_session_user_pass_enabled(session))
+ if (username_len < 0 || password_len < 0)
+ {
+ msg(D_TLS_ERRORS, "TLS Error: Username (%d) or password (%d) too long",
+ abs(username_len), abs(password_len));
+ auth_set_client_reason(multi, "Username or password is too long. "
+ "Maximum length is 128 bytes");
+
+ /* treat the same as failed username/password and do not error
+ * out (goto error) to sent an AUTH_FAILED back to the client */
+ ks->authenticated = KS_AUTH_FALSE;
+ }
+ else if (tls_session_user_pass_enabled(session))
{
/* Perform username/password authentication */
- if (!username_status || !password_status)
+ if (!username_len || !password_len)
{
CLEAR(*up);
if (!(session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL))