Markus Moeller has re-implemented several of the coder functions for use by Kerberos helpers.

This patch seeks to de-duplicate them and combine the resulting code back into the libmiscencoding.la "base64.h" implementation.


Changes include:

* old function API renamed to old_*() and existing code update to use the names. Some code has been updated to use the new API.

* new estimator base64_encode_len()/base64_decode_len() function added to provide details of much much buffer space the output will require.

* new API encoder and decoder functions added which accept caller provided buffers and encode/decode an arbitrary string into them.

* also fixes a bug where if the input text or output buffer was too short the coder functions would crop a few bytes off the end of the result.


Some optimizations have been added by myself over and above Markus changes:

* optimized to short-circuit on several more variations of empty input and nil result buffer.

* sub-loop optimizations added to reduce the number of if() calls made by the new code.

 * split encoder into terminated (C-str) and non-terminated variants.

I have also now documented both old and new APIs functions.

Amos
--
Please be using
  Current Stable Squid 2.7.STABLE9 or 3.1.12
  Beta testers wanted for 3.2.0.7 and 3.1.12.1
=== modified file 'helpers/negotiate_auth/kerberos/Makefile.am'
--- helpers/negotiate_auth/kerberos/Makefile.am	2010-08-13 12:05:25 +0000
+++ helpers/negotiate_auth/kerberos/Makefile.am	2011-04-16 15:24:58 +0000
@@ -5,17 +5,22 @@
 
 libexec_PROGRAMS = negotiate_kerberos_auth negotiate_kerberos_auth_test
 
-SOURCE = negotiate_kerberos_auth.cc base64.cc base64.h
-SOURCE_test = negotiate_kerberos_auth_test.cc base64.cc base64.h
-
-negotiate_kerberos_auth_SOURCES = $(SOURCE)
 AM_CPPFLAGS = $(INCLUDES) -I$(srcdir)
-negotiate_kerberos_auth_test_SOURCES = $(SOURCE_test)
-
-
+
+negotiate_kerberos_auth_SOURCES = negotiate_kerberos_auth.cc
 negotiate_kerberos_auth_LDFLAGS = 
-negotiate_kerberos_auth_LDADD = $(COMPAT_LIB) $(XTRA_LIBS) $(KRB5LIBS)
+negotiate_kerberos_auth_LDADD = \
+	$(top_builddir)/lib/libmiscencoding.la \
+	$(COMPAT_LIB) \
+	$(KRB5LIBS) \
+	$(XTRA_LIBS)
+
+negotiate_kerberos_auth_test_SOURCES = negotiate_kerberos_auth_test.cc
 negotiate_kerberos_auth_test_LDFLAGS = 
-negotiate_kerberos_auth_test_LDADD = $(COMPAT_LIB) $(XTRA_LIBS) $(KRB5LIBS)
+negotiate_kerberos_auth_test_LDADD = \
+	$(top_builddir)/lib/libmiscencoding.la \
+	$(COMPAT_LIB) \
+	$(KRB5LIBS) \
+	$(XTRA_LIBS)
 
 man_MANS = negotiate_kerberos_auth.8

