base64: fix Curl_base64_encode and Curl_base64_decode interfaces
authorYang Tse <yangsita@gmail.com>
Wed, 24 Aug 2011 06:07:36 +0000 (08:07 +0200)
committerYang Tse <yangsita@gmail.com>
Wed, 24 Aug 2011 06:10:30 +0000 (08:10 +0200)
Previous interfaces for these libcurl internal functions did not allow to tell
apart a legitimate zero size result from an error condition. These functions
now return a CURLcode indicating function success or otherwise specific error.
Output size is returned using a pointer argument.

All usage of these two functions, and others closely related, has been adapted
to the new interfaces. Relative error and OOM handling adapted or added where
missing. Unit test 1302 also adapted.

18 files changed:
lib/base64.c
lib/curl_base64.h
lib/curl_ntlm.c
lib/http.c
lib/http_digest.c
lib/http_negotiate.c
lib/http_negotiate_sspi.c
lib/http_ntlm.c
lib/krb4.c
lib/krb5.c
lib/ldap.c
lib/openldap.c
lib/security.c
lib/smtp.c
lib/warnless.c
lib/warnless.h
tests/server/getpart.c
tests/unit/unit1302.c

index 812fd67c2754e3aaa4f5d72dbe60f667f520ff57..23ebb4aa90b65380eb9cbc7ab68dde753a35900d 100644 (file)
@@ -68,12 +68,19 @@ static void decodeQuantum(unsigned char *dest, const char *src)
 /*
  * Curl_base64_decode()
  *
- * Given a base64 string at src, decode it and return an allocated memory in
- * the *outptr. Returns the length of the decoded data.
+ * Given a base64 NUL-terminated string at src, decode it and return a
+ * pointer in *outptr to a newly allocated memory area holding decoded
+ * data. Size of decoded data is returned in variable pointed by outlen.
+ *
+ * Returns CURLE_OK on success, otherwise specific error code. Function
+ * output shall not be considered valid unless CURLE_OK is returned.
+ *
+ * When decoded data length is 0, returns NULL in *outptr.
  *
  * @unittest: 1302
  */
-size_t Curl_base64_decode(const char *src, unsigned char **outptr)
+CURLcode Curl_base64_decode(const char *src,
+                            unsigned char **outptr, size_t *outlen)
 {
   size_t length = 0;
   size_t equalsTerm = 0;
@@ -84,6 +91,7 @@ size_t Curl_base64_decode(const char *src, unsigned char **outptr)
   unsigned char *newstr;
 
   *outptr = NULL;
+  *outlen = 0;
 
   while((src[length] != '=') && src[length])
     length++;
@@ -97,7 +105,7 @@ size_t Curl_base64_decode(const char *src, unsigned char **outptr)
 
   /* Don't allocate a buffer if the decoded length is 0 */
   if(numQuantums == 0)
-    return 0;
+    return CURLE_OK;
 
   rawlen = (numQuantums * 3) - equalsTerm;
 
@@ -105,7 +113,7 @@ size_t Curl_base64_decode(const char *src, unsigned char **outptr)
   (which may be partially thrown out) and the zero terminator. */
   newstr = malloc(rawlen+4);
   if(!newstr)
-    return 0;
+    return CURLE_OUT_OF_MEMORY;
 
   *outptr = newstr;
 
@@ -124,23 +132,34 @@ size_t Curl_base64_decode(const char *src, unsigned char **outptr)
     newstr[i] = lastQuantum[i];
 
   newstr[i] = '\0'; /* zero terminate */
-  return rawlen;
+
+  *outlen = rawlen; /* return size of decoded data */
+
+  return CURLE_OK;
 }
 
 /*
  * Curl_base64_encode()
  *
- * Returns the length of the newly created base64 string. The third argument
- * is a pointer to an allocated area holding the base64 data. If something
- * went wrong, 0 is returned.
+ * Given a pointer to an input buffer and an input size, encode it and
+ * return a pointer in *outptr to a newly allocated memory area holding
+ * encoded data. Size of encoded data is returned in variable pointed by
+ * outlen.
+ *
+ * Input length of 0 indicates input buffer holds a NUL-terminated string.
+ *
+ * Returns CURLE_OK on success, otherwise specific error code. Function
+ * output shall not be considered valid unless CURLE_OK is returned.
+ *
+ * When encoded data length is 0, returns NULL in *outptr.
  *
  * @unittest: 1302
  */
