url: use same credentials on redirect

Previously it could lose the username and only use the password.

Added test 998 and 999 to verify.

Reported-by: Tobias Bora
Fixes #15262
Closes #15282
This commit is contained in:
Daniel Stenberg 2024-10-12 23:54:39 +02:00
parent eb77297ccc
commit 9bee39bfed
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
6 changed files with 257 additions and 73 deletions

View file

@ -679,6 +679,9 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
}
if(data->set.str[STRING_USERNAME] ||
data->set.str[STRING_PASSWORD])
data->state.creds_from = CREDS_OPTION;
if(!result)
result = Curl_setstropt(&data->state.aptr.user,
data->set.str[STRING_USERNAME]);

View file

@ -1860,10 +1860,10 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return result;
/*
* username and password set with their own options override the
* credentials possibly set in the URL.
* username and password set with their own options override the credentials
* possibly set in the URL, but netrc does not.
*/
if(!data->set.str[STRING_PASSWORD]) {
if(!data->state.aptr.passwd || (data->state.creds_from != CREDS_OPTION)) {
uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
if(!uc) {
char *decoded;
@ -1876,12 +1876,13 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
result = Curl_setstropt(&data->state.aptr.passwd, decoded);
if(result)
return result;
data->state.creds_from = CREDS_URL;
}
else if(uc != CURLUE_NO_PASSWORD)
return Curl_uc_to_curlcode(uc);
}
if(!data->set.str[STRING_USERNAME]) {
if(!data->state.aptr.user || (data->state.creds_from != CREDS_OPTION)) {
/* we do not 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 */
@ -1895,13 +1896,10 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return result;
conn->user = decoded;
result = Curl_setstropt(&data->state.aptr.user, decoded);
data->state.creds_from = CREDS_URL;
}
else if(uc != CURLUE_NO_USER)
return Curl_uc_to_curlcode(uc);
else if(data->state.aptr.passwd) {
/* no user was set but a password, set a blank user */
result = Curl_setstropt(&data->state.aptr.user, "");
}
if(result)
return result;
}
@ -2685,7 +2683,8 @@ static CURLcode override_login(struct Curl_easy *data,
int ret;
bool url_provided = FALSE;
if(data->state.aptr.user) {
if(data->state.aptr.user &&
(data->state.creds_from != CREDS_NETRC)) {
/* there was a username in the URL. Use the URL decoded version */
userp = &data->state.aptr.user;
url_provided = TRUE;
@ -2733,6 +2732,7 @@ static CURLcode override_login(struct Curl_easy *data,
result = Curl_setstropt(&data->state.aptr.user, *userp);
if(result)
return result;
data->state.creds_from = CREDS_NETRC;
}
}
if(data->state.aptr.user) {
@ -2750,6 +2750,7 @@ static CURLcode override_login(struct Curl_easy *data,
CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
if(result)
return result;
data->state.creds_from = CREDS_NETRC;
}
if(data->state.aptr.passwd) {
uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,

View file

@ -1206,6 +1206,11 @@ struct urlpieces {
char *query;
};
#define CREDS_NONE 0
#define CREDS_URL 1 /* from URL */
#define CREDS_OPTION 2 /* set with a CURLOPT_ */
#define CREDS_NETRC 3 /* found in netrc */
struct UrlState {
/* buffers to store authentication data in, as parsed from input options */
struct curltime keeps_speed; /* for the progress meter really */
@ -1344,7 +1349,6 @@ struct UrlState {
char *proxypasswd;
#endif
} aptr;
unsigned char httpwant; /* when non-zero, a specific HTTP version requested
to be used in the library's request(s) */
unsigned char httpversion; /* the lowest HTTP version*10 reported by any
@ -1354,6 +1358,9 @@ struct UrlState {
unsigned char select_bits; /* != 0 -> bitmask of socket events for this
transfer overriding anything the socket may
report */
unsigned int creds_from:2; /* where is the server credentials originating
from, see the CREDS_* defines above */
/* when curl_easy_perform() is called, the multi handle is "owned" by
the easy handle so curl_easy_cleanup() on such an easy handle will
also close the multi handle! */