=== removed file 'helpers/negotiate_auth/kerberos/base64.cc'
--- helpers/negotiate_auth/kerberos/base64.cc	2010-11-20 11:31:38 +0000
+++ helpers/negotiate_auth/kerberos/base64.cc	1970-01-01 00:00:00 +0000
@@ -1,161 +0,0 @@
-/*
- * Markus Moeller has modified the following code from Squid
- */
-
-#include "config.h"
-#include "base64.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-
-static void ska_base64_init(void);
-
-static int base64_initialized = 0;
-#define BASE64_VALUE_SZ 256
-int base64_value[BASE64_VALUE_SZ];
-const char base64_code[] =
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-
-static void
-ska_base64_init(void)
-{
-    int i;
-
-    for (i = 0; i < BASE64_VALUE_SZ; i++)
-        base64_value[i] = -1;
-
-    for (i = 0; i < 64; i++)
-        base64_value[(int) base64_code[i]] = i;
-    base64_value[(int) '='] = 0;
-
-    base64_initialized = 1;
-}
-
-void
-ska_base64_decode(char *result, const char *data, int result_size)
-{
-    int j;
-    int c;
-    long val;
-    if (!data)
-        return;
-    if (!base64_initialized)
-        ska_base64_init();
-    val = c = 0;
-
-    for (j = 0; *data; data++) {
-        unsigned int k = ((unsigned char) *data) % BASE64_VALUE_SZ;
-        if (base64_value[k] < 0)
-            continue;
-        val <<= 6;
-        val += base64_value[k];
-        if (++c < 4)
-            continue;
-        /* One quantum of four encoding characters/24 bit */
-        if (j >= result_size)
-            break;
-        result[j++] = val >> 16;	/* High 8 bits */
-        if (j >= result_size)
-            break;
-        result[j++] = (val >> 8) & 0xff;	/* Mid 8 bits */
-        if (j >= result_size)
-            break;
-        result[j++] = val & 0xff;	/* Low 8 bits */
-        val = c = 0;
-    }
-    return;
-}
-
-/* adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments */
-void
-ska_base64_encode(char *result, const char *data, int result_size,
-                  int data_size)
-{
-    int bits = 0;
-    int char_count = 0;
-    int out_cnt = 0;
-
-    if (!data)
-        return;
-
-    if (!base64_initialized)
-        ska_base64_init();
-
-    while (data_size--) {
-        int c = (unsigned char) *data++;
-        bits += c;
-        char_count++;
-        if (char_count == 3) {
-            if (out_cnt >= result_size)
-                break;
-            result[out_cnt++] = base64_code[bits >> 18];
-            if (out_cnt >= result_size)
-                break;
-            result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
-            if (out_cnt >= result_size)
-                break;
-            result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
-            if (out_cnt >= result_size)
-                break;
-            result[out_cnt++] = base64_code[bits & 0x3f];
-            bits = 0;
-            char_count = 0;
-        } else {
-            bits <<= 8;
-        }
-    }
-    if (char_count != 0) {
-        bits <<= 16 - (8 * char_count);
-        if (out_cnt >= result_size)
-            goto end;
-        result[out_cnt++] = base64_code[bits >> 18];
-        if (out_cnt >= result_size)
-            goto end;
-        result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
-        if (char_count == 1) {
-            if (out_cnt >= result_size)
-                goto end;
-            result[out_cnt++] = '=';
-            if (out_cnt >= result_size)
-                goto end;
-            result[out_cnt++] = '=';
-        } else {
-            if (out_cnt >= result_size)
-                goto end;
-            result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
-            if (out_cnt >= result_size)
-                goto end;
-            result[out_cnt++] = '=';
-        }
-    }
-end:
-    if (out_cnt >= result_size) {
-        result[result_size - 1] = '\0';		/* terminate */
-    } else {
-        result[out_cnt] = '\0';	/* terminate */
-    }
-    return;
-}
-
-int
-ska_base64_encode_len(int len)
-{
-    return ((len + 2) / 3 * 4) + 1;
-}
-
-int
-ska_base64_decode_len(const char *data)
-{
-    int i, j;
-
-    j = 0;
-    for (i = strlen(data) - 1; i >= 0; i--) {
-        if (data[i] == '=')
-            j++;
-        if (data[i] != '=')
-            break;
-    }
-    return strlen(data) / 4 * 3 - j;
-}

=== removed file 'helpers/negotiate_auth/kerberos/base64.h'
--- helpers/negotiate_auth/kerberos/base64.h	2010-08-14 00:12:49 +0000
+++ helpers/negotiate_auth/kerberos/base64.h	1970-01-01 00:00:00 +0000
@@ -1,10 +0,0 @@
-/*
- * Markus Moeller has modified the following code from Squid
- */
-
-void ska_base64_decode(char *result, const char *data, int result_size);
-void ska_base64_encode(char *result, const char *data, int result_size,
-                       int data_size);
-
-int ska_base64_encode_len(int len);
-int ska_base64_decode_len(const char *data);