-size_t Curl_base64_encode(struct SessionHandle *data,
-                          const char *inputbuff, size_t insize,
-                          char **outptr)
+CURLcode Curl_base64_encode(struct SessionHandle *data,
+                            const char *inputbuff, size_t insize,
+                            char **outptr, size_t *outlen)
 {
-  CURLcode res;
+  CURLcode error;
   unsigned char ibuf[3];
   unsigned char obuf[4];
   int i;
@@ -151,24 +170,25 @@ size_t Curl_base64_encode(struct SessionHandle *data,
 
   const char *indata = inputbuff;
 
-  *outptr = NULL; /* set to NULL in case of failure before we reach the end */
+  *outptr = NULL;
+  *outlen = 0;
 
   if(0 == insize)
     insize = strlen(indata);
 
   base64data = output = malloc(insize*4/3+4);
   if(NULL == output)
-    return 0;
+    return CURLE_OUT_OF_MEMORY;
 
   /*
    * The base64 data needs to be created using the network encoding
    * not the host encoding.  And we can't change the actual input
    * so we copy it to a buffer, translate it, and use that instead.
    */
-  res = Curl_convert_clone(data, indata, insize, &convbuf);
-  if(res) {
+  error = Curl_convert_clone(data, indata, insize, &convbuf);
+  if(error) {
     free(output);
-    return 0;
+    return error;
   }
 
   if(convbuf)
@@ -215,12 +235,14 @@ size_t Curl_base64_encode(struct SessionHandle *data,
     }
     output += 4;
   }
-  *output=0;
-  *outptr = base64data; /* make it return the actual data memory */
+  *output = '\0';
+  *outptr = base64data; /* return pointer to new data, allocated memory */
 
   if(convbuf)
     free(convbuf);
 
-  return strlen(base64data); /* return the length of the new data */
+  *outlen = strlen(base64data); /* return the length of the new data */
+
+  return CURLE_OK;
 }
 /* ---- End of Base64 Encoding ---- */
index 2498a0a2259e5f09dd85a733cc547be967eeec50..6e200d2ec4143b4d44a4fc14ab38bac8cc688c54 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  *
  ***************************************************************************/
 
-size_t Curl_base64_encode(struct SessionHandle *data,
-                          const char *inputbuff, size_t insize,
-                          char **outptr);
+CURLcode Curl_base64_encode(struct SessionHandle *data,
+                            const char *inputbuff, size_t insize,
+                            char **outptr, size_t *outlen);
 
-size_t Curl_base64_decode(const char *src, unsigned char **outptr);
+CURLcode Curl_base64_decode(const char *src,
+                            unsigned char **outptr, size_t *outlen);
 
 #endif /* HEADER_CURL_BASE64_H */
index c0289e5d41c923218a3c9a4f54d9ea04c8740632..b555f5ab653076f5a96d50e8a782eb5aec143cb7 100644 (file)
@@ -305,16 +305,22 @@ CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data,
                                         (*) -> Optional
   */
 
-  size_t size;
-  unsigned char *buffer;
+  size_t size = 0;
+  unsigned char *buffer = NULL;
+  CURLcode error;
 
 #if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI)
   (void)data;
 #endif
 
-  size = Curl_base64_decode(header, &buffer);
-  if(!buffer)
-    return CURLE_OUT_OF_MEMORY;
+  error = Curl_base64_decode(header, &buffer, &size);
+  if(error)
+    return error;
+
+  if(!buffer) {
+    infof(data, "NTLM handshake failure (unhandled condition)\n");
+    return CURLE_REMOTE_ACCESS_DENIED;
+  }
 
 #ifdef USE_WINDOWS_SSPI
   ntlm->type_2 = malloc(size + 1);
index 4952ddd64297755ca6bcd096a0d0ba38a6d3fcbd..edf3e163fdddfe47f5a95a79d372846865a44b36 100644 (file)
@@ -231,11 +231,13 @@ static char *copy_header_value(const char *h)
  */
 static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
 {
-  char *authorization;
-  struct SessionHandle *data=conn->data;
+  size_t size = 0;
+  char *authorization = NULL;
+  struct SessionHandle *data = conn->data;
   char **userp;
   const char *user;
   const char *pwd;
+  CURLcode error;
 
   if(proxy) {
     userp = &conn->allocptr.proxyuserpwd;
@@ -249,20 +251,24 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
   }
 
   snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd);
-  if(Curl_base64_encode(data, data->state.buffer,
-                        strlen(data->state.buffer),
-                        &authorization) > 0) {
-    if(*userp)
-      free(*userp);
-    *userp = aprintf( "%sAuthorization: Basic %s\r\n",
-                      proxy?"Proxy-":"",
-                      authorization);
-    free(authorization);
-    if(!*userp)
-      return CURLE_OUT_OF_MEMORY;
-  }
-  else
+
+  error = Curl_base64_encode(data,
+                             data->state.buffer, strlen(data->state.buffer),
+                             &authorization, &size);
+  if(error)
+    return error;
+
+  if(!authorization)
+    return CURLE_REMOTE_ACCESS_DENIED;
+
+  Curl_safefree(*userp);
+  *userp = aprintf("%sAuthorization: Basic %s\r\n",
+                   proxy?"Proxy-":"",
+                   authorization);
+  free(authorization);
+  if(!*userp)
     return CURLE_OUT_OF_MEMORY;
+
   return CURLE_OK;
 }
 
index 3ca0389e9bc91bc407d21569c6975226532e697c..b41e62306e5e418978e8613f2df946d43a512770 100644 (file)
@@ -280,7 +280,8 @@ CURLcode Curl_output_digest(struct connectdata *conn,
   unsigned char *ha1;
   unsigned char ha2[33];/* 32 digits and 1 zero byte */
   char cnoncebuf[7];
-  char *cnonce;
+  char *cnonce = NULL;
+  size_t cnonce_sz = 0;
   char *tmp = NULL;
   struct timeval now;
 
@@ -343,10 +344,12 @@ CURLcode Curl_output_digest(struct connectdata *conn,
     /* Generate a cnonce */
     now = Curl_tvnow();
     snprintf(cnoncebuf, sizeof(cnoncebuf), "%06ld", (long)now.tv_sec);
-    if(Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), &cnonce))
-      d->cnonce = cnonce;
-    else
-      return CURLE_OUT_OF_MEMORY;
+
+    rc = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf),
+                            &cnonce, &cnonce_sz);
+    if(rc)
+      return rc;
+    d->cnonce = cnonce;
   }
 
   /*
index b3d870c9c6d36f0801fef6286c89961c43646682..f0cf16b9e7c77e25f5969ef643974cb70b6ee69d 100644 (file)
@@ -138,9 +138,11 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy,
   gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
   gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
   int ret;
-  size_t len, rawlen;
+  size_t len;
+  size_t rawlen = 0;
   bool gss;
   const char* protocol;
+  CURLcode error;
 
   while(*header && ISSPACE(*header))
     header++;
@@ -183,9 +185,9 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy,
 
   len = strlen(header);
   if(len > 0) {
-    rawlen = Curl_base64_decode(header,
-                                (unsigned char **)&input_token.value);
-    if(rawlen == 0)
+    error = Curl_base64_decode(header,
+                               (unsigned char **)&input_token.value, &rawlen);
+    if(error || rawlen == 0)
       return -1;
     input_token.length = rawlen;
 
@@ -270,8 +272,9 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
   struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
     &conn->data->state.negotiate;
   char *encoded = NULL;
-  size_t len;
+  size_t len = 0;
   char *userp;
+  CURLcode error;
 
 #ifdef HAVE_SPNEGO /* Handle SPNEGO */
   if(checkprefix("Negotiate", neg_ctx->protocol)) {
@@ -317,13 +320,21 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
     }
   }
 #endif
