multi_split: check for NULL when allocating parts and bpart, and for failure of sk_BI...
[oweals/openssl.git] / crypto / asn1 / asn_mime.c
index 6d8a9bf90f1d3d0ae502c8356d5ac25d7e8c89cc..171c83dbfcc1cbb3b32232d80cd49b1db2800a0c 100644 (file)
@@ -102,7 +102,7 @@ static int mime_param_cmp(const MIME_PARAM * const *a,
 static void mime_param_free(MIME_PARAM *param);
 static int mime_bound_check(char *line, int linelen, char *bound, int blen);
 static int multi_split(BIO *bio, char *bound, STACK_OF(BIO) **ret);
-static int strip_eol(char *linebuf, int *plen);
+static int strip_eol(char *linebuf, int *plen, int flags);
 static MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, char *name);
 static MIME_PARAM *mime_param_find(MIME_HEADER *hdr, char *name);
 static void mime_hdr_free(MIME_HEADER *hdr);
@@ -554,14 +554,30 @@ int SMIME_crlf_copy(BIO *in, BIO *out, int flags)
                }
        else
                {
+               int eolcnt = 0;
                if(flags & SMIME_TEXT)
                        BIO_printf(out, "Content-Type: text/plain\r\n\r\n");
                while ((len = BIO_gets(in, linebuf, MAX_SMLEN)) > 0)
                        {
-                       eol = strip_eol(linebuf, &len);
+                       eol = strip_eol(linebuf, &len, flags);
                        if (len)
+                               {
+                               /* Not EOF: write out all CRLF */
+                               if (flags & SMIME_ASCIICRLF)
+                                       {
+                                       int i;
+                                       for(i = 0; i < eolcnt; i++)
+                                               BIO_write(out, "\r\n", 2);
+                                       eolcnt = 0;
+                                       }
                                BIO_write(out, linebuf, len);
-                       if(eol) BIO_write(out, "\r\n", 2);
+                               if(eol)
+                                       BIO_write(out, "\r\n", 2);
+                               }
+                       else if (flags & SMIME_ASCIICRLF)
+                               eolcnt++;       
+                       else if(eol)
+                               BIO_write(out, "\r\n", 2);
                        }
                }
        (void)BIO_flush(out);
@@ -620,21 +636,34 @@ static int multi_split(BIO *bio, char *bound, STACK_OF(BIO) **ret)
        first = 1;
        parts = sk_BIO_new_null();
        *ret = parts;
+       if (*ret == NULL)
+               return 0;
        while ((len = BIO_gets(bio, linebuf, MAX_SMLEN)) > 0) {
                state = mime_bound_check(linebuf, len, bound, blen);
                if(state == 1) {
                        first = 1;
                        part++;
                } else if(state == 2) {
-                       sk_BIO_push(parts, bpart);
+                       if (!sk_BIO_push(parts, bpart))
+                               {
+                               BIO_free(bpart);
+                               return 0;
+                               }
                        return 1;
                } else if(part) {
                        /* Strip CR+LF from linebuf */
-                       next_eol = strip_eol(linebuf, &len);
+                       next_eol = strip_eol(linebuf, &len, 0);
                        if(first) {
                                first = 0;
-                               if(bpart) sk_BIO_push(parts, bpart);
+                               if(bpart)
+                                       if (!sk_BIO_push(parts, bpart))
+                                               {
+                                               BIO_free(bpart);
+                                               return 0;
+                                               }
                                bpart = BIO_new(BIO_s_mem());
+                               if (bpart == NULL)
+                                       return 0;
                                BIO_set_mem_eof_return(bpart, 0);
                        } else if (eol)
                                BIO_write(bpart, "\r\n", 2);
@@ -643,6 +672,8 @@ static int multi_split(BIO *bio, char *bound, STACK_OF(BIO) **ret)
                                BIO_write(bpart, linebuf, len);
                }
        }
+       if (bpart != NULL)
+               BIO_free(bpart);
        return 0;
 }
 
@@ -667,6 +698,8 @@ static STACK_OF(MIME_HEADER) *mime_parse_hdr(BIO *bio)
        int len, state, save_state = 0;
 
        headers = sk_MIME_HEADER_new(mime_hdr_cmp);
