From 9deaf399553050b3b426e8a39d0ffd22430bf72d Mon Sep 17 00:00:00 2001
From: Matthias Andree <matthias.andree@gmx.de>
Date: Sat, 14 Apr 2018 21:39:58 +0200
Subject: In-depth fix for to64frombits() BASE64 encoder buffer sizing.

---
 base64.c    | 10 ++++++++--
 cram.c      |  2 +-
 fetchmail.h |  4 ++--
 gssapi.c    |  4 ++--
 imap.c      |  2 +-
 ntlmsubr.c  |  4 ++--
 smtp.c      |  8 ++++----
 7 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/base64.c b/base64.c
index 1453257b..3cd41691 100644
--- a/base64.c
+++ b/base64.c
@@ -27,23 +27,27 @@ static const char base64val[] = {
 };
 #define DECODE64(c)  (isascii((unsigned char)(c)) ? base64val[c] : BAD)
 
-void to64frombits(char *out, const void *in_, int inlen)
+int to64frombits(char *out, const void *in_, int inlen, size_t outlen)
 /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
 {
+    int rc = 0;
     const unsigned char *in = (const unsigned char *)in_;
 
     for (; inlen >= 3; inlen -= 3)
     {
+	if (outlen < 5) { rc = -1; goto fail; } /* buffer too small */
 	*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;
+	outlen -= 4;
     }
     if (inlen > 0)
     {
 	unsigned char fragment;
     
+	if (outlen < 5) { rc = -1; goto fail; } /* buffer too small */
 	*out++ = base64digits[in[0] >> 2];
 	fragment = (in[0] << 4) & 0x30;
 	if (inlen > 1)
@@ -52,7 +56,9 @@ void to64frombits(char *out, const void *in_, int inlen)
 	*out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
 	*out++ = '=';
     }
+fail:
     *out = '\0';
+    return rc;
 }
 
 int from64tobits(void *out_, const char *in, int maxlen)
@@ -103,7 +109,7 @@ int from64tobits(void *out_, const char *in, int maxlen)
     } while 
 	(*in && *in != '\r' && digit4 != '=');
 
-    return (len);
+    return len;
 }
 
 /* base64.c ends here */
diff --git a/cram.c b/cram.c
index cf33393e..4ac4a31f 100644
--- a/cram.c
+++ b/cram.c
@@ -122,7 +122,7 @@ int do_cram_md5 (int sock, const char *command, struct query *ctl, const char *s
               response[8], response[9], response[10], response[11],
               response[12], response[13], response[14], response[15]);
 
-    to64frombits (buf1, reply, strlen(reply));
+    to64frombits (buf1, reply, strlen(reply), sizeof buf1);
 
     /* ship the authentication back, accept the server's responses */
     /* PMDF5.2 IMAP has a bug that requires this to be a single write */
diff --git a/fetchmail.h b/fetchmail.h
index 98f07742..d2939c64 100644
--- a/fetchmail.h
+++ b/fetchmail.h
@@ -640,8 +640,8 @@ int prc_parse_file(const char *, const flag);
 int prc_filecheck(const char *, const flag);
 
 /* base64.c */
-void to64frombits(char *, const void *, int);
-int from64tobits(void *, const char *, int maxlen);
+int to64frombits(char *, const void *, int inlen, size_t outlen);
+int from64tobits(void *, const char *, int mxoutlen);
 
 /* unmime.c */
 /* Bit-mask returned by MimeBodyType */
diff --git a/gssapi.c b/gssapi.c
index e92ecdfd..818b599b 100644
--- a/gssapi.c
+++ b/gssapi.c
@@ -202,7 +202,7 @@ cancelfail:
 		return result;
 	    return PS_AUTHFAIL;
 	}
-	to64frombits(buf1, send_token.value, send_token.length);
+	to64frombits(buf1, send_token.value, send_token.length, sizeof buf1);
 	gss_release_buffer(&min_stat, &send_token);
 
 	suppress_tags = TRUE;
@@ -286,7 +286,7 @@ cancelfail:
 	    report(stderr, GT_("GSSAPI send_token too large (%lu) while sending username.\n"), (unsigned long)send_token.length);
 	    goto cancelfail;
     }