-  len = Curl_base64_encode(conn->data,
-                           neg_ctx->output_token.value,
-                           neg_ctx->output_token.length,
-                           &encoded);
+  error = Curl_base64_encode(conn->data,
+                             neg_ctx->output_token.value,
+                             neg_ctx->output_token.length,
+                             &encoded, &len);
+  if(error) {
+    Curl_safefree(neg_ctx->output_token.value);
+    neg_ctx->output_token.value = NULL;
+    return error;
+  }
 
-  if(len == 0)
-    return CURLE_OUT_OF_MEMORY;
+  if(len == 0) {
+    Curl_safefree(neg_ctx->output_token.value);
+    neg_ctx->output_token.value = NULL;
+    return CURLE_REMOTE_ACCESS_DENIED;
+  }
 
   userp = aprintf("%sAuthorization: %s %s\r\n", proxy ? "Proxy-" : "",
                   neg_ctx->protocol, encoded);
index 875ed3cfdf9beae08f1ad5bc4cbd6ac979cd9ded..08d01627475b3d63e52550828377eadbb1e8741e 100644 (file)
@@ -82,7 +82,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy,
 {
   struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
     &conn->data->state.negotiate;
-  BYTE                          *input_token = 0;
+  BYTE              *input_token = 0;
   SecBufferDesc     out_buff_desc;
   SecBuffer         out_sec_buff;
   SecBufferDesc     in_buff_desc;
@@ -94,6 +94,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy,
   size_t len = 0, input_token_len = 0;
   bool gss = FALSE;
   const char* protocol;
+  CURLcode error;
 
   while(*header && ISSPACE(*header))
     header++;
@@ -176,9 +177,10 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy,
     if(!input_token)
       return -1;
 
-    input_token_len = Curl_base64_decode(header,
-                                         (unsigned char **)&input_token);
-    if(input_token_len == 0)
+    error = Curl_base64_decode(header,
+                               (unsigned char **)&input_token,
+                               &input_token_len);
+    if(error || input_token_len == 0)
       return -1;
   }
 
@@ -238,16 +240,19 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
   struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
     &conn->data->state.negotiate;
   char *encoded = NULL;
-  size_t len;
+  size_t len = 0;
   char *userp;
+  CURLcode error;
 
-  len = Curl_base64_encode(conn->data,
-                           (const char*)neg_ctx->output_token,
-                           neg_ctx->output_token_length,
-                           &encoded);
+  error = Curl_base64_encode(conn->data,
+                             (const char*)neg_ctx->output_token,
+                             neg_ctx->output_token_length,
+                             &encoded, &len);
+  if(error)
+    return error;
 
   if(len == 0)
-    return CURLE_OUT_OF_MEMORY;
+    return CURLE_REMOTE_ACCESS_DENIED;
 
   userp = aprintf("%sAuthorization: %s %s\r\n", proxy ? "Proxy-" : "",
                   neg_ctx->protocol, encoded);
