96c8c8cef2
Resolves: CVE-2020-12783
201 lines
5.8 KiB
Diff
201 lines
5.8 KiB
Diff
diff --git a/src/auths/auth-spa.c b/src/auths/auth-spa.c
|
|
index fc363df..44c99e9 100644
|
|
--- a/src/auths/auth-spa.c
|
|
+++ b/src/auths/auth-spa.c
|
|
@@ -374,27 +374,27 @@ void
|
|
spa_bits_to_base64 (uschar *out, const uschar *in, int inlen)
|
|
/* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
|
|
{
|
|
- for (; inlen >= 3; inlen -= 3)
|
|
- {
|
|
- *out++ = base64digits[in[0] >> 2];
|
|
- *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
|
|
- *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
|
|
- *out++ = base64digits[in[2] & 0x3f];
|
|
- in += 3;
|
|
- }
|
|
- if (inlen > 0)
|
|
- {
|
|
- uschar fragment;
|
|
-
|
|
- *out++ = base64digits[in[0] >> 2];
|
|
- fragment = (in[0] << 4) & 0x30;
|
|
- if (inlen > 1)
|
|
- fragment |= in[1] >> 4;
|
|
- *out++ = base64digits[fragment];
|
|
- *out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
|
|
- *out++ = '=';
|
|
- }
|
|
- *out = '\0';
|
|
+for (; inlen >= 3; inlen -= 3)
|
|
+ {
|
|
+ *out++ = base64digits[in[0] >> 2];
|
|
+ *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
|
|
+ *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
|
|
+ *out++ = base64digits[in[2] & 0x3f];
|
|
+ in += 3;
|
|
+ }
|
|
+if (inlen > 0)
|
|
+ {
|
|
+ uschar fragment;
|
|
+
|
|
+ *out++ = base64digits[in[0] >> 2];
|
|
+ fragment = (in[0] << 4) & 0x30;
|
|
+ if (inlen > 1)
|
|
+ fragment |= in[1] >> 4;
|
|
+ *out++ = base64digits[fragment];
|
|
+ *out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
|
|
+ *out++ = '=';
|
|
+ }
|
|
+*out = '\0';
|
|
}
|
|
|
|
|
|
@@ -404,52 +404,52 @@ int
|
|
spa_base64_to_bits (char *out, int outlength, const char *in)
|
|
/* base 64 to raw bytes in quasi-big-endian order, returning count of bytes */
|
|
{
|
|
- int len = 0;
|
|
- register uschar digit1, digit2, digit3, digit4;
|
|
+int len = 0;
|
|
+uschar digit1, digit2, digit3, digit4;
|
|
|
|
- if (in[0] == '+' && in[1] == ' ')
|
|
- in += 2;
|
|
- if (*in == '\r')
|
|
- return (0);
|
|
+if (in[0] == '+' && in[1] == ' ')
|
|
+ in += 2;
|
|
+if (*in == '\r')
|
|
+ return (0);
|
|
|
|
- do
|
|
+do
|
|
+ {
|
|
+ if (len >= outlength) /* Added by PH */
|
|
+ return -1; /* Added by PH */
|
|
+ digit1 = in[0];
|
|
+ if (DECODE64 (digit1) == BAD)
|
|
+ return -1;
|
|
+ digit2 = in[1];
|
|
+ if (DECODE64 (digit2) == BAD)
|
|
+ return -1;
|
|
+ digit3 = in[2];
|
|
+ if (digit3 != '=' && DECODE64 (digit3) == BAD)
|
|
+ return -1;
|
|
+ digit4 = in[3];
|
|
+ if (digit4 != '=' && DECODE64 (digit4) == BAD)
|
|
+ return -1;
|
|
+ in += 4;
|
|
+ *out++ = (DECODE64 (digit1) << 2) | (DECODE64 (digit2) >> 4);
|
|
+ ++len;
|
|
+ if (digit3 != '=')
|
|
{
|
|
+ if (len >= outlength) /* Added by PH */
|
|
+ return -1; /* Added by PH */
|
|
+ *out++ =
|
|
+ ((DECODE64 (digit2) << 4) & 0xf0) | (DECODE64 (digit3) >> 2);
|
|
+ ++len;
|
|
+ if (digit4 != '=')
|
|
+ {
|
|
if (len >= outlength) /* Added by PH */
|
|
- return (-1); /* Added by PH */
|
|
- digit1 = in[0];
|
|
- if (DECODE64 (digit1) == BAD)
|
|
- return (-1);
|
|
- digit2 = in[1];
|
|
- if (DECODE64 (digit2) == BAD)
|
|
- return (-1);
|
|
- digit3 = in[2];
|
|
- if (digit3 != '=' && DECODE64 (digit3) == BAD)
|
|
- return (-1);
|
|
- digit4 = in[3];
|
|
- if (digit4 != '=' && DECODE64 (digit4) == BAD)
|
|
- return (-1);
|
|
- in += 4;
|
|
- *out++ = (DECODE64 (digit1) << 2) | (DECODE64 (digit2) >> 4);
|
|
+ return -1; /* Added by PH */
|
|
+ *out++ = ((DECODE64 (digit3) << 6) & 0xc0) | DECODE64 (digit4);
|
|
++len;
|
|
- if (digit3 != '=')
|
|
- {
|
|
- if (len >= outlength) /* Added by PH */
|
|
- return (-1); /* Added by PH */
|
|
- *out++ =
|
|
- ((DECODE64 (digit2) << 4) & 0xf0) | (DECODE64 (digit3) >> 2);
|
|
- ++len;
|
|
- if (digit4 != '=')
|
|
- {
|
|
- if (len >= outlength) /* Added by PH */
|
|
- return (-1); /* Added by PH */
|
|
- *out++ = ((DECODE64 (digit3) << 6) & 0xc0) | DECODE64 (digit4);
|
|
- ++len;
|
|
- }
|
|
- }
|
|
+ }
|
|
}
|
|
- while (*in && *in != '\r' && digit4 != '=');
|
|
+ }
|
|
+while (*in && *in != '\r' && digit4 != '=');
|
|
|
|
- return (len);
|
|
+return len;
|
|
}
|
|
|
|
|
|
diff --git a/src/auths/spa.c b/src/auths/spa.c
|
|
index 97e3b10..5bffdfb 100644
|
|
--- a/src/auths/spa.c
|
|
+++ b/src/auths/spa.c
|
|
@@ -139,7 +139,8 @@ SPAAuthChallenge challenge;
|
|
SPAAuthResponse response;
|
|
SPAAuthResponse *responseptr = &response;
|
|
uschar msgbuf[2048];
|
|
-uschar *clearpass;
|
|
+uschar *clearpass, *s;
|
|
+unsigned off;
|
|
|
|
/* send a 334, MS Exchange style, and grab the client's request,
|
|
unless we already have it via an initial response. */
|
|
@@ -194,9 +195,19 @@ that causes failure if the size of msgbuf is exceeded. ****/
|
|
|
|
{
|
|
int i;
|
|
- char *p = ((char*)responseptr) + IVAL(&responseptr->uUser.offset,0);
|
|
+ char * p;
|
|
int len = SVAL(&responseptr->uUser.len,0)/2;
|
|
|
|
+ if ( (off = IVAL(&responseptr->uUser.offset,0)) >= sizeof(SPAAuthResponse)
|
|
+ || len >= sizeof(responseptr->buffer)/2
|
|
+ || (p = (CS responseptr) + off) + len*2 >= CS (responseptr+1)
|
|
+ )
|
|
+ {
|
|
+ DEBUG(D_auth)
|
|
+ debug_printf("auth_spa_server(): bad uUser spec in response\n");
|
|
+ return FAIL;
|
|
+ }
|
|
+
|
|
if (len + 1 >= sizeof(msgbuf)) return FAIL;
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
@@ -245,9 +256,16 @@ spa_smb_nt_encrypt (clearpass, challenge.challengeData, ntRespData);
|
|
|
|
/* compare NT hash (LM may not be available) */
|
|
|
|
-if (memcmp(ntRespData,
|
|
- ((unsigned char*)responseptr)+IVAL(&responseptr->ntResponse.offset,0),
|
|
- 24) == 0)
|
|
+off = IVAL(&responseptr->ntResponse.offset,0);
|
|
+if (off >= sizeof(SPAAuthResponse) - 24)
|
|
+ {
|
|
+ DEBUG(D_auth)
|
|
+ debug_printf("auth_spa_server(): bad ntRespData spec in response\n");
|
|
+ return FAIL;
|
|
+ }
|
|
+s = (US responseptr) + off;
|
|
+
|
|
+if (memcmp(ntRespData, s, 24) == 0)
|
|
/* success. we have a winner. */
|
|
{
|
|
return auth_check_serv_cond(ablock);
|