From 5d2327929932bb18b0c683583f398855f0a31fed Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 23 Mar 2015 10:51:49 +0100 Subject: [PATCH] CURLOPT_PATH_AS_IS: added --path-as-is is the command line option Added docs in curl.1 and CURLOPT_PATH_AS_IS.3 Added test in test 1241 --- docs/curl.1 | 6 +++ docs/libcurl/opts/CURLOPT_PATH_AS_IS.3 | 63 +++++++++++++++++++++++++ docs/libcurl/opts/Makefile.am | 26 +++++------ include/curl/curl.h | 5 +- lib/url.c | 5 +- lib/urldata.h | 2 +- src/tool_cfgable.h | 5 +- src/tool_getparam.c | 4 ++ src/tool_help.c | 1 + src/tool_operate.c | 2 + tests/data/Makefile.inc | 2 +- tests/data/test1241 | 64 ++++++++++++++++++++++++++ 12 files changed, 165 insertions(+), 20 deletions(-) create mode 100644 docs/libcurl/opts/CURLOPT_PATH_AS_IS.3 create mode 100644 tests/data/test1241 diff --git a/docs/curl.1 b/docs/curl.1 index 67bf8effc..908f64899 100644 --- a/docs/curl.1 +++ b/docs/curl.1 @@ -1235,6 +1235,12 @@ available. (SSL/SSH) Passphrase for the private key If this option is used several times, the last one will be used. +.IP "--path-as-is" +Tell curl to not handle sequences of /../ or /./ in the given URL +path. Normally curl will squash or merge them according to standards but with +this option set you tell it not to do that. + +(Added in 7.42.0) .IP "--post301" (HTTP) Tells curl to respect RFC 2616/10.3.2 and not convert POST requests into GET requests when following a 301 redirection. The non-RFC behaviour is diff --git a/docs/libcurl/opts/CURLOPT_PATH_AS_IS.3 b/docs/libcurl/opts/CURLOPT_PATH_AS_IS.3 new file mode 100644 index 000000000..aa096c2d1 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PATH_AS_IS.3 @@ -0,0 +1,63 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2015, 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 +.\" * are also available at http://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PATH_AS_IS 3 "17 Jun 2014" "libcurl 7.42.0" "curl_easy_setopt options" +.SH NAME +CURLOPT_PATH_AS_IS \- do not handle dot dot sequences +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PATH_AS_IS, leaveit); +.SH DESCRIPTION +By setting the long \fIleavit\fP to 1, to explicitly tell libcurl to not alter +the given path before passing it on to the server. + +This tells libcurl to NOT squash sequences of "/../" or "/./" that may exist +in the URL's path part and that is supposed to be removed according to RFC +3986 section 5.2.4. + +Some server implementations are known to (erroneously) require the dot dot +sequences to remain in the path and some clients want to pass these on in +order to try out server implementations. + +By default libcurl will merge such sequences before using the path. +.SH DEFAULT +0 +.SH PROTOCOLS +All +.SH EXAMPLE +.nf +CURL *curl = curl_easy_init(); +if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/../../etc/password"); + + curl_easy_setopt(curl, CURLOPT_PATH_AS_IS, 1L); + + curl_easy_perform(curl); +} +.fi +.SH AVAILABILITY +Aded in 7.42.0 +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. +.SH "SEE ALSO" +.BR CURLOPT_STDERR "(3), " CURLOPT_DEBUGFUNCTION "(3), " diff --git a/docs/libcurl/opts/Makefile.am b/docs/libcurl/opts/Makefile.am index 3e95693a1..e032a25e8 100644 --- a/docs/libcurl/opts/Makefile.am +++ b/docs/libcurl/opts/Makefile.am @@ -90,15 +90,15 @@ man_MANS = CURLOPT_ACCEPT_ENCODING.3 CURLOPT_ACCEPTTIMEOUT_MS.3 \ CURLOPT_SSLCERT.3 CURLOPT_SSLCERTTYPE.3 CURLOPT_SSL_CIPHER_LIST.3 \ CURLOPT_SSL_CTX_DATA.3 CURLOPT_SSL_CTX_FUNCTION.3 \ CURLOPT_SSL_ENABLE_ALPN.3 CURLOPT_SSL_ENABLE_NPN.3 CURLOPT_SSLENGINE.3 \ - CURLOPT_SSLENGINE_DEFAULT.3 CURLOPT_SSL_FALSESTART.3 \ - CURLOPT_SSLKEY.3 CURLOPT_SSLKEYTYPE.3 \ - CURLOPT_SSL_OPTIONS.3 CURLOPT_SSL_SESSIONID_CACHE.3 \ - CURLOPT_SSL_VERIFYHOST.3 CURLOPT_SSL_VERIFYPEER.3 \ - CURLOPT_SSL_VERIFYSTATUS.3 CURLOPT_SSLVERSION.3 CURLOPT_STDERR.3 \ - CURLOPT_TCP_KEEPALIVE.3 CURLOPT_TCP_KEEPIDLE.3 CURLOPT_TCP_KEEPINTVL.3 \ - CURLOPT_TCP_NODELAY.3 CURLOPT_TELNETOPTIONS.3 CURLOPT_TFTP_BLKSIZE.3 \ - CURLOPT_TIMECONDITION.3 CURLOPT_TIMEOUT.3 CURLOPT_TIMEOUT_MS.3 \ - CURLOPT_TIMEVALUE.3 CURLOPT_TLSAUTH_PASSWORD.3 CURLOPT_TLSAUTH_TYPE.3 \ + CURLOPT_SSLENGINE_DEFAULT.3 CURLOPT_SSL_FALSESTART.3 CURLOPT_SSLKEY.3 \ + CURLOPT_SSLKEYTYPE.3 CURLOPT_SSL_OPTIONS.3 \ + CURLOPT_SSL_SESSIONID_CACHE.3 CURLOPT_SSL_VERIFYHOST.3 \ + CURLOPT_SSL_VERIFYPEER.3 CURLOPT_SSL_VERIFYSTATUS.3 \ + CURLOPT_SSLVERSION.3 CURLOPT_STDERR.3 CURLOPT_TCP_KEEPALIVE.3 \ + CURLOPT_TCP_KEEPIDLE.3 CURLOPT_TCP_KEEPINTVL.3 CURLOPT_TCP_NODELAY.3 \ + CURLOPT_TELNETOPTIONS.3 CURLOPT_TFTP_BLKSIZE.3 CURLOPT_TIMECONDITION.3 \ + CURLOPT_TIMEOUT.3 CURLOPT_TIMEOUT_MS.3 CURLOPT_TIMEVALUE.3 \ + CURLOPT_TLSAUTH_PASSWORD.3 CURLOPT_TLSAUTH_TYPE.3 \ CURLOPT_TLSAUTH_USERNAME.3 CURLOPT_TRANSFER_ENCODING.3 \ CURLOPT_TRANSFERTEXT.3 CURLOPT_UNRESTRICTED_AUTH.3 CURLOPT_UPLOAD.3 \ CURLOPT_URL.3 CURLOPT_USERAGENT.3 CURLOPT_USERNAME.3 CURLOPT_USERPWD.3 \ @@ -111,8 +111,8 @@ man_MANS = CURLOPT_ACCEPT_ENCODING.3 CURLOPT_ACCEPTTIMEOUT_MS.3 \ CURLMOPT_MAX_TOTAL_CONNECTIONS.3 CURLMOPT_PIPELINING.3 \ CURLMOPT_PIPELINING_SERVER_BL.3 CURLMOPT_PIPELINING_SITE_BL.3 \ CURLMOPT_SOCKETDATA.3 CURLMOPT_SOCKETFUNCTION.3 CURLMOPT_TIMERDATA.3 \ - CURLMOPT_TIMERFUNCTION.3 CURLOPT_UNIX_SOCKET_PATH.3 - + CURLMOPT_TIMERFUNCTION.3 CURLOPT_UNIX_SOCKET_PATH.3 \ + CURLOPT_PATH_AS_IS.3 HTMLPAGES = CURLOPT_ACCEPT_ENCODING.html CURLOPT_ACCEPTTIMEOUT_MS.html \ CURLOPT_ADDRESS_SCOPE.html CURLOPT_APPEND.html \ @@ -218,7 +218,7 @@ HTMLPAGES = CURLOPT_ACCEPT_ENCODING.html CURLOPT_ACCEPTTIMEOUT_MS.html \ CURLMOPT_PIPELINING_SERVER_BL.html CURLMOPT_PIPELINING_SITE_BL.html \ CURLMOPT_SOCKETDATA.html CURLMOPT_SOCKETFUNCTION.html \ CURLMOPT_TIMERDATA.html CURLMOPT_TIMERFUNCTION.html \ - CURLOPT_UNIX_SOCKET_PATH.html + CURLOPT_UNIX_SOCKET_PATH.html CURLOPT_PATH_AS_IS.html PDFPAGES = CURLOPT_ACCEPT_ENCODING.pdf CURLOPT_ACCEPTTIMEOUT_MS.pdf \ CURLOPT_ADDRESS_SCOPE.pdf CURLOPT_APPEND.pdf CURLOPT_AUTOREFERER.pdf \ @@ -321,7 +321,7 @@ PDFPAGES = CURLOPT_ACCEPT_ENCODING.pdf CURLOPT_ACCEPTTIMEOUT_MS.pdf \ CURLMOPT_PIPELINING_SERVER_BL.pdf CURLMOPT_PIPELINING_SITE_BL.pdf \ CURLMOPT_SOCKETDATA.pdf CURLMOPT_SOCKETFUNCTION.pdf \ CURLMOPT_TIMERDATA.pdf CURLMOPT_TIMERFUNCTION.pdf \ - CURLOPT_UNIX_SOCKET_PATH.pdf + CURLOPT_UNIX_SOCKET_PATH.pdf CURLOPT_PATH_AS_IS.pdf CLEANFILES = $(HTMLPAGES) $(PDFPAGES) diff --git a/include/curl/curl.h b/include/curl/curl.h index 4fcbd578b..ae1b0e4db 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, 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 @@ -1629,6 +1629,9 @@ typedef enum { /* Set if we should enable TLS false start. */ CINIT(SSL_FALSESTART, LONG, 233), + /* Do not squash dot-dot sequences */ + CINIT(PATH_AS_IS, LONG, 234), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/lib/url.c b/lib/url.c index 82faaf18a..e7d13d2d8 100644 --- a/lib/url.c +++ b/lib/url.c @@ -2613,6 +2613,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; #endif + case CURLOPT_PATH_AS_IS: + data->set.path_as_is = (0 != va_arg(param, long))?TRUE:FALSE; + break; default: /* unknown tag and its companion, just ignore: */ result = CURLE_UNKNOWN_OPTION; @@ -4036,7 +4039,7 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, path[0] = '/'; rebuild_url = TRUE; } - else { + else if(!data->set.path_as_is) { /* sanitise paths and remove ../ and ./ sequences according to RFC3986 */ char *newp = Curl_dedotdotify(path); if(!newp) diff --git a/lib/urldata.h b/lib/urldata.h index 01415b6ab..b1b1a678e 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1617,7 +1617,7 @@ struct UserDefined { bool ssl_enable_npn; /* TLS NPN extension? */ bool ssl_enable_alpn; /* TLS ALPN extension? */ - + bool path_as_is; /* allow dotdots? */ long expect_100_timeout; /* in milliseconds */ }; diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index e851130f4..d1f223871 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, 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 @@ -206,9 +206,8 @@ struct OperationConfig { bool nonpn; /* enable/disable TLS NPN extension */ bool noalpn; /* enable/disable TLS ALPN extension */ char *unix_socket_path; /* path to Unix domain socket */ - bool falsestart; - + bool path_as_is; struct GlobalConfig *global; struct OperationConfig *prev; struct OperationConfig *next; /* Always last in the struct */ diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 56aa03050..7f68b2852 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -177,6 +177,7 @@ static const struct LongShort aliases[]= { {"$K", "sasl-ir", FALSE}, {"$L", "test-event", FALSE}, {"$M", "unix-socket", TRUE}, + {"$N", "path-as-is", FALSE}, {"0", "http1.0", FALSE}, {"01", "http1.1", FALSE}, {"02", "http2", FALSE}, @@ -982,6 +983,9 @@ ParameterError getparameter(char *flag, /* f or -long-flag */ case 'M': /* --unix-socket */ GetStr(&config->unix_socket_path, nextarg); break; + case 'N': /* --path-as-is */ + config->path_as_is = toggle; + break; } break; case '#': /* --progress-bar */ diff --git a/src/tool_help.c b/src/tool_help.c index 69778b91a..bb7aa7c3a 100644 --- a/src/tool_help.c +++ b/src/tool_help.c @@ -154,6 +154,7 @@ static const char *const helptext[] = { " --oauth2-bearer TOKEN OAuth 2 Bearer Token (IMAP, POP3, SMTP)", " -o, --output FILE Write to FILE instead of stdout", " --pass PASS Pass phrase for the private key (SSL/SSH)", + " --path-as-is Do not squash .. sequences in URL path", " --pinnedpubkey FILE Public key (PEM/DER) to verify peer against " "(OpenSSL/GnuTLS/GSKit only)", " --post301 " diff --git a/src/tool_operate.c b/src/tool_operate.c index e2ae22e54..33a9520f9 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1045,6 +1045,8 @@ static CURLcode operate_do(struct GlobalConfig *global, if(config->falsestart) my_setopt(curl, CURLOPT_SSL_FALSESTART, 1L); } + if(config->path_as_is) + my_setopt(curl, CURLOPT_PATH_AS_IS, 1L); if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) { if(!config->insecure_ok) { diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc index 598392bd5..21504be43 100644 --- a/tests/data/Makefile.inc +++ b/tests/data/Makefile.inc @@ -124,7 +124,7 @@ test1208 test1209 test1210 test1211 test1212 test1213 test1214 test1215 \ test1216 test1217 test1218 test1219 \ test1220 test1221 test1222 test1223 test1224 test1225 test1226 test1227 \ test1228 test1229 test1230 test1231 test1232 test1233 test1234 test1235 \ -test1236 test1237 test1238 test1239 test1240 \ +test1236 test1237 test1238 test1239 test1240 test1241 \ \ test1300 test1301 test1302 test1303 test1304 test1305 test1306 test1307 \ test1308 test1309 test1310 test1311 test1312 test1313 test1314 test1315 \ diff --git a/tests/data/test1241 b/tests/data/test1241 new file mode 100644 index 000000000..aaa568868 --- /dev/null +++ b/tests/data/test1241 @@ -0,0 +1,64 @@ + + +# verify that dotdot removal can be disabled! + +HTTP +HTTP GET +HTTP proxy + + + +# +# Server-side + + +HTTP/1.1 200 OK +Content-Length: 6 +Connection: close + +-foo- + + + +HTTP/1.1 200 OK +Content-Length: 7 +Connection: close + +-cool- + + + +# +# Client-side + + +http + + +HTTP _without_ dotdot removal + + +--path-as-is --proxy http://%HOSTIP:%HTTPPORT http://test.remote.haxx.se.1241:8990/../../hej/but/who/../1241?stupid=me/../1241#soo/../1241 http://test.remote.haxx.se.1241:8990/../../hej/but/who/../12410001#/../12410001 + + + +# +# Verify data after the test has been "shot" + + +^User-Agent:.* + + +GET http://test.remote.haxx.se.1241:8990/../../hej/but/who/../1241?stupid=me/../1241 HTTP/1.1 +Host: test.remote.haxx.se.1241:8990 +Accept: */* +Proxy-Connection: Keep-Alive + +GET http://test.remote.haxx.se.1241:8990/../../hej/but/who/../12410001 HTTP/1.1 +Host: test.remote.haxx.se.1241:8990 +Accept: */* +Proxy-Connection: Keep-Alive + + + +