diff --git a/docs/cmdline-opts/disallow-username-in-url.d b/docs/cmdline-opts/disallow-username-in-url.d new file mode 100644 index 000000000..a7f46ea15 --- /dev/null +++ b/docs/cmdline-opts/disallow-username-in-url.d @@ -0,0 +1,7 @@ +Long: disallow-username-in-url +Help: Disallow username in url +Protocols: HTTP +Added: 7.61.0 +See-also: proto +--- +This tells curl to exit if passed a url containing a username. diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index 317c7a646..35c183d7b 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -258,6 +258,8 @@ HTTP proxy authentication methods. See \fICURLOPT_PROXYAUTH(3)\fP Enable SASL initial response. See \fICURLOPT_SASL_IR(3)\fP .IP CURLOPT_XOAUTH2_BEARER OAuth2 bearer token. See \fICURLOPT_XOAUTH2_BEARER(3)\fP +.IP CURLOPT_DISALLOW_USERNAME_IN_URL +Don't allow username in URL. See \fICURLOPT_DISALLOW_USERNAME_IN_URL(3)\fP .SH HTTP OPTIONS .IP CURLOPT_AUTOREFERER Automatically set Referer: header. See \fICURLOPT_AUTOREFERER(3)\fP diff --git a/docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.3 b/docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.3 new file mode 100644 index 000000000..ac5f913a3 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.3 @@ -0,0 +1,56 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2018, 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 https://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_DISALLOW_USERNAME_IN_URL 3 "30 May 2018" "libcurl 7.61.0" "curl_easy_setopt options" +.SH NAME +CURLOPT_DISALLOW_USERNAME_IN_URL \- disallow specifying username in the url +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DISALLOW_USERNAME_IN_URL, long disallow); +.SH DESCRIPTION +A long parameter set to 1 tells the library to not allow URLs that include a +username. +.SH DEFAULT +0 (disabled) - user names are allowed by default. +.SH PROTOCOLS +Several +.SH EXAMPLE +.nf +CURL *curl = curl_easy_init(); +if(curl) { + + curl_easy_setopt(curl, CURLOPT_URL, "http://example.com"); + curl_easy_setopt(curl, CURLOPT_DISALLOW_USERNAME_IN_URL, 1L); + + curl_easy_perform(curl); +} +.fi +.SH AVAILABILITY +Added in libcurl 7.61.0 +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. + +curl_easy_perform() will return CURLE_LOGIN_DENIED if this option is enabled +and a URL containing a username is specified. +.SH "SEE ALSO" +.BR libcurl-security "(3), ", CURLOPT_PROTOCOLS "(3)" diff --git a/docs/libcurl/opts/Makefile.inc b/docs/libcurl/opts/Makefile.inc index 5db8b8f3e..32485e292 100644 --- a/docs/libcurl/opts/Makefile.inc +++ b/docs/libcurl/opts/Makefile.inc @@ -114,6 +114,7 @@ man_MANS = \ CURLOPT_DEBUGFUNCTION.3 \ CURLOPT_DEFAULT_PROTOCOL.3 \ CURLOPT_DIRLISTONLY.3 \ + CURLOPT_DISALLOW_USERNAME_IN_URL.3 \ CURLOPT_DNS_CACHE_TIMEOUT.3 \ CURLOPT_DNS_INTERFACE.3 \ CURLOPT_DNS_LOCAL_IP4.3 \ diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index 4b6e74346..7448b4f43 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -376,6 +376,7 @@ CURLOPT_DEBUGDATA 7.9.6 CURLOPT_DEBUGFUNCTION 7.9.6 CURLOPT_DEFAULT_PROTOCOL 7.45.0 CURLOPT_DIRLISTONLY 7.17.0 +CURLOPT_DISALLOW_USERNAME_IN_URL 7.61.0 CURLOPT_DNS_CACHE_TIMEOUT 7.9.3 CURLOPT_DNS_INTERFACE 7.33.0 CURLOPT_DNS_LOCAL_IP4 7.33.0 diff --git a/include/curl/curl.h b/include/curl/curl.h index 034c6da7e..067b34ded 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -1853,6 +1853,9 @@ typedef enum { CINIT(TLS13_CIPHERS, STRINGPOINT, 276), CINIT(PROXY_TLS13_CIPHERS, STRINGPOINT, 277), + /* Disallow specifying username/login in URL. */ + CINIT(DISALLOW_USERNAME_IN_URL, LONG, 278), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/lib/setopt.c b/lib/setopt.c index 93a4dd2b5..5ecf5b97f 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -2590,6 +2590,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, case CURLOPT_DNS_SHUFFLE_ADDRESSES: data->set.dns_shuffle_addresses = (0 != va_arg(param, long)) ? TRUE:FALSE; break; + case CURLOPT_DISALLOW_USERNAME_IN_URL: + data->set.disallow_username_in_url = + (0 != va_arg(param, long)) ? TRUE : FALSE; + break; default: /* unknown tag and its companion, just ignore: */ result = CURLE_UNKNOWN_OPTION; diff --git a/lib/url.c b/lib/url.c index 411a0c814..c62221048 100644 --- a/lib/url.c +++ b/lib/url.c @@ -3170,6 +3170,13 @@ static CURLcode parse_url_login(struct Curl_easy *data, if(userp) { char *newname; + if(data->set.disallow_username_in_url) { + failf(data, "Option DISALLOW_USERNAME_IN_URL is set " + "and url contains username."); + result = CURLE_LOGIN_DENIED; + goto out; + } + /* We have a user in the URL */ conn->bits.userpwd_in_url = TRUE; conn->bits.user_passwd = TRUE; /* enable user+password */ diff --git a/lib/urldata.h b/lib/urldata.h index f1b67c3d1..7e647a2a6 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1689,6 +1689,7 @@ struct UserDefined { curl_resolver_start_callback resolver_start; /* optional callback called before resolver start */ void *resolver_start_client; /* pointer to pass to resolver start callback */ + bool disallow_username_in_url; /* disallow username in url */ }; struct Names { diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 237c2bd7f..a0363e9a7 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -255,6 +255,7 @@ struct OperationConfig { long happy_eyeballs_timeout_ms; /* happy eyeballs timeout in milliseconds. 0 is valid. default: CURL_HET_DEFAULT. */ bool haproxy_protocol; /* whether to send HAProxy protocol v1 */ + bool disallow_username_in_url; /* disallow usernames in URLs */ 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 a9f448112..186168252 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -82,6 +82,7 @@ static const struct LongShort aliases[]= { {"*d", "ciphers", ARG_STRING}, {"*D", "dns-interface", ARG_STRING}, {"*e", "disable-epsv", ARG_BOOL}, + {"*f", "disallow-username-in-url", ARG_BOOL}, {"*E", "epsv", ARG_BOOL}, /* 'epsv' made like this to make --no-epsv and --epsv to work although --disable-epsv is the documented option */ @@ -621,6 +622,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ case 'e': /* --disable-epsv */ config->disable_epsv = toggle; break; + case 'f': /* --disallow-username-in-url */ + config->disallow_username_in_url = toggle; + break; case 'E': /* --epsv */ config->disable_epsv = (!toggle)?TRUE:FALSE; break; diff --git a/src/tool_help.c b/src/tool_help.c index 3218cf67d..b829e76ef 100644 --- a/src/tool_help.c +++ b/src/tool_help.c @@ -108,6 +108,8 @@ static const struct helptxt helptext[] = { "Inhibit using EPRT or LPRT"}, {" --disable-epsv", "Inhibit using EPSV"}, + {" --disallow-username-in-url", + "Disallow username in url"}, {" --dns-interface ", "Interface to use for DNS requests"}, {" --dns-ipv4-addr
", diff --git a/src/tool_operate.c b/src/tool_operate.c index 0a1b1a48d..26fc251f5 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1474,6 +1474,9 @@ static CURLcode operate_do(struct GlobalConfig *global, if(config->haproxy_protocol) my_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L); + if(config->disallow_username_in_url) + my_setopt(curl, CURLOPT_DISALLOW_USERNAME_IN_URL, 1L); + /* initialize retry vars for loop below */ retry_sleep_default = (config->retry_delay) ? config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */ diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc index bce8c9798..0b487ec68 100644 --- a/tests/data/Makefile.inc +++ b/tests/data/Makefile.inc @@ -196,6 +196,6 @@ test2056 test2057 test2058 test2059 test2060 test2061 test2062 test2063 \ test2064 test2065 test2066 test2067 test2068 test2069 \ \ test2070 test2071 test2072 test2073 \ -test2074 \ +test2074 test2075 \ \ test3000 test3001 diff --git a/tests/data/test2075 b/tests/data/test2075 new file mode 100644 index 000000000..88db7ae29 --- /dev/null +++ b/tests/data/test2075 @@ -0,0 +1,34 @@ + + + +--disallow-username-in-url +HTTP + + + +# +# Client-side + + +http + + +none + + +Verify usernames are not allowed in url + + +--disallow-username-in-url http://username:password@example.com/ + + + +# +# Verify data after the test has been "shot" + +# CURLE_LOGIN_DENIED is code 67 + +67 + + +