=== modified file 'helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc'
--- helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc	2011-03-14 06:15:51 +0000
+++ helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc	2011-04-20 13:46:46 +0000
@@ -374,13 +374,12 @@
             fprintf(stdout, "BH Invalid negotiate request\n");
             continue;
         }
-        input_token.length = ska_base64_decode_len(buf + 3);
+        input_token.length = base64_decode_len(buf + 3);
         debug((char *) "%s| %s: DEBUG: Decode '%s' (decoded length: %d).\n",
               LogTime(), PROGRAM, buf + 3, (int) input_token.length);
         input_token.value = xmalloc(input_token.length);
 
-        ska_base64_decode((char *) input_token.value, buf + 3, input_token.length);
-
+        base64_decode((char *) input_token.value, buf + 3, input_token.length);
 
         if ((input_token.length >= sizeof ntlmProtocol + 1) &&
                 (!memcmp(input_token.value, ntlmProtocol, sizeof ntlmProtocol))) {
@@ -427,14 +426,14 @@
         if (output_token.length) {
             spnegoToken = (const unsigned char *) output_token.value;
             spnegoTokenLength = output_token.length;
-            token = (char *) xmalloc(ska_base64_encode_len(spnegoTokenLength));
+            token = (char *) xmalloc(base64_encode_len(spnegoTokenLength));
             if (token == NULL) {
                 debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
                 fprintf(stdout, "BH Not enough memory\n");
                 goto cleanup;
             }
-            ska_base64_encode(token, (const char *) spnegoToken,
-                              ska_base64_encode_len(spnegoTokenLength), spnegoTokenLength);
+            base64_encode_str(token, (const char *) spnegoToken,
+                              base64_encode_len(spnegoTokenLength), spnegoTokenLength);
 
             if (check_gss_err(major_status, minor_status, "gss_accept_sec_context()", log))
                 goto cleanup;

=== modified file 'helpers/negotiate_auth/kerberos/negotiate_kerberos_auth_test.cc'
--- helpers/negotiate_auth/kerberos/negotiate_kerberos_auth_test.cc	2011-03-14 06:15:51 +0000
+++ helpers/negotiate_auth/kerberos/negotiate_kerberos_auth_test.cc	2011-04-20 13:45:51 +0000
@@ -196,9 +196,9 @@
         goto cleanup;
 
     if (output_token.length) {
-        token = (char *) xmalloc(ska_base64_encode_len(output_token.length));
-        ska_base64_encode(token, (const char *) output_token.value,
-                          ska_base64_encode_len(output_token.length), output_token.length);
+        token = (char *) xmalloc(base64_encode_len(output_token.length));
+        base64_encode_str(token, (const char *) output_token.value,
+                          base64_encode_len(output_token.length), output_token.length);
     }
 cleanup:
     gss_delete_sec_context(&minor_status, &gss_context, NULL);

=== modified file 'helpers/negotiate_auth/wrapper/Makefile.am'
--- helpers/negotiate_auth/wrapper/Makefile.am	2011-04-15 11:51:15 +0000
+++ helpers/negotiate_auth/wrapper/Makefile.am	2011-04-16 04:35:08 +0000
@@ -4,5 +4,8 @@
 
 libexec_PROGRAMS = negotiate_wrapper_auth
 
-negotiate_wrapper_auth_SOURCES = negotiate_wrapper.cc nw_base64.cc nw_base64.h
-negotiate_wrapper_auth_LDADD =  $(COMPAT_LIB) $(XTRA_LIBS)
+negotiate_wrapper_auth_SOURCES = negotiate_wrapper.cc
+negotiate_wrapper_auth_LDADD = \
+	$(top_builddir)/lib/libmiscencoding.la \
+	$(COMPAT_LIB) \
+	$(XTRA_LIBS)

=== modified file 'helpers/negotiate_auth/wrapper/negotiate_wrapper.cc'
--- helpers/negotiate_auth/wrapper/negotiate_wrapper.cc	2011-04-19 13:20:31 +0000
+++ helpers/negotiate_auth/wrapper/negotiate_wrapper.cc	2011-04-20 06:11:07 +0000
@@ -26,7 +26,7 @@
  */
 
 #include "config.h"
-#include "nw_base64.h"
+#include "base64.h"
 
 #if HAVE_STRING_H
 #include <string.h>
@@ -346,7 +346,7 @@
             fprintf(stdout, "BH Invalid negotiate request\n");
             continue;
         }
-        length = nw_base64_decode_len(buf + 3);
+        length = base64_decode_len(buf + 3);
         if (debug)
             fprintf(stderr, "%s| %s: Decode '%s' (decoded length: %d).\n",
                     LogTime(), PROGRAM, buf + 3, (int) length);
@@ -356,7 +356,7 @@
             return 1;
         }
 
