creds: hold credentials

Authorizdation credentials are kept in `struct Curl_creds`. This contains:

* `user`: the username, maybe the empty string
* `passwd`: the password, maybe the empty string
* `sasl_authzid`: the SASL authz value, maybe the empty string
* `oauth_bearer`: the OAUTH bearer token, maybe the empty string
* `source`: where the credentials from from
* `refcount`: a reference counter to link/unkink creds

A `creds` with all values empty is equivalent to NULL, e.g. no `creds`
instance. With reference counting, `creds` can be linked/unlinked
in several places.

See docs/internals/CREDENTIALS.md for use.

Closes #21548
This commit is contained in:
Stefan Eissing 2026-05-11 14:25:52 +02:00 committed by Daniel Stenberg
parent a32a2b0b77
commit 8f71d0fde5
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
47 changed files with 1138 additions and 962 deletions

View file

@ -53,6 +53,7 @@ INTERNALDOCS = \
internals/CLIENT-WRITERS.md \ internals/CLIENT-WRITERS.md \
internals/CODE_STYLE.md \ internals/CODE_STYLE.md \
internals/CONNECTION-FILTERS.md \ internals/CONNECTION-FILTERS.md \
internals/CREDENTIALS.md \
internals/CURLX.md \ internals/CURLX.md \
internals/DYNBUF.md \ internals/DYNBUF.md \
internals/HASH.md \ internals/HASH.md \

View file

@ -0,0 +1,75 @@
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
-->
# curl `creds`
Authorization credentials are kept in `struct Curl_creds`. This contains:
* `user`: the username, maybe the empty string
* `passwd`: the password, maybe the empty string
* `sasl_authzid`: the SASL `authz` value, maybe the empty string
* `oauth_bearer`: the OAUTH bearer token, maybe the empty string
* `source`: where the credentials from
* `refcount`: a reference counter to link/unlink `creds`
A `creds` with all values empty is equivalent to NULL, e.g. no `creds`
instance. With reference counting, `creds` can be linked in several places.
Two `creds` are the same if all values are equal apart from `source`
and `refcount`. The comparison of strings is done via `Curl_timestrcmp()`
to prevent side channel attacks.
## `creds` locations
Credentials are kept in three places:
* `data->state.creds`: the credentials to use for the transfer in talking
to the `origin` (see PEERS)
* `conn->creds`: the credentials tied to a connection (more below)
* `conn->*_proxy.creds`: credentials used to talk to the `conn->*_proxy.peer`
### `data->state.creds`
This `creds` instance is created when the transfer starts looking for a
suitable connection. For an `easy_perform()` this may happen several times
if, for example, http redirects are followed.
When an `easy_perform()` starts, the transfer's `data->state.initial_origin`
peer is cleared. When creating the connection, `conn->origin` is calculated
(e.g. who the request talks to). If `data->state.initial_origin` is not
set, the first `conn->origin` is linked there. Now `libcurl` knows where
the transfer initially talked to on all possible subsequent requests.
Credential information from `CURLOPT_*` settings is only applicable for the
initial origin. Any followup request going to another origin must not
use it. Therefore `data->state.creds` is *only* created from `CURLOPT_*`
when current origin and initial origin match.
Without credentials from `CURLOPT_*`, the URL is inspected for user and
password and `netrc` is consulted as well (when built in).
### `conn->creds`
Once `data->state.creds` is known, the connection credentials are
determined. For protocols that tie authorization to everything send
on a connection (protocols without flag `PROTOPT_CREDSPERREQUEST`),
`conn->creds` is linked to `data->state.creds`. Only connections
carrying the same credentials may be reused.
Protocol with flag `PROTOPT_CREDSPERREQUEST` leave `conn->creds` empty,
as connections for such protocols may be reused with different
credentials.
That being said, there are authentication schemes like `NTLM` and
`NEGOTIATE` that tie credentials to a connection. Those do set `conn->creds`
once they start to operate, preventing connection reuse from then on
for transfers with different credentials.
### `conn->*_proxy.creds`
Those are set during connection setup from the `CURLOPT_*` values. They
do not require any "initial origin" handling as the origin of a proxy
does not change for a transfer.

View file

@ -161,6 +161,7 @@ LIB_CFILES = \
connect.c \ connect.c \
content_encoding.c \ content_encoding.c \
cookie.c \ cookie.c \
creds.c \
cshutdn.c \ cshutdn.c \
curl_addrinfo.c \ curl_addrinfo.c \
curl_endian.c \ curl_endian.c \
@ -293,6 +294,7 @@ LIB_HFILES = \
connect.h \ connect.h \
content_encoding.h \ content_encoding.h \
cookie.h \ cookie.h \
creds.h \
curl_addrinfo.h \ curl_addrinfo.h \
curl_ctype.h \ curl_ctype.h \
curl_endian.h \ curl_endian.h \

View file

@ -387,8 +387,7 @@ connect_sub_chain:
result = Curl_cf_socks_proxy_insert_after( result = Curl_cf_socks_proxy_insert_after(
cf, data, dest, cf->conn->ip_version, cf, data, dest, cf->conn->ip_version,
cf->conn->socks_proxy.proxytype, cf->conn->socks_proxy.proxytype,
cf->conn->socks_proxy.user, cf->conn->socks_proxy.creds);
cf->conn->socks_proxy.passwd);
CURL_TRC_CF(data, cf, "added SOCKS filter to %s:%u -> %d", CURL_TRC_CF(data, cf, "added SOCKS filter to %s:%u -> %d",
dest->hostname, dest->port, result); dest->hostname, dest->port, result);

183
lib/creds.c Normal file
View file

@ -0,0 +1,183 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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.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.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "curl_setup.h"
#include <stddef.h> /* for offsetof() */
#include "creds.h"
#include "curl_trc.h"
#include "strcase.h"
#include "urldata.h"
CURLcode Curl_creds_create(const char *user,
const char *passwd,
const char *sasl_authzid,
const char *oauth_bearer,
uint8_t source,
struct Curl_creds **pcreds)
{
struct Curl_creds *creds = NULL;
size_t ulen = user ? strlen(user) : 0;
size_t plen = passwd ? strlen(passwd) : 0;
size_t salen = sasl_authzid ? strlen(sasl_authzid) : 0;
size_t olen = oauth_bearer ? strlen(oauth_bearer) : 0;
char *s, *buf;
CURLcode result = CURLE_OK;
Curl_creds_unlink(pcreds);
/* Everything empty/NULL, this is the NULL credential */
if(!ulen && !plen && !salen && !olen)
goto out;
if((ulen > CURL_MAX_INPUT_LENGTH) ||
(plen > CURL_MAX_INPUT_LENGTH) ||
(salen > CURL_MAX_INPUT_LENGTH) ||
(olen > CURL_MAX_INPUT_LENGTH)) {
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto out;
}
/* NUL terminator for user already part of struct */
creds = curlx_calloc(1, sizeof(*creds) +
ulen + plen + 1 + salen + 1 + olen + 1);
if(!creds) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
creds->refcount = 1;
creds->source = source;
/* Some compilers try to be too smart about our dynamic struct size */
buf = ((char *)creds) + offsetof(struct Curl_creds, buf);
creds->user = s = buf;
if(ulen)
memcpy(s, CURL_UNCONST(user), ulen + 1);
creds->passwd = s = buf + ulen + 1;
if(plen)
memcpy(s, CURL_UNCONST(passwd), plen + 1);
creds->sasl_authzid = s = buf + ulen + 1 + plen + 1;
if(salen)
memcpy(s, CURL_UNCONST(sasl_authzid), salen + 1);
creds->oauth_bearer = s = buf + ulen + 1 + plen + 1 + salen + 1;
if(olen)
memcpy(s, CURL_UNCONST(oauth_bearer), olen + 1);
out:
if(!result)
*pcreds = creds;
else
Curl_creds_unlink(&creds);
return result;
}
CURLcode Curl_creds_merge(const char *user,
const char *passwd,
struct Curl_creds *creds_in,
uint8_t source,
struct Curl_creds **pcreds_out)
{
struct Curl_creds *creds_out = NULL;
CURLcode result;
if(!user || !user[0])
user = Curl_creds_user(creds_in);
if(!passwd || !passwd[0])
passwd = Curl_creds_passwd(creds_in);
result = Curl_creds_create(user, passwd,
Curl_creds_sasl_authzid(creds_in),
Curl_creds_oauth_bearer(creds_in),
source, &creds_out);
Curl_creds_link(pcreds_out, creds_out);
Curl_creds_unlink(&creds_out);
return result;
}
void Curl_creds_link(struct Curl_creds **pdest, struct Curl_creds *src)
{
if(*pdest != src) {
Curl_creds_unlink(pdest);
*pdest = src;
if(src) {
DEBUGASSERT(src->refcount < UINT32_MAX);
src->refcount++;
}
}
}
void Curl_creds_unlink(struct Curl_creds **pcreds)
{
if(*pcreds) {
struct Curl_creds *creds = *pcreds;
DEBUGASSERT(creds->refcount);
*pcreds = NULL;
if(creds->refcount)
creds->refcount--;
if(!creds->refcount) {
curlx_free(creds);
}
}
}
bool Curl_creds_same_user(struct Curl_creds *creds, const char *user)
{
return creds && !Curl_timestrcmp(creds->user, user);
}
bool Curl_creds_same_passwd(struct Curl_creds *creds, const char *passwd)
{
return creds && !Curl_timestrcmp(creds->passwd, passwd);
}
bool Curl_creds_same(struct Curl_creds *c1, struct Curl_creds *c2)
{
return (c1 == c2) ||
(c1 && c2 &&
!Curl_timestrcmp(c1->user, c2->user) &&
!Curl_timestrcmp(c1->passwd, c2->passwd) &&
!Curl_timestrcmp(c1->sasl_authzid, c2->sasl_authzid) &&
!Curl_timestrcmp(c1->oauth_bearer, c2->oauth_bearer));
}
#ifdef CURLVERBOSE
void Curl_creds_trace(struct Curl_easy *data, struct Curl_creds *creds,
const char *msg)
{
if(creds) {
CURL_TRC_M(data, "%s: user=%s, passwd=%s, "
"sasl_authzid=%s, oauth_bearer=%s, source=%d",
msg,
Curl_creds_user(creds),
Curl_creds_has_passwd(creds) ? "***" : "",
Curl_creds_sasl_authzid(creds),
Curl_creds_oauth_bearer(creds),
creds->source);
}
else
CURL_TRC_M(data, "%s: -", msg);
}
#endif

86
lib/creds.h Normal file
View file

@ -0,0 +1,86 @@
#ifndef HEADER_CURL_CREDS_H
#define HEADER_CURL_CREDS_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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.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.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
struct Curl_easy;
#define CREDS_NONE 0 /* used for default username/passwd */
#define CREDS_URL 1 /* username/passwd from URL */
#define CREDS_OPTION 2 /* username/passwd set with a CURLOPT_ */
#define CREDS_NETRC 3 /* username/passwd found in netrc */
struct Curl_creds {
const char *user; /* non-NULL, maybe empty string */
const char *passwd; /* non-NULL, maybe empty string */
const char *sasl_authzid; /* non-NULL, maybe empty string */
const char *oauth_bearer; /* non-NULL, maybe empty string */
uint32_t refcount;
uint8_t source; /* CREDS_* value */
char buf[1];
};
CURLcode Curl_creds_create(const char *user,
const char *passwd,
const char *sasl_authzid,
const char *oauth_bearer,
uint8_t source,
struct Curl_creds **pcreds);
/* Create credentials by overriding `user` and/or `passwd` in `creds_in` */
CURLcode Curl_creds_merge(const char *user,
const char *passwd,
struct Curl_creds *creds_in,
uint8_t source,
struct Curl_creds **pcreds_out);
/* Unlink any creds in `*pdest`, assign src, increase src
* refcount when not NULL. */
void Curl_creds_link(struct Curl_creds **pdest, struct Curl_creds *src);
/* Drop a reference, creds may be passed as NULL */
void Curl_creds_unlink(struct Curl_creds **pcreds);
/* TRUE if both creds are NULL or have same username and password. */
bool Curl_creds_same(struct Curl_creds *c1, struct Curl_creds *c2);
bool Curl_creds_same_user(struct Curl_creds *creds, const char *user);
bool Curl_creds_same_passwd(struct Curl_creds *creds, const char *passwd);
/* Provides properties for creds or, if creds is NULL, the empty string */
#define Curl_creds_has_user(c) ((c) && (c)->user[0])
#define Curl_creds_has_passwd(c) ((c) && (c)->passwd[0])
#define Curl_creds_has_oauth_bearer(c) ((c) && (c)->oauth_bearer[0])
#define Curl_creds_user(c) ((c)? (c)->user : "")
#define Curl_creds_passwd(c) ((c)? (c)->passwd : "")
#define Curl_creds_sasl_authzid(c) ((c)? (c)->sasl_authzid : "")
#define Curl_creds_oauth_bearer(c) ((c)? (c)->oauth_bearer : "")
#ifdef CURLVERBOSE
void Curl_creds_trace(struct Curl_easy *data, struct Curl_creds *creds,
const char *msg);
#endif
#endif /* HEADER_CURL_CREDS_H */

View file

