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/CODE_STYLE.md \
internals/CONNECTION-FILTERS.md \
internals/CREDENTIALS.md \
internals/CURLX.md \
internals/DYNBUF.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 \
content_encoding.c \
cookie.c \
creds.c \
cshutdn.c \
curl_addrinfo.c \
curl_endian.c \
@ -293,6 +294,7 @@ LIB_HFILES = \
connect.h \
content_encoding.h \
cookie.h \
creds.h \
curl_addrinfo.h \
curl_ctype.h \
curl_endian.h \

View file

@ -387,8 +387,7 @@ connect_sub_chain:
result = Curl_cf_socks_proxy_insert_after(
cf, data, dest, cf->conn->ip_version,
cf->conn->socks_proxy.proxytype,
cf->conn->socks_proxy.user,
cf->conn->socks_proxy.passwd);
cf->conn->socks_proxy.creds);
CURL_TRC_CF(data, cf, "added SOCKS filter to %s:%u -> %d",
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)
{
/* Have credentials been provided? */
if(data->conn->user[0])
if(data->conn->creds)
return TRUE;
/* 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)
{
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->state1 = SASL_EXTERNAL;
sctx->sasl->authused = SASL_MECH_EXTERNAL;
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 FALSE;
@ -316,7 +318,7 @@ static bool sasl_choose_krb5(struct Curl_easy *data, struct sasl_ctx *sctx)
{
if((sctx->enabledmechs & SASL_MECH_GSSAPI) &&
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] ?
data->set.str[STRING_SERVICE_NAME] :
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) {
struct kerberos5data *krb5 = Curl_auth_krb5_get(sctx->conn);
sctx->result = !krb5 ? CURLE_OUT_OF_MEMORY :
Curl_auth_create_gssapi_user_message(data, sctx->conn->user,
sctx->conn->passwd,
Curl_auth_create_gssapi_user_message(data, sctx->conn->creds,
service,
sctx->conn->origin->hostname,
(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);
sctx->state1 = SASL_GSASL;
sctx->state2 = SASL_GSASL;
sctx->result = Curl_auth_gsasl_start(data, sctx->conn->user,
sctx->conn->passwd, gsasl);
sctx->result = Curl_auth_gsasl_start(data, sctx->conn->creds, gsasl);
if(!sctx->result && (sctx->sasl->force_ir || data->set.sasl_ir))
sctx->result = Curl_auth_gsasl_token(data, &nullmsg, gsasl, &sctx->resp);
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) {
struct ntlmdata *ntlm = Curl_auth_ntlm_get(sctx->conn, FALSE);
sctx->result = !ntlm ? CURLE_OUT_OF_MEMORY :
Curl_auth_create_ntlm_type1_message(data,
sctx->conn->user,
sctx->conn->passwd,
Curl_auth_create_ntlm_type1_message(data, sctx->conn->creds,
service, hostname,
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)
{
const char *oauth_bearer =
(!data->state.this_is_a_follow || data->set.allow_auth_to_other_hosts) ?
data->set.str[STRING_BEARER] : NULL;
if(oauth_bearer && (sctx->enabledmechs & SASL_MECH_OAUTHBEARER)) {
if(Curl_creds_has_oauth_bearer(data->state.creds) &&
(sctx->enabledmechs & SASL_MECH_OAUTHBEARER)) {
const char *hostname;
int 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)
sctx->result =
Curl_auth_create_oauth_bearer_message(sctx->conn->user,
hostname, port,
oauth_bearer, &sctx->resp);
Curl_auth_create_oauth_bearer_message(sctx->conn->creds,
hostname, port, &sctx->resp);
return TRUE;
}
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)
{
const char *oauth_bearer =
(!data->state.this_is_a_follow || data->set.allow_auth_to_other_hosts) ?
data->set.str[STRING_BEARER] : NULL;
if(oauth_bearer && (sctx->enabledmechs & SASL_MECH_XOAUTH2)) {
if(Curl_creds_has_oauth_bearer(sctx->conn->creds) &&
(sctx->enabledmechs & SASL_MECH_XOAUTH2)) {
sctx->mech = SASL_MECH_STRING_XOAUTH2;
sctx->state1 = SASL_OAUTH2;
sctx->sasl->authused = SASL_MECH_XOAUTH2;
if(sctx->sasl->force_ir || data->set.sasl_ir)
sctx->result = Curl_auth_create_xoauth_bearer_message(sctx->conn->user,
oauth_bearer,
&sctx->resp);
sctx->result = Curl_auth_create_xoauth_bearer_message(
sctx->conn->creds, &sctx->resp);
return TRUE;
}
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)
sctx->result =
Curl_auth_create_plain_message(sctx->conn->sasl_authzid,
sctx->conn->user, sctx->conn->passwd,
&sctx->resp);
Curl_auth_create_plain_message(sctx->conn->creds, &sctx->resp);
return TRUE;
}
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;
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 FALSE;
@ -606,7 +595,6 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
data->set.str[STRING_SERVICE_NAME] :
sasl->params->service;
#endif
const char *oauth_bearer = data->set.str[STRING_BEARER];
struct bufref serverdata;
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;
return result;
case SASL_PLAIN:
result = Curl_auth_create_plain_message(conn->sasl_authzid,
conn->user, conn->passwd, &resp);
result = Curl_auth_create_plain_message(conn->creds, &resp);
break;
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;
break;
case SASL_LOGIN_PASSWD:
Curl_auth_create_login_message(conn->passwd, &resp);
Curl_auth_create_login_message(Curl_creds_passwd(conn->creds), &resp);
break;
case SASL_EXTERNAL:
Curl_auth_create_external_message(conn->user, &resp);
Curl_auth_create_external_message(Curl_creds_user(conn->creds), &resp);
break;
#ifdef USE_GSASL
case SASL_GSASL:
@ -663,15 +650,15 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
case SASL_CRAMMD5:
result = get_server_message(sasl, data, &serverdata);
if(!result)
result = Curl_auth_create_cram_md5_message(&serverdata, conn->user,
conn->passwd, &resp);
result = Curl_auth_create_cram_md5_message(&serverdata, conn->creds,
&resp);
break;
case SASL_DIGESTMD5:
result = get_server_message(sasl, data, &serverdata);
if(!result)
result = Curl_auth_create_digest_md5_message(data, &serverdata,
conn->user, conn->passwd,
service, &resp);
conn->creds, service,
&resp);
if(!result && (sasl->params->flags & SASL_FLAG_BASE64))
newstate = SASL_DIGESTMD5_RESP;
break;
@ -685,8 +672,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
/* Create the type-1 message */
struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, FALSE);
result = !ntlm ? CURLE_OUT_OF_MEMORY :
Curl_auth_create_ntlm_type1_message(data,
conn->user, conn->passwd,
Curl_auth_create_ntlm_type1_message(data, conn->creds,
service, hostname,
ntlm, &resp);
newstate = SASL_NTLM_TYPE2MSG;
@ -700,9 +686,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
if(!result)
result = Curl_auth_decode_ntlm_type2_message(data, &serverdata, ntlm);
if(!result)
result = Curl_auth_create_ntlm_type3_message(data, conn->user,
conn->passwd, ntlm,
&resp);
result = Curl_auth_create_ntlm_type3_message(data, conn->creds,
ntlm, &resp);
break;
}
#endif
@ -711,7 +696,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
case SASL_GSSAPI: {
struct kerberos5data *krb5 = Curl_auth_krb5_get(conn);
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,
(bool)sasl->mutual_auth, NULL,
krb5, &resp);
@ -727,7 +712,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
else if(sasl->mutual_auth) {
/* Decode the user token challenge and create the optional response
message */
result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
result = Curl_auth_create_gssapi_user_message(data, NULL,
NULL, NULL,
(bool)sasl->mutual_auth,
&serverdata,
@ -736,10 +721,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
}
else
/* Decode the security challenge and create the response message */
result = Curl_auth_create_gssapi_security_message(data,
conn->sasl_authzid,
&serverdata,
krb5, &resp);
result = Curl_auth_create_gssapi_security_message(
data, Curl_creds_sasl_authzid(conn->creds), &serverdata,
krb5, &resp);
}
break;
case SASL_GSSAPI_NO_DATA:
@ -750,10 +734,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
if(!krb5)
result = CURLE_OUT_OF_MEMORY;
else
result = Curl_auth_create_gssapi_security_message(data,
conn->sasl_authzid,
&serverdata,
krb5, &resp);
result = Curl_auth_create_gssapi_security_message(
data, Curl_creds_sasl_authzid(conn->creds), &serverdata,
krb5, &resp);
}
break;
#endif
@ -761,18 +744,16 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
case SASL_OAUTH2:
/* Create the authorization message */
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,
port,
oauth_bearer,
&resp);
/* Failures maybe sent by the server as continuations for OAUTHBEARER */
newstate = SASL_OAUTH2_RESP;
}
else
result = Curl_auth_create_xoauth_bearer_message(conn->user,
oauth_bearer,
result = Curl_auth_create_xoauth_bearer_message(conn->creds,
&resp);
break;
@ -862,7 +843,7 @@ static void sasl_unchosen(struct Curl_easy *data, unsigned short mech,
else {
if(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);
}
}
@ -904,7 +885,8 @@ CURLcode Curl_sasl_is_blocked(struct SASL *sasl, struct Curl_easy *data)
"auth mechanisms");
else {
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");
sasl_unchosen(data, SASL_MECH_GSSAPI, enabledmechs,
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,
CURL_SASL_NTLM, Curl_auth_is_ntlm_supported(), NULL);
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");
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");
}
#endif /* CURLVERBOSE */