-    to64frombits(buf1, send_token.value, send_token.length);
+    to64frombits(buf1, send_token.value, send_token.length, sizeof buf1);
 
     suppress_tags = TRUE;
     result = gen_transact(sock, "%s", buf1);
diff --git a/imap.c b/imap.c
index 82c01b6d..3eb831f9 100644
--- a/imap.c
+++ b/imap.c
@@ -392,7 +392,7 @@ static int do_authcert (int sock, const char *command, const char *name)
     {
         size_t len = strlen(name);
         if ((len / 3) + ((len % 3) ? 4 : 0)  < sizeof(buf))
-            to64frombits (buf, name, strlen(name));
+            to64frombits (buf, name, strlen(name), sizeof buf);
         else
             return PS_AUTHFAIL; /* buffer too small. */
     }
diff --git a/ntlmsubr.c b/ntlmsubr.c
index 057c1b91..cf305ef0 100644
--- a/ntlmsubr.c
+++ b/ntlmsubr.c
@@ -44,7 +44,7 @@ int ntlm_helper(int sock, struct query *ctl, const char *proto)
 	dumpSmbNtlmAuthRequest(stdout, &request);
 
     memset(msgbuf,0,sizeof msgbuf);
-    to64frombits (msgbuf, &request, SmbLength(&request));
+    to64frombits (msgbuf, &request, SmbLength(&request), sizeof msgbuf);
 
     if (outlevel >= O_MONITOR)
 	report(stdout, "%s> %s\n", proto, msgbuf);
@@ -95,7 +95,7 @@ int ntlm_helper(int sock, struct query *ctl, const char *proto)
 	dumpSmbNtlmAuthResponse(stdout, &response);
 
     memset(msgbuf,0,sizeof msgbuf);
-    to64frombits (msgbuf, &response, SmbLength(&response));
+    to64frombits (msgbuf, &response, SmbLength(&response), sizeof msgbuf);
 
     if (outlevel >= O_MONITOR)
 	report(stdout, "%s> %s\n", proto, msgbuf);
diff --git a/smtp.c b/smtp.c
index 1c99c696..01e709d0 100644
--- a/smtp.c
+++ b/smtp.c
@@ -106,7 +106,7 @@ static void SMTP_auth(int sock, char smtp_mode, char *username, char *password,
 		digest[9], digest[10], digest[11], digest[12], digest[13],
 		digest[14], digest[15]);
 
-		to64frombits(b64buf, tmp, strlen(tmp));
+		to64frombits(b64buf, tmp, strlen(tmp), sizeof b64buf);
 		SockPrintf(sock, "%s\r\n", b64buf);
 		SMTP_ok(sock, smtp_mode, TIMEOUT_DEFAULT);
 	}
@@ -122,7 +122,7 @@ static void SMTP_auth(int sock, char smtp_mode, char *username, char *password,
 			if (tmp[c] == '^')
 				tmp[c] = '\0';
 		}
-		to64frombits(b64buf, tmp, len);
+		to64frombits(b64buf, tmp, len, sizeof b64buf);
 		SockPrintf(sock, "AUTH PLAIN %s\r\n", b64buf);
 		SMTP_ok(sock, smtp_mode, TIMEOUT_DEFAULT);
 	}
@@ -144,7 +144,7 @@ static void SMTP_auth(int sock, char smtp_mode, char *username, char *password,
 			SMTP_auth_error(sock, GT_("Bad base64 reply from server.\n"));
 			return;
 		}
-		to64frombits(b64buf, username, strlen(username));
+		to64frombits(b64buf, username, strlen(username), sizeof b64buf);
 		SockPrintf(sock, "%s\r\n", b64buf);
 		SockRead(sock, smtp_response, sizeof(smtp_response) - 1);
 		strlcpy(tmp, smtp_response, sizeof(tmp));
@@ -159,7 +159,7 @@ static void SMTP_auth(int sock, char smtp_mode, char *username, char *password,
 			SMTP_auth_error(sock, GT_("Bad base64 reply from server.\n"));
 			return;
 		}
-		to64frombits(b64buf, password, strlen(password));
+		to64frombits(b64buf, password, strlen(password), sizeof b64buf);
 		SockPrintf(sock, "%s\r\n", b64buf);
 		SMTP_ok(sock, smtp_mode, TIMEOUT_DEFAULT);
 	}
-- 
cgit v1.2.3