From 9deaf399553050b3b426e8a39d0ffd22430bf72d Mon Sep 17 00:00:00 2001 From: Matthias Andree 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