summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/http.c21
-rw-r--r--lib/http_aws_sigv4.c4
-rw-r--r--lib/http_digest.c9
-rw-r--r--lib/http_digest.h1
-rw-r--r--lib/http_ntlm.c12
-rw-r--r--lib/setopt.c1
-rw-r--r--lib/transfer.c14
-rw-r--r--lib/url.c190
-rw-r--r--lib/urldata.h6
-rw-r--r--tests/data/Makefile.inc2
-rw-r--r--tests/data/test1348
-rw-r--r--tests/data/test67555
12 files changed, 211 insertions, 112 deletions
diff --git a/lib/http.c b/lib/http.c
index d6eceb7d5..33e4c62e5 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -298,26 +298,27 @@ static CURLcode http_output_basic(struct Curl_easy *data, bool proxy)
{
size_t size = 0;
char *authorization = NULL;
- struct connectdata *conn = data->conn;
char **userp;
const char *user;
const char *pwd;
CURLcode result;
char *out;
+ /* credentials are unique per transfer for HTTP, do not use the ones for the
+ connection */
if(proxy) {
#ifndef CURL_DISABLE_PROXY
userp = &data->state.aptr.proxyuserpwd;
- user = conn->http_proxy.user;
- pwd = conn->http_proxy.passwd;
+ user = data->state.aptr.proxyuser;
+ pwd = data->state.aptr.proxypasswd;
#else
return CURLE_NOT_BUILT_IN;
#endif
}
else {
userp = &data->state.aptr.userpwd;
- user = conn->user;
- pwd = conn->passwd;
+ user = data->state.aptr.user;
+ pwd = data->state.aptr.passwd;
}
out = aprintf("%s:%s", user, pwd ? pwd : "");
@@ -709,7 +710,6 @@ output_auth_headers(struct Curl_easy *data,
if(authstatus->picked == CURLAUTH_DIGEST) {
auth = "Digest";
result = Curl_output_digest(data,
- conn,
proxy,
(const unsigned char *)request,
(const unsigned char *)path);
@@ -756,11 +756,14 @@ output_auth_headers(struct Curl_easy *data,
#ifndef CURL_DISABLE_PROXY
infof(data, "%s auth using %s with user '%s'\n",
proxy ? "Proxy" : "Server", auth,
- proxy ? (conn->http_proxy.user ? conn->http_proxy.user : "") :
- (conn->user ? conn->user : ""));
+ proxy ? (data->state.aptr.proxyuser ?
+ data->state.aptr.proxyuser : "") :
+ (data->state.aptr.user ?
+ data->state.aptr.user : ""));
#else
infof(data, "Server auth using %s with user '%s'\n",
- auth, conn->user ? conn->user : "");
+ auth, data->state.aptr.user ?
+ data->state.aptr.user : "");
#endif
authstatus->multipass = (!authstatus->done) ? TRUE : FALSE;
}
diff --git a/lib/http_aws_sigv4.c b/lib/http_aws_sigv4.c
index 8fd1c77e6..a04b46a35 100644
--- a/lib/http_aws_sigv4.c
+++ b/lib/http_aws_sigv4.c
@@ -99,8 +99,8 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
char *request_type = NULL;
char *credential_scope = NULL;
char *str_to_sign = NULL;
- const char *user = conn->user ? conn->user : "";
- const char *passwd = conn->passwd ? conn->passwd : "";
+ const char *user = data->state.aptr.user ? data->state.aptr.user : "";
+ const char *passwd = data->state.aptr.passwd ? data->state.aptr.passwd : "";
char *secret = NULL;
unsigned char tmp_sign0[32] = {0};
unsigned char tmp_sign1[32] = {0};
diff --git a/lib/http_digest.c b/lib/http_digest.c
index 596b215db..132f3930c 100644
--- a/lib/http_digest.c
+++ b/lib/http_digest.c
@@ -67,7 +67,6 @@ CURLcode Curl_input_digest(struct Curl_easy *data,
}
CURLcode Curl_output_digest(struct Curl_easy *data,
- struct connectdata *conn,
bool proxy,
const unsigned char *request,
const unsigned char *uripath)
@@ -97,16 +96,16 @@ CURLcode Curl_output_digest(struct Curl_easy *data,
#else
digest = &data->state.proxydigest;
allocuserpwd = &data->state.aptr.proxyuserpwd;
- userp = conn->http_proxy.user;
- passwdp = conn->http_proxy.passwd;
+ userp = data->state.aptr.proxyuser;
+ passwdp = data->state.aptr.proxypasswd;
authp = &data->state.authproxy;
#endif
}
else {
digest = &data->state.digest;
allocuserpwd = &data->state.aptr.userpwd;
- userp = conn->user;
- passwdp = conn->passwd;
+ userp = data->state.aptr.user;
+ passwdp = data->state.aptr.passwd;
authp = &data->state.authhost;
}
diff --git a/lib/http_digest.h b/lib/http_digest.h
index 106caa7c4..89438d1a1 100644
--- a/lib/http_digest.h
+++ b/lib/http_digest.h
@@ -31,7 +31,6 @@ CURLcode Curl_input_digest(struct Curl_easy *data,
/* this is for creating digest header output */
CURLcode Curl_output_digest(struct Curl_easy *data,
- struct connectdata *conn,
bool proxy,
const unsigned char *request,
const unsigned char *uripath);
diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c
index 6cb829edf..4fa38f0b0 100644
--- a/lib/http_ntlm.c
+++ b/lib/http_ntlm.c
@@ -140,10 +140,10 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
if(proxy) {
#ifndef CURL_DISABLE_PROXY
allocuserpwd = &data->state.aptr.proxyuserpwd;
- userp = conn->http_proxy.user;
- passwdp = conn->http_proxy.passwd;
+ userp = data->state.aptr.proxyuser;
+ passwdp = data->state.aptr.proxypasswd;
service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
- data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
+ data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
hostname = conn->http_proxy.host.name;
ntlm = &conn->proxyntlm;
state = &conn->proxy_ntlm_state;
@@ -154,10 +154,10 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
}
else {
allocuserpwd = &data->state.aptr.userpwd;
- userp = conn->user;
- passwdp = conn->passwd;
+ userp = data->state.aptr.user;
+ passwdp = data->state.aptr.passwd;
service = data->set.str[STRING_SERVICE_NAME] ?
- data->set.str[STRING_SERVICE_NAME] : "HTTP";
+ data->set.str[STRING_SERVICE_NAME] : "HTTP";
hostname = conn->host.name;
ntlm = &conn->ntlm;
state = &conn->http_ntlm_state;
diff --git a/lib/setopt.c b/lib/setopt.c
index a12873760..7edc75f5f 100644
--- a/lib/setopt.c
+++ b/lib/setopt.c
@@ -1413,7 +1413,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
result = Curl_setstropt(&data->set.str[STRING_USERNAME],
va_arg(param, char *));
break;
-
case CURLOPT_PASSWORD:
/*
* authentication password to use in the operation
diff --git a/lib/transfer.c b/lib/transfer.c
index 0b27b3455..ae414cfc5 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -79,6 +79,7 @@
#include "strcase.h"
#include "urlapi-int.h"
#include "hsts.h"
+#include "setopt.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -1508,6 +1509,19 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
}
+ if(!result)
+ result = Curl_setstropt(&data->state.aptr.user,
+ data->set.str[STRING_USERNAME]);
+ if(!result)
+ result = Curl_setstropt(&data->state.aptr.passwd,
+ data->set.str[STRING_PASSWORD]);
+ if(!result)
+ result = Curl_setstropt(&data->state.aptr.proxyuser,
+ data->set.str[STRING_PROXYUSERNAME]);
+ if(!result)
+ result = Curl_setstropt(&data->state.aptr.proxypasswd,
+ data->set.str[STRING_PROXYPASSWORD]);
+
data->req.headerbytecount = 0;
return result;
}
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;
diff --git a/lib/urldata.h b/lib/urldata.h
index b78bf905c..b37344f8c 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1436,6 +1436,12 @@ struct UrlState {
char *cookiehost;
char *rtsp_transport;
char *te; /* TE: request header */
+
+ /* transfer credentials */
+ char *user;
+ char *passwd;
+ char *proxyuser;
+ char *proxypasswd;
} aptr;
#ifdef CURLDEBUG
diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
index 0b0e90d3e..f6e48e3de 100644
--- a/tests/data/Makefile.inc
+++ b/tests/data/Makefile.inc
@@ -90,7 +90,7 @@ test635 test636 test637 test638 test639 test640 test641 test642 \
test643 test644 test645 test646 test647 test648 test649 test650 test651 \
test652 test653 test654 test655 test656 test658 test659 test660 test661 \
test662 test663 test664 test665 test666 test667 test668 test669 \
-test670 test671 test672 test673 test674 \
+test670 test671 test672 test673 test674 test675 \
\
test700 test701 test702 test703 test704 test705 test706 test707 test708 \
test709 test710 test711 test712 test713 test714 test715 test716 test717 \
diff --git a/tests/data/test134 b/tests/data/test134
index e314b662e..4ca63accd 100644
--- a/tests/data/test134
+++ b/tests/data/test134
@@ -33,10 +33,12 @@ dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr
<server>
ftp
</server>
- <name>
+<name>
FTP (optional .netrc; programmatic user/passwd) dir list PASV
- </name>
- <command>
+</name>
+
+# -u overrides netrc which overrides the URL
+<command>
--netrc-optional --netrc-file log/netrc134 -u romulus:rhemus ftp://mary:mark@%HOSTIP:%FTPPORT/
</command>
<file name="log/netrc134" >
diff --git a/tests/data/test675 b/tests/data/test675
new file mode 100644
index 000000000..19549dd69
--- /dev/null
+++ b/tests/data/test675
@@ -0,0 +1,55 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+HTTP Basic auth
+</keywords>
+</info>
+# Server-side
+<reply>
+<data>
+HTTP/1.1 200 OK swsclose
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Content-Type: text/html
+Content-Length: 26
+
+the content would go here
+</data>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+ <name>
+HTTP connection re-use and different credentials
+ </name>
+
+<command>
+http://user1:foo1@%HOSTIP:%HTTPPORT/user1/675 http://user2:foo2@%HOSTIP:%HTTPPORT/user2/675
+</command>
+<features>
+proxy
+</features>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+GET /user1/675 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Authorization: Basic dXNlcjE6Zm9vMQ==
+User-Agent: curl/%VERSION
+Accept: */*
+
+GET /user2/675 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Authorization: Basic dXNlcjI6Zm9vMg==
+User-Agent: curl/%VERSION
+Accept: */*
+
+</protocol>
+</verify>
+</testcase>