+       if (!headers)
+               return NULL;
        while ((len = BIO_gets(bio, linebuf, MAX_SMLEN)) > 0) {
        /* If whitespace at line start then continuation line */
        if(mhdr && isspace((unsigned char)linebuf[0])) state = MIME_NAME;
@@ -799,8 +832,8 @@ static char *strip_end(char *name)
 
 static MIME_HEADER *mime_hdr_new(char *name, char *value)
 {
-       MIME_HEADER *mhdr;
-       char *tmpname, *tmpval, *p;
+       MIME_HEADER *mhdr = NULL;
+       char *tmpname = NULL, *tmpval = NULL, *p;
        int c;
        if(name) {
                if(!(tmpname = BUF_strdup(name))) return NULL;
@@ -811,9 +844,10 @@ static MIME_HEADER *mime_hdr_new(char *name, char *value)
                                *p = c;
                        }
                }
-       } else tmpname = NULL;
+       }
        if(value) {
-               if(!(tmpval = BUF_strdup(value))) return NULL;
+               if(!(tmpval = BUF_strdup(value)))
+                       goto err;
                for(p = tmpval ; *p; p++) {
                        c = (unsigned char)*p;
                        if(isupper(c)) {
@@ -821,23 +855,33 @@ static MIME_HEADER *mime_hdr_new(char *name, char *value)
                                *p = c;
                        }
                }
-       } else tmpval = NULL;
+       }
        mhdr = (MIME_HEADER *) OPENSSL_malloc(sizeof(MIME_HEADER));
-       if(!mhdr) return NULL;
+       if(!mhdr) goto err;
        mhdr->name = tmpname;
        mhdr->value = tmpval;
-       if(!(mhdr->params = sk_MIME_PARAM_new(mime_param_cmp))) return NULL;
+       if(!(mhdr->params = sk_MIME_PARAM_new(mime_param_cmp)))
+               goto err;
        return mhdr;
+
+       err:
+       if (tmpname != NULL)
+               OPENSSL_free(tmpname);
+       if (tmpval != NULL)
+               OPENSSL_free(tmpval);
+       if (mhdr != NULL)
+               OPENSSL_free(mhdr);
+       return NULL;
 }
                
 static int mime_hdr_addparam(MIME_HEADER *mhdr, char *name, char *value)
 {
-       char *tmpname, *tmpval, *p;
+       char *tmpname=NULL, *tmpval=NULL, *p;
        int c;
-       MIME_PARAM *mparam;
+       MIME_PARAM *mparam=NULL;
        if(name) {
                tmpname = BUF_strdup(name);
-               if(!tmpname) return 0;
+               if(!tmpname) goto err;
                for(p = tmpname ; *p; p++) {
                        c = (unsigned char)*p;
                        if(isupper(c)) {
@@ -845,26 +889,34 @@ static int mime_hdr_addparam(MIME_HEADER *mhdr, char *name, char *value)
                                *p = c;
                        }
                }
-       } else tmpname = NULL;
+       }
        if(value) {
                tmpval = BUF_strdup(value);
-               if(!tmpval) return 0;
-       } else tmpval = NULL;
+               if(!tmpval) goto err;
+       }
        /* Parameter values are case sensitive so leave as is */
        mparam = (MIME_PARAM *) OPENSSL_malloc(sizeof(MIME_PARAM));
-       if(!mparam) return 0;
+       if(!mparam) goto err;
        mparam->param_name = tmpname;
        mparam->param_value = tmpval;
-       sk_MIME_PARAM_push(mhdr->params, mparam);
+       if (!sk_MIME_PARAM_push(mhdr->params, mparam))
+               goto err;
        return 1;
+err:
+       if (tmpname != NULL)
+               OPENSSL_free(tmpname);
+       if (tmpval != NULL)
+               OPENSSL_free(tmpval);
+       if (mparam != NULL)
+               OPENSSL_free(mparam);
+       return 0;
 }
 
 static int mime_hdr_cmp(const MIME_HEADER * const *a,
                        const MIME_HEADER * const *b)
 {
-       if ((*a)->name == NULL || (*b)->name == NULL)
-               return (*a)->name - (*b)->name < 0 ? -1 :
-                       (*a)->name - (*b)->name > 0 ? 1 : 0;
+       if (!(*a)->name || !(*b)->name)
+               return !!(*a)->name - !!(*b)->name;
 
        return(strcmp((*a)->name, (*b)->name));
 }
@@ -872,6 +924,8 @@ static int mime_hdr_cmp(const MIME_HEADER * const *a,
 static int mime_param_cmp(const MIME_PARAM * const *a,
                        const MIME_PARAM * const *b)
 {
+       if (!(*a)->param_name || !(*b)->param_name)
+               return !!(*a)->param_name - !!(*b)->param_name;
        return(strcmp((*a)->param_name, (*b)->param_name));
 }
 
@@ -931,7 +985,7 @@ static int mime_bound_check(char *line, int linelen, char *bound, int blen)
        return 0;
 }
 
-static int strip_eol(char *linebuf, int *plen)
+static int strip_eol(char *linebuf, int *plen, int flags)
        {
        int len = *plen;
        char *p, c;
@@ -942,6 +996,8 @@ static int strip_eol(char *linebuf, int *plen)
                c = *p;
                if (c == '\n')
                        is_eol = 1;
+               else if (is_eol && flags & SMIME_ASCIICRLF && c < 33)
+                       continue;
                else if (c != '\r')
                        break;
                }