diff --git a/lib/escape.c b/lib/escape.c index b0922bc936840a..0dd5a1d0a68719 100644 --- a/lib/escape.c +++ b/lib/escape.c @@ -31,6 +31,7 @@ #include "urldata.h" #include "warnless.h" #include "non-ascii.h" +#include "escape.h" #define _MPRINTF_REPLACE /* use our functions only */ #include @@ -84,7 +85,7 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength) char *testing_ptr = NULL; unsigned char in; /* we need to treat the characters unsigned */ size_t newlen = alloc; - int strindex=0; + size_t strindex=0; size_t length; CURLcode res; @@ -132,23 +133,29 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength) } /* - * Unescapes the given URL escaped string of given length. Returns a - * pointer to a malloced string with length given in *olen. - * If length == 0, the length is assumed to be strlen(string). - * If olen == NULL, no output length is stored. + * Curl_urldecode() URL decodes the given string. + * + * Optionally detects control characters (byte codes lower than 32) in the + * data and rejects such data. + * + * Returns a pointer to a malloced string in *ostring with length given in + * *olen. If length == 0, the length is assumed to be strlen(string). + * */ -char *curl_easy_unescape(CURL *handle, const char *string, int length, - int *olen) +CURLcode Curl_urldecode(struct SessionHandle *data, + const char *string, size_t length, + char **ostring, size_t *olen, + bool reject_ctrl) { - int alloc = (length?length:(int)strlen(string))+1; + size_t alloc = (length?length:strlen(string))+1; char *ns = malloc(alloc); unsigned char in; - int strindex=0; + size_t strindex=0; unsigned long hex; CURLcode res; if(!ns) - return NULL; + return CURLE_OUT_OF_MEMORY; while(--alloc > 0) { in = *string; @@ -164,16 +171,20 @@ char *curl_easy_unescape(CURL *handle, const char *string, int length, in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */ - res = Curl_convert_from_network(handle, &in, 1); + res = Curl_convert_from_network(data, &in, 1); if(res) { /* Curl_convert_from_network calls failf if unsuccessful */ free(ns); - return NULL; + return res; } string+=2; alloc-=2; } + if(reject_ctrl && (in < 0x20)) { + free(ns); + return CURLE_URL_MALFORMAT; + } ns[strindex++] = in; string++; @@ -183,7 +194,33 @@ char *curl_easy_unescape(CURL *handle, const char *string, int length, if(olen) /* store output size */ *olen = strindex; - return ns; + + if(ostring) + /* store output string */ + *ostring = ns; + + return CURLE_OK; +} + +/* + * Unescapes the given URL escaped string of given length. Returns a + * pointer to a malloced string with length given in *olen. + * If length == 0, the length is assumed to be strlen(string). + * If olen == NULL, no output length is stored. + */ +char *curl_easy_unescape(CURL *handle, const char *string, int length, + int *olen) +{ + char *str = NULL; + size_t inputlen = length; + size_t outputlen; + CURLcode res = Curl_urldecode(handle, string, inputlen, &str, &outputlen, + FALSE); + if(res) + return NULL; + if(olen) + *olen = curlx_uztosi(outputlen); + return str; } /* For operating systems/environments that use different malloc/free diff --git a/lib/escape.h b/lib/escape.h index 04b06a973bbc11..4c7f84133b6c56 100644 --- a/lib/escape.h +++ b/lib/escape.h @@ -1,5 +1,5 @@ -#ifndef __ESCAPE_H -#define __ESCAPE_H +#ifndef HEADER_CURL_ESCAPE_H +#define HEADER_CURL_ESCAPE_H /*************************************************************************** * _ _ ____ _ @@ -8,7 +8,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -25,5 +25,9 @@ /* Escape and unescape URL encoding in strings. The functions return a new * allocated string or NULL if an error occurred. */ +CURLcode Curl_urldecode(struct SessionHandle *data, + const char *string, size_t length, + char **ostring, size_t *olen, + bool reject_crlf); #endif diff --git a/lib/imap.c b/lib/imap.c index c39664d86d775a..c6701417d0449b 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -953,17 +953,12 @@ static CURLcode imap_parse_url_path(struct connectdata *conn) struct imap_conn *imapc = &conn->proto.imapc; struct SessionHandle *data = conn->data; const char *path = data->state.path; - int len; if(!*path) path = "INBOX"; /* url decode the path and use this mailbox */ - imapc->mailbox = curl_easy_unescape(data, path, 0, &len); - if(!imapc->mailbox) - return CURLE_OUT_OF_MEMORY; - - return CURLE_OK; + return Curl_urldecode(data, path, 0, &imapc->mailbox, NULL, TRUE); } /* call this when the DO phase has completed */ diff --git a/lib/pop3.c b/lib/pop3.c index b7781109b3816d..cc360b8b95e1b8 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -914,11 +914,7 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn) const char *path = data->state.path; /* url decode the path and use this mailbox */ - pop3c->mailbox = curl_easy_unescape(data, path, 0, NULL); - if(!pop3c->mailbox) - return CURLE_OUT_OF_MEMORY; - - return CURLE_OK; + return Curl_urldecode(data, path, 0, &pop3c->mailbox, NULL, TRUE); } /* call this when the DO phase has completed */ diff --git a/lib/smtp.c b/lib/smtp.c index 4cb25efcaee40a..553c697d063edb 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -1244,7 +1244,6 @@ static CURLcode smtp_connect(struct connectdata *conn, struct SessionHandle *data = conn->data; struct pingpong *pp = &smtpc->pp; const char *path = conn->data->state.path; - int len; char localhost[HOSTNAME_MAX + 1]; *done = FALSE; /* default to not done yet */ @@ -1316,9 +1315,9 @@ static CURLcode smtp_connect(struct connectdata *conn, } /* url decode the path and use it as domain with EHLO */ - smtpc->domain = curl_easy_unescape(conn->data, path, 0, &len); - if(!smtpc->domain) - return CURLE_OUT_OF_MEMORY; + result = Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE); + if(result) + return result; /* When we connect, we start in the state where we await the server greeting */