-        nw_base64_decode(token, buf + 3, length);
+        base64_decode(token, buf + 3, length);
 
         if ((static_cast<size_t>(length) >= sizeof(ntlmProtocol) + 1) &&
                 (!memcmp(token, ntlmProtocol, sizeof ntlmProtocol))) {

=== removed file 'helpers/negotiate_auth/wrapper/nw_base64.cc'
--- helpers/negotiate_auth/wrapper/nw_base64.cc	2011-04-16 14:43:18 +0000
+++ helpers/negotiate_auth/wrapper/nw_base64.cc	1970-01-01 00:00:00 +0000
@@ -1,83 +0,0 @@
-/*
- * Markus Moeller has modified the following code from Squid
- */
-#include "config.h"
-#include "nw_base64.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-
-static void nw_base64_init(void);
-
-static int base64_initialized = 0;
-#define BASE64_VALUE_SZ 256
-int base64_value[BASE64_VALUE_SZ];
-const char base64_code[] =
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-
-static void
-nw_base64_init(void)
-{
-    int i;
-
-    for (i = 0; i < BASE64_VALUE_SZ; i++)
-        base64_value[i] = -1;
-
-    for (i = 0; i < 64; i++)
-        base64_value[(int) base64_code[i]] = i;
-    base64_value[(int)'='] = 0;
-
-    base64_initialized = 1;
-}
-
-void
-nw_base64_decode(char *result, const char *data, int result_size)
-{
-    int j;
-    int c;
-    long val;
-    if (!data)
-        return;
-    if (!base64_initialized)
-        nw_base64_init();
-    val = c = 0;
-
-    for (j = 0; *data; data++) {
-        unsigned int k = ((unsigned char) *data) % BASE64_VALUE_SZ;
-        if (base64_value[k] < 0)
-            continue;
-        val <<= 6;
-        val += base64_value[k];
-        if (++c < 4)
-            continue;
-        /* One quantum of four encoding characters/24 bit */
-        if (j >= result_size)
-            break;
-        result[j++] = val >> 16;	/* High 8 bits */
-        if (j >= result_size)
-            break;
-        result[j++] = (val >> 8) & 0xff;	/* Mid 8 bits */
-        if (j >= result_size)
-            break;
-        result[j++] = val & 0xff;	/* Low 8 bits */
-        val = c = 0;
-    }
-    return;
-}
-
-int
-nw_base64_decode_len(const char *data)
-{
-    int i, j;
-
-    j = 0;
-    for (i = strlen(data) - 1; i >= 0; i--) {
-        if (data[i] == '=')
-            j++;
-        if (data[i] != '=')
-            break;
-    }
-    return strlen(data) / 4 * 3 - j;
-}

=== removed file 'helpers/negotiate_auth/wrapper/nw_base64.h'
--- helpers/negotiate_auth/wrapper/nw_base64.h	2011-04-15 11:51:15 +0000
+++ helpers/negotiate_auth/wrapper/nw_base64.h	1970-01-01 00:00:00 +0000
@@ -1,11 +0,0 @@
-#ifndef _NW_BASE64_H
-#define _NW_BASE64_H
-
-/*
- * Markus Moeller has modified the following code from Squid
- */
-
-void nw_base64_decode(char *result, const char *data, int result_size);
-int nw_base64_decode_len(const char *data);
-
-#endif

=== modified file 'helpers/ntlm_auth/fake/ntlm_fake_auth.cc'
--- helpers/ntlm_auth/fake/ntlm_fake_auth.cc	2011-01-25 21:30:11 +0000
+++ helpers/ntlm_auth/fake/ntlm_fake_auth.cc	2011-04-19 02:43:57 +0000
@@ -174,7 +174,7 @@
             *p = '\0';		/* strip \n */
         buflen = strlen(buf);   /* keep this so we only scan the buffer for \0 once per loop */
         if (buflen > 3)
-            packet = (ntlmhdr*)base64_decode(buf + 3);
+            packet = (ntlmhdr*)old_base64_decode(buf + 3);
         if (buflen > 3 && NTLM_packet_debug_enabled) {
             strncpy(helper_command, buf, 2);
             helper_command[2] = '\0';

=== modified file 'helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc'
--- helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc	2011-04-09 02:37:59 +0000
+++ helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc	2011-04-16 13:28:41 +0000
@@ -525,9 +525,9 @@
 
     if (memcmp(buf, "KK ", 3) == 0) {	/* authenticate-request */
         /* figure out what we got */
-        decoded = base64_decode(buf + 3);
+        decoded = old_base64_decode(buf + 3);
         /* Note: we don't need to manage memory at this point, since
-         *  base64_decode returns a pointer to static storage.
+         *  old_base64_decode returns a pointer to static storage.
          */
 
         if (!decoded) {		/* decoding failure, return error */

=== modified file 'include/base64.h'
--- include/base64.h	2010-11-02 00:12:43 +0000
+++ include/base64.h	2011-04-20 13:47:45 +0000
@@ -5,10 +5,53 @@
 extern "C" {
 #endif
 
-    extern char *base64_decode(const char *coded);
-    extern const char *base64_encode(const char *decoded);
+    // Decoding functions
+
+    /// Calculate the decoded length of a given nul-terminated blob.
+    /// NUL pointer and empty strings are accepted, result is zero.
+    /// Any return value <= zero means no decoded result can be produced.
+    extern int base64_decode_len(const char *data);
+
+    /// Decode a base-64 encoded blob into a provided buffer.
+    /// Will not terminate the resulting string.
+    /// In-place decoding overlap is supported if result is equal or earlier that the source pointer.
+    ///
+    /// \return number of bytes filled in result.
+    extern int base64_decode(char *result, const char *p, unsigned int result_size);
+
+    // Old decoder. Now a wrapper for the new.
+    // Output is presented in a static buffer which will only remain valid until next call.
+    // Ensures a nul-terminated result. Will always return non-NULL.
+    extern char *old_base64_decode(const char *coded);
+
+
+    // Encoding functions
+
+    /// Calculate the buffer size required to hold the encoded form of a string of length 'len'.
+    extern int base64_encode_len(int len);
+
+    /// Base-64 encode a string into a given buffer.
+    /// Will not terminate the resulting string.
+    /// \return the number of bytes filled in result.
+    extern int base64_encode(char *result, const char *data, int result_size, int data_size);
+
+    /// Base-64 encode a string into a given buffer.
+    /// Will terminate the resulting string.
+    /// \return the number of bytes filled in result. Including the terminator.
+    extern int base64_encode_str(char *result, const char *data, int result_size, int data_size);
+
+    /// Base-64 encode a binary array.
+    /// Output is presented in a static buffer which will only remain valid until next call.
+    /// Ensures a nul-terminated result. Will always return non-NULL.
     extern const char *base64_encode_bin(const char *data, int len);
 
+    // Old decoder. Now a wrapper for the new.
+    // Output is presented in a static buffer which will only remain valid until next call.
+    // Ensures a nul-terminated result. Will always return non-NULL.
+    // Will terminate the resulting string.
+    extern const char *old_base64_encode(const char *decoded);
+
+
 #ifdef __cplusplus
 }
 #endif

=== modified file 'lib/base64.c'
--- lib/base64.c	2010-11-01 05:44:28 +0000
+++ lib/base64.c	2011-04-28 04:57:44 +0000
@@ -1,5 +1,10 @@
 /*
  * $Id$
+ *
+ * AUTHOR: Unknown
+ * AUTHOR: Markus Moeller
+ *
+ * Encoders adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments.
  */
 
 #include "config.h"
@@ -37,19 +42,49 @@
     base64_initialized = 1;
 }
 
+int
+base64_decode_len(const char *data)
+{
+    int i, j;
+
+    if (!data || !*data)
+        return 0;
+
+    j = 0;
+    for (i = strlen(data) - 1; i >= 0; i--) {
+        if (data[i] == '=')
+            j++;
+        if (data[i] != '=')
+            break;
+    }
+    return strlen(data) / 4 * 3 - j;
+}
+
+// old version. Wrapper for the new.
 char *
-base64_decode(const char *p)
+old_base64_decode(const char *p)
 {
     static char result[BASE64_RESULT_SZ];
-    int j;
-    int c;
-    long val;
+    memset(result, '\0', sizeof(result));
     if (!p)
         return NULL;
+    base64_decode(result, p, sizeof(result));
+    result[BASE64_RESULT_SZ-1] = '\0';
+    return result;
+}
+
+int
+base64_decode(char *result, const char *p, unsigned int result_size)
+{
+    int j = 0;
+    int c;
+    long val;
+    if (!p || !result || result_size == 0)
+        return j;
     if (!base64_initialized)
         base64_init();
     val = c = 0;
-    for (j = 0; *p && j + 4 < BASE64_RESULT_SZ; p++) {
+    for (; *p; p++) {
         unsigned int k = ((unsigned char) *p) % BASE64_VALUE_SZ;
         if (base64_value[k] < 0)
             continue;
@@ -58,39 +93,95 @@
         if (++c < 4)
             continue;
         /* One quantum of four encoding characters/24 bit */
-        result[j++] = (val >> 16) & 0xff;	/* High 8 bits */
-        result[j++] = (val >> 8) & 0xff;	/* Mid 8 bits */
-        result[j++] = val & 0xff;	/* Low 8 bits */
+        if (j+4 <= result_size) {
+            // Speed optimization: plenty of space, avoid some per-byte checks.
+            result[j++] = (val >> 16) & 0xff;	/* High 8 bits */
+            result[j++] = (val >> 8) & 0xff;	/* Mid 8 bits */
+            result[j++] = val & 0xff;		/* Low 8 bits */
+        } else {
+            // part-quantum goes a bit slower with per-byte checks
+            result[j++] = (val >> 16) & 0xff;	/* High 8 bits */
+            if (j == result_size)
+                return j;
+            result[j++] = (val >> 8) & 0xff;	/* Mid 8 bits */
+            if (j == result_size)
+                return j;
+            result[j++] = val & 0xff;		/* Low 8 bits */
+        }
+        if (j == result_size)
+            return j;
         val = c = 0;
     }
-    result[j] = 0;
-    return result;
-}
-
-/* adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments */
+    return j;
+}
+
+int
+base64_encode_len(int len)
+{
+    return ((len + 2) / 3 * 4) + 1;
+}
+
 const char *
-base64_encode(const char *decoded_str)
+old_base64_encode(const char *decoded_str)
 {
     static char result[BASE64_RESULT_SZ];
+    base64_encode_str(result, decoded_str, sizeof(result), strlen(decoded_str));
+    return result;
+}
+
+int
+base64_encode_str(char *result, const char *data, int result_size, int data_size)
+{
+    int used = base64_encode(result, data, result_size, data_size);
+    /* terminate */
+    if (used >= result_size) {
+        result[result_size - 1] = '\0';
+        return result_size;
+    } else {
+        result[used++] = '\0';
+    }
+    return used;
+}
+
+/* adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments */
+int
+base64_encode(char *result, const char *data, int result_size, int data_size)
+{
     int bits = 0;
     int char_count = 0;
     int out_cnt = 0;
-    int c;
 
-    if (!decoded_str)
-        return decoded_str;
+    if (!data || !*data || !result || result_size < 1 || data_size < 1)
+        return 0;
 
     if (!base64_initialized)
         base64_init();
 
-    while ((c = (unsigned char) *decoded_str++) && out_cnt < sizeof(result) - 5) {
+    while (data_size--) {
+        int c = (unsigned char) *data++;
         bits += c;
         char_count++;
         if (char_count == 3) {
-            result[out_cnt++] = base64_code[bits >> 18];
-            result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
-            result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
-            result[out_cnt++] = base64_code[bits & 0x3f];
+            if (out_cnt >= result_size)
+                break;
+            if (out_cnt+4 <= result_size) {
+                result[out_cnt++] = base64_code[bits >> 18];
+                result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
+                result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
+                result[out_cnt++] = base64_code[bits & 0x3f];
+            } else {
+                // part-quantum goes a bit slower with per-byte checks
+                result[out_cnt++] = base64_code[bits >> 18];
+                if (out_cnt >= result_size)
+                    break;
+                result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
+                if (out_cnt >= result_size)
+                    break;
+                result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
+                if (out_cnt >= result_size)
+                    break;
+                result[out_cnt++] = base64_code[bits & 0x3f];
+            }
             bits = 0;
             char_count = 0;
         } else {
@@ -99,18 +190,29 @@
     }
     if (char_count != 0) {
         bits <<= 16 - (8 * char_count);
+        if (out_cnt >= result_size)
+            return result_size;
         result[out_cnt++] = base64_code[bits >> 18];
+        if (out_cnt >= result_size)
+            return result_size;
         result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
         if (char_count == 1) {
+            if (out_cnt >= result_size)
+                return result_size;
             result[out_cnt++] = '=';
+            if (out_cnt >= result_size)
+                return result_size;
             result[out_cnt++] = '=';
         } else {
+            if (out_cnt >= result_size)
+                return result_size;
             result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
+            if (out_cnt >= result_size)
+                return result_size;
             result[out_cnt++] = '=';
         }
     }
-    result[out_cnt] = '\0';	/* terminate */
-    return result;
+    return (out_cnt >= result_size?result_size:out_cnt);
 }
 
 /* adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments */

=== modified file 'src/HttpHeader.cc'
--- src/HttpHeader.cc	2011-03-22 12:23:25 +0000
+++ src/HttpHeader.cc	2011-04-16 13:25:52 +0000
@@ -1414,7 +1414,7 @@
     if (!*field)		/* no authorization cookie */
         return NULL;
 
-    return base64_decode(field);
+    return old_base64_decode(field);
 }
 
 ETag

=== modified file 'src/adaptation/icap/ModXact.cc'
--- src/adaptation/icap/ModXact.cc	2011-04-07 12:42:02 +0000
+++ src/adaptation/icap/ModXact.cc	2011-04-16 15:38:01 +0000
@@ -1425,7 +1425,7 @@
     if (request->auth_user_request != NULL) {
         char const *name = request->auth_user_request->username();
         if (name) {
-            const char *value = TheConfig.client_username_encode ? base64_encode(name) : name;
+            const char *value = TheConfig.client_username_encode ? old_base64_encode(name) : name;
             buf.Printf("%s: %s\r\n", TheConfig.client_username_header, value);
         }
     }

=== modified file 'src/http.cc'
--- src/http.cc	2011-04-06 16:25:36 +0000
+++ src/http.cc	2011-04-16 15:38:59 +0000
@@ -1606,7 +1606,7 @@
         snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
 
         httpHeaderPutStrf(hdr_out, header, "Basic %s",
-                          base64_encode(loginbuf));
+                          old_base64_encode(loginbuf));
         return;
     }
 
@@ -1619,7 +1619,7 @@
                  SQUIDSTRINGPRINT(orig_request->extacl_user),
                  SQUIDSTRINGPRINT(orig_request->extacl_passwd));
         httpHeaderPutStrf(hdr_out, header, "Basic %s",
-                          base64_encode(loginbuf));
+                          old_base64_encode(loginbuf));
         return;
     }
 
