summaryrefslogtreecommitdiff
path: root/lib/url.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2021-02-12 10:27:42 +0100
committerDaniel Stenberg <daniel@haxx.se>2021-02-13 22:36:15 +0100
commit46620b97431e19c53ce82e55055c85830f088cf4 (patch)
tree672f1b6b90b0dc5dc2693df105ab010def1cd35a /lib/url.c
parente992770e8d16e4be2a3da8aa2cef5cfc12e22372 (diff)
downloadcurl-46620b97431e19c53ce82e55055c85830f088cf4.tar.gz
http: use credentials from transfer, not connection
HTTP auth "accidentally" worked before this cleanup since the code would always overwrite the connection credentials with the credentials from the most recent transfer and since HTTP auth is typically done first thing, this has not been an issue. It was still wrong and subject to possible race conditions or future breakage if the sequence of functions would change. The data.set.str[] strings MUST remain unmodified exactly as set by the user, and the credentials to use internally are instead set/updated in state.aptr.* Added test 675 to verify different credentials used in two requests done over a reused HTTP connection, which previously behaved wrongly. Fixes #6542 Closes #6545
Diffstat (limited to 'lib/url.c')
-rw-r--r--lib/url.c190
1 files changed, 106 insertions, 84 deletions
diff --git a/lib/url.c b/lib/url.c
index d21e4ad4f..3e3355d6b 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -449,6 +449,10 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_safefree(data->state.aptr.host);
Curl_safefree(data->state.aptr.cookiehost);
Curl_safefree(data->state.aptr.rtsp_transport);
+ Curl_safefree(data->state.aptr.user);
+ Curl_safefree(data->state.aptr.passwd);
+ Curl_safefree(data->state.aptr.proxyuser);
+ Curl_safefree(data->state.aptr.proxypasswd);
#ifndef CURL_DISABLE_DOH
if(data->req.doh) {
@@ -1699,11 +1703,11 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
}
conn->bits.proxy_user_passwd =
- (data->set.str[STRING_PROXYUSERNAME]) ? TRUE : FALSE;
+ (data->state.aptr.proxyuser) ? TRUE : FALSE;
conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
#endif /* CURL_DISABLE_PROXY */
- conn->bits.user_passwd = (data->set.str[STRING_USERNAME]) ? TRUE : FALSE;
+ conn->bits.user_passwd = (data->state.aptr.user) ? TRUE : FALSE;
#ifndef CURL_DISABLE_FTP
conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
@@ -1970,36 +1974,50 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
if(result)
return result;
- /* we don't use the URL API's URL decoder option here since it rejects
- control codes and we want to allow them for some schemes in the user and
- password fields */
- uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
- if(!uc) {
- char *decoded;
- result = Curl_urldecode(NULL, data->state.up.user, 0, &decoded, NULL,
- conn->handler->flags&PROTOPT_USERPWDCTRL ?
- REJECT_ZERO : REJECT_CTRL);
- if(result)
- return result;
- conn->user = decoded;
- conn->bits.user_passwd = TRUE;
+ /*
+ * User name and password set with their own options override the
+ * credentials possibly set in the URL.
+ */
+ if(!data->state.aptr.user) {
+ /* we don't use the URL API's URL decoder option here since it rejects
+ control codes and we want to allow them for some schemes in the user
+ and password fields */
+ uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
+ if(!uc) {
+ char *decoded;
+ result = Curl_urldecode(NULL, data->state.up.user, 0, &decoded, NULL,
+ conn->handler->flags&PROTOPT_USERPWDCTRL ?
+ REJECT_ZERO : REJECT_CTRL);
+ if(result)
+ return result;
+ conn->user = decoded;
+ conn->bits.user_passwd = TRUE;
+ result = Curl_setstropt(&data->state.aptr.user, decoded);
+ if(result)
+ return result;
+ }
+ else if(uc != CURLUE_NO_USER)
+ return Curl_uc_to_curlcode(uc);
}
- else if(uc != CURLUE_NO_USER)
- return Curl_uc_to_curlcode(uc);
- uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
- if(!uc) {
- char *decoded;
- result = Curl_urldecode(NULL, data->state.up.password, 0, &decoded, NULL,
- conn->handler->flags&PROTOPT_USERPWDCTRL ?
- REJECT_ZERO : REJECT_CTRL);
- if(result)
- return result;
- conn->passwd = decoded;
- conn->bits.user_passwd = TRUE;
+ if(!data->state.aptr.passwd) {
+ uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
+ if(!uc) {
+ char *decoded;
+ result = Curl_urldecode(NULL, data->state.up.password, 0, &decoded, NULL,
+ conn->handler->flags&PROTOPT_USERPWDCTRL ?
+ REJECT_ZERO : REJECT_CTRL);
+ if(result)
+ return result;
+ conn->passwd = decoded;
+ conn->bits.user_passwd = TRUE;
+ result = Curl_setstropt(&data->state.aptr.passwd, decoded);
+ if(result)
+ return result;
+ }
+ else if(uc != CURLUE_NO_PASSWORD)
+ return Curl_uc_to_curlcode(uc);
}
- else if(uc != CURLUE_NO_PASSWORD)
- return Curl_uc_to_curlcode(uc);
uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
CURLU_URLDECODE);
@@ -2390,6 +2408,10 @@ static CURLcode parse_proxy(struct Curl_easy *data,
if(proxyuser || proxypasswd) {
Curl_safefree(proxyinfo->user);
proxyinfo->user = proxyuser;
+ result = Curl_setstropt(&data->state.aptr.proxyuser,
+ proxyuser);
+ if(result)
+ goto error;
Curl_safefree(proxyinfo->passwd);
if(!proxypasswd) {
proxypasswd = strdup("");
@@ -2399,6 +2421,10 @@ static CURLcode parse_proxy(struct Curl_easy *data,
}
}
proxyinfo->passwd = proxypasswd;
+ result = Curl_setstropt(&data->state.aptr.proxypasswd,
+ proxypasswd);
+ if(result)
+ goto error;
conn->bits.proxy_user_passwd = TRUE; /* enable it */
}
@@ -2455,18 +2481,26 @@ static CURLcode parse_proxy(struct Curl_easy *data,
static CURLcode parse_proxy_auth(struct Curl_easy *data,
struct connectdata *conn)
{
- const char *proxyuser = data->set.str[STRING_PROXYUSERNAME] ?
- data->set.str[STRING_PROXYUSERNAME] : "";
- const char *proxypasswd = data->set.str[STRING_PROXYPASSWORD] ?
- data->set.str[STRING_PROXYPASSWORD] : "";
+ const char *proxyuser = data->state.aptr.proxyuser ?
+ data->state.aptr.proxyuser : "";
+ const char *proxypasswd = data->state.aptr.proxypasswd ?
+ data->state.aptr.proxypasswd : "";
CURLcode result = CURLE_OK;
- if(proxyuser)
+ if(proxyuser) {
result = Curl_urldecode(data, proxyuser, 0, &conn->http_proxy.user, NULL,
REJECT_ZERO);
- if(!result && proxypasswd)
+ if(!result)
+ result = Curl_setstropt(&data->state.aptr.proxyuser,
+ conn->http_proxy.user);
+ }
+ if(!result && proxypasswd) {
result = Curl_urldecode(data, proxypasswd, 0, &conn->http_proxy.passwd,
NULL, REJECT_ZERO);
+ if(!result)
+ result = Curl_setstropt(&data->state.aptr.proxypasswd,
+ conn->http_proxy.passwd);
+ }
return result;
}
@@ -2808,44 +2842,19 @@ static CURLcode parse_remote_port(struct Curl_easy *data,
* option or a .netrc file, if applicable.
*/
static CURLcode override_login(struct Curl_easy *data,
- struct connectdata *conn,
- char **userp, char **passwdp, char **optionsp)
+ struct connectdata *conn)
{
- bool user_changed = FALSE;
- bool passwd_changed = FALSE;
CURLUcode uc;
+ char **userp = &conn->user;
+ char **passwdp = &conn->passwd;
+ char **optionsp = &conn->options;
if(data->set.use_netrc == CURL_NETRC_REQUIRED && conn->bits.user_passwd) {
- /* ignore user+password in the URL */
- if(*userp) {
- Curl_safefree(*userp);
- user_changed = TRUE;
- }
- if(*passwdp) {
- Curl_safefree(*passwdp);
- passwd_changed = TRUE;
- }
+ Curl_safefree(*userp);
+ Curl_safefree(*passwdp);
conn->bits.user_passwd = FALSE; /* disable user+password */
}
- if(data->set.str[STRING_USERNAME]) {
- free(*userp);
- *userp = strdup(data->set.str[STRING_USERNAME]);
- if(!*userp)
- return CURLE_OUT_OF_MEMORY;
- conn->bits.user_passwd = TRUE; /* enable user+password */
- user_changed = TRUE;
- }
-
- if(data->set.str[STRING_PASSWORD]) {
- free(*passwdp);
- *passwdp = strdup(data->set.str[STRING_PASSWORD]);
- if(!*passwdp)
- return CURLE_OUT_OF_MEMORY;
- conn->bits.user_passwd = TRUE; /* enable user+password */
- passwd_changed = TRUE;
- }
-
if(data->set.str[STRING_OPTIONS]) {
free(*optionsp);
*optionsp = strdup(data->set.str[STRING_OPTIONS]);
@@ -2854,8 +2863,7 @@ static CURLcode override_login(struct Curl_easy *data,
}
conn->bits.netrc = FALSE;
- if(data->set.use_netrc != CURL_NETRC_IGNORED &&
- (!*userp || !**userp || !*passwdp || !**passwdp)) {
+ if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
bool netrc_user_changed = FALSE;
bool netrc_passwd_changed = FALSE;
int ret;
@@ -2865,8 +2873,8 @@ static CURLcode override_login(struct Curl_easy *data,
&netrc_user_changed, &netrc_passwd_changed,
data->set.str[STRING_NETRC_FILE]);
if(ret > 0) {
- infof(data, "Couldn't find host %s in the .netrc file; using defaults\n",
- conn->host.name);
+ infof(data, "Couldn't find host %s in the %s file; using defaults\n",
+ conn->host.name, data->set.str[STRING_NETRC_FILE]);
}
else if(ret < 0) {
return CURLE_OUT_OF_MEMORY;
@@ -2877,29 +2885,44 @@ static CURLcode override_login(struct Curl_easy *data,
different host or similar. */
conn->bits.netrc = TRUE;
conn->bits.user_passwd = TRUE; /* enable user+password */
-
- if(netrc_user_changed) {
- user_changed = TRUE;
- }
- if(netrc_passwd_changed) {
- passwd_changed = TRUE;
- }
}
}
/* for updated strings, we update them in the URL */
- if(user_changed) {
- uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp,
+ if(*userp) {
+ CURLcode result = Curl_setstropt(&data->state.aptr.user, *userp);
+ if(result)
+ return result;
+ }
+ if(data->state.aptr.user) {
+ uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user,
CURLU_URLENCODE);
if(uc)
return Curl_uc_to_curlcode(uc);
+ if(!*userp) {
+ *userp = strdup(data->state.aptr.user);
+ if(!*userp)
+ return CURLE_OUT_OF_MEMORY;
+ }
}
- if(passwd_changed) {
- uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp,
- CURLU_URLENCODE);
+
+ if(*passwdp) {
+ CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
+ if(result)
+ return result;
+ }
+ if(data->state.aptr.passwd) {
+ uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
+ data->state.aptr.passwd, CURLU_URLENCODE);
if(uc)
return Curl_uc_to_curlcode(uc);
+ if(!*passwdp) {
+ *passwdp = strdup(data->state.aptr.passwd);
+ if(!*passwdp)
+ return CURLE_OUT_OF_MEMORY;
+ }
}
+
return CURLE_OK;
}
@@ -3560,8 +3583,7 @@ static CURLcode create_conn(struct Curl_easy *data,
/* Check for overridden login details and set them accordingly so they
they are known when protocol->setup_connection is called! */
- result = override_login(data, conn, &conn->user, &conn->passwd,
- &conn->options);
+ result = override_login(data, conn);
if(result)
goto out;