From 31e53584db5879894809fbde5445aac7553ac3e2 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 23 Jun 2020 16:13:50 +0200 Subject: escape: make the URL decode able to reject only %00 bytes ... or all "control codes" or nothing. Assisted-by: Nicolas Sterchele --- lib/curl_path.c | 4 ++-- lib/dict.c | 3 ++- lib/escape.c | 21 +++++++++++++++------ lib/escape.h | 11 +++++++++-- lib/file.c | 2 +- lib/ftp.c | 7 ++++--- lib/gopher.c | 2 +- lib/imap.c | 10 ++++++---- lib/ldap.c | 7 ++++--- lib/mqtt.c | 3 ++- lib/pop3.c | 4 ++-- lib/smb.c | 4 ++-- lib/smtp.c | 5 +++-- lib/tftp.c | 2 +- lib/url.c | 4 ++-- lib/urlapi.c | 5 ++++- 16 files changed, 60 insertions(+), 34 deletions(-) diff --git a/lib/curl_path.c b/lib/curl_path.c index f42963463..fbd98cb39 100644 --- a/lib/curl_path.c +++ b/lib/curl_path.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, 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 @@ -42,7 +42,7 @@ CURLcode Curl_getworkingpath(struct connectdata *conn, size_t working_path_len; CURLcode result = Curl_urldecode(data, data->state.up.path, 0, &working_path, - &working_path_len, FALSE); + &working_path_len, REJECT_ZERO); if(result) return result; diff --git a/lib/dict.c b/lib/dict.c index c802deeff..f529b48f7 100644 --- a/lib/dict.c +++ b/lib/dict.c @@ -99,7 +99,8 @@ static char *unescape_word(struct Curl_easy *data, const char *inputbuff) char *dictp; size_t len; - CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len, FALSE); + CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len, + REJECT_NADA); if(!newp || result) return NULL; diff --git a/lib/escape.c b/lib/escape.c index 26d44df7b..2bea145f4 100644 --- a/lib/escape.c +++ b/lib/escape.c @@ -123,19 +123,26 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string, /* * 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). * * 'data' can be set to NULL but then this function can't convert network * data to host for non-ascii. + * + * ctrl options: + * - REJECT_NADA: accept everything + * - REJECT_CTRL: rejects control characters (byte codes lower than 32) in + * the data + * - REJECT_ZERO: rejects decoded zero bytes + * + * The values for the enum starts at 2, to make the assert detect legacy + * invokes that used TRUE/FALSE (0 and 1). */ + CURLcode Curl_urldecode(struct Curl_easy *data, const char *string, size_t length, char **ostring, size_t *olen, - bool reject_ctrl) + enum urlreject ctrl) { size_t alloc; char *ns; @@ -144,6 +151,7 @@ CURLcode Curl_urldecode(struct Curl_easy *data, CURLcode result = CURLE_OK; DEBUGASSERT(string); + DEBUGASSERT(ctrl >= REJECT_NADA); /* crash on TRUE/FALSE */ alloc = (length?length:strlen(string)) + 1; ns = malloc(alloc); @@ -179,7 +187,8 @@ CURLcode Curl_urldecode(struct Curl_easy *data, alloc -= 2; } - if(reject_ctrl && (in < 0x20)) { + if(((ctrl == REJECT_CTRL) && (in < 0x20)) || + ((ctrl == REJECT_ZERO) && (in == 0))) { free(ns); return CURLE_URL_MALFORMAT; } @@ -213,7 +222,7 @@ char *curl_easy_unescape(struct Curl_easy *data, const char *string, size_t inputlen = length; size_t outputlen; CURLcode res = Curl_urldecode(data, string, inputlen, &str, &outputlen, - FALSE); + REJECT_NADA); if(res) return NULL; diff --git a/lib/escape.h b/lib/escape.h index d8bbe5cb0..586db7e67 100644 --- a/lib/escape.h +++ b/lib/escape.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, 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,9 +25,16 @@ * allocated string or NULL if an error occurred. */ bool Curl_isunreserved(unsigned char in); + +enum urlreject { + REJECT_NADA = 2, + REJECT_CTRL, + REJECT_ZERO +}; + CURLcode Curl_urldecode(struct Curl_easy *data, const char *string, size_t length, char **ostring, size_t *olen, - bool reject_crlf); + enum urlreject ctrl); #endif /* HEADER_CURL_ESCAPE_H */ diff --git a/lib/file.c b/lib/file.c index 576a79463..cd3e49c33 100644 --- a/lib/file.c +++ b/lib/file.c @@ -144,7 +144,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) size_t real_path_len; CURLcode result = Curl_urldecode(data, data->state.up.path, 0, &real_path, - &real_path_len, FALSE); + &real_path_len, REJECT_ZERO); if(result) return result; diff --git a/lib/ftp.c b/lib/ftp.c index 6fb4a3243..8ff3d13bc 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -1452,7 +1452,7 @@ static CURLcode ftp_state_list(struct connectdata *conn) /* url-decode before evaluation: e.g. paths starting/ending with %2f */ const char *slashPos = NULL; char *rawPath = NULL; - result = Curl_urldecode(data, ftp->path, 0, &rawPath, NULL, TRUE); + result = Curl_urldecode(data, ftp->path, 0, &rawPath, NULL, REJECT_CTRL); if(result) return result; @@ -3194,7 +3194,8 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, if(!result) /* get the url-decoded "raw" path */ - result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, TRUE); + result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, + REJECT_CTRL); if(result) { /* We can limp along anyway (and should try to since we may already be in * the error path) */ @@ -4110,7 +4111,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) ftpc->cwdfail = FALSE; /* url-decode ftp path before further evaluation */ - result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, TRUE); + result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, REJECT_CTRL); if(result) return result; diff --git a/lib/gopher.c b/lib/gopher.c index c48098f75..b4811b289 100644 --- a/lib/gopher.c +++ b/lib/gopher.c @@ -116,7 +116,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) newp += 2; /* ... and finally unescape */ - result = Curl_urldecode(data, newp, 0, &sel, &len, FALSE); + result = Curl_urldecode(data, newp, 0, &sel, &len, REJECT_ZERO); free(gopherpath); if(result) return result; diff --git a/lib/imap.c b/lib/imap.c index 14c76f08e..cad0e5908 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -1957,7 +1957,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn) end--; result = Curl_urldecode(data, begin, end - begin, &imap->mailbox, NULL, - TRUE); + REJECT_CTRL); if(result) return result; } @@ -1979,7 +1979,8 @@ static CURLcode imap_parse_url_path(struct connectdata *conn) return CURLE_URL_MALFORMAT; /* Decode the name parameter */ - result = Curl_urldecode(data, begin, ptr - begin, &name, NULL, TRUE); + result = Curl_urldecode(data, begin, ptr - begin, &name, NULL, + REJECT_CTRL); if(result) return result; @@ -1989,7 +1990,8 @@ static CURLcode imap_parse_url_path(struct connectdata *conn) ptr++; /* Decode the value parameter */ - result = Curl_urldecode(data, begin, ptr - begin, &value, &valuelen, TRUE); + result = Curl_urldecode(data, begin, ptr - begin, &value, &valuelen, + REJECT_CTRL); if(result) { free(name); return result; @@ -2077,7 +2079,7 @@ static CURLcode imap_parse_custom_request(struct connectdata *conn) if(custom) { /* URL decode the custom request */ - result = Curl_urldecode(data, custom, 0, &imap->custom, NULL, TRUE); + result = Curl_urldecode(data, custom, 0, &imap->custom, NULL, REJECT_CTRL); /* Extract the parameters if specified */ if(!result) { diff --git a/lib/ldap.c b/lib/ldap.c index 27306580d..512def659 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -883,7 +883,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp) LDAP_TRACE(("DN '%s'\n", dn)); /* Unescape the DN */ - result = Curl_urldecode(conn->data, dn, 0, &unescaped, NULL, FALSE); + result = Curl_urldecode(conn->data, dn, 0, &unescaped, NULL, REJECT_ZERO); if(result) { rc = LDAP_NO_MEMORY; @@ -949,7 +949,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp) /* Unescape the attribute */ result = Curl_urldecode(conn->data, attributes[i], 0, &unescaped, NULL, - FALSE); + REJECT_ZERO); if(result) { free(attributes); @@ -1018,7 +1018,8 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp) LDAP_TRACE(("filter '%s'\n", filter)); /* Unescape the filter */ - result = Curl_urldecode(conn->data, filter, 0, &unescaped, NULL, FALSE); + result = Curl_urldecode(conn->data, filter, 0, &unescaped, NULL, + REJECT_ZERO); if(result) { rc = LDAP_NO_MEMORY; diff --git a/lib/mqtt.c b/lib/mqtt.c index d09aab4ee..f6f441614 100644 --- a/lib/mqtt.c +++ b/lib/mqtt.c @@ -211,7 +211,8 @@ static CURLcode mqtt_get_topic(struct connectdata *conn, char *path = conn->data->state.up.path; if(strlen(path) > 1) { - result = Curl_urldecode(conn->data, path + 1, 0, topic, topiclen, FALSE); + result = Curl_urldecode(conn->data, path + 1, 0, topic, topiclen, + REJECT_NADA); } else { failf(conn->data, "Error: No topic specified."); diff --git a/lib/pop3.c b/lib/pop3.c index 2f490b2f1..9ff5c78fd 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -1390,7 +1390,7 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn) const char *path = &data->state.up.path[1]; /* skip leading path */ /* URL decode the path for the message ID */ - return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE); + return Curl_urldecode(data, path, 0, &pop3->id, NULL, REJECT_CTRL); } /*********************************************************************** @@ -1408,7 +1408,7 @@ static CURLcode pop3_parse_custom_request(struct connectdata *conn) /* URL decode the custom request */ if(custom) - result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE); + result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, REJECT_CTRL); return result; } diff --git a/lib/smb.c b/lib/smb.c index 12f99257f..d493adcc0 100644 --- a/lib/smb.c +++ b/lib/smb.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2014, Bill Nagel , Exacq Technologies - * Copyright (C) 2016-2019, Daniel Stenberg, , et al. + * Copyright (C) 2016-2020, 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 @@ -964,7 +964,7 @@ static CURLcode smb_parse_url_path(struct connectdata *conn) /* URL decode the path */ CURLcode result = Curl_urldecode(data, data->state.up.path, 0, &path, NULL, - TRUE); + REJECT_CTRL); if(result) return result; diff --git a/lib/smtp.c b/lib/smtp.c index ec936480e..685513b3b 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -1689,7 +1689,8 @@ static CURLcode smtp_parse_url_path(struct connectdata *conn) } /* URL decode the path and use it as the domain in our EHLO */ - return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE); + return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, + REJECT_CTRL); } /*********************************************************************** @@ -1707,7 +1708,7 @@ static CURLcode smtp_parse_custom_request(struct connectdata *conn) /* URL decode the custom request */ if(custom) - result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, TRUE); + result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, REJECT_CTRL); return result; } diff --git a/lib/tftp.c b/lib/tftp.c index 4f2f973a8..378d95608 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -487,7 +487,7 @@ static CURLcode tftp_send_first(struct tftp_state_data *state, file name so we skip the always-present first letter of the path string. */ result = Curl_urldecode(data, &state->conn->data->state.up.path[1], 0, - &filename, NULL, FALSE); + &filename, NULL, REJECT_ZERO); if(result) return result; diff --git a/lib/url.c b/lib/url.c index 8225e617a..8163fb58b 100644 --- a/lib/url.c +++ b/lib/url.c @@ -2373,10 +2373,10 @@ static CURLcode parse_proxy_auth(struct Curl_easy *data, if(proxyuser) result = Curl_urldecode(data, proxyuser, 0, &conn->http_proxy.user, NULL, - FALSE); + REJECT_ZERO); if(!result && proxypasswd) result = Curl_urldecode(data, proxypasswd, 0, &conn->http_proxy.passwd, - NULL, FALSE); + NULL, REJECT_ZERO); return result; } diff --git a/lib/urlapi.c b/lib/urlapi.c index 37937fbca..398364b34 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -1185,7 +1185,10 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, if(urldecode) { char *decoded; size_t dlen; - CURLcode res = Curl_urldecode(NULL, *part, 0, &decoded, &dlen, TRUE); + /* this unconditional rejection of control bytes is documented + API behavior */ + CURLcode res = Curl_urldecode(NULL, *part, 0, &decoded, &dlen, + REJECT_CTRL); free(*part); if(res) { *part = NULL; -- cgit v1.2.1