@@ -1640,7 +1640,7 @@
 #endif /* HAVE_KRB5 && HAVE_GSSAPI */
 
     httpHeaderPutStrf(hdr_out, header, "Basic %s",
-                      base64_encode(orig_request->peer_login));
+                      old_base64_encode(orig_request->peer_login));
     return;
 }
 
@@ -1771,7 +1771,7 @@
     if (!hdr_out->has(HDR_AUTHORIZATION)) {
         if (!request->flags.proxying && *request->login) {
             httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
-                              base64_encode(request->login));
+                              old_base64_encode(request->login));
         }
     }
 

=== modified file 'tools/cachemgr.cc'
--- tools/cachemgr.cc	2011-04-12 11:33:32 +0000
+++ tools/cachemgr.cc	2011-04-20 13:44:10 +0000
@@ -1053,16 +1053,17 @@
         return;
 
     /* host | time | user | passwd */
-    snprintf(buf, sizeof(buf), "%s|%d|%s|%s",
-             req->hostname,
-             (int) now,
-             req->user_name ? req->user_name : "",
-             req->passwd);
-
+    int blen = snprintf(buf, sizeof(buf), "%s|%d|%s|%s",
+                        req->hostname,
+                        (int) now,
+                        req->user_name ? req->user_name : "",
+                        req->passwd);
     debug("cmgr: pre-encoded for pub: %s\n", buf);