View file

@ -743,7 +743,7 @@ static CURLcode ftp_state_user(struct Curl_easy *data,
struct connectdata *conn)
{
CURLcode result = Curl_pp_sendf(data, &ftpc->pp, "USER %s",
conn->user ? conn->user : "");
Curl_creds_user(conn->creds));
if(!result) {
ftpc->ftp_trying_alternative = FALSE;
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)) {
/* 331 Password required for ...
(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)
ftp_state(data, ftpc, FTP_PASS);
}

View file

@ -250,14 +250,14 @@ char *Curl_copy_header_value(const char *header)
*
* 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;
char *authorization = NULL;
char **p_hd;
const char *user;
const char *pwd;
CURLcode result;
struct Curl_creds *creds = NULL;
char *out;
/* 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) {
#ifndef CURL_DISABLE_PROXY
p_hd = &data->req.hd_proxy_auth;
user = data->state.aptr.proxyuser;
pwd = data->state.aptr.proxypasswd;
creds = conn->http_proxy.creds;
#else
(void)conn;
return CURLE_NOT_BUILT_IN;
#endif
}
else {
p_hd = &data->req.hd_auth;
user = data->state.aptr.user;
pwd = data->state.aptr.passwd;
creds = data->state.creds;
}
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)
return CURLE_OUT_OF_MEMORY;
@ -320,10 +324,11 @@ static CURLcode http_output_bearer(struct Curl_easy *data)
char **userp;
CURLcode result = CURLE_OK;
DEBUGASSERT(Curl_creds_has_oauth_bearer(data->state.creds));
userp = &data->req.hd_auth;
curlx_free(*userp);
*userp = curl_maprintf("Authorization: Bearer %s\r\n",
data->set.str[STRING_BEARER]);
Curl_creds_oauth_bearer(data->state.creds));
if(!*userp) {
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
* something else. This is an error.
*/
if((httpcode == 401) && !data->state.aptr.user)
if((httpcode == 401) && !data->state.creds)
return TRUE;
#ifndef CURL_DISABLE_PROXY
if((httpcode == 407) && !data->conn->bits.proxy_user_passwd)
if((httpcode == 407) && !data->conn->http_proxy.creds)
return TRUE;
#endif
@ -551,7 +556,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
CURLcode result = CURLE_OK;
unsigned long authmask = ~0UL;
if(!data->set.str[STRING_BEARER])
if(!Curl_creds_has_oauth_bearer(data->state.creds))
authmask &= (unsigned long)~CURLAUTH_BEARER;
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)
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.authneg && data->req.httpcode < 300))) {
pickhost = pickoneauth(&data->state.authhost, authmask);
@ -578,7 +583,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
}
}
#ifndef CURL_DISABLE_PROXY
if(conn->bits.proxy_user_passwd &&
if(conn->http_proxy.creds &&
((data->req.httpcode == 407) ||
(data->req.authneg && data->req.httpcode < 300))) {
pickproxy = pickoneauth(&data->state.authproxy,
@ -694,14 +699,14 @@ static CURLcode output_auth_headers(struct Curl_easy *data,
/* Basic */
if(
#ifndef CURL_DISABLE_PROXY
(proxy && conn->bits.proxy_user_passwd &&
(proxy && conn->http_proxy.creds &&
!Curl_checkProxyheaders(data, conn,
STRCONST("Proxy-authorization"))) ||
#endif
(!proxy && data->state.aptr.user &&
(!proxy && data->state.creds &&
!Curl_checkheaders(data, STRCONST("Authorization")))) {
auth = "Basic";
result = http_output_basic(data, proxy);
result = http_output_basic(data, conn, proxy);
if(result)
return result;
}
@ -714,8 +719,7 @@ static CURLcode output_auth_headers(struct Curl_easy *data,
#ifndef CURL_DISABLE_BEARER_AUTH
if(authstatus->picked == CURLAUTH_BEARER) {
/* Bearer */
if(!proxy && data->set.str[STRING_BEARER] &&
Curl_auth_allowed_to_host(data) &&
if(!proxy && Curl_creds_has_oauth_bearer(data->state.creds) &&
!Curl_checkheaders(data, STRCONST("Authorization"))) {
auth = "Bearer";
result = http_output_bearer(data);
@ -737,15 +741,15 @@ static CURLcode output_auth_headers(struct Curl_easy *data,
data->info.httpauthpicked = authstatus->picked;
infof(data, "%s auth using %s with user '%s'",
proxy ? "Proxy" : "Server", auth,
proxy ? (data->state.aptr.proxyuser ?
data->state.aptr.proxyuser : "") :
(data->state.aptr.user ?
data->state.aptr.user : ""));
proxy ? (conn->http_proxy.creds ?
conn->http_proxy.creds->user : "") :
(data->state.creds ?
data->state.creds->user : ""));
#else
(void)proxy;
infof(data, "Server auth using %s with user '%s'",
auth, data->state.aptr.user ?
data->state.aptr.user : "");
auth, data->state.creds ?
data->state.creds->user : "");
#endif
authstatus->multipass = !authstatus->done;
}
@ -780,14 +784,13 @@ CURLcode Curl_http_output_auth(struct Curl_easy *data,
if(
#ifndef CURL_DISABLE_PROXY
(!conn->bits.httpproxy || !conn->bits.proxy_user_passwd) &&
(!conn->bits.httpproxy || !conn->http_proxy.creds) &&
#endif
!data->state.aptr.user &&
#ifdef USE_SPNEGO
!(authhost->want & CURLAUTH_NEGOTIATE) &&
!(authproxy->want & CURLAUTH_NEGOTIATE) &&
#endif
!data->set.str[STRING_BEARER]) {
!data->state.creds) {
/* no authentication with no user or password */
authhost->done = TRUE;
authproxy->done = TRUE;
@ -832,13 +835,9 @@ CURLcode Curl_http_output_auth(struct Curl_easy *data,
with it */
authproxy->done = TRUE;
/* To prevent the user+password to get sent to other than the original host
due to a location-follow */
if(Curl_auth_allowed_to_host(data)
#ifndef CURL_DISABLE_NETRC
|| conn->bits.netrc
#endif
)
/* Either we have credentials for the origin we talk to or
performing authentication is allowed here */
if(data->state.creds || Curl_auth_allowed_to_host(data))
result = output_auth_headers(data, conn, authhost, request,
path_and_query, FALSE);
else
@ -1227,8 +1226,6 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
return CURLE_OUT_OF_MEMORY;
}
else {
bool same_origin;
CURLcode result;
CURLU *u = curl_url();
if(!u)
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);
}
same_origin = Curl_url_same_origin(u, data->state.uh);
curl_url_cleanup(u);
#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
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);
@ -2005,9 +1989,6 @@ static CURLcode http_set_aptr_host(struct Curl_easy *data)
struct dynamically_allocated_data *aptr = &data->state.aptr;
const char *ptr;
if(!data->state.this_is_a_follow)
Curl_peer_link(&data->state.first_origin, conn->origin);
curlx_safefree(aptr->host);
#ifndef CURL_DISABLE_COOKIES
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"));
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
/* 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
@ -2138,6 +2119,19 @@ static CURLcode http_target(struct Curl_easy *data,
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. */
uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT);
if(uc) {

View file

@ -848,7 +848,8 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
char *request_type = NULL;
char *credential_scope = 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;
unsigned char sign0[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);
secret = curl_maprintf("%.*s4%s", (int)curlx_strlen(&provider0),
curlx_str(&provider0), data->state.aptr.passwd ?
data->state.aptr.passwd : "");
curlx_str(&provider0), passwd);
if(!secret)
goto fail;
/* make provider0 part done uppercase */

View file

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

View file

@ -40,8 +40,10 @@ static void http_auth_nego_reset(struct connectdata *conn,
{
if(proxy)
conn->proxy_negotiate_state = GSS_AUTHNONE;
else
else {
conn->http_negotiate_state = GSS_AUTHNONE;
Curl_creds_unlink(&conn->creds);
}
if(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;
/* Point to the username, password, service and host */
const char *userp;
const char *passwdp;
struct Curl_creds *creds = NULL;
const char *service;
const char *host;
@ -64,8 +65,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
if(proxy) {
#ifndef CURL_DISABLE_PROXY
userp = conn->http_proxy.user;
passwdp = conn->http_proxy.passwd;
creds = conn->http_proxy.creds;
service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
host = conn->http_proxy.peer->hostname;
@ -75,8 +75,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
#endif
}
else {
userp = conn->user;
passwdp = conn->passwd;
creds = data->state.creds;
service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] : "HTTP";
host = conn->origin->hostname;
@ -87,13 +86,6 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
if(!neg_ctx)
return CURLE_OUT_OF_MEMORY;
/* Not set means empty */
if(!userp)
userp = "";
if(!passwdp)
passwdp = "";
/* Obtain the input token, if any */
header += strlen("Negotiate");
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 */
/* 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);
#ifdef GSS_C_CHANNEL_BOUND_FLAG
@ -145,6 +137,16 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
if(result)
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;
}

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 */
char **allocuserpwd;
/* point to the username, password, service and host */
const char *userp;
const char *passwdp;
/* point to credentials, service and host */
struct Curl_creds *creds = NULL;
const char *service = NULL;
const char *hostname = NULL;
@ -140,8 +139,7 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
if(proxy) {
#ifndef CURL_DISABLE_PROXY
allocuserpwd = &data->req.hd_proxy_auth;
userp = data->state.aptr.proxyuser;
passwdp = data->state.aptr.proxypasswd;
creds = conn->http_proxy.creds;
service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
hostname = conn->http_proxy.peer->hostname;
@ -153,26 +151,19 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
}
else {
allocuserpwd = &data->req.hd_auth;
userp = data->state.aptr.user;
passwdp = data->state.aptr.passwd;
creds = data->state.creds;
service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] : "HTTP";
hostname = conn->origin->hostname;
state = &conn->http_ntlm_state;
authp = &data->state.authhost;
}
ntlm = Curl_auth_ntlm_get(conn, proxy);
if(!ntlm)
return CURLE_OUT_OF_MEMORY;
authp->done = FALSE;
/* not set means empty */
if(!userp)
userp = "";
if(!passwdp)
passwdp = "";
#ifdef USE_WINDOWS_SSPI
if(!Curl_pSecFn) {
/* 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) {
case NTLMSTATE_TYPE1:
default: /* for the weird cases we (re)start here */
/* Create a type-1 message */
result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp, service,
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);
}
result = Curl_auth_create_ntlm_type1_message(data, creds, service,
hostname, ntlm, &ntlmmsg);
if(!result) {
DEBUGASSERT(Curl_bufref_len(&ntlmmsg) != 0);
@ -215,8 +214,7 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
case NTLMSTATE_TYPE2:
/* We already received the type-2 message, create a type-3 message */
result = Curl_auth_create_ntlm_type3_message(data, userp, passwdp,
ntlm, &ntlmmsg);
result = Curl_auth_create_ntlm_type3_message(data, creds, ntlm, &ntlmmsg);
if(!result && Curl_bufref_len(&ntlmmsg)) {
result = curlx_base64_encode(Curl_bufref_uptr(&ntlmmsg),
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
connect phase if we do not */
if(!data->state.aptr.user) {
if(!data->state.creds) {
imap_state(data, imapc, IMAP_STOP);
return result;
}
/* Make sure the username and password are in the correct atom format */
user = imap_atom(conn->user, FALSE);
passwd = imap_atom(conn->passwd, FALSE);
user = imap_atom(Curl_creds_user(conn->creds), FALSE);
passwd = imap_atom(Curl_creds_passwd(conn->creds), FALSE);
/* Send the LOGIN command */
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 */
result = Curl_sasl_start(&imapc->sasl, data, (bool)imapc->ir_supported,
&progress);
if(!result) {
if(progress == SASL_INPROGRESS)
imap_state(data, imapc, IMAP_AUTHENTICATE);

View file

@ -252,8 +252,10 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
#else
char *host = NULL;
#endif
char *user = NULL;
char *passwd = NULL;
const char *user = Curl_creds_has_user(data->state.creds) ?
data->state.creds->user : NULL;
const char *passwd = Curl_creds_has_passwd(data->state.creds) ?
data->state.creds->passwd : NULL;
struct ip_quadruple ipquad;
bool is_ipv6;
BerElement *ber = NULL;
@ -295,11 +297,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
host = conn->origin->hostname;
#endif
if(data->state.aptr.user) {
user = conn->user;
passwd = conn->passwd;
}
#ifdef USE_WIN32_LDAP
if(ldap_ssl)
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;
/* extracting username from request */
const char *username = data->state.aptr.user ? data->state.aptr.user : "";
const size_t ulen = strlen(username);
/* extracting password from request */
const char *passwd = data->state.aptr.passwd ? data->state.aptr.passwd : "";
const size_t plen = strlen(passwd);
struct Curl_creds *creds = data->state.creds;
const size_t ulen = creds ? strlen(creds->user) : 0;
const size_t plen = creds ? strlen(creds->passwd) : 0;
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
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) {
start_pwd += 2;
rc = add_user(username, ulen,
rc = add_user(creds->user, ulen,
(unsigned char *)packet, start_user, remain_pos);
if(rc) {
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(plen) {
rc = add_passwd(passwd, plen, packet, start_pwd, remain_pos);
rc = add_passwd(creds->passwd, plen, packet, start_pwd, remain_pos);
if(rc) {
failf(data, "Password too long: [%zu]", plen);
result = CURLE_WEIRD_SERVER_REPLY;
@ -351,8 +349,7 @@ static CURLcode mqtt_connect(struct Curl_easy *data)
end:
if(packet)
curlx_free(packet);
curlx_safefree(data->state.aptr.user);
curlx_safefree(data->state.aptr.passwd);
Curl_creds_unlink(&data->state.creds);
return result;
}

View file

@ -36,6 +36,7 @@
#endif
#include "netrc.h"
#include "creds.h"
#include "strcase.h"
#include "curl_get_line.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 */
struct netrc_state {
struct Curl_creds *existing;
char *login;
char *password;
enum host_lookup_state state;
@ -116,7 +118,6 @@ struct netrc_state {
unsigned char found; /* FOUND_LOGIN | FOUND_PASSWORD bits */
bool our_login;
bool done;
bool specific_login;
};
/*
@ -250,8 +251,7 @@ static void netrc_new_machine(struct netrc_state *ns)
ns->found = 0;
ns->our_login = FALSE;
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)
{
if(ns->keyword == LOGIN) {
if(ns->specific_login)
ns->our_login = !Curl_timestrcmp(ns->login, tok);
if(Curl_creds_has_user(ns->existing))
ns->our_login = !Curl_timestrcmp(ns->existing->user, tok);
else {
ns->our_login = TRUE;
curlx_free(ns->login);
@ -289,15 +289,15 @@ static NETRCcode netrc_hostvalid(struct netrc_state *ns, const char *tok)
ns->keyword = PASSWORD;
else if(curl_strequal("machine", tok)) {
/* 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 */
((!ns->specific_login || ns->our_login) ||
/* either there was no specific login to search for, or this
is the specific one we wanted */
(ns->specific_login && !(ns->found & FOUND_LOGIN)))) {
/* or we look for a specific login, but that was not specified */
(!specific_login || ns->our_login ||
/* and found a login that is suitable
(either matched specific one or simply present) */
(specific_login && !(ns->found & FOUND_LOGIN)))) {
/* or we look for a specific login, but no login was not specified */
ns->done = TRUE;
return NETRC_OK;
@ -361,38 +361,48 @@ static NETRCcode netrc_handle_token(struct netrc_state *ns,
* resources on error.
*/
static NETRCcode netrc_finalize(struct netrc_state *ns,
char **loginp,
char **passwordp,
struct store_netrc *store)
struct store_netrc *store,
struct Curl_creds **pcreds)
{
NETRCcode retcode = ns->retcode;
if(!retcode) {
if(!ns->password && ns->our_login) {
/* success without a password, set a blank one */
ns->password = curlx_strdup("");
if(!ns->password)
if(!ns->password) {
retcode = NETRC_OUT_OF_MEMORY;
goto out;
}
}
else if(!ns->login && !ns->password)
else if(!ns->login && !ns->password) {
/* a default with no credentials */
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
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);
store->loaded = FALSE;
if(!ns->specific_login)
curlx_free(ns->login);
curlx_free(ns->password);
}
return retcode;
}
@ -402,21 +412,20 @@ static NETRCcode netrc_finalize(struct netrc_state *ns,
*/
static NETRCcode parsenetrc(struct store_netrc *store,
const char *host,
char **loginp,
char **passwordp,
const char *netrcfile)
struct Curl_creds *existing,
const char *netrcfile,
struct Curl_creds **pcreds)
{
const char *netrcbuffer;
struct dynbuf token;
struct dynbuf *filebuf = &store->filebuf;
struct netrc_state ns;
DEBUGASSERT(!existing || !Curl_creds_has_passwd(existing));
memset(&ns, 0, sizeof(ns));
ns.retcode = NETRC_NO_MATCH;
ns.login = *loginp;
ns.specific_login = !!ns.login;
ns.existing = existing;
DEBUGASSERT(!*passwordp);
curlx_dyn_init(&token, MAX_NETRC_TOKEN);
if(!store->loaded) {
@ -466,7 +475,7 @@ static NETRCcode parsenetrc(struct store_netrc *store,
out:
curlx_dyn_free(&token);
return netrc_finalize(&ns, loginp, passwordp, store);
return netrc_finalize(&ns, store, pcreds);
}
const char *Curl_netrc_strerror(NETRCcode ret)
@ -493,12 +502,14 @@ const char *Curl_netrc_strerror(NETRCcode ret)
* in.
*/
NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host,
char **loginp, char **passwordp,
const char *netrcfile)
struct Curl_creds *existing,
const char *netrcfile,
struct Curl_creds **pcreds)
{
NETRCcode retcode = NETRC_OK;
char *filealloc = NULL;
Curl_creds_unlink(pcreds);
if(!netrcfile) {
char *home = 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);
if(!filealloc) {
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);
#ifdef _WIN32
if(retcode == NETRC_FILE_MISSING) {
@ -556,14 +568,17 @@ NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host,
curlx_free(homea);
return NETRC_OUT_OF_MEMORY;
}
retcode = parsenetrc(store, host, loginp, passwordp, filealloc);
retcode = parsenetrc(store, host, existing, filealloc, pcreds);
curlx_free(filealloc);
}
#endif
curlx_free(homea);
}
else
retcode = parsenetrc(store, host, loginp, passwordp, netrcfile);
retcode = parsenetrc(store, host, existing, netrcfile, pcreds);
out:
if(retcode)
Curl_creds_unlink(pcreds);
return retcode;
}

View file

@ -29,6 +29,8 @@
#include "curlx/dynbuf.h"
struct Curl_creds;
struct store_netrc {
struct dynbuf filebuf;
char *filename;
@ -49,8 +51,9 @@ void Curl_netrc_init(struct store_netrc *store);
void Curl_netrc_cleanup(struct store_netrc *store);
NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host,
char **loginp, char **passwordp,
const char *netrcfile);
struct Curl_creds *existing,
const char *netrcfile,
struct Curl_creds **pcreds);
/* Assume: (*passwordp)[0]=0, host[0] != 0.
* If (*loginp)[0] = 0, search for login and password within a machine
* 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_len = 0;
if(data->state.aptr.user) {
binddn = conn->user;
passwd.bv_val = conn->passwd;
if(data->state.creds) {
binddn = Curl_creds_user(conn->creds);
passwd.bv_val = CURL_UNCONST(Curl_creds_passwd(conn->creds));
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);
if(rc != LDAP_SUCCESS)
return oldap_map_error(rc,
data->state.aptr.user ?
data->state.creds ?
CURLE_LOGIN_DENIED : CURLE_LDAP_CANNOT_BIND);
oldap_state(data, li, newstate);
return CURLE_OK;
@ -911,7 +911,7 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
else if(ssl_installed(conn)) {
if(li->sasl.prefmech != SASL_AUTH_NONE)
result = oldap_perform_mechs(data);
else if(data->state.aptr.user)
else if(data->state.creds)
result = oldap_perform_bind(data, OLDAP_BIND);
else {
/* 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
connect phase if we do not */
if(!data->state.aptr.user) {
if(!data->state.creds) {
pop3_state(data, POP3_STOP);
return result;
@ -535,7 +535,7 @@ static CURLcode pop3_perform_user(struct Curl_easy *data,
/* Send the USER command */
result = Curl_pp_sendf(data, &pop3c->pp, "USER %s",
conn->user ? conn->user : "");
Curl_creds_user(conn->creds));
if(!result)
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
connect phase if we do not */
if(!data->state.aptr.user) {
if(!data->state.creds) {
pop3_state(data, POP3_STOP);
return result;
@ -578,8 +578,8 @@ static CURLcode pop3_perform_apop(struct Curl_easy *data,
Curl_MD5_update(ctxt, (const unsigned char *)pop3c->apoptimestamp,
curlx_uztoui(strlen(pop3c->apoptimestamp)));
Curl_MD5_update(ctxt, (const unsigned char *)conn->passwd,
curlx_uztoui(strlen(conn->passwd)));
Curl_MD5_update(ctxt, (const unsigned char *)Curl_creds_passwd(conn->creds),
curlx_uztoui(strlen(Curl_creds_passwd(conn->creds))));
/* Finalise the 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++)
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)
pop3_state(data, POP3_APOP);
@ -1038,7 +1039,8 @@ static CURLcode pop3_state_user_resp(struct Curl_easy *data, int pop3code,
}
else
/* 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)
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_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
* Since all RTSP requests are included here, there is no need to
* support custom requests like HTTP.

View file

@ -61,7 +61,7 @@ enum smb_conn_state {
/* SMB connection data, kept at connection */
struct smb_conn {
enum smb_conn_state state;
char *user;
const char *user;
char *domain;
char *share;
unsigned char challenge[8];
@ -468,13 +468,14 @@ static CURLcode smb_connect(struct Curl_easy *data, bool *done)
struct connectdata *conn = data->conn;
struct smb_conn *smbc = Curl_conn_meta_get(conn, CURL_META_SMB_CONN);
char *slash;
const char *user = Curl_creds_user(conn->creds);
(void)done;
if(!smbc)
return CURLE_FAILED_INIT;
/* 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;
/* Initialize the connection state */
@ -487,19 +488,19 @@ static CURLcode smb_connect(struct Curl_easy *data, bool *done)
return CURLE_OUT_OF_MEMORY;
/* Parse the username, domain, and password */
slash = strchr(conn->user, '/');
slash = strchr(user, '/');
if(!slash)
slash = strchr(conn->user, '\\');
slash = strchr(user, '\\');
if(slash) {
smbc->user = slash + 1;
smbc->domain = curlx_strdup(conn->user);
smbc->domain = curlx_strdup(user);
if(!smbc->domain)
return CURLE_OUT_OF_MEMORY;
smbc->domain[slash - conn->user] = 0;
smbc->domain[slash - user] = 0;
}
else {
smbc->user = conn->user;
smbc->user = user;
smbc->domain = curlx_strdup(conn->origin->hostname);
if(!smbc->domain)
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[24];
size_t byte_count;
const char *passwd = Curl_creds_passwd(conn->creds);
if(!smbc || !req)
return CURLE_FAILED_INIT;
@ -680,9 +682,9 @@ static CURLcode smb_send_setup(struct Curl_easy *data)
if(byte_count > sizeof(msg.bytes))
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_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);
memset(&msg, 0, sizeof(msg) - sizeof(msg.bytes));

View file

@ -99,8 +99,7 @@ struct socks_ctx {
enum socks_state_t state;
struct bufq iobuf;
struct Curl_peer *dest;
const char *user;
const char *passwd;
struct Curl_creds *creds;
CURLproxycode presult;
uint32_t resolv_id;
uint8_t ip_version;
@ -287,8 +286,8 @@ static CURLproxycode socks4_req_add_user(struct socks_ctx *sx,
CURLcode result;
size_t nwritten;
if(sx->user) {
size_t plen = strlen(sx->user);
if(sx->creds) {
size_t plen = strlen(sx->creds->user);
if(plen > 255) {
/* 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
@ -297,7 +296,7 @@ static CURLproxycode socks4_req_add_user(struct socks_ctx *sx,
return CURLPX_LONG_USER;
}
/* 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);
if(result || (nwritten != (plen + 1)))
return CURLPX_SEND_REQUEST;
@ -603,7 +602,7 @@ static CURLproxycode socks5_req0_init(struct Curl_cfilter *cf,
"CURLOPT_SOCKS5_AUTH: %u", auth);
if(!(auth & CURLAUTH_BASIC))
/* disable username/password auth */
sx->user = NULL;
Curl_creds_unlink(&sx->creds);
req[0] = 5; /* version */
nauths = 1;
@ -614,7 +613,7 @@ static CURLproxycode socks5_req0_init(struct Curl_cfilter *cf,
req[1 + nauths] = 1; /* GSS-API */
}
#endif
if(sx->user) {
if(sx->creds) {
++nauths;
req[1 + nauths] = 2; /* username/password */
}
@ -687,9 +686,9 @@ static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf,
unsigned char buf[2];
CURLcode result;
if(sx->user && sx->passwd) {
ulen = strlen(sx->user);
plen = strlen(sx->passwd);
if(sx->creds) {
ulen = strlen(sx->creds->user);
plen = strlen(sx->creds->passwd);
/* the lengths must fit in a single byte */
if(ulen > 255) {
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))
return CURLPX_SEND_REQUEST;
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))
return CURLPX_SEND_REQUEST;
}
@ -723,7 +723,8 @@ static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf,
if(result || (nwritten != 1))
return CURLPX_SEND_REQUEST;
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))
return CURLPX_SEND_REQUEST;
}
@ -1185,6 +1186,7 @@ static void socks_proxy_ctx_free(struct socks_ctx *ctx)
{
if(ctx) {
Curl_peer_unlink(&ctx->dest);
Curl_creds_unlink(&ctx->creds);
Curl_bufq_free(&ctx->iobuf);
curlx_free(ctx);
}
@ -1259,10 +1261,8 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
out:
*done = (bool)cf->connected;
if(*done || result) {
ctx->user = NULL;
ctx->passwd = NULL;
}
if(*done || result)
Curl_creds_unlink(&ctx->creds);
return result;
}
@ -1361,8 +1361,7 @@ CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
struct Curl_peer *dest,
uint8_t ip_version,
uint8_t proxy_type,
const char *user,
const char *passwd)
struct Curl_creds *creds)
{
struct Curl_cfilter *cf;
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);
ctx->ip_version = ip_version;
ctx->proxy_type = proxy_type;
ctx->user = user;
ctx->passwd = passwd;
Curl_creds_link(&ctx->creds, creds);
Curl_bufq_init2(&ctx->iobuf, SOCKS_CHUNK_SIZE, SOCKS_CHUNKS,
BUFQ_OPT_SOFT_LIMIT);

View file

@ -28,6 +28,7 @@
#ifndef CURL_DISABLE_PROXY
struct Curl_peer;
struct Curl_creds;
/*
* 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,
uint8_t ip_version,
uint8_t proxy_type,
const char *user,
const char *passwd);
struct Curl_creds *creds);
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
was given on the command line */
if(data->state.aptr.user) {
if(data->state.creds) {
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"));
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);
if(!beg) {
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);
}
/*
* 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
* 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
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.followlocation = 0; /* reset the location-follow counter */
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;
}
if(!result)
result = Curl_reset_userpwd(data);
if(!result)
result = Curl_reset_proxypwd(data);
data->req.headerbytecount = 0;
Curl_headers_cleanup(data);
return result;

View file

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

View file

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

View file

@ -47,18 +47,19 @@
* Returns CURLE_OK on success.
*/
CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
struct bufref *out)
{
struct HMAC_context *ctxt;
unsigned char digest[MD5_DIGEST_LEN];
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 */
ctxt = Curl_HMAC_init(&Curl_HMAC_MD5,
(const unsigned char *)passwdp,
curlx_uztoui(strlen(passwdp)));
(const unsigned char *)passwd,
curlx_uztoui(strlen(passwd)));
if(!ctxt)
return CURLE_OUT_OF_MEMORY;
@ -73,7 +74,7 @@ CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg,
/* Generate the response */
response = curl_maprintf(
"%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[11], digest[12], digest[13], digest[14], digest[15]);
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,
const struct bufref *chlg,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
const char *service,
struct bufref *out)
{
size_t i;
struct MD5_context *ctxt;
const char *userp = Curl_creds_user(creds);
const char *passwdp = Curl_creds_passwd(creds);
char *response = NULL;
unsigned char digest[MD5_DIGEST_LEN];
char HA1_hex[(2 * MD5_DIGEST_LEN) + 1];
@ -666,8 +667,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
* Parameters:
*
* data [in] - The session handle.
* userp [in] - The username.
* passwdp [in] - The user's password.
* creds [in] - The credentials
* request [in] - The HTTP request.
* uripath [in] - The path of the HTTP uri.
* 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(
struct Curl_easy *data,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
const unsigned char *request,
const unsigned char *uripath,
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 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 request_digest[65];
unsigned char ha1[65]; /* 64 digits and 1 zero byte */
@ -986,29 +987,28 @@ oom:
* Returns CURLE_OK on success.
*/
CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
const unsigned char *request,
const unsigned char *uripath,
struct digestdata *digest,
char **outptr, size_t *outlen)
{
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,
outptr, outlen,
auth_digest_md5_to_ascii,
Curl_md5it);
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,
outptr, outlen,
auth_digest_sha256_to_ascii,
Curl_sha256it);
#ifdef CURL_HAVE_SHA512_256
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,
outptr, outlen,
auth_digest_sha256_to_ascii,

View file

@ -28,6 +28,7 @@
#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_DIGEST_AUTH)
#include "creds.h"
#include "vauth/vauth.h"
#include "vauth/digest.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,
const struct bufref *chlg,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
const char *service,
struct bufref *out)
{
@ -137,9 +137,10 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
if(userp && *userp) {
if(Curl_creds_has_user(creds)) {
/* Populate our identity structure */
result = Curl_create_sspi_identity(userp, passwdp, &identity);
result = Curl_create_sspi_identity(creds->user, creds->passwd,
&identity);
if(result) {
curlx_free(spn);
curlx_free(output_token);
@ -381,8 +382,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
* Returns CURLE_OK on success.
*/
CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
const unsigned char *request,
const unsigned char *uripath,
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
has changed then delete that context. */
if((userp && !digest->user) || (!userp && digest->user) ||
(passwdp && !digest->passwd) || (!passwdp && digest->passwd) ||
(userp && digest->user && Curl_timestrcmp(userp, digest->user)) ||
(passwdp && digest->passwd && Curl_timestrcmp(passwdp, digest->passwd))) {
if(!Curl_creds_same(creds, digest->creds)) {
if(digest->http_context) {
Curl_pSecFn->DeleteSecurityContext(digest->http_context);
curlx_safefree(digest->http_context);
}
curlx_safefree(digest->user);
curlx_safefree(digest->passwd);
Curl_creds_unlink(&digest->creds);
}
if(digest->http_context) {
@ -473,13 +469,13 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
unsigned long attrs;
TCHAR *spn;
/* free the copy of user/passwd used to make the previous identity */
curlx_safefree(digest->user);
curlx_safefree(digest->passwd);
/* free the credentials used to make the previous identity */
Curl_creds_unlink(&digest->creds);
if(userp && *userp) {
if(Curl_creds_has_user(creds)) {
/* 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);
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 */
p_identity = NULL;
if(userp) {
digest->user = curlx_strdup(userp);
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;
}
}
if(creds)
Curl_creds_link(&digest->creds, creds);
/* Acquire our credentials handle */
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 */
curlx_safefree(digest->user);
curlx_safefree(digest->passwd);
Curl_creds_unlink(&digest->creds);
}
#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,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
struct gsasldata *gsasl)
{
#if GSASL_VERSION_NUMBER >= 0x010b00
int res;
res =
#endif
gsasl_property_set(gsasl->client, GSASL_AUTHID, userp);
gsasl_property_set(gsasl->client, GSASL_AUTHID, creds->user);
#if GSASL_VERSION_NUMBER >= 0x010b00
if(res != GSASL_OK) {
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
res =
#endif
gsasl_property_set(gsasl->client, GSASL_PASSWORD, passwdp);
gsasl_property_set(gsasl->client, GSASL_PASSWORD, creds->passwd);
#if GSASL_VERSION_NUMBER >= 0x010b00
if(res != GSASL_OK) {
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.
*/
CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
const char *service,
const char *host,
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 output_token = GSS_C_EMPTY_BUFFER;
(void)userp;
(void)passwdp;
(void)creds;
if(!krb5->spn) {
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.
*/
CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
const char *service,
const char *host,
const bool mutual_auth,
@ -128,9 +127,10 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
if(!krb5->credentials) {
/* 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 */
result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity);
result = Curl_create_sspi_identity(
creds->user, creds->passwd, &krb5->identity);
if(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.
*/
CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
const char *service,
const char *host,
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
domain are empty */
(void)data;
(void)userp;
(void)passwdp;
(void)creds;
(void)service;
(void)host;
@ -542,8 +540,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
* Returns CURLE_OK on success.
*/
CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
struct ntlmdata *ntlm,
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
name. Copy the name used by Firefox. */
static const char host[] = "WORKSTATION";
const char *userp = Curl_creds_user(creds);
const char *passwdp = Curl_creds_passwd(creds);
const char *user;
const char *domain = "";
size_t hostoff = 0;

View file

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

View file

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

View file

@ -70,8 +70,7 @@ bool Curl_auth_is_spnego_supported(void)
* Returns CURLE_OK on success.
*/
CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
const char *user,
const char *password,
struct Curl_creds *creds,
const char *service,
const char *host,
const char *chlg64,
@ -90,8 +89,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
struct gss_channel_bindings_struct chan;
#endif
(void)user;
(void)password;
(void)creds;
if(nego->context && nego->status == GSS_S_COMPLETE) {
/* 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.
*/
CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
const char *user,
const char *password,
struct Curl_creds *creds,
const char *service,
const char *host,
const char *chlg64,
@ -133,9 +132,10 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
if(!nego->credentials) {
/* 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 */
result = Curl_create_sspi_identity(user, password, &nego->identity);
result = Curl_create_sspi_identity(creds->user, creds->passwd,
&nego->identity);
if(result)
return result;

View file

@ -24,6 +24,7 @@
#include "curl_setup.h"
#include "vauth/vauth.h"
#include "creds.h"
#include "curlx/multibyte.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.
*/
bool Curl_auth_user_contains_domain(const char *user)
bool Curl_auth_user_contains_domain(struct Curl_creds *creds)
{
bool valid = FALSE;
if(user && *user) {
if(Curl_creds_has_user(creds)) {
/* 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)
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
* "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)
{
return !data->state.this_is_a_follow ||
data->set.allow_auth_to_other_hosts ||
(data->state.first_origin &&
Curl_peer_equal(data->state.first_origin, data->conn->origin));
return data->set.allow_auth_to_other_hosts ||
Curl_peer_equal(data->state.initial_origin, data->conn->origin);
}
#ifdef USE_NTLM

View file

@ -30,6 +30,7 @@
#include "urldata.h"
struct Curl_easy;
struct Curl_creds;
struct connectdata;
#ifndef CURL_DISABLE_DIGEST_AUTH
@ -69,12 +70,10 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host,
#endif
/* 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 */
CURLcode Curl_auth_create_plain_message(const char *authzid,
const char *authcid,
const char *passwd,
CURLcode Curl_auth_create_plain_message(struct Curl_creds *creds,
struct bufref *out);
/* 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
/* This is used to generate a CRAM-MD5 response message */
CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
struct bufref *out);
/* 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 */
CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
const struct bufref *chlg,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
const char *service,
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 */
CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
const unsigned char *request,
const unsigned char *uripath,
struct digestdata *digest,
@ -140,8 +136,7 @@ bool Curl_auth_gsasl_is_supported(struct Curl_easy *data,
struct gsasldata *gsasl);
/* This is used to start a gsasl method */
CURLcode Curl_auth_gsasl_start(struct Curl_easy *data,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
struct gsasldata *gsasl);
/* 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 */
CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
const char *service,
const char *host,
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 */
CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
struct ntlmdata *ntlm,
struct bufref *out);
@ -221,15 +214,13 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
#endif /* USE_NTLM */
/* 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 long port,
const char *bearer,
struct bufref *out);
/* This is used to generate a base64 encoded XOAuth 2.0 message */
CURLcode Curl_auth_create_xoauth_bearer_message(const char *user,
const char *bearer,
CURLcode Curl_auth_create_xoauth_bearer_message(struct Curl_creds *creds,
struct bufref *out);
#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
message */
CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
const char *userp,
const char *passwdp,
struct Curl_creds *creds,
const char *service,
const char *host,
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
message */
CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
const char *user,
const char *password,
struct Curl_creds *creds,
const char *service,
const char *host,
const char *chlg64,

View file

@ -633,7 +633,8 @@ restart:
if(nprompts != 1)
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)
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,
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)
return SSH_AGAIN;
else if(rc == SSH_AUTH_SUCCESS) {
@ -2571,9 +2573,10 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
return CURLE_FAILED_INIT;
}
if(conn->user && conn->user[0] != '\0') {
infof(data, "User: %s", conn->user);
rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_USER, conn->user);
if(Curl_creds_has_user(conn->creds)) {
infof(data, "User: %s", conn->creds->user);
rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_USER,
conn->creds->user);
if(rc != SSH_OK) {
failf(data, "Could not set user");
return CURLE_FAILED_INIT;

View file

@ -148,11 +148,12 @@ static void kbd_callback(const char *name, int name_len,
#endif /* CURL_LIBSSH2_DEBUG */
if(num_prompts == 1) {
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
uses the LIBSSH2_FREE_FUNC callback */
responses[0].text = Curl_cstrdup(conn->passwd);
responses[0].text = Curl_cstrdup(passwd);
responses[0].length =
responses[0].text == NULL ? 0 : curlx_uztoui(strlen(conn->passwd));
responses[0].text == NULL ? 0 : curlx_uztoui(strlen(passwd));
}
(void)prompts;
} /* kbd_callback */
@ -1496,9 +1497,9 @@ static CURLcode ssh_state_authlist(struct Curl_easy *data,
* Therefore always specify it here.
*/
struct connectdata *conn = data->conn;
const char *user = Curl_creds_user(conn->creds);
sshc->authlist = libssh2_userauth_list(sshc->ssh_session,
conn->user,
curlx_uztoui(strlen(conn->user)));
user, curlx_uztoui(strlen(user)));
if(!sshc->authlist) {
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.
*/
struct connectdata *conn = data->conn;
const char *user = Curl_creds_user(conn->creds);
int rc =
libssh2_userauth_publickey_fromfile_ex(sshc->ssh_session,
conn->user,
curlx_uztoui(
strlen(conn->user)),
user,
curlx_uztoui(strlen(user)),
sshc->rsa_pub,
sshc->rsa, sshc->passphrase);
if(rc == LIBSSH2_ERROR_EAGAIN)
@ -1579,11 +1580,13 @@ static CURLcode ssh_state_auth_pass(struct Curl_easy *data,
struct ssh_conn *sshc)
{
struct connectdata *conn = data->conn;
const char *user = Curl_creds_user(conn->creds);
const char *passwd = Curl_creds_passwd(conn->creds);
int rc =
libssh2_userauth_password_ex(sshc->ssh_session, conn->user,
curlx_uztoui(strlen(conn->user)),
conn->passwd,
curlx_uztoui(strlen(conn->passwd)),
libssh2_userauth_password_ex(sshc->ssh_session, user,
curlx_uztoui(strlen(user)),
passwd,
curlx_uztoui(strlen(passwd)),
NULL);
if(rc == LIBSSH2_ERROR_EAGAIN) {
return CURLE_AGAIN;
@ -1680,7 +1683,7 @@ static CURLcode ssh_state_auth_agent(struct Curl_easy *data,
if(rc == 0) {
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);
if(rc < 0) {
@ -1727,11 +1730,10 @@ static CURLcode ssh_state_auth_key(struct Curl_easy *data,
{
/* Authentication failed. Continue with keyboard-interactive now. */
struct connectdata *conn = data->conn;
const char *user = Curl_creds_user(conn->creds);
int rc =
libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session,
conn->user,
curlx_uztoui(
strlen(conn->user)),
user, curlx_uztoui(strlen(user)),
&kbd_callback);
if(rc == LIBSSH2_ERROR_EAGAIN)
return CURLE_AGAIN;
@ -3452,9 +3454,9 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
if(!sshc)
return CURLE_FAILED_INIT;
infof(data, "User: '%s'", conn->user);
infof(data, "User: '%s'", Curl_creds_user(conn->creds));
#ifdef CURL_LIBSSH2_DEBUG
infof(data, "Password: %s", conn->passwd);
infof(data, "Password: %s", Curl_creds_passwd(conn->creds));
sock = conn->sock[FIRSTSOCKET];
#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_VERBOSE, 1L);
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_URL, URL);

View file

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