index 2c60e5275c87c2155a07fef13e09edec0fb7077d..c5ee679a99cdb6fbbbc219a2174ec4010195e1ac 100644 (file)
@@ -455,8 +455,9 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
 {
   size_t size = 0;
   char *base64 = NULL;
+  size_t base64_sz = 0;
   unsigned char ntlmbuf[NTLM_BUFSIZE];
-  CURLcode res;
+  CURLcode error;
 
   /* point to the address of the pointer that holds the string to sent to the
      server, which is for a plain host or for a HTTP proxy */
@@ -516,14 +517,19 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
 
     /* Create a type-1 message */
 
-    res = Curl_ntlm_create_type1_message(userp, passwdp,
-                                         ntlm, ntlmbuf, &size);
+    error = Curl_ntlm_create_type1_message(userp, passwdp,
+                                           ntlm, ntlmbuf, &size);
+    if(error)
+      return error;
 
-    if(CURLE_OK == res) {
-      /* now size is the size of the base64 encoded package size */
-      size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
+    if(size > 0) {
+      /* convert the binary blob into base64 */
+      error = Curl_base64_encode(NULL, (char *)ntlmbuf, size,
+                                 &base64, &base64_sz);
+      if(error)
+        return error;
 
-      if(size > 0) {
+      if(base64_sz > 0) {
         Curl_safefree(*allocuserpwd);
         *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
                                 proxy ? "Proxy-" : "",
@@ -532,35 +538,36 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
         free(base64);
       }
     }
-    else
-      return CURLE_OUT_OF_MEMORY; /* FIX TODO */
 
     break;
 
   case NTLMSTATE_TYPE2:
     /* We already received the type-2 message, create a type-3 message */
 
-    res = Curl_ntlm_create_type3_message(conn->data, userp, passwdp,
-                                         ntlm, ntlmbuf, &size);
+    error = Curl_ntlm_create_type3_message(conn->data, userp, passwdp,
+                                           ntlm, ntlmbuf, &size);
+    if(error)
+      return error;
 
-    if(CURLE_OK == res) {
+    if(size > 0) {
       /* convert the binary blob into base64 */
-      size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
+      error = Curl_base64_encode(NULL, (char *)ntlmbuf, size,
+                                 &base64, &base64_sz);
+      if(error)
+        return error;
 
-      if(size > 0) {
+      if(base64_sz > 0) {
         Curl_safefree(*allocuserpwd);
         *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
                                 proxy ? "Proxy-" : "",
                                 base64);
         DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
         free(base64);
+
+        ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
+        authp->done = TRUE;
       }
     }
-    else
-      return CURLE_OUT_OF_MEMORY; /* FIX TODO */
-
-    ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
-    authp->done = TRUE;
 
     break;
 
index 30b1c664edf90b923c16b83adff0529cb2a9b14b..2c5676a63d1eec19f3b0eb5fff58c1e00e0afb10 100644 (file)
@@ -201,7 +201,7 @@ krb4_auth(void *app_data, struct connectdata *conn)
   int ret;
   char *p;
   unsigned char *ptr;
-  size_t len;
+  size_t len = 0;
   KTEXT_ST adat;
   MSG_DAT msg_data;
   int checksum;
@@ -212,6 +212,7 @@ krb4_auth(void *app_data, struct connectdata *conn)
   int l = sizeof(conn->local_addr);
   struct SessionHandle *data = conn->data;
   CURLcode result;
+  size_t base64_sz = 0;
 
   if(getsockname(conn->sock[FIRSTSOCKET],
                  (struct sockaddr *)LOCAL_ADDR, &l) < 0)
@@ -247,8 +248,10 @@ krb4_auth(void *app_data, struct connectdata *conn)
   }
 #endif
 
-  if(Curl_base64_encode(conn->data, (char *)adat.dat, adat.length, &p) < 1) {
-    Curl_failf(data, "Out of memory base64-encoding");
+  result = Curl_base64_encode(conn->data, (char *)adat.dat, adat.length,
+                              &p, &base64_sz)
+  if(result) {
+    Curl_failf(data, "base64-encoding: %s", curl_easy_strerror(result));
     return AUTH_CONTINUE;
   }
 
@@ -273,10 +276,15 @@ krb4_auth(void *app_data, struct connectdata *conn)
     return AUTH_ERROR;
   }
   p += 5;
-  len = Curl_base64_decode(p, &ptr);
+  result = Curl_base64_decode(p, &ptr, &len);
+  if(result) {
+    Curl_failf(data, "base64-decoding: %s", curl_easy_strerror(result));
+    return AUTH_ERROR;
+  }
   if(len > sizeof(adat.dat)-1) {
     free(ptr);
-    len=0;
+    ptr = NULL;
+    len = 0;
   }
   if(!len || !ptr) {
     Curl_failf(data, "Failed to decode base64 from server");
@@ -330,11 +338,12 @@ CURLcode Curl_krb_kauth(struct connectdata *conn)
   char *name;
   char *p;
   char passwd[100];
-  size_t tmp;
+  size_t tmp = 0;
   ssize_t nread;
   enum protection_level save;
   CURLcode result;
   unsigned char *ptr;
+  size_t base64_sz = 0;
 
   save = krb4_set_command_prot(conn, PROT_PRIVATE);
 
@@ -360,10 +369,15 @@ CURLcode Curl_krb_kauth(struct connectdata *conn)
   }
 
   p += 2;
-  tmp = Curl_base64_decode(p, &ptr);
+  result = Curl_base64_decode(p, &ptr, &tmp);
+  if(result) {
+    Curl_failf(conn->data, "base64-decoding: %s", curl_easy_strerror(result));
+    return result;
+  }
   if(tmp >= sizeof(tkt.dat)) {
     free(ptr);
-    tmp=0;
+    ptr = NULL;
+    tmp = 0;
   }
   if(!tmp || !ptr) {
     Curl_failf(conn->data, "Failed to decode base64 in reply");
@@ -404,11 +418,12 @@ CURLcode Curl_krb_kauth(struct connectdata *conn)
   memset(key, 0, sizeof(key));
   memset(schedule, 0, sizeof(schedule));
   memset(passwd, 0, sizeof(passwd));
-  if(Curl_base64_encode(conn->data, (char *)tktcopy.dat, tktcopy.length, &p)
-     < 1) {
-    failf(conn->data, "Out of memory base64-encoding.");
+  result = Curl_base64_encode(conn->data, (char *)tktcopy.dat, tktcopy.length,
+                              &p, &base64_sz)
+  if(result) {
+    Curl_failf(conn->data, "base64-encoding: %s", curl_easy_strerror(result));
     krb4_set_command_prot(conn, save);
-    return CURLE_OUT_OF_MEMORY;
+    return result;
   }
   memset (tktcopy.dat, 0, tktcopy.length);
 
index 0422cda35e2f7dea7829c628accdf1e73255e16a..c5f635c1e7176072dea0afb0fd5d5d3360af0278 100644 (file)
@@ -172,6 +172,7 @@ krb5_auth(void *app_data, struct connectdata *conn)
   gss_name_t gssname;
   gss_ctx_id_t *context = app_data;
   struct gss_channel_bindings_struct chan;
+  size_t base64_sz = 0;
 
   if(getsockname(conn->sock[FIRSTSOCKET],
                  (struct sockaddr *)LOCAL_ADDR, &l) < 0)
@@ -251,9 +252,10 @@ krb5_auth(void *app_data, struct connectdata *conn)
       }
 
       if(output_buffer.length != 0) {
-        if(Curl_base64_encode(data, (char *)output_buffer.value,
-                              output_buffer.length, &p) < 1) {
-          Curl_infof(data, "Out of memory base64-encoding\n");
+        result = Curl_base64_encode(data, (char *)output_buffer.value,
+                                    output_buffer.length, &p, &base64_sz)
+        if(result) {
+          Curl_infof(data,"base64-encoding: %s\n", curl_easy_strerror(result));
           ret = AUTH_CONTINUE;
           break;
         }
@@ -281,10 +283,11 @@ krb5_auth(void *app_data, struct connectdata *conn)
         p = data->state.buffer + 4;
         p = strstr(p, "ADAT=");
         if(p) {
-          _gssresp.length = Curl_base64_decode(p + 5, (unsigned char **)
-                                               &_gssresp.value);
-          if(_gssresp.length < 1) {
-            Curl_failf(data, "Out of memory base64-encoding\n");
+          result = Curl_base64_decode(p + 5,
+                                      (unsigned char **)&_gssresp.value,
+                                      &_gssresp.length);
+          if(result) {
+            Curl_failf(data,"base64-decoding: %s", curl_easy_strerror(result));
             ret = AUTH_CONTINUE;
             break;
           }
index 9692ed9d72a4f6b69d8103fd721e0232997b7704..0fcbc22e05079afba5abc9f0ddcf6b30280664f9 100644 (file)
@@ -176,9 +176,9 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
   struct SessionHandle *data=conn->data;
   int ldap_proto = LDAP_VERSION3;
   int ldap_ssl = 0;
-  char *val_b64;
-  size_t val_b64_sz;
-  curl_off_t dlsize=0;
+  char *val_b64 = NULL;
+  size_t val_b64_sz = 0;
+  curl_off_t dlsize = 0;
 #ifdef LDAP_OPT_NETWORK_TIMEOUT
   struct timeval ldap_timeout = {10,0}; /* 10 sec connection/search timeout */
 #endif
@@ -405,10 +405,20 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
                       (char *)attribute +
                       (strlen((char *)attribute) - 7)) == 0)) {
             /* Binary attribute, encode to base64. */
-            val_b64_sz = Curl_base64_encode(data,
-                                            vals[i]->bv_val,
-                                            vals[i]->bv_len,
-                                            &val_b64);
+            CURLcode error = Curl_base64_encode(data,
+                                                vals[i]->bv_val,
+                                                vals[i]->bv_len,
+                                                &val_b64,
+                                                &val_b64_sz);
+            if(error) {
+              ldap_value_free_len(vals);
+              ldap_memfree(attribute);
+              ldap_memfree(dn);
+              if(ber)
+                ber_free(ber, 0);
+              status = error;
+              goto quit;
+            }
             if(val_b64_sz > 0) {
               Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz);
               free(val_b64);
index 69523cb3719c71b594b16d5401cd5655daedb081..0708925248869c7061835a35990e2adb147a62f3 100644 (file)
@@ -544,12 +544,21 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
           }
         }
         if(binary || binval) {
-          char *val_b64;
+          char *val_b64 = NULL;
+          size_t val_b64_sz = 0;
           /* Binary value, encode to base64. */
-          size_t val_b64_sz = Curl_base64_encode(data,
-                                            bvals[i].bv_val,
-                                            bvals[i].bv_len,
-                                            &val_b64);
+          CURLcode error = Curl_base64_encode(data,
+                                              bvals[i].bv_val,
+                                              bvals[i].bv_len,
+                                              &val_b64,
+                                              &val_b64_sz);
+          if(error) {
+            ber_memfree(bvals);
+            ber_free(ber, 0);
+            ldap_msgfree(result);
+            *err = error;
+            return -1;
+          }
           Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
           data->req.bytecount += 2;
           if(val_b64_sz > 0) {
index af61f3aed9d771b97a4ab099391a9cc5ea8ac9e9..595a7337e41c4cffacd92d78d8efd0fa37bf2f34 100644 (file)
@@ -61,6 +61,7 @@
 #include "ftp.h"
 #include "sendf.h"
 #include "rawstr.h"
+#include "warnless.h"
 
 /* The last #include file should be: */
 #include "memdebug.h"
@@ -280,12 +281,13 @@ static ssize_t sec_recv(struct connectdata *conn, int sockindex,
 static void do_sec_send(struct connectdata *conn, curl_socket_t fd,
                         const char *from, int length)
 {
-  size_t bytes;
-  size_t htonl_bytes;
-  char *buffer;
+  int bytes, htonl_bytes; /* 32-bit integers for htonl */
+  char *buffer = NULL;
   char *cmd_buffer;
+  size_t cmd_size = 0;
+  CURLcode error;
   enum protection_level prot_level = conn->data_prot;
-  bool iscmd = prot_level == PROT_CMD;
+  bool iscmd = (prot_level == PROT_CMD)?TRUE:FALSE
 
   DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST);
 
@@ -297,9 +299,17 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd,
   }
   bytes = conn->mech->encode(conn->app_data, from, length, prot_level,
                              (void**)&buffer, conn);
+  if(!buffer || bytes <= 0)
+    return; /* error */
+
   if(iscmd) {
-    bytes = Curl_base64_encode(conn->data, buffer, bytes, &cmd_buffer);
-    if(bytes > 0) {
+    error = Curl_base64_encode(conn->data, buffer, curlx_sitouz(bytes),
+                               &cmd_buffer, &cmd_size);
+    if(error) {
+      free(buffer);
+      return; /* error */
+    }
+    if(cmd_size > 0) {
       static const char *enc = "ENC ";
       static const char *mic = "MIC ";
       if(prot_level == PROT_PRIVATE)
@@ -307,7 +317,7 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd,
       else
         socket_write(conn, fd, mic, 4);
 
-      socket_write(conn, fd, cmd_buffer, bytes);
+      socket_write(conn, fd, cmd_buffer, cmd_size);
       socket_write(conn, fd, "\r\n", 2);
       infof(conn->data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic,
             cmd_buffer);
@@ -317,7 +327,7 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd,
   else {
     htonl_bytes = htonl(bytes);
     socket_write(conn, fd, &htonl_bytes, sizeof(htonl_bytes));
-    socket_write(conn, fd, buffer, bytes);
+    socket_write(conn, fd, buffer, curlx_sitouz(bytes));
   }
   free(buffer);
 }
@@ -362,14 +372,20 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer,
   int decoded_len;
   char *buf;
   int ret_code;
+  size_t decoded_sz = 0;
+  CURLcode error;
 
   DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
 
-  decoded_len = Curl_base64_decode(buffer + 4, (unsigned char **)&buf);
-  if(decoded_len <= 0) {
+  error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz);
+  if(error || decoded_sz == 0)
+    return -1;
+
+  if(decoded_sz > (size_t)INT_MAX) {
     free(buf);
     return -1;
   }
+  decoded_len = curlx_uztosi(decoded_sz);
 
   decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len,
                                    level, conn);
index 5fa98934655e8784f4ccfdd6eed55d03b686f197..9550c0fccfaff0a6245b346e671fa555f7ce9aee 100644 (file)
@@ -341,7 +341,8 @@ static CURLcode smtp_state_helo(struct connectdata *conn)
   return CURLE_OK;
 }
 
-static size_t smtp_auth_plain_data(struct connectdata * conn, char * * outptr)
+static CURLcode smtp_auth_plain_data(struct connectdata *conn,
+                                     char **outptr, size_t *outlen)
 {
   char plainauth[2 * MAX_CURL_USER_LENGTH + MAX_CURL_PASSWORD_LENGTH];
   size_t ulen;
@@ -350,8 +351,11 @@ static size_t smtp_auth_plain_data(struct connectdata * conn, char * * outptr)
   ulen = strlen(conn->user);
   plen = strlen(conn->passwd);
 
-  if(2 * ulen + plen + 2 > sizeof plainauth)
-    return 0;
+  if(2 * ulen + plen + 2 > sizeof plainauth) {
+    *outlen = 0;
+    *outptr = NULL;
+    return CURLE_OUT_OF_MEMORY; /* plainauth too small */
+  }
 
   memcpy(plainauth, conn->user, ulen);
   plainauth[ulen] = '\0';
@@ -359,21 +363,25 @@ static size_t smtp_auth_plain_data(struct connectdata * conn, char * * outptr)
   plainauth[2 * ulen + 1] = '\0';
   memcpy(plainauth + 2 * ulen + 2, conn->passwd, plen);
   return Curl_base64_encode(conn->data, plainauth, 2 * ulen + plen + 2,
-                            outptr);
+                            outptr, outlen);
 }
 
-static size_t smtp_auth_login_user(struct connectdata * conn, char * * outptr)
+static CURLcode smtp_auth_login_user(struct connectdata *conn,
+                                     char **outptr, size_t *outlen)
 {
-  size_t ulen;
-
-  ulen = strlen(conn->user);
+  size_t ulen = strlen(conn->user);
 
   if(!ulen) {
     *outptr = strdup("=");
-    return *outptr? 1: 0;
+    if(*outptr) {
+      *outlen = (size_t) 1;
+      return CURLE_OK;
+    }
+    *outlen = 0;
+    return CURLE_OUT_OF_MEMORY;
   }
 
-  return Curl_base64_encode(conn->data, conn->user, ulen, outptr);
+  return Curl_base64_encode(conn->data, conn->user, ulen, outptr, outlen);
 }
 
 static CURLcode smtp_authenticate(struct connectdata *conn)
@@ -409,13 +417,13 @@ static CURLcode smtp_authenticate(struct connectdata *conn)
       mech = "PLAIN";
       state1 = SMTP_AUTHPLAIN;
       state2 = SMTP_AUTH;
-      l = smtp_auth_plain_data(conn, &initresp);
+      result = smtp_auth_plain_data(conn, &initresp, &l);
     }
     else if(smtpc->authmechs & SMTP_AUTH_LOGIN) {
       mech = "LOGIN";
       state1 = SMTP_AUTHLOGIN;
       state2 = SMTP_AUTHPASSWD;
-      l = smtp_auth_login_user(conn, &initresp);
+      result = smtp_auth_login_user(conn, &initresp, &l);
     }
     else {
       infof(conn->data, "No known auth mechanisms supported!\n");
@@ -423,24 +431,20 @@ static CURLcode smtp_authenticate(struct connectdata *conn)
     }
 
     if(!result) {
-      if(!l)
-        result = CURLE_OUT_OF_MEMORY;
-      else if(initresp &&
-              l + strlen(mech) <= 512 - 8) {   /* AUTH <mech> ...<crlf> */
+      if(initresp &&
+         l + strlen(mech) <= 512 - 8) { /* AUTH <mech> ...<crlf> */
         result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
-        free(initresp);
 
         if(!result)
           state(conn, state2);
       }
       else {
-        Curl_safefree(initresp);
-
         result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
 
         if(!result)
           state(conn, state1);
       }
+      Curl_safefree(initresp);
     }
   }
 
@@ -571,8 +575,8 @@ static CURLcode smtp_state_authplain_resp(struct connectdata *conn,
 {
   CURLcode result = CURLE_OK;
   struct SessionHandle *data = conn->data;
-  size_t l;
-  char * plainauth;
+  size_t l = 0;
+  char * plainauth = NULL;
 
   (void)instate; /* no use for this yet */
 
@@ -581,16 +585,16 @@ static CURLcode smtp_state_authplain_resp(struct connectdata *conn,
     result = CURLE_LOGIN_DENIED;
   }
   else {
-    l = smtp_auth_plain_data(conn, &plainauth);
+    result = smtp_auth_plain_data(conn, &plainauth, &l);
 
-    if(!l)
-      result = CURLE_OUT_OF_MEMORY;
-    else {
-      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth);
-      free(plainauth);
+    if(!result) {
+      if(plainauth) {
+        result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth);
 
-      if(!result)
-        state(conn, SMTP_AUTH);
+        if(!result)
+          state(conn, SMTP_AUTH);
+      }
+      Curl_safefree(plainauth);
     }
   }
 
@@ -604,8 +608,8 @@ static CURLcode smtp_state_authlogin_resp(struct connectdata *conn,
 {
   CURLcode result = CURLE_OK;
   struct SessionHandle *data = conn->data;
-  size_t l;
-  char * authuser;
+  size_t l = 0;
+  char * authuser = NULL;
 
   (void)instate; /* no use for this yet */
 
@@ -614,16 +618,16 @@ static CURLcode smtp_state_authlogin_resp(struct connectdata *conn,
     result = CURLE_LOGIN_DENIED;
   }
   else {
-    l = smtp_auth_login_user(conn, &authuser);
+    result = smtp_auth_login_user(conn, &authuser, &l);
 
-    if(!l)
-      result = CURLE_OUT_OF_MEMORY;
-    else {
-      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser);
-      free(authuser);
+    if(!result) {
+      if(authuser) {
+        result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser);
 
-      if(!result)
-        state(conn, SMTP_AUTHPASSWD);
+        if(!result)
+          state(conn, SMTP_AUTHPASSWD);
+      }
+      Curl_safefree(authuser);
     }
   }
 
@@ -638,8 +642,8 @@ static CURLcode smtp_state_authpasswd_resp(struct connectdata *conn,
   CURLcode result = CURLE_OK;
   struct SessionHandle *data = conn->data;
   size_t plen;
-  size_t l;
-  char *authpasswd;
+  size_t l = 0;
+  char *authpasswd = NULL;
 
   (void)instate; /* no use for this yet */
 
@@ -653,16 +657,16 @@ static CURLcode smtp_state_authpasswd_resp(struct connectdata *conn,
     if(!plen)
       result = Curl_pp_sendf(&conn->proto.smtpc.pp, "=");
     else {
-      l = Curl_base64_encode(data, conn->passwd, plen, &authpasswd);
+      result = Curl_base64_encode(data, conn->passwd, plen, &authpasswd, &l);
 
-      if(!l)
-        result = CURLE_OUT_OF_MEMORY;
-      else {
-        result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd);
-        free(authpasswd);
+      if(!result) {
+        if(authpasswd) {
+          result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd);
 
-        if(!result)
-          state(conn, SMTP_AUTH);
+          if(!result)
+            state(conn, SMTP_AUTH);
+        }
+        Curl_safefree(authpasswd);
       }
     }
   }
@@ -682,8 +686,8 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn,
   char * chlg64 = data->state.buffer;
   unsigned char * chlg;
   size_t chlglen;
-  size_t l;
-  char * rplyb64;
+  size_t l = 0;
+  char * rplyb64 = NULL;
   HMAC_context * ctxt;
   unsigned char digest[16];
   char reply[MAX_CURL_USER_LENGTH + 32 /* 2 * size of MD5 digest */ + 1];
@@ -711,9 +715,9 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn,
     if(++l) {
       chlg64[l] = '\0';
 
-      chlglen = Curl_base64_decode(chlg64, &chlg);
-      if(!chlglen)
-        return CURLE_OUT_OF_MEMORY;
+      result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+      if(result)
+        return result;
     }
   }
 
@@ -723,17 +727,14 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn,
                         (unsigned int)(strlen(conn->passwd)));
 
   if(!ctxt) {
-    if(chlg)
-      free(chlg);
-
+    Curl_safefree(chlg);
     return CURLE_OUT_OF_MEMORY;
   }
 
   if(chlglen > 0)
     Curl_HMAC_update(ctxt, chlg, (unsigned int)(chlglen));
 
-  if(chlg)
-    free(chlg);
+  Curl_safefree(chlg);
 
   Curl_HMAC_final(ctxt, digest);
 
@@ -746,16 +747,16 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn,
            digest[12], digest[13], digest[14], digest[15]);
 
   /* Encode it to base64 and send it. */
-  l = Curl_base64_encode(data, reply, 0, &rplyb64);
+  result = Curl_base64_encode(data, reply, 0, &rplyb64, &l);
 
-  if(!l)
-    result = CURLE_OUT_OF_MEMORY;
-  else {
-    result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
-    free(rplyb64);
+  if(!result) {
+    if(rplyb64) {
+      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
 
-    if(!result)
-      state(conn, SMTP_AUTH);
+      if(!result)
+        state(conn, SMTP_AUTH);
+    }
+    Curl_safefree(rplyb64);
   }
 
   return result;
index 37d15ce87d547b87638488fc9bc3a59b669b5bb1..0f5fb5f4d17e36f077971e6aa1163a3295467070 100644 (file)
@@ -268,6 +268,25 @@ size_t curlx_sotouz(curl_off_t sonum)
 #endif
 }
 
+/*
+** signed int to unsigned size_t
+*/
+
+size_t curlx_sitouz(int sinum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  DEBUGASSERT(sinum >= 0);
+  return (size_t) sinum;
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
 #if defined(__INTEL_COMPILER) && defined(__unix__)
 
 int curlx_FD_ISSET(int fd, fd_set *fdset)
index 9ac59ac29bb139e7920678f345ec4a802e748501..27cf57c31abb64b1a2aaed26ef1b145cdf2b548a 100644 (file)
@@ -38,6 +38,8 @@ ssize_t curlx_uztosz(size_t uznum);
 
 size_t curlx_sotouz(curl_off_t sonum);
 
+size_t curlx_sitouz(int sinum);
+
 #if defined(__INTEL_COMPILER) && defined(__unix__)
 
 int curlx_FD_ISSET(int fd, fd_set *fdset);
index 743cb21b94095b9e3f203efd109510a5e7a48104..2351e1cc3a1409dbfdc24bf940c7dea8bd80e9bd 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -166,7 +166,9 @@ static int appenddata(char  **dst_buf,   /* dest buffer */
 
   if(src_b64) {
     /* base64 decode the given buffer */
-    src_len = Curl_base64_decode(src_buf, &buf64.as_uchar);
+    int error = (int) Curl_base64_decode(src_buf, &buf64.as_uchar, &src_len);
+    if(error)
+      return GPE_OUT_OF_MEMORY;
     src_buf = buf64.as_char;
     if(!src_len || !src_buf) {
       /*
index 7a61ec0621c51a573951769a2d84d371ca0af5f8..fc50c88656e97d211d71e19d308573dad5be5a97 100644 (file)
@@ -45,63 +45,80 @@ UNITTEST_START
 
 char *output;
 unsigned char *decoded;
-size_t rc;
+size_t size = 0;
+unsigned char anychar = 'x';
+CURLcode rc;
 
-rc = Curl_base64_encode(data, "i", 1, &output);
-fail_unless( rc == 4 , "return code should be 4" );
+rc = Curl_base64_encode(data, "i", 1, &output, &size);
+fail_unless(rc == CURLE_OK, "return code should be CURLE_OK");
+fail_unless(size == 4, "size should be 4");
 verify_memory( output, "aQ==", 4);
 Curl_safefree(output);
 
-rc = Curl_base64_encode(data, "ii", 2, &output);
-fail_unless( rc == 4 , "return code should be 4" );
+rc = Curl_base64_encode(data, "ii", 2, &output, &size);
+fail_unless(rc == CURLE_OK, "return code should be CURLE_OK");
+fail_unless(size == 4, "size should be 4");
 verify_memory( output, "aWk=", 4);
 Curl_safefree(output);
 
-rc = Curl_base64_encode(data, "iii", 3, &output);
-fail_unless( rc == 4 , "return code should be 4" );
+rc = Curl_base64_encode(data, "iii", 3, &output, &size);
+fail_unless(rc == CURLE_OK, "return code should be CURLE_OK");
+fail_unless(size == 4, "size should be 4");
 verify_memory( output, "aWlp", 4);
 Curl_safefree(output);
 
-rc = Curl_base64_encode(data, "iiii", 4, &output);
-fail_unless( rc == 8 , "return code should be 8" );
+rc = Curl_base64_encode(data, "iiii", 4, &output, &size);
+fail_unless(rc == CURLE_OK, "return code should be CURLE_OK");
+fail_unless(size == 8, "size should be 8");
 verify_memory( output, "aWlpaQ==", 8);
 Curl_safefree(output);
 
 /* 0 length makes it do strlen() */
-rc = Curl_base64_encode(data, "iiii", 0, &output);
-fail_unless( rc == 8 , "return code should be 8" );
+rc = Curl_base64_encode(data, "iiii", 0, &output, &size);
+fail_unless(rc == CURLE_OK, "return code should be CURLE_OK");
+fail_unless(size == 8, "size should be 8");
 verify_memory( output, "aWlpaQ==", 8);
 Curl_safefree(output);
 
-rc = Curl_base64_decode("aWlpaQ==", &decoded);
-fail_unless(rc == 4, "return code should be 4");
+rc = Curl_base64_decode("aWlpaQ==", &decoded, &size);
+fail_unless(rc == CURLE_OK, "return code should be CURLE_OK");
+fail_unless(size == 4, "size should be 4");
 verify_memory(decoded, "iiii", 4);
 Curl_safefree(decoded);
 
-rc = Curl_base64_decode("aWlp", &decoded);
-fail_unless(rc == 3, "return code should be 3");
+rc = Curl_base64_decode("aWlp", &decoded, &size);
+fail_unless(rc == CURLE_OK, "return code should be CURLE_OK");
+fail_unless(size == 3, "size should be 3");
 verify_memory(decoded, "iii", 3);
 Curl_safefree(decoded);
 
-rc = Curl_base64_decode("aWk=", &decoded);
-fail_unless(rc == 2, "return code should be 2");
+rc = Curl_base64_decode("aWk=", &decoded, &size);
+fail_unless(rc == CURLE_OK, "return code should be CURLE_OK");
+fail_unless(size == 2, "size should be 2");
 verify_memory(decoded, "ii", 2);
 Curl_safefree(decoded);
 
-rc = Curl_base64_decode("aQ==", &decoded);
-fail_unless(rc == 1, "return code should be 1");
+rc = Curl_base64_decode("aQ==", &decoded, &size);
+fail_unless(rc == CURLE_OK, "return code should be CURLE_OK");
+fail_unless(size == 1, "size should be 1");
 verify_memory(decoded, "i", 2);
 Curl_safefree(decoded);
 
 /* this is an illegal input */
-decoded = NULL;
-rc = Curl_base64_decode("aQ", &decoded);
-fail_unless(rc == 0, "return code should be 0");
+size = 1; /* not zero */
+decoded = &anychar; /* not NULL */
+rc = Curl_base64_decode("aQ", &decoded, &size);
+/* return code indiferent, but output shall be as follows */
+fail_unless(size == 0, "size should be 0");
 fail_if(decoded, "returned pointer should be NULL");
 
 /* this is garbage input that libcurl decodes as far as possible */
-rc = Curl_base64_decode("a\x1f==", &decoded);
-fail_unless(rc == 1, "return code should be 1");
+size = 0;
+decoded = NULL;
+rc = Curl_base64_decode("a\x1f==", &decoded, &size);
+fail_unless(rc == CURLE_OK, "return code should be CURLE_OK");
+fail_unless(size == 1, "size should be 1");
+fail_if(!decoded, "returned pointer should not be NULL");
 Curl_safefree(decoded);
 
 UNITTEST_STOP