-    debug("cmgr: encoded: '%s'\n", base64_encode(buf));
 
-    req->pub_auth = xstrdup(base64_encode(buf));
+    int elen = base64_encode_len(blen);
+    req->pub_auth = (char *) xmalloc(elen);
+    base64_encode_str(req->pub_auth, buf, elen, blen);
+    debug("cmgr: encoded: '%s'\n", req->pub_auth);
 }
 
 static void
@@ -1080,7 +1081,9 @@
     if (!req->pub_auth || strlen(req->pub_auth) < 4 + strlen(safe_str(req->hostname)))
         return;
 
-    buf = xstrdup(base64_decode(req->pub_auth));
+    int alen = base64_decode_len(req->pub_auth);
+    buf = (char*)xmalloc(alen);
+    base64_decode(buf, req->pub_auth, sizeof(req->pub_auth));
 
     debug("cmgr: length ok\n");
 
@@ -1136,16 +1139,18 @@
 {
     static char buf[1024];
     size_t stringLength = 0;
-    const char *str64;
 
     if (!req->passwd)
         return "";
 
-    snprintf(buf, sizeof(buf), "%s:%s",
-             req->user_name ? req->user_name : "",
-             req->passwd);
+    int blen = snprintf(buf, sizeof(buf), "%s:%s",
+                        req->user_name ? req->user_name : "",
+                        req->passwd);
 
-    str64 = base64_encode(buf);
+    int alen = base64_encode_len(blen);
+    char *str64 = static_cast<char*>(xmalloc(alen));
+    if (base64_encode_str(str64, buf, alen, blen) == 0)
+        return "";
 
     stringLength += snprintf(buf, sizeof(buf), "Authorization: Basic %s\r\n", str64);
 

=== modified file 'tools/squidclient.cc'
--- tools/squidclient.cc	2011-02-17 14:57:33 +0000
+++ tools/squidclient.cc	2011-04-16 15:41:44 +0000
@@ -489,7 +489,7 @@
                 exit(1);
             }
             snprintf(buf, BUFSIZ, "%s:%s", user, password);
-            snprintf(buf, BUFSIZ, "Proxy-Authorization: Basic %s\r\n", base64_encode(buf));
+            snprintf(buf, BUFSIZ, "Proxy-Authorization: Basic %s\r\n", old_base64_encode(buf));
             strcat(msg, buf);
         }
         if (www_user) {
@@ -504,7 +504,7 @@
                 exit(1);
             }
             snprintf(buf, BUFSIZ, "%s:%s", user, password);
-            snprintf(buf, BUFSIZ, "Authorization: Basic %s\r\n", base64_encode(buf));
+            snprintf(buf, BUFSIZ, "Authorization: Basic %s\r\n", old_base64_encode(buf));
             strcat(msg, buf);
         }
 #if HAVE_GSSAPI

Reply via email to