@ -276,7 +276,7 @@ static CURLcode build_message(struct SASL *sasl, struct bufref *msg)
bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data) bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
{ {
/* Have credentials been provided? */ /* Have credentials been provided? */
if(data->conn->user[0]) if(data->conn->creds)
return TRUE; return TRUE;
/* EXTERNAL can authenticate without a username and/or password */ /* EXTERNAL can authenticate without a username and/or password */
@ -299,13 +299,15 @@ struct sasl_ctx {
static bool sasl_choose_external(struct Curl_easy *data, struct sasl_ctx *sctx) static bool sasl_choose_external(struct Curl_easy *data, struct sasl_ctx *sctx)
{ {
if((sctx->enabledmechs & SASL_MECH_EXTERNAL) && !sctx->conn->passwd[0]) { if((sctx->enabledmechs & SASL_MECH_EXTERNAL) &&
!Curl_creds_has_passwd(sctx->conn->creds)) {
sctx->mech = SASL_MECH_STRING_EXTERNAL; sctx->mech = SASL_MECH_STRING_EXTERNAL;
sctx->state1 = SASL_EXTERNAL; sctx->state1 = SASL_EXTERNAL;
sctx->sasl->authused = SASL_MECH_EXTERNAL; sctx->sasl->authused = SASL_MECH_EXTERNAL;
if(sctx->sasl->force_ir || data->set.sasl_ir) if(sctx->sasl->force_ir || data->set.sasl_ir)
Curl_auth_create_external_message(sctx->conn->user, &sctx->resp); Curl_auth_create_external_message(
Curl_creds_user(sctx->conn->creds), &sctx->resp);
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
@ -316,7 +318,7 @@ static bool sasl_choose_krb5(struct Curl_easy *data, struct sasl_ctx *sctx)
{ {
if((sctx->enabledmechs & SASL_MECH_GSSAPI) && if((sctx->enabledmechs & SASL_MECH_GSSAPI) &&
Curl_auth_is_gssapi_supported() && Curl_auth_is_gssapi_supported() &&
Curl_auth_user_contains_domain(sctx->conn->user)) { Curl_auth_user_contains_domain(sctx->conn->creds)) {
const char *service = data->set.str[STRING_SERVICE_NAME] ? const char *service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] : data->set.str[STRING_SERVICE_NAME] :
sctx->sasl->params->service; sctx->sasl->params->service;
@ -330,8 +332,7 @@ static bool sasl_choose_krb5(struct Curl_easy *data, struct sasl_ctx *sctx)
if(sctx->sasl->force_ir || data->set.sasl_ir) { if(sctx->sasl->force_ir || data->set.sasl_ir) {
struct kerberos5data *krb5 = Curl_auth_krb5_get(sctx->conn); struct kerberos5data *krb5 = Curl_auth_krb5_get(sctx->conn);
sctx->result = !krb5 ? CURLE_OUT_OF_MEMORY : sctx->result = !krb5 ? CURLE_OUT_OF_MEMORY :
Curl_auth_create_gssapi_user_message(data, sctx->conn->user, Curl_auth_create_gssapi_user_message(data, sctx->conn->creds,
sctx->conn->passwd,
service, service,
sctx->conn->origin->hostname, sctx->conn->origin->hostname,
(bool)sctx->sasl->mutual_auth, (bool)sctx->sasl->mutual_auth,
@ -375,8 +376,7 @@ static bool sasl_choose_gsasl(struct Curl_easy *data, struct sasl_ctx *sctx)
Curl_bufref_init(&nullmsg); Curl_bufref_init(&nullmsg);
sctx->state1 = SASL_GSASL; sctx->state1 = SASL_GSASL;
sctx->state2 = SASL_GSASL; sctx->state2 = SASL_GSASL;
sctx->result = Curl_auth_gsasl_start(data, sctx->conn->user, sctx->result = Curl_auth_gsasl_start(data, sctx->conn->creds, gsasl);
sctx->conn->passwd, gsasl);
if(!sctx->result && (sctx->sasl->force_ir || data->set.sasl_ir)) if(!sctx->result && (sctx->sasl->force_ir || data->set.sasl_ir))
sctx->result = Curl_auth_gsasl_token(data, &nullmsg, gsasl, &sctx->resp); sctx->result = Curl_auth_gsasl_token(data, &nullmsg, gsasl, &sctx->resp);
return TRUE; return TRUE;
@ -427,9 +427,7 @@ static bool sasl_choose_ntlm(struct Curl_easy *data, struct sasl_ctx *sctx)
if(sctx->sasl->force_ir || data->set.sasl_ir) { if(sctx->sasl->force_ir || data->set.sasl_ir) {
struct ntlmdata *ntlm = Curl_auth_ntlm_get(sctx->conn, FALSE); struct ntlmdata *ntlm = Curl_auth_ntlm_get(sctx->conn, FALSE);
sctx->result = !ntlm ? CURLE_OUT_OF_MEMORY : sctx->result = !ntlm ? CURLE_OUT_OF_MEMORY :
Curl_auth_create_ntlm_type1_message(data, Curl_auth_create_ntlm_type1_message(data, sctx->conn->creds,
sctx->conn->user,
sctx->conn->passwd,
service, hostname, service, hostname,
ntlm, &sctx->resp); ntlm, &sctx->resp);
} }
@ -441,11 +439,8 @@ static bool sasl_choose_ntlm(struct Curl_easy *data, struct sasl_ctx *sctx)
static bool sasl_choose_oauth(struct Curl_easy *data, struct sasl_ctx *sctx) static bool sasl_choose_oauth(struct Curl_easy *data, struct sasl_ctx *sctx)
{ {
const char *oauth_bearer = if(Curl_creds_has_oauth_bearer(data->state.creds) &&
(!data->state.this_is_a_follow || data->set.allow_auth_to_other_hosts) ? (sctx->enabledmechs & SASL_MECH_OAUTHBEARER)) {
data->set.str[STRING_BEARER] : NULL;
if(oauth_bearer && (sctx->enabledmechs & SASL_MECH_OAUTHBEARER)) {
const char *hostname; const char *hostname;
int port; int port;
Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port); Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port);
@ -457,9 +452,8 @@ static bool sasl_choose_oauth(struct Curl_easy *data, struct sasl_ctx *sctx)
if(sctx->sasl->force_ir || data->set.sasl_ir) if(sctx->sasl->force_ir || data->set.sasl_ir)
sctx->result = sctx->result =
Curl_auth_create_oauth_bearer_message(sctx->conn->user, Curl_auth_create_oauth_bearer_message(sctx->conn->creds,
hostname, port, hostname, port, &sctx->resp);
oauth_bearer, &sctx->resp);
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
@ -467,19 +461,15 @@ static bool sasl_choose_oauth(struct Curl_easy *data, struct sasl_ctx *sctx)
static bool sasl_choose_oauth2(struct Curl_easy *data, struct sasl_ctx *sctx) static bool sasl_choose_oauth2(struct Curl_easy *data, struct sasl_ctx *sctx)
{ {
const char *oauth_bearer = if(Curl_creds_has_oauth_bearer(sctx->conn->creds) &&
(!data->state.this_is_a_follow || data->set.allow_auth_to_other_hosts) ? (sctx->enabledmechs & SASL_MECH_XOAUTH2)) {
data->set.str[STRING_BEARER] : NULL;
if(oauth_bearer && (sctx->enabledmechs & SASL_MECH_XOAUTH2)) {
sctx->mech = SASL_MECH_STRING_XOAUTH2; sctx->mech = SASL_MECH_STRING_XOAUTH2;
sctx->state1 = SASL_OAUTH2; sctx->state1 = SASL_OAUTH2;
sctx->sasl->authused = SASL_MECH_XOAUTH2; sctx->sasl->authused = SASL_MECH_XOAUTH2;
if(sctx->sasl->force_ir || data->set.sasl_ir) if(sctx->sasl->force_ir || data->set.sasl_ir)
sctx->result = Curl_auth_create_xoauth_bearer_message(sctx->conn->user, sctx->result = Curl_auth_create_xoauth_bearer_message(
oauth_bearer, sctx->conn->creds, &sctx->resp);
&sctx->resp);
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
@ -494,9 +484,7 @@ static bool sasl_choose_plain(struct Curl_easy *data, struct sasl_ctx *sctx)
if(sctx->sasl->force_ir || data->set.sasl_ir) if(sctx->sasl->force_ir || data->set.sasl_ir)
sctx->result = sctx->result =
Curl_auth_create_plain_message(sctx->conn->sasl_authzid, Curl_auth_create_plain_message(sctx->conn->creds, &sctx->resp);
sctx->conn->user, sctx->conn->passwd,
&sctx->resp);
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
@ -511,7 +499,8 @@ static bool sasl_choose_login(struct Curl_easy *data, struct sasl_ctx *sctx)
sctx->sasl->authused = SASL_MECH_LOGIN; sctx->sasl->authused = SASL_MECH_LOGIN;
if(sctx->sasl->force_ir || data->set.sasl_ir) if(sctx->sasl->force_ir || data->set.sasl_ir)
Curl_auth_create_login_message(sctx->conn->user, &sctx->resp); Curl_auth_create_login_message(
Curl_creds_user(sctx->conn->creds), &sctx->resp);
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
@ -606,7 +595,6 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
data->set.str[STRING_SERVICE_NAME] : data->set.str[STRING_SERVICE_NAME] :
sasl->params->service; sasl->params->service;
#endif #endif
const char *oauth_bearer = data->set.str[STRING_BEARER];
struct bufref serverdata; struct bufref serverdata;
Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port); Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port);
@ -634,18 +622,17 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
*progress = SASL_DONE; *progress = SASL_DONE;
return result; return result;
case SASL_PLAIN: case SASL_PLAIN:
result = Curl_auth_create_plain_message(conn->sasl_authzid, result = Curl_auth_create_plain_message(conn->creds, &resp);
conn->user, conn->passwd, &resp);
break; break;
case SASL_LOGIN: case SASL_LOGIN:
Curl_auth_create_login_message(conn->user, &resp); Curl_auth_create_login_message(Curl_creds_user(conn->creds), &resp);
newstate = SASL_LOGIN_PASSWD; newstate = SASL_LOGIN_PASSWD;
break; break;
case SASL_LOGIN_PASSWD: case SASL_LOGIN_PASSWD:
Curl_auth_create_login_message(conn->passwd, &resp); Curl_auth_create_login_message(Curl_creds_passwd(conn->creds), &resp);
break; break;
case SASL_EXTERNAL: case SASL_EXTERNAL:
Curl_auth_create_external_message(conn->user, &resp); Curl_auth_create_external_message(Curl_creds_user(conn->creds), &resp);
break; break;
#ifdef USE_GSASL #ifdef USE_GSASL
case SASL_GSASL: case SASL_GSASL:
@ -663,15 +650,15 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
case SASL_CRAMMD5: case SASL_CRAMMD5:
result = get_server_message(sasl, data, &serverdata); result = get_server_message(sasl, data, &serverdata);
if(!result) if(!result)
result = Curl_auth_create_cram_md5_message(&serverdata, conn->user, result = Curl_auth_create_cram_md5_message(&serverdata, conn->creds,
conn->passwd, &resp); &resp);
break; break;
case SASL_DIGESTMD5: case SASL_DIGESTMD5:
result = get_server_message(sasl, data, &serverdata); result = get_server_message(sasl, data, &serverdata);
if(!result) if(!result)
result = Curl_auth_create_digest_md5_message(data, &serverdata, result = Curl_auth_create_digest_md5_message(data, &serverdata,
conn->user, conn->passwd, conn->creds, service,
service, &resp); &resp);
if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) if(!result && (sasl->params->flags & SASL_FLAG_BASE64))
newstate = SASL_DIGESTMD5_RESP; newstate = SASL_DIGESTMD5_RESP;
break; break;
@ -685,8 +672,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
/* Create the type-1 message */ /* Create the type-1 message */
struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, FALSE); struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, FALSE);
result = !ntlm ? CURLE_OUT_OF_MEMORY : result = !ntlm ? CURLE_OUT_OF_MEMORY :
Curl_auth_create_ntlm_type1_message(data, Curl_auth_create_ntlm_type1_message(data, conn->creds,
conn->user, conn->passwd,
service, hostname, service, hostname,
ntlm, &resp); ntlm, &resp);
newstate = SASL_NTLM_TYPE2MSG; newstate = SASL_NTLM_TYPE2MSG;
@ -700,9 +686,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
if(!result) if(!result)
result = Curl_auth_decode_ntlm_type2_message(data, &serverdata, ntlm); result = Curl_auth_decode_ntlm_type2_message(data, &serverdata, ntlm);
if(!result) if(!result)
result = Curl_auth_create_ntlm_type3_message(data, conn->user, result = Curl_auth_create_ntlm_type3_message(data, conn->creds,
conn->passwd, ntlm, ntlm, &resp);
&resp);
break; break;
} }
#endif #endif
@ -711,7 +696,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
case SASL_GSSAPI: { case SASL_GSSAPI: {
struct kerberos5data *krb5 = Curl_auth_krb5_get(conn); struct kerberos5data *krb5 = Curl_auth_krb5_get(conn);
result = !krb5 ? CURLE_OUT_OF_MEMORY : result = !krb5 ? CURLE_OUT_OF_MEMORY :
Curl_auth_create_gssapi_user_message(data, conn->user, conn->passwd, Curl_auth_create_gssapi_user_message(data, conn->creds,
service, conn->origin->hostname, service, conn->origin->hostname,
(bool)sasl->mutual_auth, NULL, (bool)sasl->mutual_auth, NULL,
krb5, &resp); krb5, &resp);
@ -727,7 +712,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
else if(sasl->mutual_auth) { else if(sasl->mutual_auth) {
/* Decode the user token challenge and create the optional response /* Decode the user token challenge and create the optional response
message */ message */
result = Curl_auth_create_gssapi_user_message(data, NULL, NULL, result = Curl_auth_create_gssapi_user_message(data, NULL,
NULL, NULL, NULL, NULL,
(bool)sasl->mutual_auth, (bool)sasl->mutual_auth,
&serverdata, &serverdata,
@ -736,10 +721,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
} }
else else
/* Decode the security challenge and create the response message */ /* Decode the security challenge and create the response message */
result = Curl_auth_create_gssapi_security_message(data, result = Curl_auth_create_gssapi_security_message(
conn->sasl_authzid, data, Curl_creds_sasl_authzid(conn->creds), &serverdata,
&serverdata, krb5, &resp);
krb5, &resp);
} }
break; break;
case SASL_GSSAPI_NO_DATA: case SASL_GSSAPI_NO_DATA:
@ -750,10 +734,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
if(!krb5) if(!krb5)
result = CURLE_OUT_OF_MEMORY; result = CURLE_OUT_OF_MEMORY;
else else
result = Curl_auth_create_gssapi_security_message(data, result = Curl_auth_create_gssapi_security_message(
conn->sasl_authzid, data, Curl_creds_sasl_authzid(conn->creds), &serverdata,
&serverdata, krb5, &resp);
krb5, &resp);
} }
break; break;
#endif #endif
@ -761,18 +744,16 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
case SASL_OAUTH2: case SASL_OAUTH2:
/* Create the authorization message */ /* Create the authorization message */
if(sasl->authused == SASL_MECH_OAUTHBEARER) { if(sasl->authused == SASL_MECH_OAUTHBEARER) {
result = Curl_auth_create_oauth_bearer_message(conn->user, result = Curl_auth_create_oauth_bearer_message(conn->creds,
hostname, hostname,
port, port,
oauth_bearer,
&resp); &resp);
/* Failures maybe sent by the server as continuations for OAUTHBEARER */ /* Failures maybe sent by the server as continuations for OAUTHBEARER */
newstate = SASL_OAUTH2_RESP; newstate = SASL_OAUTH2_RESP;
} }
else else
result = Curl_auth_create_xoauth_bearer_message(conn->user, result = Curl_auth_create_xoauth_bearer_message(conn->creds,
oauth_bearer,
&resp); &resp);
break; break;
@ -862,7 +843,7 @@ static void sasl_unchosen(struct Curl_easy *data, unsigned short mech,
else { else {
if(param_missing) if(param_missing)
infof(data, "SASL: %s is missing %s", mname, param_missing); infof(data, "SASL: %s is missing %s", mname, param_missing);
if(!data->conn->user[0]) if(!Curl_creds_has_user(data->conn->creds))
infof(data, "SASL: %s is missing username", mname); infof(data, "SASL: %s is missing username", mname);
} }
} }
@ -904,7 +885,8 @@ CURLcode Curl_sasl_is_blocked(struct SASL *sasl, struct Curl_easy *data)
"auth mechanisms"); "auth mechanisms");
else { else {
infof(data, "SASL: no auth mechanism offered could be selected"); infof(data, "SASL: no auth mechanism offered could be selected");
if((enabledmechs & SASL_MECH_EXTERNAL) && data->conn->passwd[0]) if((enabledmechs & SASL_MECH_EXTERNAL) &&
Curl_creds_has_passwd(data->conn->creds))
infof(data, "SASL: auth EXTERNAL not chosen with password"); infof(data, "SASL: auth EXTERNAL not chosen with password");
sasl_unchosen(data, SASL_MECH_GSSAPI, enabledmechs, sasl_unchosen(data, SASL_MECH_GSSAPI, enabledmechs,
CURL_SASL_KERBEROS5, Curl_auth_is_gssapi_supported(), NULL); CURL_SASL_KERBEROS5, Curl_auth_is_gssapi_supported(), NULL);
@ -919,10 +901,10 @@ CURLcode Curl_sasl_is_blocked(struct SASL *sasl, struct Curl_easy *data)
sasl_unchosen(data, SASL_MECH_NTLM, enabledmechs, sasl_unchosen(data, SASL_MECH_NTLM, enabledmechs,
CURL_SASL_NTLM, Curl_auth_is_ntlm_supported(), NULL); CURL_SASL_NTLM, Curl_auth_is_ntlm_supported(), NULL);
sasl_unchosen(data, SASL_MECH_OAUTHBEARER, enabledmechs, TRUE, TRUE, sasl_unchosen(data, SASL_MECH_OAUTHBEARER, enabledmechs, TRUE, TRUE,
data->set.str[STRING_BEARER] ? Curl_creds_has_oauth_bearer(data->conn->creds) ?
NULL : "CURLOPT_XOAUTH2_BEARER"); NULL : "CURLOPT_XOAUTH2_BEARER");
sasl_unchosen(data, SASL_MECH_XOAUTH2, enabledmechs, TRUE, TRUE, sasl_unchosen(data, SASL_MECH_XOAUTH2, enabledmechs, TRUE, TRUE,
data->set.str[STRING_BEARER] ? Curl_creds_has_oauth_bearer(data->conn->creds) ?
NULL : "CURLOPT_XOAUTH2_BEARER"); NULL : "CURLOPT_XOAUTH2_BEARER");
} }
#endif /* CURLVERBOSE */ #endif /* CURLVERBOSE */

View file

@ -743,7 +743,7 @@ static CURLcode ftp_state_user(struct Curl_easy *data,
struct connectdata *conn) struct connectdata *conn)
{ {
CURLcode result = Curl_pp_sendf(data, &ftpc->pp, "USER %s", CURLcode result = Curl_pp_sendf(data, &ftpc->pp, "USER %s",
conn->user ? conn->user : ""); Curl_creds_user(conn->creds));
if(!result) { if(!result) {
ftpc->ftp_trying_alternative = FALSE; ftpc->ftp_trying_alternative = FALSE;
ftp_state(data, ftpc, FTP_USER); ftp_state(data, ftpc, FTP_USER);
@ -2941,7 +2941,8 @@ static CURLcode ftp_state_user_resp(struct Curl_easy *data,
if((ftpcode == 331) && (ftpc->state == FTP_USER)) { if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
/* 331 Password required for ... /* 331 Password required for ...
(the server requires to send the user's password too) */ (the server requires to send the user's password too) */
result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s", data->conn->passwd); result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s",
Curl_creds_passwd(data->conn->creds));
if(!result) if(!result)
ftp_state(data, ftpc, FTP_PASS); ftp_state(data, ftpc, FTP_PASS);
} }

View file

@ -250,14 +250,14 @@ char *Curl_copy_header_value(const char *header)
* *
* Returns CURLcode. * Returns CURLcode.
*/ */
static CURLcode http_output_basic(struct Curl_easy *data, bool proxy) static CURLcode http_output_basic(struct Curl_easy *data,
struct connectdata *conn, bool proxy)
{ {
size_t size = 0; size_t size = 0;
char *authorization = NULL; char *authorization = NULL;
char **p_hd; char **p_hd;
const char *user;
const char *pwd;
CURLcode result; CURLcode result;
struct Curl_creds *creds = NULL;
char *out; char *out;
/* credentials are unique per transfer for HTTP, do not use the ones for the /* credentials are unique per transfer for HTTP, do not use the ones for the
@ -265,19 +265,23 @@ static CURLcode http_output_basic(struct Curl_easy *data, bool proxy)
if(proxy) { if(proxy) {
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
p_hd = &data->req.hd_proxy_auth; p_hd = &data->req.hd_proxy_auth;
user = data->state.aptr.proxyuser; creds = conn->http_proxy.creds;
pwd = data->state.aptr.proxypasswd;
#else #else
(void)conn;
return CURLE_NOT_BUILT_IN; return CURLE_NOT_BUILT_IN;
#endif #endif
} }
else { else {
p_hd = &data->req.hd_auth; p_hd = &data->req.hd_auth;
user = data->state.aptr.user; creds = data->state.creds;
pwd = data->state.aptr.passwd;
} }
out = curl_maprintf("%s:%s", user ? user : "", pwd ? pwd : ""); if(!creds) {
DEBUGASSERT(0);
return CURLE_FAILED_INIT;
}
out = curl_maprintf("%s:%s", creds->user, creds->passwd);
if(!out) if(!out)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
@ -320,10 +324,11 @@ static CURLcode http_output_bearer(struct Curl_easy *data)
char **userp; char **userp;
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
DEBUGASSERT(Curl_creds_has_oauth_bearer(data->state.creds));
userp = &data->req.hd_auth; userp = &data->req.hd_auth;
curlx_free(*userp); curlx_free(*userp);
*userp = curl_maprintf("Authorization: Bearer %s\r\n", *userp = curl_maprintf("Authorization: Bearer %s\r\n",
data->set.str[STRING_BEARER]); Curl_creds_oauth_bearer(data->state.creds));
if(!*userp) { if(!*userp) {
result = CURLE_OUT_OF_MEMORY; result = CURLE_OUT_OF_MEMORY;
@ -527,10 +532,10 @@ static bool http_should_fail(struct Curl_easy *data, int httpcode)
* Either we are not authenticating, or we are supposed to be authenticating * Either we are not authenticating, or we are supposed to be authenticating
* something else. This is an error. * something else. This is an error.
*/ */
if((httpcode == 401) && !data->state.aptr.user) if((httpcode == 401) && !data->state.creds)
return TRUE; return TRUE;
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
if((httpcode == 407) && !data->conn->bits.proxy_user_passwd) if((httpcode == 407) && !data->conn->http_proxy.creds)
return TRUE; return TRUE;
#endif #endif
@ -551,7 +556,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
unsigned long authmask = ~0UL; unsigned long authmask = ~0UL;
if(!data->set.str[STRING_BEARER]) if(!Curl_creds_has_oauth_bearer(data->state.creds))
authmask &= (unsigned long)~CURLAUTH_BEARER; authmask &= (unsigned long)~CURLAUTH_BEARER;
if(100 <= data->req.httpcode && data->req.httpcode <= 199) if(100 <= data->req.httpcode && data->req.httpcode <= 199)
@ -561,7 +566,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
if(data->state.authproblem) if(data->state.authproblem)
return data->set.http_fail_on_error ? CURLE_HTTP_RETURNED_ERROR : CURLE_OK; return data->set.http_fail_on_error ? CURLE_HTTP_RETURNED_ERROR : CURLE_OK;
if((data->state.aptr.user || data->set.str[STRING_BEARER]) && if(data->state.creds &&
((data->req.httpcode == 401) || ((data->req.httpcode == 401) ||
(data->req.authneg && data->req.httpcode < 300))) { (data->req.authneg && data->req.httpcode < 300))) {
pickhost = pickoneauth(&data->state.authhost, authmask); pickhost = pickoneauth(&data->state.authhost, authmask);
@ -578,7 +583,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
} }
} }
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
if(conn->bits.proxy_user_passwd && if(conn->http_proxy.creds &&
((data->req.httpcode == 407) || ((data->req.httpcode == 407) ||
(data->req.authneg && data->req.httpcode < 300))) { (data->req.authneg && data->req.httpcode < 300))) {
pickproxy = pickoneauth(&data->state.authproxy, pickproxy = pickoneauth(&data->state.authproxy,
@ -694,14 +699,14 @@ static CURLcode output_auth_headers(struct Curl_easy *data,
/* Basic */ /* Basic */
if( if(
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
(proxy && conn->bits.proxy_user_passwd && (proxy && conn->http_proxy.creds &&
!Curl_checkProxyheaders(data, conn, !Curl_checkProxyheaders(data, conn,
STRCONST("Proxy-authorization"))) || STRCONST("Proxy-authorization"))) ||
#endif #endif
(!proxy && data->state.aptr.user && (!proxy && data->state.creds &&
!Curl_checkheaders(data, STRCONST("Authorization")))) { !Curl_checkheaders(data, STRCONST("Authorization")))) {
auth = "Basic"; auth = "Basic";
result = http_output_basic(data, proxy); result = http_output_basic(data, conn, proxy);
if(result) if(result)
return result; return result;
} }
@ -714,8 +719,7 @@ static CURLcode output_auth_headers(struct Curl_easy *data,
#ifndef CURL_DISABLE_BEARER_AUTH #ifndef CURL_DISABLE_BEARER_AUTH
if(authstatus->picked == CURLAUTH_BEARER) { if(authstatus->picked == CURLAUTH_BEARER) {
/* Bearer */ /* Bearer */
if(!proxy && data->set.str[STRING_BEARER] && if(!proxy && Curl_creds_has_oauth_bearer(data->state.creds) &&
Curl_auth_allowed_to_host(data) &&
!Curl_checkheaders(data, STRCONST("Authorization"))) { !Curl_checkheaders(data, STRCONST("Authorization"))) {
auth = "Bearer"; auth = "Bearer";
result = http_output_bearer(data); result = http_output_bearer(data);
@ -737,15 +741,15 @@ static CURLcode output_auth_headers(struct Curl_easy *data,
data->info.httpauthpicked = authstatus->picked; data->info.httpauthpicked = authstatus->picked;
infof(data, "%s auth using %s with user '%s'", infof(data, "%s auth using %s with user '%s'",
proxy ? "Proxy" : "Server", auth, proxy ? "Proxy" : "Server", auth,
proxy ? (data->state.aptr.proxyuser ? proxy ? (conn->http_proxy.creds ?
data->state.aptr.proxyuser : "") : conn->http_proxy.creds->user : "") :
(data->state.aptr.user ? (data->state.creds ?
data->state.aptr.user : "")); data->state.creds->user : ""));
#else #else
(void)proxy; (void)proxy;
infof(data, "Server auth using %s with user '%s'", infof(data, "Server auth using %s with user '%s'",
auth, data->state.aptr.user ? auth, data->state.creds ?
data->state.aptr.user : ""); data->state.creds->user : "");
#endif #endif
authstatus->multipass = !authstatus->done; authstatus->multipass = !authstatus->done;
} }
@ -780,14 +784,13 @@ CURLcode Curl_http_output_auth(struct Curl_easy *data,
if( if(
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
(!conn->bits.httpproxy || !conn->bits.proxy_user_passwd) && (!conn->bits.httpproxy || !conn->http_proxy.creds) &&
#endif #endif
!data->state.aptr.user &&
#ifdef USE_SPNEGO #ifdef USE_SPNEGO
!(authhost->want & CURLAUTH_NEGOTIATE) && !(authhost->want & CURLAUTH_NEGOTIATE) &&
!(authproxy->want & CURLAUTH_NEGOTIATE) && !(authproxy->want & CURLAUTH_NEGOTIATE) &&
#endif #endif
!data->set.str[STRING_BEARER]) { !data->state.creds) {
/* no authentication with no user or password */ /* no authentication with no user or password */
authhost->done = TRUE; authhost->done = TRUE;
authproxy->done = TRUE; authproxy->done = TRUE;
@ -832,13 +835,9 @@ CURLcode Curl_http_output_auth(struct Curl_easy *data,
with it */ with it */
authproxy->done = TRUE; authproxy->done = TRUE;
/* To prevent the user+password to get sent to other than the original host /* Either we have credentials for the origin we talk to or
due to a location-follow */ performing authentication is allowed here */
if(Curl_auth_allowed_to_host(data) if(data->state.creds || Curl_auth_allowed_to_host(data))
#ifndef CURL_DISABLE_NETRC
|| conn->bits.netrc
#endif
)
result = output_auth_headers(data, conn, authhost, request, result = output_auth_headers(data, conn, authhost, request,
path_and_query, FALSE); path_and_query, FALSE);
else else
@ -1227,8 +1226,6 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
else { else {
bool same_origin;
CURLcode result;
CURLU *u = curl_url(); CURLU *u = curl_url();
if(!u) if(!u)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
@ -1242,29 +1239,16 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
return Curl_uc_to_curlcode(uc); return Curl_uc_to_curlcode(uc);
} }
same_origin = Curl_url_same_origin(u, data->state.uh);
curl_url_cleanup(u);
#ifndef CURL_DISABLE_DIGEST_AUTH #ifndef CURL_DISABLE_DIGEST_AUTH
if(!same_origin) {
Curl_auth_digest_cleanup(&data->state.digest); bool same_origin = Curl_url_same_origin(u, data->state.uh);
curl_url_cleanup(u);
if(!same_origin)
Curl_auth_digest_cleanup(&data->state.digest);
}
#else
curl_url_cleanup(u);
#endif #endif
if((!same_origin && !data->set.allow_auth_to_other_hosts) ||
!data->set.str[STRING_USERNAME]) {
result = Curl_reset_userpwd(data);
if(result) {
curlx_free(follow_url);
return result;
}
curlx_safefree(data->state.aptr.user);
curlx_safefree(data->state.aptr.passwd);
}
result = Curl_reset_proxypwd(data);
if(result) {
curlx_free(follow_url);
return result;
}
} }
DEBUGASSERT(follow_url); DEBUGASSERT(follow_url);
@ -2005,9 +1989,6 @@ static CURLcode http_set_aptr_host(struct Curl_easy *data)
struct dynamically_allocated_data *aptr = &data->state.aptr; struct dynamically_allocated_data *aptr = &data->state.aptr;
const char *ptr; const char *ptr;
if(!data->state.this_is_a_follow)
Curl_peer_link(&data->state.first_origin, conn->origin);
curlx_safefree(aptr->host); curlx_safefree(aptr->host);
#ifndef CURL_DISABLE_COOKIES #ifndef CURL_DISABLE_COOKIES
curlx_safefree(data->req.cookiehost); curlx_safefree(data->req.cookiehost);
@ -2015,7 +1996,7 @@ static CURLcode http_set_aptr_host(struct Curl_easy *data)
ptr = Curl_checkheaders(data, STRCONST("Host")); ptr = Curl_checkheaders(data, STRCONST("Host"));
if(ptr && (!data->state.this_is_a_follow || if(ptr && (!data->state.this_is_a_follow ||
Curl_peer_equal(data->state.first_origin, conn->origin))) { Curl_peer_equal(data->state.initial_origin, conn->origin))) {
#ifndef CURL_DISABLE_COOKIES #ifndef CURL_DISABLE_COOKIES
/* If we have a given custom Host: header, we extract the hostname in /* If we have a given custom Host: header, we extract the hostname in
order to possibly use it for cookie reasons later on. We only allow the order to possibly use it for cookie reasons later on. We only allow the
@ -2138,6 +2119,19 @@ static CURLcode http_target(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
} }
else if(data->state.creds && (data->state.creds->source != CREDS_URL)) {
/* credentials not from the URL need to be set */
uc = curl_url_set(h, CURLUPART_USER,
data->state.creds->user, CURLU_URLENCODE);
if(!uc)
uc = curl_url_set(h, CURLUPART_PASSWORD,
data->state.creds->passwd, CURLU_URLENCODE);
if(uc) {
curl_url_cleanup(h);
return Curl_uc_to_curlcode(uc);
}
}
/* Extract the URL to use in the request. */ /* Extract the URL to use in the request. */
uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT); uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT);
if(uc) { if(uc) {

View file

@ -848,7 +848,8 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
char *request_type = NULL; char *request_type = NULL;
char *credential_scope = NULL; char *credential_scope = NULL;
char *str_to_sign = NULL; char *str_to_sign = NULL;
const char *user = data->state.aptr.user ? data->state.aptr.user : ""; const char *user = Curl_creds_user(data->state.creds);
const char *passwd = Curl_creds_passwd(data->state.creds);
char *secret = NULL; char *secret = NULL;
unsigned char sign0[CURL_SHA256_DIGEST_LENGTH] = { 0 }; unsigned char sign0[CURL_SHA256_DIGEST_LENGTH] = { 0 };
unsigned char sign1[CURL_SHA256_DIGEST_LENGTH] = { 0 }; unsigned char sign1[CURL_SHA256_DIGEST_LENGTH] = { 0 };
@ -1068,8 +1069,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
str_to_sign); str_to_sign);
secret = curl_maprintf("%.*s4%s", (int)curlx_strlen(&provider0), secret = curl_maprintf("%.*s4%s", (int)curlx_strlen(&provider0),
curlx_str(&provider0), data->state.aptr.passwd ? curlx_str(&provider0), passwd);
data->state.aptr.passwd : "");
if(!secret) if(!secret)
goto fail; goto fail;
/* make provider0 part done uppercase */ /* make provider0 part done uppercase */

View file

@ -77,8 +77,7 @@ CURLcode Curl_output_digest(struct Curl_easy *data,
char **allocuserpwd; char **allocuserpwd;
/* Point to the name and password for this */ /* Point to the name and password for this */
const char *userp; struct Curl_creds *creds = NULL;
const char *passwdp;
/* Point to the correct struct with this */ /* Point to the correct struct with this */
struct digestdata *digest; struct digestdata *digest;
@ -90,28 +89,19 @@ CURLcode Curl_output_digest(struct Curl_easy *data,
#else #else
digest = &data->state.proxydigest; digest = &data->state.proxydigest;
allocuserpwd = &data->req.hd_proxy_auth; allocuserpwd = &data->req.hd_proxy_auth;
userp = data->state.aptr.proxyuser; creds = data->conn->http_proxy.creds;
passwdp = data->state.aptr.proxypasswd;
authp = &data->state.authproxy; authp = &data->state.authproxy;
#endif #endif
} }
else { else {
digest = &data->state.digest; digest = &data->state.digest;
allocuserpwd = &data->req.hd_auth; allocuserpwd = &data->req.hd_auth;
userp = data->state.aptr.user; creds = data->state.creds;
passwdp = data->state.aptr.passwd;
authp = &data->state.authhost; authp = &data->state.authhost;
} }
curlx_safefree(*allocuserpwd); curlx_safefree(*allocuserpwd);
/* not set means empty */
if(!userp)
userp = "";
if(!passwdp)
passwdp = "";
#ifdef USE_WINDOWS_SSPI #ifdef USE_WINDOWS_SSPI
have_chlg = !!digest->input_token; have_chlg = !!digest->input_token;
#else #else
@ -123,8 +113,8 @@ CURLcode Curl_output_digest(struct Curl_easy *data,
return CURLE_OK; return CURLE_OK;
} }
result = Curl_auth_create_digest_http_message(data, userp, passwdp, result = Curl_auth_create_digest_http_message(data, creds, request,
request, uripath, digest, uripath, digest,
&response, &len); &response, &len);
if(result) if(result)
return result; return result;

View file

@ -40,8 +40,10 @@ static void http_auth_nego_reset(struct connectdata *conn,
{ {
if(proxy) if(proxy)
conn->proxy_negotiate_state = GSS_AUTHNONE; conn->proxy_negotiate_state = GSS_AUTHNONE;
else else {
conn->http_negotiate_state = GSS_AUTHNONE; conn->http_negotiate_state = GSS_AUTHNONE;
Curl_creds_unlink(&conn->creds);
}
if(neg_ctx) if(neg_ctx)
Curl_auth_cleanup_spnego(neg_ctx); Curl_auth_cleanup_spnego(neg_ctx);
} }
@ -53,8 +55,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
size_t len; size_t len;
/* Point to the username, password, service and host */ /* Point to the username, password, service and host */
const char *userp; struct Curl_creds *creds = NULL;
const char *passwdp;
const char *service; const char *service;
const char *host; const char *host;
@ -64,8 +65,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
if(proxy) { if(proxy) {
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
userp = conn->http_proxy.user; creds = conn->http_proxy.creds;
passwdp = conn->http_proxy.passwd;
service = data->set.str[STRING_PROXY_SERVICE_NAME] ? service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
host = conn->http_proxy.peer->hostname; host = conn->http_proxy.peer->hostname;
@ -75,8 +75,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
#endif #endif
} }
else { else {
userp = conn->user; creds = data->state.creds;
passwdp = conn->passwd;
service = data->set.str[STRING_SERVICE_NAME] ? service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] : "HTTP"; data->set.str[STRING_SERVICE_NAME] : "HTTP";
host = conn->origin->hostname; host = conn->origin->hostname;
@ -87,13 +86,6 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
if(!neg_ctx) if(!neg_ctx)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
/* Not set means empty */
if(!userp)
userp = "";
if(!passwdp)
passwdp = "";
/* Obtain the input token, if any */ /* Obtain the input token, if any */
header += strlen("Negotiate"); header += strlen("Negotiate");
curlx_str_passblanks(&header); curlx_str_passblanks(&header);
@ -135,7 +127,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
#endif /* GSS_C_CHANNEL_BOUND_FLAG */ #endif /* GSS_C_CHANNEL_BOUND_FLAG */
/* Initialize the security context and decode our challenge */ /* Initialize the security context and decode our challenge */
result = Curl_auth_decode_spnego_message(data, userp, passwdp, service, result = Curl_auth_decode_spnego_message(data, creds, service,
host, header, neg_ctx); host, header, neg_ctx);
#ifdef GSS_C_CHANNEL_BOUND_FLAG #ifdef GSS_C_CHANNEL_BOUND_FLAG
@ -145,6 +137,16 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
if(result) if(result)
http_auth_nego_reset(conn, neg_ctx, proxy); http_auth_nego_reset(conn, neg_ctx, proxy);
if(!proxy) {
/* Start it up. From this time onwards, the connection is tied
* tp the credentials used. */
if(conn->creds && !Curl_creds_same(creds, conn->creds)) {
DEBUGASSERT(0); /* should not happen. */
return CURLE_FAILED_INIT;
}
Curl_creds_link(&conn->creds, creds);
}
return result; return result;
} }

View file

@ -122,9 +122,8 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
server, which is for a plain host or for an HTTP proxy */ server, which is for a plain host or for an HTTP proxy */
char **allocuserpwd; char **allocuserpwd;
/* point to the username, password, service and host */ /* point to credentials, service and host */
const char *userp; struct Curl_creds *creds = NULL;
const char *passwdp;
const char *service = NULL; const char *service = NULL;
const char *hostname = NULL; const char *hostname = NULL;
@ -140,8 +139,7 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
if(proxy) { if(proxy) {
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
allocuserpwd = &data->req.hd_proxy_auth; allocuserpwd = &data->req.hd_proxy_auth;
userp = data->state.aptr.proxyuser; creds = conn->http_proxy.creds;
passwdp = data->state.aptr.proxypasswd;
service = data->set.str[STRING_PROXY_SERVICE_NAME] ? 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.peer->hostname; hostname = conn->http_proxy.peer->hostname;
@ -153,26 +151,19 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
} }
else { else {
allocuserpwd = &data->req.hd_auth; allocuserpwd = &data->req.hd_auth;
userp = data->state.aptr.user; creds = data->state.creds;
passwdp = data->state.aptr.passwd;
service = data->set.str[STRING_SERVICE_NAME] ? service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] : "HTTP"; data->set.str[STRING_SERVICE_NAME] : "HTTP";
hostname = conn->origin->hostname; hostname = conn->origin->hostname;
state = &conn->http_ntlm_state; state = &conn->http_ntlm_state;
authp = &data->state.authhost; authp = &data->state.authhost;
} }
ntlm = Curl_auth_ntlm_get(conn, proxy); ntlm = Curl_auth_ntlm_get(conn, proxy);
if(!ntlm) if(!ntlm)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
authp->done = FALSE; authp->done = FALSE;
/* not set means empty */
if(!userp)
userp = "";
if(!passwdp)
passwdp = "";
#ifdef USE_WINDOWS_SSPI #ifdef USE_WINDOWS_SSPI
if(!Curl_pSecFn) { if(!Curl_pSecFn) {
/* not thread-safe and leaks - use curl_global_init() to avoid */ /* not thread-safe and leaks - use curl_global_init() to avoid */
@ -195,8 +186,16 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
switch(*state) { switch(*state) {
case NTLMSTATE_TYPE1: case NTLMSTATE_TYPE1:
default: /* for the weird cases we (re)start here */ default: /* for the weird cases we (re)start here */
/* Create a type-1 message */ if(!proxy) {
result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp, service, /* Start it up. From this time onwards, the connection is tied
* tp the credentials used. */
if(conn->creds && !Curl_creds_same(creds, conn->creds)) {
DEBUGASSERT(0); /* should not happen. */
return CURLE_FAILED_INIT;
}
Curl_creds_link(&conn->creds, creds);
}
result = Curl_auth_create_ntlm_type1_message(data, creds, service,
hostname, ntlm, &ntlmmsg); hostname, ntlm, &ntlmmsg);
if(!result) { if(!result) {
DEBUGASSERT(Curl_bufref_len(&ntlmmsg) != 0); DEBUGASSERT(Curl_bufref_len(&ntlmmsg) != 0);
@ -215,8 +214,7 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
case NTLMSTATE_TYPE2: case NTLMSTATE_TYPE2:
/* We already received the type-2 message, create a type-3 message */ /* We already received the type-2 message, create a type-3 message */
result = Curl_auth_create_ntlm_type3_message(data, userp, passwdp, result = Curl_auth_create_ntlm_type3_message(data, creds, ntlm, &ntlmmsg);
ntlm, &ntlmmsg);
if(!result && Curl_bufref_len(&ntlmmsg)) { if(!result && Curl_bufref_len(&ntlmmsg)) {
result = curlx_base64_encode(Curl_bufref_uptr(&ntlmmsg), result = curlx_base64_encode(Curl_bufref_uptr(&ntlmmsg),
Curl_bufref_len(&ntlmmsg), &base64, &len); Curl_bufref_len(&ntlmmsg), &base64, &len);

View file

@ -597,15 +597,15 @@ static CURLcode imap_perform_login(struct Curl_easy *data,
/* Check we have a username and password to authenticate with and end the /* Check we have a username and password to authenticate with and end the
connect phase if we do not */ connect phase if we do not */
if(!data->state.aptr.user) { if(!data->state.creds) {
imap_state(data, imapc, IMAP_STOP); imap_state(data, imapc, IMAP_STOP);
return result; return result;
} }
/* Make sure the username and password are in the correct atom format */ /* Make sure the username and password are in the correct atom format */
user = imap_atom(conn->user, FALSE); user = imap_atom(Curl_creds_user(conn->creds), FALSE);
passwd = imap_atom(conn->passwd, FALSE); passwd = imap_atom(Curl_creds_passwd(conn->creds), FALSE);
/* Send the LOGIN command */ /* Send the LOGIN command */
result = imap_sendf(data, imapc, "LOGIN %s %s", user ? user : "", result = imap_sendf(data, imapc, "LOGIN %s %s", user ? user : "",
@ -712,7 +712,6 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data,
/* Calculate the SASL login details */ /* Calculate the SASL login details */
result = Curl_sasl_start(&imapc->sasl, data, (bool)imapc->ir_supported, result = Curl_sasl_start(&imapc->sasl, data, (bool)imapc->ir_supported,
&progress); &progress);
if(!result) { if(!result) {
if(progress == SASL_INPROGRESS) if(progress == SASL_INPROGRESS)
imap_state(data, imapc, IMAP_AUTHENTICATE); imap_state(data, imapc, IMAP_AUTHENTICATE);

View file

@ -252,8 +252,10 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
#else #else
char *host = NULL; char *host = NULL;
#endif #endif
char *user = NULL; const char *user = Curl_creds_has_user(data->state.creds) ?
char *passwd = NULL; data->state.creds->user : NULL;
const char *passwd = Curl_creds_has_passwd(data->state.creds) ?
data->state.creds->passwd : NULL;
struct ip_quadruple ipquad; struct ip_quadruple ipquad;
bool is_ipv6; bool is_ipv6;
BerElement *ber = NULL; BerElement *ber = NULL;
@ -295,11 +297,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
host = conn->origin->hostname; host = conn->origin->hostname;
#endif #endif
if(data->state.aptr.user) {
user = conn->user;
passwd = conn->passwd;
}
#ifdef USE_WIN32_LDAP #ifdef USE_WIN32_LDAP
if(ldap_ssl) if(ldap_ssl)
server = ldap_sslinit(host, (curl_ldap_num_t)ipquad.remote_port, 1); server = ldap_sslinit(host, (curl_ldap_num_t)ipquad.remote_port, 1);

View file

@ -280,11 +280,9 @@ static CURLcode mqtt_connect(struct Curl_easy *data)
char *packet = NULL; char *packet = NULL;
/* extracting username from request */ /* extracting username from request */
const char *username = data->state.aptr.user ? data->state.aptr.user : ""; struct Curl_creds *creds = data->state.creds;
const size_t ulen = strlen(username); const size_t ulen = creds ? strlen(creds->user) : 0;
/* extracting password from request */ const size_t plen = creds ? strlen(creds->passwd) : 0;
const char *passwd = data->state.aptr.passwd ? data->state.aptr.passwd : "";
const size_t plen = strlen(passwd);
const size_t payloadlen = ulen + plen + MQTT_CLIENTID_LEN + 2 + const size_t payloadlen = ulen + plen + MQTT_CLIENTID_LEN + 2 +
/* The plus 2s below are for the MSB and LSB describing the length of the /* The plus 2s below are for the MSB and LSB describing the length of the
string to be added on the payload. Refer to spec 1.5.2 and 1.5.4 */ string to be added on the payload. Refer to spec 1.5.2 and 1.5.4 */
@ -326,7 +324,7 @@ static CURLcode mqtt_connect(struct Curl_easy *data)
if(ulen) { if(ulen) {
start_pwd += 2; start_pwd += 2;
rc = add_user(username, ulen, rc = add_user(creds->user, ulen,
(unsigned char *)packet, start_user, remain_pos); (unsigned char *)packet, start_user, remain_pos);
if(rc) { if(rc) {
failf(data, "Username too long: [%zu]", ulen); failf(data, "Username too long: [%zu]", ulen);
@ -337,7 +335,7 @@ static CURLcode mqtt_connect(struct Curl_easy *data)
/* if passwd was provided, add it to the packet */ /* if passwd was provided, add it to the packet */
if(plen) { if(plen) {
rc = add_passwd(passwd, plen, packet, start_pwd, remain_pos); rc = add_passwd(creds->passwd, plen, packet, start_pwd, remain_pos);
if(rc) { if(rc) {
failf(data, "Password too long: [%zu]", plen); failf(data, "Password too long: [%zu]", plen);
result = CURLE_WEIRD_SERVER_REPLY; result = CURLE_WEIRD_SERVER_REPLY;
@ -351,8 +349,7 @@ static CURLcode mqtt_connect(struct Curl_easy *data)
end: end:
if(packet) if(packet)
curlx_free(packet); curlx_free(packet);
curlx_safefree(data->state.aptr.user); Curl_creds_unlink(&data->state.creds);
curlx_safefree(data->state.aptr.passwd);
return result; return result;
} }

View file

@ -36,6 +36,7 @@
#endif #endif
#include "netrc.h" #include "netrc.h"
#include "creds.h"
#include "strcase.h" #include "strcase.h"
#include "curl_get_line.h" #include "curl_get_line.h"
#include "curlx/fopen.h" #include "curlx/fopen.h"
@ -108,6 +109,7 @@ static NETRCcode file2memory(const char *filename, struct dynbuf *filebuf)
/* bundled parser state to keep function signatures compact */ /* bundled parser state to keep function signatures compact */
struct netrc_state { struct netrc_state {
struct Curl_creds *existing;
char *login; char *login;
char *password; char *password;
enum host_lookup_state state; enum host_lookup_state state;
@ -116,7 +118,6 @@ struct netrc_state {
unsigned char found; /* FOUND_LOGIN | FOUND_PASSWORD bits */ unsigned char found; /* FOUND_LOGIN | FOUND_PASSWORD bits */
bool our_login; bool our_login;
bool done; bool done;
bool specific_login;
}; };
/* /*
@ -250,8 +251,7 @@ static void netrc_new_machine(struct netrc_state *ns)
ns->found = 0; ns->found = 0;
ns->our_login = FALSE; ns->our_login = FALSE;
curlx_safefree(ns->password); curlx_safefree(ns->password);
if(!ns->specific_login) curlx_safefree(ns->login);
curlx_safefree(ns->login);
} }
/* /*
@ -263,8 +263,8 @@ static void netrc_new_machine(struct netrc_state *ns)
static NETRCcode netrc_hostvalid(struct netrc_state *ns, const char *tok) static NETRCcode netrc_hostvalid(struct netrc_state *ns, const char *tok)
{ {
if(ns->keyword == LOGIN) { if(ns->keyword == LOGIN) {
if(ns->specific_login) if(Curl_creds_has_user(ns->existing))
ns->our_login = !Curl_timestrcmp(ns->login, tok); ns->our_login = !Curl_timestrcmp(ns->existing->user, tok);
else { else {
ns->our_login = TRUE; ns->our_login = TRUE;
curlx_free(ns->login); curlx_free(ns->login);
@ -289,15 +289,15 @@ static NETRCcode netrc_hostvalid(struct netrc_state *ns, const char *tok)
ns->keyword = PASSWORD; ns->keyword = PASSWORD;
else if(curl_strequal("machine", tok)) { else if(curl_strequal("machine", tok)) {
/* a new machine here */ /* a new machine here */
bool specific_login = Curl_creds_has_user(ns->existing);
if(ns->found & FOUND_PASSWORD && if((ns->found & FOUND_PASSWORD) &&
/* a password was provided for this host */ /* a password was provided for this host */
(!specific_login || ns->our_login ||
((!ns->specific_login || ns->our_login) || /* and found a login that is suitable
/* either there was no specific login to search for, or this (either matched specific one or simply present) */
is the specific one we wanted */ (specific_login && !(ns->found & FOUND_LOGIN)))) {
(ns->specific_login && !(ns->found & FOUND_LOGIN)))) { /* or we look for a specific login, but no login was not specified */
/* or we look for a specific login, but that was not specified */
ns->done = TRUE; ns->done = TRUE;
return NETRC_OK; return NETRC_OK;
@ -361,38 +361,48 @@ static NETRCcode netrc_handle_token(struct netrc_state *ns,
* resources on error. * resources on error.
*/ */
static NETRCcode netrc_finalize(struct netrc_state *ns, static NETRCcode netrc_finalize(struct netrc_state *ns,
char **loginp, struct store_netrc *store,
char **passwordp, struct Curl_creds **pcreds)
struct store_netrc *store)
{ {
NETRCcode retcode = ns->retcode; NETRCcode retcode = ns->retcode;
if(!retcode) { if(!retcode) {
if(!ns->password && ns->our_login) { if(!ns->password && ns->our_login) {
/* success without a password, set a blank one */ /* success without a password, set a blank one */
ns->password = curlx_strdup(""); ns->password = curlx_strdup("");
if(!ns->password) if(!ns->password) {
retcode = NETRC_OUT_OF_MEMORY; retcode = NETRC_OUT_OF_MEMORY;
goto out;
}
} }
else if(!ns->login && !ns->password) else if(!ns->login && !ns->password) {
/* a default with no credentials */ /* a default with no credentials */
retcode = NETRC_NO_MATCH; retcode = NETRC_NO_MATCH;
goto out;
}
} }
if(!retcode) {
/* success */
if(!ns->specific_login)
*loginp = ns->login;
/* netrc_finalize() can return a password even when specific_login is set if(!retcode) {
/* success
netrc_finalize() can return a password even when specific_login is set
but our_login is false (e.g., host matched but the requested login but our_login is false (e.g., host matched but the requested login
never matched). See test 685. */ never matched). See test 685. */
*passwordp = ns->password; const char *login = Curl_creds_has_user(ns->existing) ?
ns->existing->user : ns->login;
/* success without a password, set a blank one */
const char *passwd = ns->password ? ns->password : "";
if(Curl_creds_create(login, passwd, NULL, NULL, CREDS_NETRC, pcreds)) {
retcode = NETRC_OUT_OF_MEMORY;
goto out;
}
} }
else {
out:
curlx_free(ns->login);
curlx_free(ns->password);
if(retcode) {
curlx_dyn_free(&store->filebuf); curlx_dyn_free(&store->filebuf);
store->loaded = FALSE; store->loaded = FALSE;
if(!ns->specific_login)
curlx_free(ns->login);
curlx_free(ns->password);
} }
return retcode; return retcode;
} }
@ -402,21 +412,20 @@ static NETRCcode netrc_finalize(struct netrc_state *ns,
*/ */
static NETRCcode parsenetrc(struct store_netrc *store, static NETRCcode parsenetrc(struct store_netrc *store,
const char *host, const char *host,
char **loginp, struct Curl_creds *existing,
char **passwordp, const char *netrcfile,
const char *netrcfile) struct Curl_creds **pcreds)
{ {
const char *netrcbuffer; const char *netrcbuffer;
struct dynbuf token; struct dynbuf token;
struct dynbuf *filebuf = &store->filebuf; struct dynbuf *filebuf = &store->filebuf;
struct netrc_state ns; struct netrc_state ns;
DEBUGASSERT(!existing || !Curl_creds_has_passwd(existing));
memset(&ns, 0, sizeof(ns)); memset(&ns, 0, sizeof(ns));
ns.retcode = NETRC_NO_MATCH; ns.retcode = NETRC_NO_MATCH;
ns.login = *loginp; ns.existing = existing;
ns.specific_login = !!ns.login;
DEBUGASSERT(!*passwordp);
curlx_dyn_init(&token, MAX_NETRC_TOKEN); curlx_dyn_init(&token, MAX_NETRC_TOKEN);
if(!store->loaded) { if(!store->loaded) {
@ -466,7 +475,7 @@ static NETRCcode parsenetrc(struct store_netrc *store,
out: out:
curlx_dyn_free(&token); curlx_dyn_free(&token);
return netrc_finalize(&ns, loginp, passwordp, store); return netrc_finalize(&ns, store, pcreds);
} }
const char *Curl_netrc_strerror(NETRCcode ret) const char *Curl_netrc_strerror(NETRCcode ret)
@ -493,12 +502,14 @@ const char *Curl_netrc_strerror(NETRCcode ret)
* in. * in.
*/ */
NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host, NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host,
char **loginp, char **passwordp, struct Curl_creds *existing,
const char *netrcfile) const char *netrcfile,
struct Curl_creds **pcreds)
{ {
NETRCcode retcode = NETRC_OK; NETRCcode retcode = NETRC_OK;
char *filealloc = NULL; char *filealloc = NULL;
Curl_creds_unlink(pcreds);
if(!netrcfile) { if(!netrcfile) {
char *home = NULL; char *home = NULL;
char *homea = NULL; char *homea = NULL;
@ -543,10 +554,11 @@ NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host,
filealloc = curl_maprintf("%s%s.netrc", home, DIR_CHAR); filealloc = curl_maprintf("%s%s.netrc", home, DIR_CHAR);
if(!filealloc) { if(!filealloc) {
curlx_free(homea); curlx_free(homea);
return NETRC_OUT_OF_MEMORY; retcode = NETRC_OUT_OF_MEMORY;
goto out;
} }
} }
retcode = parsenetrc(store, host, loginp, passwordp, filealloc); retcode = parsenetrc(store, host, existing, filealloc, pcreds);
curlx_free(filealloc); curlx_free(filealloc);
#ifdef _WIN32 #ifdef _WIN32
if(retcode == NETRC_FILE_MISSING) { if(retcode == NETRC_FILE_MISSING) {
@ -556,14 +568,17 @@ NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host,
curlx_free(homea); curlx_free(homea);
return NETRC_OUT_OF_MEMORY; return NETRC_OUT_OF_MEMORY;
} }
retcode = parsenetrc(store, host, loginp, passwordp, filealloc); retcode = parsenetrc(store, host, existing, filealloc, pcreds);
curlx_free(filealloc); curlx_free(filealloc);
} }
#endif #endif
curlx_free(homea); curlx_free(homea);
} }
else else
retcode = parsenetrc(store, host, loginp, passwordp, netrcfile); retcode = parsenetrc(store, host, existing, netrcfile, pcreds);
out:
if(retcode)
Curl_creds_unlink(pcreds);
return retcode; return retcode;
} }

View file

@ -29,6 +29,8 @@
#include "curlx/dynbuf.h" #include "curlx/dynbuf.h"
struct Curl_creds;
struct store_netrc { struct store_netrc {
struct dynbuf filebuf; struct dynbuf filebuf;
char *filename; char *filename;
@ -49,8 +51,9 @@ void Curl_netrc_init(struct store_netrc *store);
void Curl_netrc_cleanup(struct store_netrc *store); void Curl_netrc_cleanup(struct store_netrc *store);
NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host, NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host,
char **loginp, char **passwordp, struct Curl_creds *existing,
const char *netrcfile); const char *netrcfile,
struct Curl_creds **pcreds);
/* Assume: (*passwordp)[0]=0, host[0] != 0. /* Assume: (*passwordp)[0]=0, host[0] != 0.
* If (*loginp)[0] = 0, search for login and password within a machine * If (*loginp)[0] = 0, search for login and password within a machine
* section in the netrc. * section in the netrc.

View file

@ -345,9 +345,9 @@ static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate)
passwd.bv_val = NULL; passwd.bv_val = NULL;
passwd.bv_len = 0; passwd.bv_len = 0;
if(data->state.aptr.user) { if(data->state.creds) {
binddn = conn->user; binddn = Curl_creds_user(conn->creds);
passwd.bv_val = conn->passwd; passwd.bv_val = CURL_UNCONST(Curl_creds_passwd(conn->creds));
passwd.bv_len = strlen(passwd.bv_val); passwd.bv_len = strlen(passwd.bv_val);
} }
@ -355,7 +355,7 @@ static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate)
NULL, NULL, &li->msgid); NULL, NULL, &li->msgid);
if(rc != LDAP_SUCCESS) if(rc != LDAP_SUCCESS)
return oldap_map_error(rc, return oldap_map_error(rc,
data->state.aptr.user ? data->state.creds ?
CURLE_LOGIN_DENIED : CURLE_LDAP_CANNOT_BIND); CURLE_LOGIN_DENIED : CURLE_LDAP_CANNOT_BIND);
oldap_state(data, li, newstate); oldap_state(data, li, newstate);
return CURLE_OK; return CURLE_OK;
@ -911,7 +911,7 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
else if(ssl_installed(conn)) { else if(ssl_installed(conn)) {
if(li->sasl.prefmech != SASL_AUTH_NONE) if(li->sasl.prefmech != SASL_AUTH_NONE)
result = oldap_perform_mechs(data); result = oldap_perform_mechs(data);
else if(data->state.aptr.user) else if(data->state.creds)
result = oldap_perform_bind(data, OLDAP_BIND); result = oldap_perform_bind(data, OLDAP_BIND);
else { else {
/* Version 3 supported: no bind required */ /* Version 3 supported: no bind required */

View file

@ -527,7 +527,7 @@ static CURLcode pop3_perform_user(struct Curl_easy *data,
/* Check we have a username and password to authenticate with and end the /* Check we have a username and password to authenticate with and end the
connect phase if we do not */ connect phase if we do not */
if(!data->state.aptr.user) { if(!data->state.creds) {
pop3_state(data, POP3_STOP); pop3_state(data, POP3_STOP);
return result; return result;
@ -535,7 +535,7 @@ static CURLcode pop3_perform_user(struct Curl_easy *data,
/* Send the USER command */ /* Send the USER command */
result = Curl_pp_sendf(data, &pop3c->pp, "USER %s", result = Curl_pp_sendf(data, &pop3c->pp, "USER %s",
conn->user ? conn->user : ""); Curl_creds_user(conn->creds));
if(!result) if(!result)
pop3_state(data, POP3_USER); pop3_state(data, POP3_USER);
@ -564,7 +564,7 @@ static CURLcode pop3_perform_apop(struct Curl_easy *data,
/* Check we have a username and password to authenticate with and end the /* Check we have a username and password to authenticate with and end the
connect phase if we do not */ connect phase if we do not */
if(!data->state.aptr.user) { if(!data->state.creds) {
pop3_state(data, POP3_STOP); pop3_state(data, POP3_STOP);
return result; return result;
@ -578,8 +578,8 @@ static CURLcode pop3_perform_apop(struct Curl_easy *data,
Curl_MD5_update(ctxt, (const unsigned char *)pop3c->apoptimestamp, Curl_MD5_update(ctxt, (const unsigned char *)pop3c->apoptimestamp,
curlx_uztoui(strlen(pop3c->apoptimestamp))); curlx_uztoui(strlen(pop3c->apoptimestamp)));
Curl_MD5_update(ctxt, (const unsigned char *)conn->passwd, Curl_MD5_update(ctxt, (const unsigned char *)Curl_creds_passwd(conn->creds),
curlx_uztoui(strlen(conn->passwd))); curlx_uztoui(strlen(Curl_creds_passwd(conn->creds))));
/* Finalise the digest */ /* Finalise the digest */
Curl_MD5_final(ctxt, digest); Curl_MD5_final(ctxt, digest);
@ -588,7 +588,8 @@ static CURLcode pop3_perform_apop(struct Curl_easy *data,
for(i = 0; i < MD5_DIGEST_LEN; i++) for(i = 0; i < MD5_DIGEST_LEN; i++)
curl_msnprintf(&secret[2 * i], 3, "%02x", digest[i]); curl_msnprintf(&secret[2 * i], 3, "%02x", digest[i]);
result = Curl_pp_sendf(data, &pop3c->pp, "APOP %s %s", conn->user, secret); result = Curl_pp_sendf(data, &pop3c->pp, "APOP %s %s",
Curl_creds_user(conn->creds), secret);
if(!result) if(!result)
pop3_state(data, POP3_APOP); pop3_state(data, POP3_APOP);
@ -1038,7 +1039,8 @@ static CURLcode pop3_state_user_resp(struct Curl_easy *data, int pop3code,
} }
else else
/* Send the PASS command */ /* Send the PASS command */
result = Curl_pp_sendf(data, &pop3c->pp, "PASS %s", conn->passwd); result = Curl_pp_sendf(data, &pop3c->pp, "PASS %s",
Curl_creds_passwd(conn->creds));
if(!result) if(!result)
pop3_state(data, POP3_PASS); pop3_state(data, POP3_PASS);

View file

@ -301,12 +301,6 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
rtsp->CSeq_sent = data->state.rtsp_next_client_CSeq; rtsp->CSeq_sent = data->state.rtsp_next_client_CSeq;
rtsp->CSeq_recv = 0; rtsp->CSeq_recv = 0;
/* Setup the first_* fields to allow auth details get sent
to this origin */
if(!data->state.first_origin)
Curl_peer_link(&data->state.first_origin, conn->origin);
/* Setup the 'p_request' pointer to the proper p_request string /* Setup the 'p_request' pointer to the proper p_request string
* Since all RTSP requests are included here, there is no need to * Since all RTSP requests are included here, there is no need to
* support custom requests like HTTP. * support custom requests like HTTP.

View file

@ -61,7 +61,7 @@ enum smb_conn_state {
/* SMB connection data, kept at connection */ /* SMB connection data, kept at connection */
struct smb_conn { struct smb_conn {
enum smb_conn_state state; enum smb_conn_state state;
char *user; const char *user;
char *domain; char *domain;
char *share; char *share;
unsigned char challenge[8]; unsigned char challenge[8];
@ -468,13 +468,14 @@ static CURLcode smb_connect(struct Curl_easy *data, bool *done)
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
struct smb_conn *smbc = Curl_conn_meta_get(conn, CURL_META_SMB_CONN); struct smb_conn *smbc = Curl_conn_meta_get(conn, CURL_META_SMB_CONN);
char *slash; char *slash;
const char *user = Curl_creds_user(conn->creds);
(void)done; (void)done;
if(!smbc) if(!smbc)
return CURLE_FAILED_INIT; return CURLE_FAILED_INIT;
/* Check we have a username and password to authenticate with */ /* Check we have a username and password to authenticate with */
if(!data->state.aptr.user) if(!Curl_creds_has_user(data->state.creds))
return CURLE_LOGIN_DENIED; return CURLE_LOGIN_DENIED;
/* Initialize the connection state */ /* Initialize the connection state */
@ -487,19 +488,19 @@ static CURLcode smb_connect(struct Curl_easy *data, bool *done)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
/* Parse the username, domain, and password */ /* Parse the username, domain, and password */
slash = strchr(conn->user, '/'); slash = strchr(user, '/');
if(!slash) if(!slash)
slash = strchr(conn->user, '\\'); slash = strchr(user, '\\');
if(slash) { if(slash) {
smbc->user = slash + 1; smbc->user = slash + 1;
smbc->domain = curlx_strdup(conn->user); smbc->domain = curlx_strdup(user);
if(!smbc->domain) if(!smbc->domain)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
smbc->domain[slash - conn->user] = 0; smbc->domain[slash - user] = 0;
} }
else { else {
smbc->user = conn->user; smbc->user = user;
smbc->domain = curlx_strdup(conn->origin->hostname); smbc->domain = curlx_strdup(conn->origin->hostname);
if(!smbc->domain) if(!smbc->domain)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
@ -670,6 +671,7 @@ static CURLcode smb_send_setup(struct Curl_easy *data)
unsigned char nt_hash[21]; unsigned char nt_hash[21];
unsigned char nt[24]; unsigned char nt[24];
size_t byte_count; size_t byte_count;
const char *passwd = Curl_creds_passwd(conn->creds);
if(!smbc || !req) if(!smbc || !req)
return CURLE_FAILED_INIT; return CURLE_FAILED_INIT;
@ -680,9 +682,9 @@ static CURLcode smb_send_setup(struct Curl_easy *data)
if(byte_count > sizeof(msg.bytes)) if(byte_count > sizeof(msg.bytes))
return CURLE_FILESIZE_EXCEEDED; return CURLE_FILESIZE_EXCEEDED;
Curl_ntlm_core_mk_lm_hash(conn->passwd, lm_hash); Curl_ntlm_core_mk_lm_hash(passwd, lm_hash);
Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm); Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm);
Curl_ntlm_core_mk_nt_hash(conn->passwd, nt_hash); Curl_ntlm_core_mk_nt_hash(passwd, nt_hash);
Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt); Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt);
memset(&msg, 0, sizeof(msg) - sizeof(msg.bytes)); memset(&msg, 0, sizeof(msg) - sizeof(msg.bytes));

View file

@ -99,8 +99,7 @@ struct socks_ctx {
enum socks_state_t state; enum socks_state_t state;
struct bufq iobuf; struct bufq iobuf;
struct Curl_peer *dest; struct Curl_peer *dest;
const char *user; struct Curl_creds *creds;
const char *passwd;
CURLproxycode presult; CURLproxycode presult;
uint32_t resolv_id; uint32_t resolv_id;
uint8_t ip_version; uint8_t ip_version;
@ -287,8 +286,8 @@ static CURLproxycode socks4_req_add_user(struct socks_ctx *sx,
CURLcode result; CURLcode result;
size_t nwritten; size_t nwritten;
if(sx->user) { if(sx->creds) {
size_t plen = strlen(sx->user); size_t plen = strlen(sx->creds->user);
if(plen > 255) { if(plen > 255) {
/* there is no real size limit to this field in the protocol, but /* there is no real size limit to this field in the protocol, but
SOCKS5 limits the proxy user field to 255 bytes and it seems likely SOCKS5 limits the proxy user field to 255 bytes and it seems likely
@ -297,7 +296,7 @@ static CURLproxycode socks4_req_add_user(struct socks_ctx *sx,
return CURLPX_LONG_USER; return CURLPX_LONG_USER;
} }
/* add proxy name WITH trailing zero */ /* add proxy name WITH trailing zero */
result = Curl_bufq_cwrite(&sx->iobuf, sx->user, plen + 1, result = Curl_bufq_cwrite(&sx->iobuf, sx->creds->user, plen + 1,
&nwritten); &nwritten);
if(result || (nwritten != (plen + 1))) if(result || (nwritten != (plen + 1)))
return CURLPX_SEND_REQUEST; return CURLPX_SEND_REQUEST;
@ -603,7 +602,7 @@ static CURLproxycode socks5_req0_init(struct Curl_cfilter *cf,
"CURLOPT_SOCKS5_AUTH: %u", auth); "CURLOPT_SOCKS5_AUTH: %u", auth);
if(!(auth & CURLAUTH_BASIC)) if(!(auth & CURLAUTH_BASIC))
/* disable username/password auth */ /* disable username/password auth */
sx->user = NULL; Curl_creds_unlink(&sx->creds);
req[0] = 5; /* version */ req[0] = 5; /* version */
nauths = 1; nauths = 1;
@ -614,7 +613,7 @@ static CURLproxycode socks5_req0_init(struct Curl_cfilter *cf,
req[1 + nauths] = 1; /* GSS-API */ req[1 + nauths] = 1; /* GSS-API */
} }
#endif #endif
if(sx->user) { if(sx->creds) {
++nauths; ++nauths;
req[1 + nauths] = 2; /* username/password */ req[1 + nauths] = 2; /* username/password */
} }
@ -687,9 +686,9 @@ static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf,
unsigned char buf[2]; unsigned char buf[2];
CURLcode result; CURLcode result;
if(sx->user && sx->passwd) { if(sx->creds) {
ulen = strlen(sx->user); ulen = strlen(sx->creds->user);
plen = strlen(sx->passwd); plen = strlen(sx->creds->passwd);
/* the lengths must fit in a single byte */ /* the lengths must fit in a single byte */
if(ulen > 255) { if(ulen > 255) {
failf(data, "Excessive username length for proxy auth"); failf(data, "Excessive username length for proxy auth");
@ -714,7 +713,8 @@ static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf,
if(result || (nwritten != 2)) if(result || (nwritten != 2))
return CURLPX_SEND_REQUEST; return CURLPX_SEND_REQUEST;
if(ulen) { if(ulen) {
result = Curl_bufq_cwrite(&sx->iobuf, sx->user, ulen, &nwritten); result = Curl_bufq_cwrite(&sx->iobuf, sx->creds->user, ulen,
&nwritten);
if(result || (nwritten != ulen)) if(result || (nwritten != ulen))
return CURLPX_SEND_REQUEST; return CURLPX_SEND_REQUEST;
} }
@ -723,7 +723,8 @@ static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf,
if(result || (nwritten != 1)) if(result || (nwritten != 1))
return CURLPX_SEND_REQUEST; return CURLPX_SEND_REQUEST;
if(plen) { if(plen) {
result = Curl_bufq_cwrite(&sx->iobuf, sx->passwd, plen, &nwritten); result = Curl_bufq_cwrite(&sx->iobuf, sx->creds->passwd, plen,
&nwritten);
if(result || (nwritten != plen)) if(result || (nwritten != plen))
return CURLPX_SEND_REQUEST; return CURLPX_SEND_REQUEST;
} }
@ -1185,6 +1186,7 @@ static void socks_proxy_ctx_free(struct socks_ctx *ctx)
{ {
if(ctx) { if(ctx) {
Curl_peer_unlink(&ctx->dest); Curl_peer_unlink(&ctx->dest);
Curl_creds_unlink(&ctx->creds);
Curl_bufq_free(&ctx->iobuf); Curl_bufq_free(&ctx->iobuf);
curlx_free(ctx); curlx_free(ctx);
} }
@ -1259,10 +1261,8 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
out: out:
*done = (bool)cf->connected; *done = (bool)cf->connected;
if(*done || result) { if(*done || result)
ctx->user = NULL; Curl_creds_unlink(&ctx->creds);
ctx->passwd = NULL;
}
return result; return result;
} }
@ -1361,8 +1361,7 @@ CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
struct Curl_peer *dest, struct Curl_peer *dest,
uint8_t ip_version, uint8_t ip_version,
uint8_t proxy_type, uint8_t proxy_type,
const char *user, struct Curl_creds *creds)
const char *passwd)
{ {
struct Curl_cfilter *cf; struct Curl_cfilter *cf;
struct socks_ctx *ctx; struct socks_ctx *ctx;
@ -1391,8 +1390,7 @@ CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
Curl_peer_link(&ctx->dest, dest); Curl_peer_link(&ctx->dest, dest);
ctx->ip_version = ip_version; ctx->ip_version = ip_version;
ctx->proxy_type = proxy_type; ctx->proxy_type = proxy_type;
ctx->user = user; Curl_creds_link(&ctx->creds, creds);
ctx->passwd = passwd;
Curl_bufq_init2(&ctx->iobuf, SOCKS_CHUNK_SIZE, SOCKS_CHUNKS, Curl_bufq_init2(&ctx->iobuf, SOCKS_CHUNK_SIZE, SOCKS_CHUNKS,
BUFQ_OPT_SOFT_LIMIT); BUFQ_OPT_SOFT_LIMIT);

View file

@ -28,6 +28,7 @@
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
struct Curl_peer; struct Curl_peer;
struct Curl_creds;
/* /*
* Helper read-from-socket functions. Does the same as Curl_read() but it * Helper read-from-socket functions. Does the same as Curl_read() but it
@ -58,8 +59,7 @@ CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
struct Curl_peer *dest, struct Curl_peer *dest,
uint8_t ip_version, uint8_t ip_version,
uint8_t proxy_type, uint8_t proxy_type,
const char *user, struct Curl_creds *creds);
const char *passwd);
extern struct Curl_cftype Curl_cft_socks_proxy; extern struct Curl_cftype Curl_cft_socks_proxy;

View file

@ -840,13 +840,14 @@ static CURLcode check_telnet_options(struct Curl_easy *data,
/* Add the username as an environment variable if it /* Add the username as an environment variable if it
was given on the command line */ was given on the command line */
if(data->state.aptr.user) { if(data->state.creds) {
char buffer[256]; char buffer[256];
if(str_is_nonascii(data->conn->user)) { if(str_is_nonascii(Curl_creds_user(data->conn->creds))) {
DEBUGF(infof(data, "set a non ASCII username in telnet")); DEBUGF(infof(data, "set a non ASCII username in telnet"));
return CURLE_BAD_FUNCTION_ARGUMENT; return CURLE_BAD_FUNCTION_ARGUMENT;
} }
curl_msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user); curl_msnprintf(buffer, sizeof(buffer), "USER,%s",
Curl_creds_user(data->conn->creds));
beg = curl_slist_append(tn->telnet_vars, buffer); beg = curl_slist_append(tn->telnet_vars, buffer);
if(!beg) { if(!beg) {
curl_slist_free_all(tn->telnet_vars); curl_slist_free_all(tn->telnet_vars);

View file

@ -438,40 +438,6 @@ void Curl_init_CONNECT(struct Curl_easy *data)
data->state.upload = (data->state.httpreq == HTTPREQ_PUT); data->state.upload = (data->state.httpreq == HTTPREQ_PUT);
} }
/*
* Restore the user credentials to those set in options.
*/
CURLcode Curl_reset_userpwd(struct Curl_easy *data)
{
CURLcode result;
if(data->set.str[STRING_USERNAME] || data->set.str[STRING_PASSWORD])
data->state.creds_from = CREDS_OPTION;
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]);
return result;
}
/*
* Restore the proxy credentials to those set in options.
*/
CURLcode Curl_reset_proxypwd(struct Curl_easy *data)
{
#ifndef CURL_DISABLE_PROXY
CURLcode 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]);
return result;
#else
(void)data;
return CURLE_OK;
#endif
}
/* /*
* Curl_pretransfer() is called immediately before a transfer starts, and only * Curl_pretransfer() is called immediately before a transfer starts, and only
* once for one transfer no matter if it has redirects or do multi-pass * once for one transfer no matter if it has redirects or do multi-pass
@ -524,6 +490,9 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
#endif #endif
data->state.httpreq = data->set.method; data->state.httpreq = data->set.method;
/* initial transfer request coming up, forget the initial origin
* from a previous perform() on this handle. */
Curl_peer_unlink(&data->state.initial_origin);
data->state.requests = 0; data->state.requests = 0;
data->state.followlocation = 0; /* reset the location-follow counter */ data->state.followlocation = 0; /* reset the location-follow counter */
data->state.this_is_a_follow = FALSE; /* reset this */ data->state.this_is_a_follow = FALSE; /* reset this */
@ -625,11 +594,6 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
if(!result)
result = Curl_reset_userpwd(data);
if(!result)
result = Curl_reset_proxypwd(data);
data->req.headerbytecount = 0; data->req.headerbytecount = 0;
Curl_headers_cleanup(data); Curl_headers_cleanup(data);
return result; return result;

View file

@ -31,8 +31,6 @@ char *Curl_checkheaders(const struct Curl_easy *data,
void Curl_init_CONNECT(struct Curl_easy *data); void Curl_init_CONNECT(struct Curl_easy *data);
CURLcode Curl_reset_userpwd(struct Curl_easy *data);
CURLcode Curl_reset_proxypwd(struct Curl_easy *data);
CURLcode Curl_pretransfer(struct Curl_easy *data); CURLcode Curl_pretransfer(struct Curl_easy *data);
CURLcode Curl_sendrecv(struct Curl_easy *data); CURLcode Curl_sendrecv(struct Curl_easy *data);

671
lib/url.c

File diff suppressed because it is too large Load diff

View file

@ -55,6 +55,7 @@
#include "asyn.h" #include "asyn.h"
#include "cookie.h" #include "cookie.h"
#include "creds.h"
#include "psl.h" #include "psl.h"
#include "formdata.h" #include "formdata.h"
#include "http_chunks.h" /* for the structs and enum stuff */ #include "http_chunks.h" /* for the structs and enum stuff */
@ -206,10 +207,9 @@ struct digestdata {
BYTE *input_token; BYTE *input_token;
size_t input_token_len; size_t input_token_len;
CtxtHandle *http_context; CtxtHandle *http_context;
/* copy of user/passwd used to make the identity for http_context. /* linked credentials used to make the identity for http_context.
either may be NULL. */ may be NULL. */
char *user; struct Curl_creds *creds;
char *passwd;
#else #else
char *nonce; char *nonce;
char *cnonce; char *cnonce;
@ -249,7 +249,6 @@ struct ConnectBits {
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
BIT(httpproxy); /* if set, this transfer is done through an HTTP proxy */ BIT(httpproxy); /* if set, this transfer is done through an HTTP proxy */
BIT(socksproxy); /* if set, this transfer is done through a socks proxy */ BIT(socksproxy); /* if set, this transfer is done through a socks proxy */
BIT(proxy_user_passwd); /* user+password for the proxy? */
BIT(tunnel_proxy); /* if CONNECT is used to "tunnel" through the proxy. BIT(tunnel_proxy); /* if CONNECT is used to "tunnel" through the proxy.
This is implicit when SSL-protocols are used through This is implicit when SSL-protocols are used through
proxies, but can also be enabled explicitly by proxies, but can also be enabled explicitly by
@ -275,9 +274,6 @@ struct ConnectBits {
EPRT does not work we disable it for the forthcoming EPRT does not work we disable it for the forthcoming
requests */ requests */
BIT(ftp_use_data_ssl); /* Enabled SSL for the data connection */ BIT(ftp_use_data_ssl); /* Enabled SSL for the data connection */
#endif
#ifndef CURL_DISABLE_NETRC
BIT(netrc); /* name+password provided by netrc */
#endif #endif
BIT(bound); /* set true if bind() has already been done on this socket/ BIT(bound); /* set true if bind() has already been done on this socket/
connection */ connection */
@ -328,9 +324,8 @@ struct ip_quadruple {
struct proxy_info { struct proxy_info {
struct Curl_peer *peer; /* proxy to this peer */ struct Curl_peer *peer; /* proxy to this peer */
struct Curl_creds *creds; /* use these credentials, maybe NULL */
uint8_t proxytype; /* what kind of proxy that is in use */ uint8_t proxytype; /* what kind of proxy that is in use */
char *user; /* proxy username string, allocated */
char *passwd; /* proxy password string, allocated */
}; };
/* /*
@ -370,11 +365,8 @@ struct connectdata {
struct proxy_info socks_proxy; struct proxy_info socks_proxy;
struct proxy_info http_proxy; struct proxy_info http_proxy;
#endif #endif
char *user; /* username string, allocated */ struct Curl_creds *creds; /* When connection itself is tied to credentials */
char *passwd; /* password string, allocated */
char *options; /* options string, allocated */ char *options; /* options string, allocated */
char *sasl_authzid; /* authorization identity string, allocated */
char *oauth_bearer; /* OAUTH2 bearer, allocated */
struct curltime created; /* creation time */ struct curltime created; /* creation time */
struct curltime lastused; /* when returned to the connection pool as idle */ struct curltime lastused; /* when returned to the connection pool as idle */
@ -652,11 +644,6 @@ struct urlpieces {
char *query; 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 { struct UrlState {
/* buffers to store authentication data in, as parsed from input options */ /* buffers to store authentication data in, as parsed from input options */
struct curltime keeps_speed; /* for the progress meter really */ struct curltime keeps_speed; /* for the progress meter really */
@ -672,10 +659,10 @@ struct UrlState {
curl_off_t current_speed; /* the ProgressShow() function sets this, curl_off_t current_speed; /* the ProgressShow() function sets this,
bytes / second */ bytes / second */
/* origin of the first (not followed) request. /* Origin of the initial (e.g. not followed) request of a transfer.
if set, this is the origin we sent authorization to, none else. Credentials from CURLOPT_* are only valid for this origin.
Used to make Location: following not keep sending user+password. */ Always set once a transfer starts searching for connections. */
struct Curl_peer *first_origin; struct Curl_peer *initial_origin;
int os_errno; /* filled in with errno whenever an error occurs */ int os_errno; /* filled in with errno whenever an error occurs */
int requests; /* request counter: redirects + authentication retakes */ int requests; /* request counter: redirects + authentication retakes */
@ -765,6 +752,8 @@ struct UrlState {
struct store_netrc netrc; struct store_netrc netrc;
#endif #endif
struct Curl_creds *creds; /* Credentials for the origin only */
/* Dynamically allocated strings, MUST be freed before this struct is /* Dynamically allocated strings, MUST be freed before this struct is
killed. */ killed. */
struct dynamically_allocated_data { struct dynamically_allocated_data {
@ -776,14 +765,6 @@ struct UrlState {
#ifndef CURL_DISABLE_RTSP #ifndef CURL_DISABLE_RTSP
char *rtsp_transport; char *rtsp_transport;
#endif #endif
/* transfer credentials */
char *user;
char *passwd;
#ifndef CURL_DISABLE_PROXY
char *proxyuser;
char *proxypasswd;
#endif
} aptr; } aptr;
#ifndef CURL_DISABLE_HTTP #ifndef CURL_DISABLE_HTTP
struct http_negotiation http_neg; struct http_negotiation http_neg;
@ -793,8 +774,6 @@ struct UrlState {
CONN_MAX_RETRIES */ CONN_MAX_RETRIES */
uint8_t httpreq; /* Curl_HttpReq; what kind of HTTP request (if any) uint8_t httpreq; /* Curl_HttpReq; what kind of HTTP request (if any)
is this */ is this */
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 /* 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 the easy handle so curl_easy_cleanup() on such an easy handle will

View file

@ -40,24 +40,21 @@
* *
* Parameters: * Parameters:
* *
* authzid [in] - The authorization identity. * creds [in] - The credentials.
* authcid [in] - The authentication identity.
* passwd [in] - The password. * passwd [in] - The password.
* out [out] - The result storage. * out [out] - The result storage.
* *
* Returns CURLE_OK on success. * Returns CURLE_OK on success.
*/ */
CURLcode Curl_auth_create_plain_message(const char *authzid, CURLcode Curl_auth_create_plain_message(struct Curl_creds *creds,
const char *authcid,
const char *passwd,
struct bufref *out) struct bufref *out)
{ {
size_t len; size_t len;
char *auth; char *auth;
size_t zlen = (authzid == NULL ? 0 : strlen(authzid)); size_t zlen = strlen(Curl_creds_sasl_authzid(creds));
size_t clen = strlen(authcid); size_t clen = strlen(Curl_creds_user(creds));
size_t plen = strlen(passwd); size_t plen = strlen(Curl_creds_passwd(creds));
if((zlen > CURL_MAX_INPUT_LENGTH) || (clen > CURL_MAX_INPUT_LENGTH) || if((zlen > CURL_MAX_INPUT_LENGTH) || (clen > CURL_MAX_INPUT_LENGTH) ||
(plen > CURL_MAX_INPUT_LENGTH)) (plen > CURL_MAX_INPUT_LENGTH))
@ -65,8 +62,10 @@ CURLcode Curl_auth_create_plain_message(const char *authzid,
len = zlen + clen + plen + 2; len = zlen + clen + plen + 2;
auth = curl_maprintf("%s%c%s%c%s", authzid ? authzid : "", '\0', auth = curl_maprintf("%s%c%s%c%s",
authcid, '\0', passwd); Curl_creds_sasl_authzid(creds), '\0',
Curl_creds_user(creds), '\0',
Curl_creds_passwd(creds));
if(!auth) if(!auth)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
Curl_bufref_set(out, auth, len, curl_free); Curl_bufref_set(out, auth, len, curl_free);

View file

@ -47,18 +47,19 @@
* Returns CURLE_OK on success. * Returns CURLE_OK on success.
*/ */
CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg, CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
struct bufref *out) struct bufref *out)
{ {
struct HMAC_context *ctxt; struct HMAC_context *ctxt;
unsigned char digest[MD5_DIGEST_LEN]; unsigned char digest[MD5_DIGEST_LEN];
char *response; char *response;
const char *user = Curl_creds_user(creds);
const char *passwd = Curl_creds_passwd(creds);
/* Compute the digest using the password as the key */ /* Compute the digest using the password as the key */
ctxt = Curl_HMAC_init(&Curl_HMAC_MD5, ctxt = Curl_HMAC_init(&Curl_HMAC_MD5,
(const unsigned char *)passwdp, (const unsigned char *)passwd,
curlx_uztoui(strlen(passwdp))); curlx_uztoui(strlen(passwd)));
if(!ctxt) if(!ctxt)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
@ -73,7 +74,7 @@ CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg,
/* Generate the response */ /* Generate the response */
response = curl_maprintf( response = curl_maprintf(
"%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
userp, digest[0], digest[1], digest[2], digest[3], digest[4], user, digest[0], digest[1], digest[2], digest[3], digest[4],
digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], digest[5], digest[6], digest[7], digest[8], digest[9], digest[10],
digest[11], digest[12], digest[13], digest[14], digest[15]); digest[11], digest[12], digest[13], digest[14], digest[15]);
if(!response) if(!response)

View file

@ -332,13 +332,14 @@ bool Curl_auth_is_digest_supported(void)
*/ */
CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
const struct bufref *chlg, const struct bufref *chlg,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
const char *service, const char *service,
struct bufref *out) struct bufref *out)
{ {
size_t i; size_t i;
struct MD5_context *ctxt; struct MD5_context *ctxt;
const char *userp = Curl_creds_user(creds);
const char *passwdp = Curl_creds_passwd(creds);
char *response = NULL; char *response = NULL;
unsigned char digest[MD5_DIGEST_LEN]; unsigned char digest[MD5_DIGEST_LEN];
char HA1_hex[(2 * MD5_DIGEST_LEN) + 1]; char HA1_hex[(2 * MD5_DIGEST_LEN) + 1];
@ -666,8 +667,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
* Parameters: * Parameters:
* *
* data [in] - The session handle. * data [in] - The session handle.
* userp [in] - The username. * creds [in] - The credentials
* passwdp [in] - The user's password.
* request [in] - The HTTP request. * request [in] - The HTTP request.
* uripath [in] - The path of the HTTP uri. * uripath [in] - The path of the HTTP uri.
* digest [in/out] - The digest data struct being used and modified. * digest [in/out] - The digest data struct being used and modified.
@ -679,8 +679,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
*/ */
static CURLcode auth_create_digest_http_message( static CURLcode auth_create_digest_http_message(
struct Curl_easy *data, struct Curl_easy *data,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
const unsigned char *request, const unsigned char *request,
const unsigned char *uripath, const unsigned char *uripath,
struct digestdata *digest, struct digestdata *digest,
@ -689,6 +688,8 @@ static CURLcode auth_create_digest_http_message(
CURLcode (*hash)(unsigned char *, const unsigned char *, const size_t)) CURLcode (*hash)(unsigned char *, const unsigned char *, const size_t))
{ {
CURLcode result; CURLcode result;
const char *userp = Curl_creds_user(creds);
const char *passwdp = Curl_creds_passwd(creds);
unsigned char hashbuf[32]; /* 32 bytes/256 bits */ unsigned char hashbuf[32]; /* 32 bytes/256 bits */
unsigned char request_digest[65]; unsigned char request_digest[65];
unsigned char ha1[65]; /* 64 digits and 1 zero byte */ unsigned char ha1[65]; /* 64 digits and 1 zero byte */
@ -986,29 +987,28 @@ oom:
* Returns CURLE_OK on success. * Returns CURLE_OK on success.
*/ */
CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
const unsigned char *request, const unsigned char *request,
const unsigned char *uripath, const unsigned char *uripath,
struct digestdata *digest, struct digestdata *digest,
char **outptr, size_t *outlen) char **outptr, size_t *outlen)
{ {
if(digest->algo <= ALGO_MD5SESS) if(digest->algo <= ALGO_MD5SESS)
return auth_create_digest_http_message(data, userp, passwdp, return auth_create_digest_http_message(data, creds,
request, uripath, digest, request, uripath, digest,
outptr, outlen, outptr, outlen,
auth_digest_md5_to_ascii, auth_digest_md5_to_ascii,
Curl_md5it); Curl_md5it);
if(digest->algo <= ALGO_SHA256SESS) if(digest->algo <= ALGO_SHA256SESS)
return auth_create_digest_http_message(data, userp, passwdp, return auth_create_digest_http_message(data, creds,
request, uripath, digest, request, uripath, digest,
outptr, outlen, outptr, outlen,
auth_digest_sha256_to_ascii, auth_digest_sha256_to_ascii,
Curl_sha256it); Curl_sha256it);
#ifdef CURL_HAVE_SHA512_256 #ifdef CURL_HAVE_SHA512_256
if(digest->algo <= ALGO_SHA512_256SESS) if(digest->algo <= ALGO_SHA512_256SESS)
return auth_create_digest_http_message(data, userp, passwdp, return auth_create_digest_http_message(data, creds,
request, uripath, digest, request, uripath, digest,
outptr, outlen, outptr, outlen,
auth_digest_sha256_to_ascii, auth_digest_sha256_to_ascii,

View file

@ -28,6 +28,7 @@
#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_DIGEST_AUTH) #if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_DIGEST_AUTH)
#include "creds.h"
#include "vauth/vauth.h" #include "vauth/vauth.h"
#include "vauth/digest.h" #include "vauth/digest.h"
#include "curlx/multibyte.h" #include "curlx/multibyte.h"
@ -83,8 +84,7 @@ bool Curl_auth_is_digest_supported(void)
*/ */
CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
const struct bufref *chlg, const struct bufref *chlg,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
const char *service, const char *service,
struct bufref *out) struct bufref *out)
{ {
@ -137,9 +137,10 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
if(userp && *userp) { if(Curl_creds_has_user(creds)) {
/* Populate our identity structure */ /* Populate our identity structure */
result = Curl_create_sspi_identity(userp, passwdp, &identity); result = Curl_create_sspi_identity(creds->user, creds->passwd,
&identity);
if(result) { if(result) {
curlx_free(spn); curlx_free(spn);
curlx_free(output_token); curlx_free(output_token);
@ -381,8 +382,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
* Returns CURLE_OK on success. * Returns CURLE_OK on success.
*/ */
CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
const unsigned char *request, const unsigned char *request,
const unsigned char *uripath, const unsigned char *uripath,
struct digestdata *digest, struct digestdata *digest,
@ -421,16 +421,12 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
/* If the user/passwd that was used to make the identity for http_context /* If the user/passwd that was used to make the identity for http_context
has changed then delete that context. */ has changed then delete that context. */
if((userp && !digest->user) || (!userp && digest->user) || if(!Curl_creds_same(creds, digest->creds)) {
(passwdp && !digest->passwd) || (!passwdp && digest->passwd) ||
(userp && digest->user && Curl_timestrcmp(userp, digest->user)) ||
(passwdp && digest->passwd && Curl_timestrcmp(passwdp, digest->passwd))) {
if(digest->http_context) { if(digest->http_context) {
Curl_pSecFn->DeleteSecurityContext(digest->http_context); Curl_pSecFn->DeleteSecurityContext(digest->http_context);
curlx_safefree(digest->http_context); curlx_safefree(digest->http_context);
} }
curlx_safefree(digest->user); Curl_creds_unlink(&digest->creds);
curlx_safefree(digest->passwd);
} }
if(digest->http_context) { if(digest->http_context) {
@ -473,13 +469,13 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
unsigned long attrs; unsigned long attrs;
TCHAR *spn; TCHAR *spn;
/* free the copy of user/passwd used to make the previous identity */ /* free the credentials used to make the previous identity */
curlx_safefree(digest->user); Curl_creds_unlink(&digest->creds);
curlx_safefree(digest->passwd);
if(userp && *userp) { if(Curl_creds_has_user(creds)) {
/* Populate our identity structure */ /* Populate our identity structure */
if(Curl_create_sspi_identity(userp, passwdp, &identity)) { if(Curl_create_sspi_identity(creds->user, creds->passwd,
&identity)) {
curlx_free(output_token); curlx_free(output_token);
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
@ -499,26 +495,8 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
/* Use the current Windows user */ /* Use the current Windows user */
p_identity = NULL; p_identity = NULL;
if(userp) { if(creds)
digest->user = curlx_strdup(userp); Curl_creds_link(&digest->creds, creds);
if(!digest->user) {
curlx_free(output_token);
Curl_sspi_free_identity(p_identity);
return CURLE_OUT_OF_MEMORY;
}
}
if(passwdp) {
digest->passwd = curlx_strdup(passwdp);
if(!digest->passwd) {
curlx_free(output_token);
Curl_sspi_free_identity(p_identity);
curlx_safefree(digest->user);
return CURLE_OUT_OF_MEMORY;
}
}
/* Acquire our credentials handle */ /* Acquire our credentials handle */
status = Curl_pSecFn->AcquireCredentialsHandle(NULL, status = Curl_pSecFn->AcquireCredentialsHandle(NULL,
@ -649,8 +627,7 @@ void Curl_auth_digest_cleanup(struct digestdata *digest)
} }
/* Free the copy of user/passwd used to make the identity for http_context */ /* Free the copy of user/passwd used to make the identity for http_context */
curlx_safefree(digest->user); Curl_creds_unlink(&digest->creds);
curlx_safefree(digest->passwd);
} }
#endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_DIGEST_AUTH */ #endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_DIGEST_AUTH */

View file

@ -54,15 +54,14 @@ bool Curl_auth_gsasl_is_supported(struct Curl_easy *data,
} }
CURLcode Curl_auth_gsasl_start(struct Curl_easy *data, CURLcode Curl_auth_gsasl_start(struct Curl_easy *data,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
struct gsasldata *gsasl) struct gsasldata *gsasl)
{ {
#if GSASL_VERSION_NUMBER >= 0x010b00 #if GSASL_VERSION_NUMBER >= 0x010b00
int res; int res;
res = res =
#endif #endif
gsasl_property_set(gsasl->client, GSASL_AUTHID, userp); gsasl_property_set(gsasl->client, GSASL_AUTHID, creds->user);
#if GSASL_VERSION_NUMBER >= 0x010b00 #if GSASL_VERSION_NUMBER >= 0x010b00
if(res != GSASL_OK) { if(res != GSASL_OK) {
failf(data, "setting AUTHID failed: %s", gsasl_strerror(res)); failf(data, "setting AUTHID failed: %s", gsasl_strerror(res));
@ -73,7 +72,7 @@ CURLcode Curl_auth_gsasl_start(struct Curl_easy *data,
#if GSASL_VERSION_NUMBER >= 0x010b00 #if GSASL_VERSION_NUMBER >= 0x010b00
res = res =
#endif #endif
gsasl_property_set(gsasl->client, GSASL_PASSWORD, passwdp); gsasl_property_set(gsasl->client, GSASL_PASSWORD, creds->passwd);
#if GSASL_VERSION_NUMBER >= 0x010b00 #if GSASL_VERSION_NUMBER >= 0x010b00
if(res != GSASL_OK) { if(res != GSASL_OK) {
failf(data, "setting PASSWORD failed: %s", gsasl_strerror(res)); failf(data, "setting PASSWORD failed: %s", gsasl_strerror(res));

View file

@ -74,8 +74,7 @@ bool Curl_auth_is_gssapi_supported(void)
* Returns CURLE_OK on success. * Returns CURLE_OK on success.
*/ */
CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
const char *service, const char *service,
const char *host, const char *host,
const bool mutual_auth, const bool mutual_auth,
@ -90,8 +89,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
(void)userp; (void)creds;
(void)passwdp;
if(!krb5->spn) { if(!krb5->spn) {
gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;

View file

@ -79,8 +79,7 @@ bool Curl_auth_is_gssapi_supported(void)
* Returns CURLE_OK on success. * Returns CURLE_OK on success.
*/ */
CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
const char *service, const char *service,
const char *host, const char *host,
const bool mutual_auth, const bool mutual_auth,
@ -128,9 +127,10 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
if(!krb5->credentials) { if(!krb5->credentials) {
/* Do we have credentials to use or are we using single sign-on? */ /* Do we have credentials to use or are we using single sign-on? */
if(userp && *userp) { if(Curl_creds_has_user(creds)) {
/* Populate our identity structure */ /* Populate our identity structure */
result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity); result = Curl_create_sspi_identity(
creds->user, creds->passwd, &krb5->identity);
if(result) if(result)
return result; return result;

View file

@ -421,8 +421,7 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length)
* Returns CURLE_OK on success. * Returns CURLE_OK on success.
*/ */
CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
const char *service, const char *service,
const char *host, const char *host,
struct ntlmdata *ntlm, struct ntlmdata *ntlm,
@ -453,8 +452,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
size_t domoff = hostoff + hostlen; /* This is 0: remember that host and size_t domoff = hostoff + hostlen; /* This is 0: remember that host and
domain are empty */ domain are empty */
(void)data; (void)data;
(void)userp; (void)creds;
(void)passwdp;
(void)service; (void)service;
(void)host; (void)host;
@ -542,8 +540,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
* Returns CURLE_OK on success. * Returns CURLE_OK on success.
*/ */
CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
struct ntlmdata *ntlm, struct ntlmdata *ntlm,
struct bufref *out) struct bufref *out)
{ {
@ -579,6 +576,8 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
/* The fixed hostname we provide, in order to not leak our real local host /* The fixed hostname we provide, in order to not leak our real local host
name. Copy the name used by Firefox. */ name. Copy the name used by Firefox. */
static const char host[] = "WORKSTATION"; static const char host[] = "WORKSTATION";
const char *userp = Curl_creds_user(creds);
const char *passwdp = Curl_creds_passwd(creds);
const char *user; const char *user;
const char *domain = ""; const char *domain = "";
size_t hostoff = 0; size_t hostoff = 0;

View file

@ -76,8 +76,7 @@ bool Curl_auth_is_ntlm_supported(void)
* Returns CURLE_OK on success. * Returns CURLE_OK on success.
*/ */
CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
const char *service, const char *service,
const char *host, const char *host,
struct ntlmdata *ntlm, struct ntlmdata *ntlm,
@ -111,11 +110,12 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
if(!ntlm->output_token) if(!ntlm->output_token)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
if(userp && *userp) { if(Curl_creds_has_user(creds)) {
CURLcode result; CURLcode result;
/* Populate our identity structure */ /* Populate our identity structure */
result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity); result = Curl_create_sspi_identity(
creds->user, creds->passwd, &ntlm->identity);
if(result) if(result)
return result; return result;
@ -227,8 +227,7 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
* Returns CURLE_OK on success. * Returns CURLE_OK on success.
*/ */
CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
struct ntlmdata *ntlm, struct ntlmdata *ntlm,
struct bufref *out) struct bufref *out)
{ {
@ -240,8 +239,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
SECURITY_STATUS status; SECURITY_STATUS status;
unsigned long attrs; unsigned long attrs;
(void)passwdp; (void)creds;
(void)userp;
/* Setup the type-2 "input" security buffer */ /* Setup the type-2 "input" security buffer */
type_2_desc.ulVersion = SECBUFFER_VERSION; type_2_desc.ulVersion = SECBUFFER_VERSION;

View file

@ -47,21 +47,22 @@
* *
* Returns CURLE_OK on success. * Returns CURLE_OK on success.
*/ */
CURLcode Curl_auth_create_oauth_bearer_message(const char *user, CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_creds *creds,
const char *host, const char *host,
const long port, const long port,
const char *bearer,
struct bufref *out) struct bufref *out)
{ {
char *oauth; char *oauth;
/* Generate the message */ /* Generate the message */
if(port == 0 || port == 80) if(port == 0 || port == 80)
oauth = curl_maprintf("n,a=%s,\1host=%s\1auth=Bearer %s\1\1", user, host, oauth = curl_maprintf("n,a=%s,\1host=%s\1auth=Bearer %s\1\1",
bearer); Curl_creds_user(creds), host,
Curl_creds_oauth_bearer(creds));
else else
oauth = curl_maprintf("n,a=%s,\1host=%s\1port=%ld\1auth=Bearer %s\1\1", oauth = curl_maprintf("n,a=%s,\1host=%s\1port=%ld\1auth=Bearer %s\1\1",
user, host, port, bearer); Curl_creds_user(creds), host, port,
Curl_creds_oauth_bearer(creds));
if(!oauth) if(!oauth)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
@ -83,12 +84,13 @@ CURLcode Curl_auth_create_oauth_bearer_message(const char *user,
* *
* Returns CURLE_OK on success. * Returns CURLE_OK on success.
*/ */
CURLcode Curl_auth_create_xoauth_bearer_message(const char *user, CURLcode Curl_auth_create_xoauth_bearer_message(struct Curl_creds *creds,
const char *bearer,
struct bufref *out) struct bufref *out)
{ {
/* Generate the message */ /* Generate the message */
char *xoauth = curl_maprintf("user=%s\1auth=Bearer %s\1\1", user, bearer); char *xoauth = curl_maprintf("user=%s\1auth=Bearer %s\1\1",
Curl_creds_user(creds),
Curl_creds_oauth_bearer(creds));
if(!xoauth) if(!xoauth)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;

View file

@ -70,8 +70,7 @@ bool Curl_auth_is_spnego_supported(void)
* Returns CURLE_OK on success. * Returns CURLE_OK on success.
*/ */
CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
const char *user, struct Curl_creds *creds,
const char *password,
const char *service, const char *service,
const char *host, const char *host,
const char *chlg64, const char *chlg64,
@ -90,8 +89,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
struct gss_channel_bindings_struct chan; struct gss_channel_bindings_struct chan;
#endif #endif
(void)user; (void)creds;
(void)password;
if(nego->context && nego->status == GSS_S_COMPLETE) { if(nego->context && nego->status == GSS_S_COMPLETE) {
/* We finished successfully our part of authentication, but server /* We finished successfully our part of authentication, but server

View file

@ -78,8 +78,7 @@ bool Curl_auth_is_spnego_supported(void)
* Returns CURLE_OK on success. * Returns CURLE_OK on success.
*/ */
CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
const char *user, struct Curl_creds *creds,
const char *password,
const char *service, const char *service,
const char *host, const char *host,
const char *chlg64, const char *chlg64,
@ -133,9 +132,10 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
if(!nego->credentials) { if(!nego->credentials) {
/* Do we have credentials to use or are we using single sign-on? */ /* Do we have credentials to use or are we using single sign-on? */
if(user && *user) { if(Curl_creds_has_user(creds)) {
/* Populate our identity structure */ /* Populate our identity structure */
result = Curl_create_sspi_identity(user, password, &nego->identity); result = Curl_create_sspi_identity(creds->user, creds->passwd,
&nego->identity);
if(result) if(result)
return result; return result;

View file

@ -24,6 +24,7 @@
#include "curl_setup.h" #include "curl_setup.h"
#include "vauth/vauth.h" #include "vauth/vauth.h"
#include "creds.h"
#include "curlx/multibyte.h" #include "curlx/multibyte.h"
#include "url.h" #include "url.h"
@ -111,15 +112,16 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host,
* *
* Returns TRUE on success; otherwise FALSE. * Returns TRUE on success; otherwise FALSE.
*/ */
bool Curl_auth_user_contains_domain(const char *user) bool Curl_auth_user_contains_domain(struct Curl_creds *creds)
{ {
bool valid = FALSE; bool valid = FALSE;
if(user && *user) { if(Curl_creds_has_user(creds)) {
/* Check we have a domain name or UPN present */ /* Check we have a domain name or UPN present */
const char *p = strpbrk(user, "\\/@"); const char *p = strpbrk(creds->user, "\\/@");
valid = (p != NULL && p > user && p < user + strlen(user) - 1); valid = (p != NULL) && (p > creds->user) &&
(p < (creds->user + strlen(creds->user) - 1));
} }
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
else else
@ -133,14 +135,12 @@ bool Curl_auth_user_contains_domain(const char *user)
/* /*
* Curl_auth_allowed_to_host() tells if authentication, cookies or other * Curl_auth_allowed_to_host() tells if authentication, cookies or other
* "sensitive data" can (still) be sent to this host. * "sensitive data" can be sent to the connection's origin.
*/ */
bool Curl_auth_allowed_to_host(struct Curl_easy *data) bool Curl_auth_allowed_to_host(struct Curl_easy *data)
{ {
return !data->state.this_is_a_follow || return data->set.allow_auth_to_other_hosts ||
data->set.allow_auth_to_other_hosts || Curl_peer_equal(data->state.initial_origin, data->conn->origin);
(data->state.first_origin &&
Curl_peer_equal(data->state.first_origin, data->conn->origin));
} }
#ifdef USE_NTLM #ifdef USE_NTLM

View file

@ -30,6 +30,7 @@
#include "urldata.h" #include "urldata.h"
struct Curl_easy; struct Curl_easy;
struct Curl_creds;
struct connectdata; struct connectdata;
#ifndef CURL_DISABLE_DIGEST_AUTH #ifndef CURL_DISABLE_DIGEST_AUTH
@ -69,12 +70,10 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host,
#endif #endif
/* This is used to test if the user contains a Windows domain name */ /* This is used to test if the user contains a Windows domain name */
bool Curl_auth_user_contains_domain(const char *user); bool Curl_auth_user_contains_domain(struct Curl_creds *creds);
/* This is used to generate a PLAIN cleartext message */ /* This is used to generate a PLAIN cleartext message */
CURLcode Curl_auth_create_plain_message(const char *authzid, CURLcode Curl_auth_create_plain_message(struct Curl_creds *creds,
const char *authcid,
const char *passwd,
struct bufref *out); struct bufref *out);
/* This is used to generate a LOGIN cleartext message */ /* This is used to generate a LOGIN cleartext message */
@ -86,8 +85,7 @@ void Curl_auth_create_external_message(const char *user, struct bufref *out);
#ifndef CURL_DISABLE_DIGEST_AUTH #ifndef CURL_DISABLE_DIGEST_AUTH
/* This is used to generate a CRAM-MD5 response message */ /* This is used to generate a CRAM-MD5 response message */
CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg, CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
struct bufref *out); struct bufref *out);
/* This is used to evaluate if DIGEST is supported */ /* This is used to evaluate if DIGEST is supported */
@ -96,8 +94,7 @@ bool Curl_auth_is_digest_supported(void);
/* This is used to generate a base64 encoded DIGEST-MD5 response message */ /* This is used to generate a base64 encoded DIGEST-MD5 response message */
CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
const struct bufref *chlg, const struct bufref *chlg,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
const char *service, const char *service,
struct bufref *out); struct bufref *out);
@ -107,8 +104,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
/* This is used to generate an HTTP DIGEST response message */ /* This is used to generate an HTTP DIGEST response message */
CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
const unsigned char *request, const unsigned char *request,
const unsigned char *uripath, const unsigned char *uripath,
struct digestdata *digest, struct digestdata *digest,
@ -140,8 +136,7 @@ bool Curl_auth_gsasl_is_supported(struct Curl_easy *data,
struct gsasldata *gsasl); struct gsasldata *gsasl);
/* This is used to start a gsasl method */ /* This is used to start a gsasl method */
CURLcode Curl_auth_gsasl_start(struct Curl_easy *data, CURLcode Curl_auth_gsasl_start(struct Curl_easy *data,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
struct gsasldata *gsasl); struct gsasldata *gsasl);
/* This is used to process and generate a new SASL token */ /* This is used to process and generate a new SASL token */
@ -197,8 +192,7 @@ void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm);
/* This is used to generate a base64 encoded NTLM type-1 message */ /* This is used to generate a base64 encoded NTLM type-1 message */
CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
const char *service, const char *service,
const char *host, const char *host,
struct ntlmdata *ntlm, struct ntlmdata *ntlm,
@ -211,8 +205,7 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
/* This is used to generate a base64 encoded NTLM type-3 message */ /* This is used to generate a base64 encoded NTLM type-3 message */
CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
struct ntlmdata *ntlm, struct ntlmdata *ntlm,
struct bufref *out); struct bufref *out);
@ -221,15 +214,13 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
#endif /* USE_NTLM */ #endif /* USE_NTLM */
/* This is used to generate a base64 encoded OAuth 2.0 message */ /* This is used to generate a base64 encoded OAuth 2.0 message */
CURLcode Curl_auth_create_oauth_bearer_message(const char *user, CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_creds *creds,
const char *host, const char *host,
const long port, const long port,
const char *bearer,
struct bufref *out); struct bufref *out);
/* This is used to generate a base64 encoded XOAuth 2.0 message */ /* This is used to generate a base64 encoded XOAuth 2.0 message */
CURLcode Curl_auth_create_xoauth_bearer_message(const char *user, CURLcode Curl_auth_create_xoauth_bearer_message(struct Curl_creds *creds,
const char *bearer,
struct bufref *out); struct bufref *out);
#ifdef USE_KERBEROS5 #ifdef USE_KERBEROS5
@ -260,8 +251,7 @@ bool Curl_auth_is_gssapi_supported(void);
/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token /* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token
message */ message */
CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
const char *userp, struct Curl_creds *creds,
const char *passwdp,
const char *service, const char *service,
const char *host, const char *host,
const bool mutual_auth, const bool mutual_auth,
@ -330,8 +320,7 @@ Curl_auth_nego_get(struct connectdata *conn, bool proxy);
/* This is used to decode a base64 encoded SPNEGO (Negotiate) challenge /* This is used to decode a base64 encoded SPNEGO (Negotiate) challenge
message */ message */
CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
const char *user, struct Curl_creds *creds,
const char *password,
const char *service, const char *service,
const char *host, const char *host,
const char *chlg64, const char *chlg64,

View file

@ -633,7 +633,8 @@ restart:
if(nprompts != 1) if(nprompts != 1)
return SSH_ERROR; return SSH_ERROR;
rc = ssh_userauth_kbdint_setanswer(sshc->ssh_session, 0, conn->passwd); rc = ssh_userauth_kbdint_setanswer(sshc->ssh_session, 0,
Curl_creds_passwd(conn->creds));
if(rc < 0) if(rc < 0)
return SSH_ERROR; return SSH_ERROR;
@ -920,7 +921,8 @@ static int myssh_in_AUTH_PASS_INIT(struct Curl_easy *data,
static int myssh_in_AUTH_PASS(struct Curl_easy *data, static int myssh_in_AUTH_PASS(struct Curl_easy *data,
struct ssh_conn *sshc) struct ssh_conn *sshc)
{ {
int rc = ssh_userauth_password(sshc->ssh_session, NULL, data->conn->passwd); int rc = ssh_userauth_password(sshc->ssh_session, NULL,
Curl_creds_passwd(data->conn->creds));
if(rc == SSH_AUTH_AGAIN) if(rc == SSH_AUTH_AGAIN)
return SSH_AGAIN; return SSH_AGAIN;
else if(rc == SSH_AUTH_SUCCESS) { else if(rc == SSH_AUTH_SUCCESS) {
@ -2571,9 +2573,10 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
return CURLE_FAILED_INIT; return CURLE_FAILED_INIT;
} }
if(conn->user && conn->user[0] != '\0') { if(Curl_creds_has_user(conn->creds)) {
infof(data, "User: %s", conn->user); infof(data, "User: %s", conn->creds->user);
rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_USER, conn->user); rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_USER,
conn->creds->user);
if(rc != SSH_OK) { if(rc != SSH_OK) {
failf(data, "Could not set user"); failf(data, "Could not set user");
return CURLE_FAILED_INIT; return CURLE_FAILED_INIT;

View file

@ -148,11 +148,12 @@ static void kbd_callback(const char *name, int name_len,
#endif /* CURL_LIBSSH2_DEBUG */ #endif /* CURL_LIBSSH2_DEBUG */
if(num_prompts == 1) { if(num_prompts == 1) {
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
const char *passwd = Curl_creds_passwd(conn->creds);
/* this function must allocate memory that can be freed by libssh2, which /* this function must allocate memory that can be freed by libssh2, which
uses the LIBSSH2_FREE_FUNC callback */ uses the LIBSSH2_FREE_FUNC callback */
responses[0].text = Curl_cstrdup(conn->passwd); responses[0].text = Curl_cstrdup(passwd);
responses[0].length = responses[0].length =
responses[0].text == NULL ? 0 : curlx_uztoui(strlen(conn->passwd)); responses[0].text == NULL ? 0 : curlx_uztoui(strlen(passwd));
} }
(void)prompts; (void)prompts;
} /* kbd_callback */ } /* kbd_callback */
@ -1496,9 +1497,9 @@ static CURLcode ssh_state_authlist(struct Curl_easy *data,
* Therefore always specify it here. * Therefore always specify it here.
*/ */
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
const char *user = Curl_creds_user(conn->creds);
sshc->authlist = libssh2_userauth_list(sshc->ssh_session, sshc->authlist = libssh2_userauth_list(sshc->ssh_session,
conn->user, user, curlx_uztoui(strlen(user)));
curlx_uztoui(strlen(conn->user)));
if(!sshc->authlist) { if(!sshc->authlist) {
int rc; int rc;
@ -1527,11 +1528,11 @@ static CURLcode ssh_state_auth_pkey(struct Curl_easy *data,
/* The function below checks if the files exists, no need to stat() here. /* The function below checks if the files exists, no need to stat() here.
*/ */
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
const char *user = Curl_creds_user(conn->creds);
int rc = int rc =
libssh2_userauth_publickey_fromfile_ex(sshc->ssh_session, libssh2_userauth_publickey_fromfile_ex(sshc->ssh_session,
conn->user, user,
curlx_uztoui( curlx_uztoui(strlen(user)),
strlen(conn->user)),
sshc->rsa_pub, sshc->rsa_pub,
sshc->rsa, sshc->passphrase); sshc->rsa, sshc->passphrase);
if(rc == LIBSSH2_ERROR_EAGAIN) if(rc == LIBSSH2_ERROR_EAGAIN)
@ -1579,11 +1580,13 @@ static CURLcode ssh_state_auth_pass(struct Curl_easy *data,
struct ssh_conn *sshc) struct ssh_conn *sshc)
{ {
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
const char *user = Curl_creds_user(conn->creds);
const char *passwd = Curl_creds_passwd(conn->creds);
int rc = int rc =
libssh2_userauth_password_ex(sshc->ssh_session, conn->user, libssh2_userauth_password_ex(sshc->ssh_session, user,
curlx_uztoui(strlen(conn->user)), curlx_uztoui(strlen(user)),
conn->passwd, passwd,
curlx_uztoui(strlen(conn->passwd)), curlx_uztoui(strlen(passwd)),
NULL); NULL);
if(rc == LIBSSH2_ERROR_EAGAIN) { if(rc == LIBSSH2_ERROR_EAGAIN) {
return CURLE_AGAIN; return CURLE_AGAIN;
@ -1680,7 +1683,7 @@ static CURLcode ssh_state_auth_agent(struct Curl_easy *data,
if(rc == 0) { if(rc == 0) {
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
rc = libssh2_agent_userauth(sshc->ssh_agent, conn->user, rc = libssh2_agent_userauth(sshc->ssh_agent, Curl_creds_user(conn->creds),
sshc->sshagent_identity); sshc->sshagent_identity);
if(rc < 0) { if(rc < 0) {
@ -1727,11 +1730,10 @@ static CURLcode ssh_state_auth_key(struct Curl_easy *data,
{ {
/* Authentication failed. Continue with keyboard-interactive now. */ /* Authentication failed. Continue with keyboard-interactive now. */
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
const char *user = Curl_creds_user(conn->creds);
int rc = int rc =
libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session, libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session,
conn->user, user, curlx_uztoui(strlen(user)),
curlx_uztoui(
strlen(conn->user)),
&kbd_callback); &kbd_callback);
if(rc == LIBSSH2_ERROR_EAGAIN) if(rc == LIBSSH2_ERROR_EAGAIN)
return CURLE_AGAIN; return CURLE_AGAIN;
@ -3452,9 +3454,9 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
if(!sshc) if(!sshc)
return CURLE_FAILED_INIT; return CURLE_FAILED_INIT;
infof(data, "User: '%s'", conn->user); infof(data, "User: '%s'", Curl_creds_user(conn->creds));
#ifdef CURL_LIBSSH2_DEBUG #ifdef CURL_LIBSSH2_DEBUG
infof(data, "Password: %s", conn->passwd); infof(data, "Password: %s", Curl_creds_passwd(conn->creds));
sock = conn->sock[FIRSTSOCKET]; sock = conn->sock[FIRSTSOCKET];
#endif /* CURL_LIBSSH2_DEBUG */ #endif /* CURL_LIBSSH2_DEBUG */

View file

@ -46,7 +46,6 @@ static CURLcode test_lib1978(const char *URL)
test_setopt(curl, CURLOPT_INFILESIZE, 0L); test_setopt(curl, CURLOPT_INFILESIZE, 0L);
test_setopt(curl, CURLOPT_VERBOSE, 1L); test_setopt(curl, CURLOPT_VERBOSE, 1L);
test_setopt(curl, CURLOPT_AWS_SIGV4, "aws:amz:us-east-1:s3"); test_setopt(curl, CURLOPT_AWS_SIGV4, "aws:amz:us-east-1:s3");
test_setopt(curl, CURLOPT_USERPWD, "xxx");
test_setopt(curl, CURLOPT_HEADER, 0L); test_setopt(curl, CURLOPT_HEADER, 0L);
test_setopt(curl, CURLOPT_URL, URL); test_setopt(curl, CURLOPT_URL, URL);

View file

@ -25,17 +25,37 @@
#ifndef CURL_DISABLE_NETRC #ifndef CURL_DISABLE_NETRC
#include "netrc.h" #include "netrc.h"
#include "creds.h"
static void t1304_stop(char **password, char **login) static void t1304_stop(struct Curl_creds **pc1, struct Curl_creds **pc2)
{ {
curlx_safefree(*password); Curl_creds_unlink(pc1);
curlx_safefree(*login); Curl_creds_unlink(pc2);
}
static bool t1304_set_creds(const char *user, const char *passwd,
struct Curl_creds **pcreds)
{
Curl_creds_unlink(pcreds);
if(user || passwd)
return !Curl_creds_create(user, passwd, NULL, NULL, CREDS_NONE, pcreds);
else
return TRUE;
}
static bool t1304_no_user(struct Curl_creds *creds)
{
return !creds || !creds->user[0];
}
static bool t1304_no_passwd(struct Curl_creds *creds)
{
return !creds || !creds->passwd[0];
} }
static CURLcode test_unit1304(const char *arg) static CURLcode test_unit1304(const char *arg)
{ {
char *login = NULL; struct Curl_creds *cr_out = NULL, *cr_in = NULL;
char *password = NULL;
UNITTEST_BEGIN_SIMPLE UNITTEST_BEGIN_SIMPLE
@ -46,126 +66,119 @@ static CURLcode test_unit1304(const char *arg)
* Test a non existent host in our netrc file. * Test a non existent host in our netrc file.
*/ */
Curl_netrc_init(&store); Curl_netrc_init(&store);
result = Curl_parsenetrc(&store, "test.example.com", &login, &password, arg); result = Curl_parsenetrc(&store, "test.example.com", NULL, arg, &cr_out);
fail_unless(result == 1, "Host not found should return 1"); fail_unless(result == 1, "expected no match");
abort_unless(password == NULL, "password did not return NULL!"); abort_unless(cr_out == NULL, "creds did not return NULL!");
abort_unless(login == NULL, "user did not return NULL!");
Curl_netrc_cleanup(&store); Curl_netrc_cleanup(&store);
/* /*
* Test a non existent login in our netrc file. * Test a non existent login in our netrc file.
*/ */
login = curlx_strdup("me"); fail_unless(t1304_set_creds("me", NULL, &cr_in), "err set creds");
Curl_netrc_init(&store); Curl_netrc_init(&store);
result = Curl_parsenetrc(&store, "example.com", &login, &password, arg); result = Curl_parsenetrc(&store, "example.com", cr_in, arg, &cr_out);
fail_unless(result == 0, "Host should have been found"); fail_unless(result == 1, "expected no match");
abort_unless(password == NULL, "password is not NULL!"); abort_unless(t1304_no_passwd(cr_out), "password is not NULL!");
Curl_netrc_cleanup(&store); Curl_netrc_cleanup(&store);
curlx_free(login);
/* /*
* Test a non existent login and host in our netrc file. * Test a non existent login and host in our netrc file.
*/ */
login = curlx_strdup("me"); fail_unless(t1304_set_creds("me", NULL, &cr_in), "err set creds");
Curl_netrc_init(&store); Curl_netrc_init(&store);
result = Curl_parsenetrc(&store, "test.example.com", &login, &password, arg); result = Curl_parsenetrc(&store, "test.example.com", cr_in, arg, &cr_out);
fail_unless(result == 1, "Host not found should return 1"); fail_unless(result == 1, "expected no match");
abort_unless(password == NULL, "password is not NULL!"); abort_unless(t1304_no_passwd(cr_out), "password is not NULL!");
Curl_netrc_cleanup(&store); Curl_netrc_cleanup(&store);
curlx_free(login);
/* /*
* Test a non existent login (substring of an existing one) in our * Test a non existent login (substring of an existing one) in our
* netrc file. * netrc file.
*/ */
login = curlx_strdup("admi"); /* spellchecker:disable-line */ fail_unless(t1304_set_creds(
"admi", NULL, &cr_in), "err set creds"); /* spellchecker:disable-line */
Curl_netrc_init(&store); Curl_netrc_init(&store);
result = Curl_parsenetrc(&store, "example.com", &login, &password, arg); result = Curl_parsenetrc(&store, "example.com", cr_in, arg, &cr_out);
fail_unless(result == 0, "Host should have been found"); fail_unless(result == 1, "expected no match");
abort_unless(password == NULL, "password is not NULL!"); abort_unless(t1304_no_passwd(cr_out), "password is not NULL!");
Curl_netrc_cleanup(&store); Curl_netrc_cleanup(&store);
curlx_free(login);
/* /*
* Test a non existent login (superstring of an existing one) * Test a non existent login (superstring of an existing one)
* in our netrc file. * in our netrc file.
*/ */
login = curlx_strdup("adminn"); fail_unless(t1304_set_creds("adminn", NULL, &cr_in), "err set creds");
Curl_netrc_init(&store); Curl_netrc_init(&store);
result = Curl_parsenetrc(&store, "example.com", &login, &password, arg); result = Curl_parsenetrc(&store, "example.com", cr_in, arg, &cr_out);
fail_unless(result == 0, "Host should have been found"); fail_unless(result == 1, "expected no match");
abort_unless(password == NULL, "password is not NULL!"); abort_unless(t1304_no_passwd(cr_out), "password is not NULL!");
Curl_netrc_cleanup(&store); Curl_netrc_cleanup(&store);
curlx_free(login);
/* /*
* Test for the first existing host in our netrc file * Test for the first existing host in our netrc file
* with login[0] = 0. * with login[0] = 0.
*/ */
login = NULL; Curl_creds_unlink(&cr_in);
Curl_netrc_init(&store); Curl_netrc_init(&store);
result = Curl_parsenetrc(&store, "example.com", &login, &password, arg); result = Curl_parsenetrc(&store, "example.com", cr_in, arg, &cr_out);
fail_unless(result == 0, "Host should have been found"); fail_unless(result == 0, "Host should have been found");
abort_unless(password != NULL, "returned NULL!"); abort_unless(!t1304_no_passwd(cr_out), "returned NULL!");
fail_unless(strncmp(password, "passwd", 6) == 0, fail_unless(strncmp(Curl_creds_passwd(cr_out), "passwd", 6) == 0,
"password should be 'passwd'"); "password should be 'passwd'");
abort_unless(login != NULL, "returned NULL!"); abort_unless(!t1304_no_user(cr_out), "returned NULL!");
fail_unless(strncmp(login, "admin", 5) == 0, "login should be 'admin'"); fail_unless(strncmp(Curl_creds_user(cr_out), "admin", 5) == 0,
"login should be 'admin'");
Curl_netrc_cleanup(&store); Curl_netrc_cleanup(&store);
/* /*
* Test for the first existing host in our netrc file * Test for the first existing host in our netrc file
* with login[0] != 0. * with login[0] != 0.
*/ */
curlx_free(password); Curl_creds_unlink(&cr_in);
curlx_free(login);
password = NULL;
login = NULL;
Curl_netrc_init(&store); Curl_netrc_init(&store);
result = Curl_parsenetrc(&store, "example.com", &login, &password, arg); result = Curl_parsenetrc(&store, "example.com", cr_in, arg, &cr_out);
fail_unless(result == 0, "Host should have been found"); fail_unless(result == 0, "Host should have been found");
abort_unless(password != NULL, "returned NULL!"); abort_unless(!t1304_no_passwd(cr_out), "returned NULL!");
fail_unless(strncmp(password, "passwd", 6) == 0, fail_unless(strncmp(Curl_creds_passwd(cr_out), "passwd", 6) == 0,
"password should be 'passwd'"); "password should be 'passwd'");
abort_unless(login != NULL, "returned NULL!"); abort_unless(!t1304_no_user(cr_out), "returned NULL!");
fail_unless(strncmp(login, "admin", 5) == 0, "login should be 'admin'"); fail_unless(strncmp(Curl_creds_user(cr_out), "admin", 5) == 0,
"login should be 'admin'");
Curl_netrc_cleanup(&store); Curl_netrc_cleanup(&store);
/* /*
* Test for the second existing host in our netrc file * Test for the second existing host in our netrc file
* with login[0] = 0. * with login[0] = 0.
*/ */
curlx_free(password); Curl_creds_unlink(&cr_in);
password = NULL;
curlx_free(login);
login = NULL;
Curl_netrc_init(&store); Curl_netrc_init(&store);
result = Curl_parsenetrc(&store, "curl.example.com", &login, &password, arg); result = Curl_parsenetrc(&store, "curl.example.com", cr_in, arg, &cr_out);
fail_unless(result == 0, "Host should have been found"); fail_unless(result == 0, "Host should have been found");
abort_unless(password != NULL, "returned NULL!"); abort_unless(!t1304_no_passwd(cr_out), "returned NULL!");
fail_unless(strncmp(password, "none", 4) == 0, "password should be 'none'"); fail_unless(strncmp(Curl_creds_passwd(cr_out), "none", 4) == 0,
abort_unless(login != NULL, "returned NULL!"); "password should be 'none'");
fail_unless(strncmp(login, "none", 4) == 0, "login should be 'none'"); abort_unless(!t1304_no_user(cr_out), "returned NULL!");
fail_unless(strncmp(Curl_creds_user(cr_out), "none", 4) == 0,
"login should be 'none'");
Curl_netrc_cleanup(&store); Curl_netrc_cleanup(&store);
/* /*
* Test for the second existing host in our netrc file * Test for the second existing host in our netrc file
* with login[0] != 0. * with login[0] != 0.
*/ */
curlx_free(password); Curl_creds_unlink(&cr_in);
password = NULL;
curlx_free(login);
login = NULL;
Curl_netrc_init(&store); Curl_netrc_init(&store);
result = Curl_parsenetrc(&store, "curl.example.com", &login, &password, arg); result = Curl_parsenetrc(&store, "curl.example.com", cr_in, arg, &cr_out);
fail_unless(result == 0, "Host should have been found"); fail_unless(result == 0, "Host should have been found");
abort_unless(password != NULL, "returned NULL!"); abort_unless(!t1304_no_passwd(cr_out), "returned NULL!");
fail_unless(strncmp(password, "none", 4) == 0, "password should be 'none'"); fail_unless(strncmp(Curl_creds_passwd(cr_out), "none", 4) == 0,
abort_unless(login != NULL, "returned NULL!"); "password should be 'none'");
fail_unless(strncmp(login, "none", 4) == 0, "login should be 'none'"); abort_unless(!t1304_no_user(cr_out), "returned NULL!");
fail_unless(strncmp(Curl_creds_user(cr_out), "none", 4) == 0,
"login should be 'none'");
Curl_netrc_cleanup(&store); Curl_netrc_cleanup(&store);
UNITTEST_END(t1304_stop(&password, &login)) UNITTEST_END(t1304_stop(&cr_in, &cr_out))
} }
#else #else