]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
creds: hold credentials
authorStefan Eissing <stefan@eissing.org>
Mon, 11 May 2026 12:25:52 +0000 (14:25 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 12 May 2026 14:05:15 +0000 (16:05 +0200)
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

47 files changed:
docs/Makefile.am
docs/internals/CREDENTIALS.md [new file with mode: 0644]
lib/Makefile.inc
lib/connect.c
lib/creds.c [new file with mode: 0644]
lib/creds.h [new file with mode: 0644]
lib/curl_sasl.c
lib/ftp.c
lib/http.c
lib/http_aws_sigv4.c
lib/http_digest.c
lib/http_negotiate.c
lib/http_ntlm.c
lib/imap.c
lib/ldap.c
lib/mqtt.c
lib/netrc.c
lib/netrc.h
lib/openldap.c
lib/pop3.c
lib/rtsp.c
lib/smb.c
lib/socks.c
lib/socks.h
lib/telnet.c
lib/transfer.c
lib/transfer.h
lib/url.c
lib/urldata.h
lib/vauth/cleartext.c
lib/vauth/cram.c
lib/vauth/digest.c
lib/vauth/digest_sspi.c
lib/vauth/gsasl.c
lib/vauth/krb5_gssapi.c
lib/vauth/krb5_sspi.c
lib/vauth/ntlm.c
lib/vauth/ntlm_sspi.c
lib/vauth/oauth2.c
lib/vauth/spnego_gssapi.c
lib/vauth/spnego_sspi.c
lib/vauth/vauth.c
lib/vauth/vauth.h
lib/vssh/libssh.c
lib/vssh/libssh2.c
tests/libtest/lib1978.c
tests/unit/unit1304.c

index 01c223ccb3976bea2479a54b9a81686718a73c22..fdc4511b5cab97c65257f56b5085b5c5fcbe48fd 100644 (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                              \
diff --git a/docs/internals/CREDENTIALS.md b/docs/internals/CREDENTIALS.md
new file mode 100644 (file)
index 0000000..95c12cb
--- /dev/null
@@ -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.
index f1b0ef8f0d936a99e833a63d9227461254d469de..2c7259af0dd4cd55cd7933335f8ba1afdea260ba 100644 (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      \
index c36a7e0381d80127b5c621db586283f94a94dbad..e0f93d3c46e02d1065e36bac71583d8599dc5e65 100644 (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);
diff --git a/lib/creds.c b/lib/creds.c
new file mode 100644 (file)
index 0000000..fe8693a
--- /dev/null
@@ -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
diff --git a/lib/creds.h b/lib/creds.h
new file mode 100644 (file)
index 0000000..2eb5998
--- /dev/null
@@ -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 */
index 00eff8e6a999285b4bf1195f2fbfa1791037d8e5..6c955446fea8f05888bc8073a176709f8ff2d132 100644 (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 */
index 3f55f68d8287c3a3471c10ffc510467903067757..68c1a46ca5dca99a31300a0262d0f0d8e9ae0f87 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -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);
   }
index edca1dc1eaf5e15b237b0b3b71e1661d4bb1df84..9cb8b17b347cfd02defbc0e2705958566d37593d 100644 (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);
-#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;
+    {
+      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
   }
   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) {
index 5761acae5fe1fb78dd069787e5a0d2c2c84544eb..f77f7a088c0745010b51d305d3a3b7ac984d10bf 100644 (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 */
index e87fb362ed66a4fbb9b3ad86fac2190c2312de51..d20e165623547a571c7ca1867fcf96a9d2493452 100644 (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;
index b037bb2ec904a4f8a45fd46aea7341795ccfe7c7..d987b8b9d1d4b22be291c2693d1ae8191930e593 100644 (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;
 }
 
index 0240251a5f6a7be2c0b0cb9a09c37a47acb97ea6..1a02a0fd867a33e8bd00edb0c41138efa5a3cb20 100644 (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);
index 5ef2a2cb218901433e321ce49cd2e5dfa4c23bd7..7c73255e960b7db959d72bb667484b2cd01d06a3 100644 (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);
index 3705754476d1d5586778199afe099490ae755049..f476da4ea00d8f7ad441bfcb2046c008f5705613 100644 (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);
index d28a25bb50dd8ae9fbc8318de8f90afc86b8c772..1137909454164c8f4d58a86d466848662d874095 100644 (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;
 }
 
index 72d8feee7d94df420902e2b875b660bf3ceb1728..76fd5541ce079191c42c92190db29df3eac2a6b8 100644 (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;
 }
 
index 90318c2bd645a360fdcd560379aef9bb236cd3c0..92dd4d47c9e65a3969b6d48da287b9b322a726d3 100644 (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.
index 30e4bcc7521ce931f0bb9f8299a06443198a65c6..1ed72c1ea816ea3f1ca9f3ccdd0e8426aefef6f6 100644 (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 */
index 317c04bbe3637d5e5467763b8ef481bd1b1bd5af..b7bbd765b916a2ce8d00079354f9eb734a59a063 100644 (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);
 
index b39b8a740b76b875cf915c2094f77434f276b588..60c09cbb4b0e17b3445a46fd79cb9888474af737 100644 (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.
index 8a75b2dbae27a721aebf870f822b5cdc2641a2d0..a660f053ebb87e29f5fd25d3d828170ec5ddaf28 100644 (file)
--- a/lib/smb.c
+++ b/lib/smb.c
@@ -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));
index ed60063ab5d69055b444319547dc902a57d7873d..2d8a4f3ab6a92332e75089c74ca342ae01fb7eb2 100644 (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);
 
index e17b761f1c81fa07b89fd61b027f135a83ffccea..fca10c8332589c37c8ad7abf7d3295f22335dd84 100644 (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;
 
index c5ce9c2c97e3799990b0cd3b1d979b8e2aa24b34..d1faec87a87d086a08c38a2ff8c9086816658ee5 100644 (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);
index fd1a903dabc8a3237d6f2fa427e8c64e01dda530..721ad8d9cec7f0d0b8a3323242b8813d258f05d2 100644 (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;
index b29e70b9ec12750531f1919cebfc01605b1de787..41ec0357f681be5f4f1382ca3d7fa9a32c745acb 100644 (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);
index ba662d6a0ba92cc44cc7df7476592b60e6ef5278..298e5478a2a1e5ef929172d4b729f4010ac78204 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -249,7 +249,7 @@ CURLcode Curl_close(struct Curl_easy **datap)
 
   /* Close down all open SSL info and sessions */
   Curl_ssl_close_all(data);
-  Curl_peer_unlink(&data->state.first_origin);
+  Curl_peer_unlink(&data->state.initial_origin);
   Curl_ssl_free_certinfo(data);
 
   Curl_bufref_free(&data->state.referer);
@@ -281,6 +281,7 @@ CURLcode Curl_close(struct Curl_easy **datap)
     DEBUGASSERT(0);
 
   Curl_hash_destroy(&data->meta_hash);
+  Curl_creds_unlink(&data->state.creds);
   curlx_safefree(data->state.aptr.uagent);
   curlx_safefree(data->state.aptr.accept_encoding);
   curlx_safefree(data->state.aptr.rangeline);
@@ -292,12 +293,6 @@ CURLcode Curl_close(struct Curl_easy **datap)
 #ifndef CURL_DISABLE_RTSP
   curlx_safefree(data->state.aptr.rtsp_transport);
 #endif
-  curlx_safefree(data->state.aptr.user);
-  curlx_safefree(data->state.aptr.passwd);
-#ifndef CURL_DISABLE_PROXY
-  curlx_safefree(data->state.aptr.proxyuser);
-  curlx_safefree(data->state.aptr.proxypasswd);
-#endif
 
 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
   Curl_mime_cleanpart(data->state.formp);
@@ -511,18 +506,13 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
   }
 
 #ifndef CURL_DISABLE_PROXY
-  curlx_safefree(conn->http_proxy.user);
-  curlx_safefree(conn->socks_proxy.user);
-  curlx_safefree(conn->http_proxy.passwd);
-  curlx_safefree(conn->socks_proxy.passwd);
   Curl_peer_unlink(&conn->http_proxy.peer);
   Curl_peer_unlink(&conn->socks_proxy.peer);
+  Curl_creds_unlink(&conn->http_proxy.creds);
+  Curl_creds_unlink(&conn->socks_proxy.creds);
 #endif
-  curlx_safefree(conn->user);
-  curlx_safefree(conn->passwd);
-  curlx_safefree(conn->sasl_authzid);
+  Curl_creds_unlink(&conn->creds);
   curlx_safefree(conn->options);
-  curlx_safefree(conn->oauth_bearer);
   curlx_safefree(conn->localdev);
   Curl_ssl_conn_config_cleanup(conn);
 
@@ -567,11 +557,8 @@ static bool proxy_info_matches(const struct proxy_info *data,
                                const struct proxy_info *needle)
 {
   if((data->proxytype == needle->proxytype) &&
-     Curl_peer_same_destination(data->peer, needle->peer)) {
-
-    if(Curl_timestrcmp(data->user, needle->user) ||
-       Curl_timestrcmp(data->passwd, needle->passwd))
-      return FALSE;
+     Curl_peer_same_destination(data->peer, needle->peer) &&
+     Curl_creds_same(data->creds, needle->creds)) {
     return TRUE;
   }
   return FALSE;
@@ -950,16 +937,11 @@ static bool url_match_proto_config(struct connectdata *conn,
 static bool url_match_auth(struct connectdata *conn,
                            struct url_conn_match *m)
 {
-  if(!(m->needle->scheme->flags & PROTOPT_CREDSPERREQUEST)) {
-    /* This protocol requires credentials per connection,
-       so verify that we are using the same name and password as well */
-    if(Curl_timestrcmp(m->needle->user, conn->user) ||
-       Curl_timestrcmp(m->needle->passwd, conn->passwd) ||
-       Curl_timestrcmp(m->needle->sasl_authzid, conn->sasl_authzid) ||
-       Curl_timestrcmp(m->needle->oauth_bearer, conn->oauth_bearer)) {
-      /* one of them was different */
+  if(!Curl_creds_same(m->needle->creds, conn->creds)) {
+    if(m->needle->creds)
+      return FALSE;
+    if(!Curl_creds_same(m->data->state.creds, conn->creds))
       return FALSE;
-    }
   }
 #ifdef HAVE_GSSAPI
   /* GSS delegation differences do not actually affect every connection
@@ -1030,8 +1012,7 @@ static bool url_match_auth_ntlm(struct connectdata *conn,
      possible. (Especially we must not reuse the same connection if
      partway through a handshake!) */
   if(m->want_ntlm_http) {
-    if(Curl_timestrcmp(m->needle->user, conn->user) ||
-       Curl_timestrcmp(m->needle->passwd, conn->passwd)) {
+    if(!Curl_creds_same(m->data->state.creds, conn->creds)) {
       /* we prefer a credential match, but this is at least a connection
          that can be reused and "upgraded" to NTLM if it does
          not have any auth ongoing. */
@@ -1056,13 +1037,10 @@ static bool url_match_auth_ntlm(struct connectdata *conn,
   if(m->want_proxy_ntlm_http) {
     /* Both conn->http_proxy.user and conn->http_proxy.passwd can be
      * NULL */
-    if(!conn->http_proxy.user || !conn->http_proxy.passwd)
+    if(!conn->http_proxy.creds)
       return FALSE;
 
-    if(Curl_timestrcmp(m->needle->http_proxy.user,
-                       conn->http_proxy.user) ||
-       Curl_timestrcmp(m->needle->http_proxy.passwd,
-                       conn->http_proxy.passwd))
+    if(!Curl_creds_same(m->needle->http_proxy.creds, conn->http_proxy.creds))
       return FALSE;
   }
   else if(conn->proxy_ntlm_state != NTLMSTATE_NONE) {
@@ -1102,8 +1080,7 @@ static bool url_match_auth_nego(struct connectdata *conn,
      already authenticating with the right credentials. If not, keep looking
      so that we can reuse Negotiate connections if possible. */
   if(m->want_nego_http) {
-    if(Curl_timestrcmp(m->needle->user, conn->user) ||
-       Curl_timestrcmp(m->needle->passwd, conn->passwd))
+    if(!Curl_creds_same(m->needle->creds, conn->creds))
       return FALSE;
   }
   else if(conn->http_negotiate_state != GSS_AUTHNONE) {
@@ -1116,13 +1093,10 @@ static bool url_match_auth_nego(struct connectdata *conn,
   if(m->want_proxy_nego_http) {
     /* Both conn->http_proxy.user and conn->http_proxy.passwd can be
      * NULL */
-    if(!conn->http_proxy.user || !conn->http_proxy.passwd)
+    if(!conn->http_proxy.creds)
       return FALSE;
 
-    if(Curl_timestrcmp(m->needle->http_proxy.user,
-                       conn->http_proxy.user) ||
-       Curl_timestrcmp(m->needle->http_proxy.passwd,
-                       conn->http_proxy.passwd))
+    if(!Curl_creds_same(m->needle->http_proxy.creds, conn->http_proxy.creds))
       return FALSE;
   }
   else if(conn->proxy_negotiate_state != GSS_AUTHNONE) {
@@ -1265,7 +1239,7 @@ static bool url_attach_existing(struct Curl_easy *data,
     (needle->scheme->protocol & PROTO_FAMILY_HTTP);
 #ifndef CURL_DISABLE_PROXY
   match.want_proxy_ntlm_http =
-    needle->bits.proxy_user_passwd &&
+    needle->http_proxy.creds &&
     (data->state.authproxy.want & CURLAUTH_NTLM) &&
     (needle->scheme->protocol & PROTO_FAMILY_HTTP);
 #endif
@@ -1277,7 +1251,7 @@ static bool url_attach_existing(struct Curl_easy *data,
     (needle->scheme->protocol & PROTO_FAMILY_HTTP);
 #ifndef CURL_DISABLE_PROXY
   match.want_proxy_nego_http =
-    needle->bits.proxy_user_passwd &&
+    needle->http_proxy.creds &&
     (data->state.authproxy.want & CURLAUTH_NEGOTIATE) &&
     (needle->scheme->protocol & PROTO_FAMILY_HTTP);
 #endif
@@ -1339,7 +1313,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
     conn->bits.socksproxy = TRUE;
   }
 
-  conn->bits.proxy_user_passwd = !!data->state.aptr.proxyuser;
   conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
 #endif /* CURL_DISABLE_PROXY */
 
@@ -1452,13 +1425,76 @@ static CURLcode hsts_upgrade(struct Curl_easy *data,
 #define hsts_upgrade(x, y, z, a, b) CURLE_OK
 #endif
 
+static CURLcode url_set_data_creds(struct Curl_easy *data,
+                                   struct connectdata *conn,
+                                   CURLU *uh)
+{
+  CURLcode result = CURLE_OK;
+
+  /* We reset any existing credentials on the transfer. Then
+   * set the CURLOPT_* credentials ONLY IF the origin is the initial one. */
+  Curl_creds_unlink(&data->state.creds);
+  if((data->set.str[STRING_USERNAME] ||
+      data->set.str[STRING_PASSWORD] ||
+      data->set.str[STRING_SASL_AUTHZID] ||
+      data->set.str[STRING_BEARER]) &&
+     (data->set.allow_auth_to_other_hosts ||
+      Curl_peer_same_destination(data->state.initial_origin, conn->origin))) {
+    result = Curl_creds_create(data->set.str[STRING_USERNAME],
+                               data->set.str[STRING_PASSWORD],
+                               data->set.str[STRING_SASL_AUTHZID],
+                               data->set.str[STRING_BEARER],
+                               CREDS_OPTION, &data->state.creds);
+    if(result)
+      return result;
+  }
+
+  /* Extract credentials from the URL only if there are none OR
+   * if no CURLOPT_USER was set. */
+  if(!data->state.creds || !Curl_creds_has_user(data->state.creds)) {
+    char *udecoded = NULL;
+    char *pdecoded = NULL;
+    CURLUcode uc;
+
+    uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
+    if(uc && (uc != CURLUE_NO_USER)) {
+      result = Curl_uc_to_curlcode(uc);
+      goto out;
+    }
+    uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
+    if(uc && (uc != CURLUE_NO_PASSWORD)) {
+      result = Curl_uc_to_curlcode(uc);
+      goto out;
+    }
+    if(data->state.up.user) {
+      result = Curl_urldecode(data->state.up.user, 0, &udecoded, NULL,
+                              conn->scheme->flags&PROTOPT_USERPWDCTRL ?
+                              REJECT_ZERO : REJECT_CTRL);
+    }
+    if(!result && data->state.up.password) {
+      result = Curl_urldecode(data->state.up.password, 0, &pdecoded, NULL,
+                              conn->scheme->flags&PROTOPT_USERPWDCTRL ?
+                              REJECT_ZERO : REJECT_CTRL);
+    }
+    if(!result)
+      result = Curl_creds_merge(udecoded, pdecoded, data->state.creds,
+                                CREDS_URL, &data->state.creds);
+out:
+    curlx_free(udecoded);
+    curlx_free(pdecoded);
+    if(result)
+      failf(data, "error extracting credentials from URL");
+  }
+  return result;
+}
+
 /*
  * Parse URL and fill in the relevant members of the connection struct.
  */
 static CURLcode parseurlandfillconn(struct Curl_easy *data,
                                     struct connectdata *conn)
 {
-  CURLcode result;
+  CURLcode result = CURLE_OK;
   CURLU *uh;
   CURLUcode uc;
   bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow);
@@ -1472,8 +1508,10 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
     uh = data->state.uh = curl_url_dup(data->set.uh);
   else
     uh = data->state.uh = curl_url();
-  if(!uh)
-    return CURLE_OUT_OF_MEMORY;
+  if(!uh) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
 
   /* Calculate the *real* URL this transfer uses, applying defaults
    * where information is missing. */
@@ -1482,8 +1520,10 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
     char *url = curl_maprintf("%s://%s",
                               data->set.str[STRING_DEFAULT_PROTOCOL],
                               Curl_bufref_ptr(&data->state.url));
-    if(!url)
-      return CURLE_OUT_OF_MEMORY;
+    if(!url) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
+    }
     Curl_bufref_set(&data->state.url, url, 0, curl_free);
   }
 
@@ -1497,13 +1537,16 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
                        (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
     if(uc) {
       failf(data, "URL rejected: %s", curl_url_strerror(uc));
-      return Curl_uc_to_curlcode(uc);
+      result = Curl_uc_to_curlcode(uc);
+      goto out;
     }
 
     /* after it was parsed, get the generated normalized version */
     uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0);
-    if(uc)
-      return Curl_uc_to_curlcode(uc);
+    if(uc) {
+      result = Curl_uc_to_curlcode(uc);
+      goto out;
+    }
     Curl_bufref_set(&data->state.url, newurl, 0, curl_free);
   }
 
@@ -1515,86 +1558,64 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
   result = Curl_peer_from_url(uh, data, port_override, scope_id,
                               &data->state.up, &conn->origin);
   if(result)
-    return result;
+    goto out;
 
   result = hsts_upgrade(data, conn, uh, port_override, scope_id);
   if(result)
-    return result;
+    goto out;
 
   /* now that the origin is fixed, check and set the connection scheme */
   result = url_set_conn_scheme(data, conn, conn->origin->scheme);
   if(result)
-    return result;
+    goto out;
 
-  /*
-   * username and password set with their own options override the credentials
-   * possibly set in the URL, but netrc does not.
-   */
-  if(!data->state.aptr.passwd || (data->state.creds_from != CREDS_OPTION)) {
-    uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
-    if(!uc) {
-      char *decoded;
-      result = Curl_urldecode(data->state.up.password, 0, &decoded, NULL,
-                              conn->scheme->flags&PROTOPT_USERPWDCTRL ?
-                              REJECT_ZERO : REJECT_CTRL);
-      if(result)
-        return result;
-      conn->passwd = decoded;
-      result = Curl_setstropt(&data->state.aptr.passwd, decoded);
-      if(result)
-        return result;
-      data->state.creds_from = CREDS_URL;
-    }
-    else if(uc != CURLUE_NO_PASSWORD)
-      return Curl_uc_to_curlcode(uc);
-  }
+  /* When the transfers initial_origin is not set, this is the initial
+   * request. Remember this starting point. This is used to
+   * select credentials. */
+  if(!data->state.initial_origin)
+    Curl_peer_link(&data->state.initial_origin, conn->origin);
 
-  if(!data->state.aptr.user || (data->state.creds_from != CREDS_OPTION)) {
-    /* we do not use the URL API's URL decoder option here since it rejects
-       control codes and we want to allow them for some schemes in the user
-       and password fields */
-    uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
-    if(!uc) {
-      char *decoded;
-      result = Curl_urldecode(data->state.up.user, 0, &decoded, NULL,
-                              conn->scheme->flags&PROTOPT_USERPWDCTRL ?
-                              REJECT_ZERO : REJECT_CTRL);
-      if(result)
-        return result;
-      conn->user = decoded;
-      result = Curl_setstropt(&data->state.aptr.user, decoded);
-      data->state.creds_from = CREDS_URL;
-    }
-    else if(uc != CURLUE_NO_USER)
-      return Curl_uc_to_curlcode(uc);
-    if(result)
-      return result;
-  }
+  result = url_set_data_creds(data, conn, uh);
+  if(result)
+    goto out;
 
   uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
                     CURLU_URLDECODE);
   if(!uc) {
     conn->options = curlx_strdup(data->state.up.options);
-    if(!conn->options)
-      return CURLE_OUT_OF_MEMORY;
+    if(!conn->options) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
+    }
+  }
+  else if(uc != CURLUE_NO_OPTIONS) {
+    result = Curl_uc_to_curlcode(uc);
+    goto out;
   }
-  else if(uc != CURLUE_NO_OPTIONS)
-    return Curl_uc_to_curlcode(uc);
 
   uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path, CURLU_URLENCODE);
-  if(uc)
-    return Curl_uc_to_curlcode(uc);
+  if(uc) {
+    result = Curl_uc_to_curlcode(uc);
+    goto out;
+  }
 
   uc = curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
-  if(uc && (uc != CURLUE_NO_QUERY))
-    return CURLE_OUT_OF_MEMORY;
+  if(uc && (uc != CURLUE_NO_QUERY)) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
 
 #ifdef USE_IPV6
   /* Fill in the conn parts that do not use authority, yet. */
   conn->scope_id = conn->origin->scopeid;
 #endif
 
-  return CURLE_OK;
+#ifdef CURLVERBOSE
+  Curl_creds_trace(data, data->state.creds, "transfer credentials");
+#endif
+
+out:
+  return result;
 }
 
 /*
@@ -1770,14 +1791,15 @@ static char *url_detect_proxy(struct Curl_easy *data,
  * that may exist registered to the same proxy host.
  */
 static CURLcode parse_proxy(struct Curl_easy *data,
-                            struct connectdata *conn, const char *proxy,
-                            uint8_t proxytype)
+                            const char *proxy,
+                            bool for_pre_proxy,
+                            struct proxy_info *proxyinfo)
 {
   char *proxyuser = NULL;
   char *proxypasswd = NULL;
-  struct proxy_info *proxyinfo = NULL;
   CURLcode result = CURLE_OK;
-  struct Curl_peer *peer = NULL;
+  /* Set the start proxy type for url scheme guessing */
+  uint8_t proxytype = for_pre_proxy ? CURLPROXY_SOCKS4 : data->set.proxytype;
   CURLU *uhp = curl_url();
   CURLUcode uc;
 
@@ -1797,7 +1819,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
   }
 
   result = Curl_peer_from_proxy_url(uhp, data, proxy, proxytype,
-                                    &peer, &proxytype);
+                                    &proxyinfo->peer, &proxytype);
   if(result)
     goto error;
 
@@ -1806,22 +1828,21 @@ static CURLcode parse_proxy(struct Curl_easy *data,
     case CURLPROXY_HTTP_1_0:
     case CURLPROXY_HTTPS:
     case CURLPROXY_HTTPS2:
-      proxyinfo = &conn->http_proxy;
+      if(for_pre_proxy) {
+        failf(data, "Unsupported pre-proxy type for \'%s\'", proxy);
+        result = CURLE_COULDNT_RESOLVE_PROXY;
+        goto error;
+      }
       break;
     case CURLPROXY_SOCKS4:
     case CURLPROXY_SOCKS4A:
     case CURLPROXY_SOCKS5:
     case CURLPROXY_SOCKS5_HOSTNAME:
-      proxyinfo = &conn->socks_proxy;
       break;
     default:
-      break;
-  }
-
-  if(!proxyinfo) {
-    failf(data, "Unsupported proxy type %u for \'%s\'", proxytype, proxy);
-    result = CURLE_COULDNT_RESOLVE_PROXY;
-    goto error;
+      failf(data, "Unsupported proxy type %u for \'%s\'", proxytype, proxy);
+      result = CURLE_COULDNT_RESOLVE_PROXY;
+      goto error;
   }
 
   /* Is there a username and password given in this proxy URL? */
@@ -1837,35 +1858,29 @@ static CURLcode parse_proxy(struct Curl_easy *data,
   }
 
   if(proxyuser || proxypasswd) {
-    curlx_free(proxyinfo->user);
-    proxyinfo->user = proxyuser;
-    result = Curl_setstropt(&data->state.aptr.proxyuser, proxyuser);
-    proxyuser = NULL;
+    result = Curl_creds_create(proxyuser, proxypasswd, NULL, NULL,
+                               CREDS_URL, &proxyinfo->creds);
     if(result)
       goto error;
-    curlx_safefree(proxyinfo->passwd);
-    if(!proxypasswd) {
-      proxypasswd = curlx_strdup("");
-      if(!proxypasswd) {
-        result = CURLE_OUT_OF_MEMORY;
-        goto error;
-      }
-    }
-    proxyinfo->passwd = proxypasswd;
-    result = Curl_setstropt(&data->state.aptr.proxypasswd, proxypasswd);
-    proxypasswd = NULL;
-    if(result)
-      goto error;
-    conn->bits.proxy_user_passwd = TRUE; /* enable it */
   }
+  else if(!for_pre_proxy &&
+          (data->set.str[STRING_PROXYUSERNAME] ||
+           data->set.str[STRING_PROXYPASSWORD])) {
+    /* No user/passwd in URL, if this is not a pre-proxy, the
+     * CURLOPT_PROXY* settings apply. */
+    result = Curl_creds_create(data->set.str[STRING_PROXYUSERNAME],
+                               data->set.str[STRING_PROXYPASSWORD],
+                               NULL, NULL,
+                               CREDS_OPTION, &proxyinfo->creds);
+  }
+  else
+    Curl_creds_unlink(&proxyinfo->creds);
 
-  Curl_peer_link(&proxyinfo->peer, peer);
   proxyinfo->proxytype = proxytype;
 
 error:
   curlx_free(proxyuser);
   curlx_free(proxypasswd);
-  Curl_peer_unlink(&peer);
   curl_url_cleanup(uhp);
 #ifdef DEBUGBUILD
   if(!result) {
@@ -1876,46 +1891,14 @@ error:
   return result;
 }
 
-/*
- * Extract the user and password from the authentication string
- */
-static CURLcode parse_proxy_auth(struct Curl_easy *data,
-                                 struct connectdata *conn)
-{
-  const char *proxyuser = data->state.aptr.proxyuser ?
-    data->state.aptr.proxyuser : "";
-  const char *proxypasswd = data->state.aptr.proxypasswd ?
-    data->state.aptr.proxypasswd : "";
-  CURLcode result = CURLE_OUT_OF_MEMORY;
-
-  conn->http_proxy.user = curlx_strdup(proxyuser);
-  if(conn->http_proxy.user) {
-    conn->http_proxy.passwd = curlx_strdup(proxypasswd);
-    if(conn->http_proxy.passwd)
-      result = CURLE_OK;
-    else
-      curlx_safefree(conn->http_proxy.user);
-  }
-  return result;
-}
-
 static CURLcode url_set_conn_proxies(struct Curl_easy *data,
                                      struct connectdata *conn)
 {
   char *proxy = NULL;
-  char *socksproxy = NULL;
+  char *pre_proxy = NULL;
   char *no_proxy = NULL;
   CURLcode result = CURLE_OK;
 
-  /*************************************************************
-   * Extract the user and password from the authentication string
-   *************************************************************/
-  if(conn->bits.proxy_user_passwd) {
-    result = parse_proxy_auth(data, conn);
-    if(result)
-      goto out;
-  }
-
   /*************************************************************
    * Detect what (if any) proxy to use
    *************************************************************/
@@ -1930,9 +1913,9 @@ static CURLcode url_set_conn_proxies(struct Curl_easy *data,
   }
 
   if(data->set.str[STRING_PRE_PROXY]) {
-    socksproxy = curlx_strdup(data->set.str[STRING_PRE_PROXY]);
+    pre_proxy = curlx_strdup(data->set.str[STRING_PRE_PROXY]);
     /* if global socks proxy is set, this is it */
-    if(!socksproxy) {
+    if(!pre_proxy) {
       failf(data, "memory shortage");
       result = CURLE_OUT_OF_MEMORY;
       goto out;
@@ -1954,10 +1937,10 @@ static CURLcode url_set_conn_proxies(struct Curl_easy *data,
   if(Curl_check_noproxy(conn->origin->hostname, data->set.str[STRING_NOPROXY] ?
                         data->set.str[STRING_NOPROXY] : no_proxy)) {
     curlx_safefree(proxy);
-    curlx_safefree(socksproxy);
+    curlx_safefree(pre_proxy);
   }
 #ifndef CURL_DISABLE_HTTP
-  else if(!proxy && !socksproxy)
+  else if(!proxy && !pre_proxy)
     /* if the host is not in the noproxy list, detect proxy. */
     proxy = url_detect_proxy(data, conn);
 #endif /* CURL_DISABLE_HTTP */
@@ -1968,12 +1951,12 @@ static CURLcode url_set_conn_proxies(struct Curl_easy *data,
                            or if the protocol does not work with network */
     proxy = NULL;
   }
-  if(socksproxy && (!*socksproxy ||
+  if(pre_proxy && (!*pre_proxy ||
                     (conn->scheme->flags & PROTOPT_NONETWORK))) {
-    curlx_free(socksproxy);  /* Do not bother with an empty socks proxy string
-                                or if the protocol does not work with
-                                network */
-    socksproxy = NULL;
+    curlx_free(pre_proxy);  /* Do not bother with an empty socks proxy string
+                               or if the protocol does not work with
+                               network */
+    pre_proxy = NULL;
   }
 
   /***********************************************************************
@@ -1981,21 +1964,37 @@ static CURLcode url_set_conn_proxies(struct Curl_easy *data,
    * name, proxy type and port number, so that we can reuse an existing
    * connection that may exist registered to the same proxy host.
    ***********************************************************************/
-  if(proxy || socksproxy) {
-    if(proxy) {
-      result = parse_proxy(data, conn, proxy, conn->http_proxy.proxytype);
-      curlx_safefree(proxy); /* parse_proxy copies the proxy string */
+  if(proxy || pre_proxy) {
+    if(pre_proxy) {
+      result = parse_proxy(data, pre_proxy, TRUE, &conn->socks_proxy);
       if(result)
         goto out;
     }
 
-    if(socksproxy) {
-      result = parse_proxy(data, conn, socksproxy,
-                           conn->socks_proxy.proxytype);
-      /* parse_proxy copies the socks proxy string */
-      curlx_safefree(socksproxy);
+    if(proxy) {
+      result = parse_proxy(data, proxy, FALSE, &conn->http_proxy);
       if(result)
         goto out;
+      switch(conn->http_proxy.proxytype) {
+      case CURLPROXY_SOCKS4:
+      case CURLPROXY_SOCKS4A:
+      case CURLPROXY_SOCKS5:
+      case CURLPROXY_SOCKS5_HOSTNAME:
+        /* Whoops, it's not a HTTP proxy */
+        if(conn->socks_proxy.peer) {
+          /* and we already have a SOCKS pre-proxy. Cannot have both */
+          failf(data, "Having a SOCKS pre-proxy and proxy is not "
+                "supported with \'%s\'", proxy);
+          result = CURLE_COULDNT_RESOLVE_PROXY;
+          goto out;
+        }
+        /* switch */
+        conn->socks_proxy = conn->http_proxy;
+        memset(&conn->http_proxy, 0, sizeof(conn->http_proxy));
+        break;
+      default:
+        break;
+      }
     }
 
     if(conn->http_proxy.peer) {
@@ -2013,34 +2012,14 @@ static CURLcode url_set_conn_proxies(struct Curl_easy *data,
           /* if not converting to HTTP over the proxy, enforce tunneling */
           conn->bits.tunnel_proxy = TRUE;
       }
-      conn->bits.httpproxy = TRUE;
 #endif
     }
-    else {
-      conn->bits.httpproxy = FALSE; /* not an HTTP proxy */
-      conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
-    }
-
-    if(conn->socks_proxy.peer) {
-      if(!conn->http_proxy.peer) {
-        /* once a socks proxy */
-        if(!conn->socks_proxy.user) {
-          conn->socks_proxy.user = conn->http_proxy.user;
-          conn->http_proxy.user = NULL;
-          curlx_free(conn->socks_proxy.passwd);
-          conn->socks_proxy.passwd = conn->http_proxy.passwd;
-          conn->http_proxy.passwd = NULL;
-        }
-      }
-      conn->bits.socksproxy = TRUE;
-    }
     else
-      conn->bits.socksproxy = FALSE; /* not a socks proxy */
-  }
-  else {
-    conn->bits.socksproxy = FALSE;
-    conn->bits.httpproxy = FALSE;
+      conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
   }
+
+  conn->bits.socksproxy = !!conn->socks_proxy.peer;
+  conn->bits.httpproxy = !!conn->http_proxy.peer;
   conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;
 
   if(!conn->bits.proxy) {
@@ -2048,7 +2027,6 @@ static CURLcode url_set_conn_proxies(struct Curl_easy *data,
     conn->bits.proxy = FALSE;
     conn->bits.httpproxy = FALSE;
     conn->bits.socksproxy = FALSE;
-    conn->bits.proxy_user_passwd = FALSE;
     conn->bits.tunnel_proxy = FALSE;
     /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
        to signal that CURLPROXY_HTTPS is not used for this connection */
@@ -2057,7 +2035,7 @@ static CURLcode url_set_conn_proxies(struct Curl_easy *data,
 
 out:
 
-  curlx_free(socksproxy);
+  curlx_free(pre_proxy);
   curlx_free(proxy);
   return result;
 }
@@ -2180,41 +2158,71 @@ static CURLcode override_login(struct Curl_easy *data,
                                struct connectdata *conn)
 {
   CURLUcode uc;
-  char **userp = &conn->user;
-  char **passwdp = &conn->passwd;
   char **optionsp = &conn->options;
+#ifndef CURL_DISABLE_NETRC
+  struct Curl_creds *ncreds_in = NULL;
+  struct Curl_creds *ncreds_out = NULL;
+#endif
+  CURLcode result = CURLE_OK;
+  bool creds_changed = FALSE;
 
   if(data->set.str[STRING_OPTIONS]) {
     curlx_free(*optionsp);
     *optionsp = curlx_strdup(data->set.str[STRING_OPTIONS]);
-    if(!*optionsp)
-      return CURLE_OUT_OF_MEMORY;
+    if(!*optionsp) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
+    }
   }
 
 #ifndef CURL_DISABLE_NETRC
-  if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
-    curlx_safefree(*userp);
-    curlx_safefree(*passwdp);
-  }
-  conn->bits.netrc = FALSE;
-  if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
-    bool url_provided = FALSE;
-
-    if(data->state.aptr.user &&
-       (data->state.creds_from != CREDS_NETRC)) {
-      /* there was a username with a length in the URL. Use the URL decoded
-         version */
-      userp = &data->state.aptr.user;
-      url_provided = TRUE;
+  if(data->set.use_netrc) {
+    /* Determine how to react on already existing credentials */
+    if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
+      Curl_creds_unlink(&conn->creds);
     }
 
-    if(!*passwdp) {
-      NETRCcode ret = Curl_parsenetrc(&data->state.netrc,
-                                      conn->origin->hostname,
-                                      userp, passwdp,
-                                      data->set.str[STRING_NETRC_FILE]);
-      if(ret == NETRC_OUT_OF_MEMORY)
-        return CURLE_OUT_OF_MEMORY;
+    if(data->state.creds) {
+      switch(data->state.creds->source) {
+      case CREDS_OPTION:
+        /* we never override credentials set via CURLOPT_* */
+        goto out;
+      case CREDS_URL:
+        if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
+          /* use the URL user to search netrc */
+          result = Curl_creds_create(
+            data->state.creds->user, NULL, NULL, NULL, CREDS_URL, &ncreds_in);
+          if(result)
+            goto out;
+        }
+        else if(data->state.creds) {
+          /* only search when something is still missing */
+          Curl_creds_link(&ncreds_in, data->state.creds);
+        }
+        break;
+      default:
+        /* ignore credentials from other sources */
+        break;
+      }
+    }
+
+    /* Only search in netrc when the creds are not already complete */
+    if(!Curl_creds_has_passwd(ncreds_in)) {
+      NETRCcode ret;
+
+      CURL_TRC_M(data, "netrc: find credentials for %s, user %s",
+                 conn->origin->hostname,
+                 Curl_creds_has_user(ncreds_in) ? ncreds_in->user : "*");
+      ret = Curl_parsenetrc(&data->state.netrc,
+                            conn->origin->hostname,
+                            ncreds_in,
+                            data->set.str[STRING_NETRC_FILE],
+                            &ncreds_out);
+      DEBUGASSERT(!ret || !ncreds_out);
+      if(ret == NETRC_OUT_OF_MEMORY) {
+        result = CURLE_OUT_OF_MEMORY;
+        goto out;
+      }
       else if(ret && ((ret == NETRC_NO_MATCH) ||
                       (data->set.use_netrc == CURL_NETRC_OPTIONAL))) {
         infof(data, "Could not find host %s in the %s file; using defaults",
@@ -2225,113 +2233,76 @@ static CURLcode override_login(struct Curl_easy *data,
       else if(ret) {
         const char *m = Curl_netrc_strerror(ret);
         failf(data, ".netrc error: %s", m);
-        return CURLE_READ_ERROR;
+        result = CURLE_READ_ERROR;
+        goto out;
       }
-      else {
+      else if(ncreds_out) {
         if(!(conn->scheme->flags & PROTOPT_USERPWDCTRL)) {
           /* if the protocol cannot handle control codes in credentials, make
              sure there are none */
-          if(str_has_ctrl(*userp) || str_has_ctrl(*passwdp)) {
+          if(str_has_ctrl(ncreds_out->user) ||
+             str_has_ctrl(ncreds_out->passwd)) {
             failf(data, "control code detected in .netrc credentials");
-            return CURLE_READ_ERROR;
+            result = CURLE_READ_ERROR;
+            goto out;
           }
         }
-        /* set bits.netrc TRUE to remember that we got the name from a .netrc
-           file, so that it is safe to use even if we followed a Location: to a
-           different host or similar. */
-        conn->bits.netrc = TRUE;
+        CURL_TRC_M(data, "netrc: using credentials for %s as %s",
+                   conn->origin->hostname, ncreds_out->user);
+        result = Curl_creds_merge(ncreds_out->user, ncreds_out->passwd,
+                                  data->state.creds, CREDS_NETRC,
+                                  &data->state.creds);
+        if(result)
+          goto out;
+        creds_changed = TRUE;
       }
-    }
-    if(url_provided) {
-      curlx_free(conn->user);
-      conn->user = curlx_strdup(*userp);
-      if(!conn->user)
-        return CURLE_OUT_OF_MEMORY;
-    }
-    /* no user was set but a password, set a blank user */
-    if(!*userp && *passwdp) {
-      *userp = curlx_strdup("");
-      if(!*userp)
-        return CURLE_OUT_OF_MEMORY;
+      else
+        DEBUGASSERT(0);
     }
   }
+
 #endif
 
-  /* for updated strings, we update them in the URL */
-  if(*userp) {
-    CURLcode result;
-    if(data->state.aptr.user != *userp) {
-      /* nothing to do then */
-      result = Curl_setstropt(&data->state.aptr.user, *userp);
-      if(result)
-        return result;
-      data->state.creds_from = CREDS_NETRC;
-    }
-  }
-  if(data->state.aptr.user) {
-    uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user,
-                      CURLU_URLENCODE);
+  if(creds_changed) {
+    /* for updated strings, we update them in the URL */
+    uc = curl_url_set(data->state.uh, CURLUPART_USER,
+                      Curl_creds_user(data->state.creds), CURLU_URLENCODE);
+    if(!uc)
+      uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
+                        Curl_creds_passwd(data->state.creds), CURLU_URLENCODE);
     if(uc)
-      return Curl_uc_to_curlcode(uc);
-    if(!*userp) {
-      *userp = curlx_strdup(data->state.aptr.user);
-      if(!*userp)
-        return CURLE_OUT_OF_MEMORY;
-    }
-  }
-  if(*passwdp) {
-    CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
-    if(result)
-      return result;
-    data->state.creds_from = CREDS_NETRC;
-  }
-  if(data->state.aptr.passwd) {
-    uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
-                      data->state.aptr.passwd, CURLU_URLENCODE);
-    if(uc)
-      return Curl_uc_to_curlcode(uc);
-    if(!*passwdp) {
-      *passwdp = curlx_strdup(data->state.aptr.passwd);
-      if(!*passwdp)
-        return CURLE_OUT_OF_MEMORY;
-    }
+      result = Curl_uc_to_curlcode(uc);
   }
 
-  return CURLE_OK;
+out:
+#ifndef CURL_DISABLE_NETRC
+  Curl_creds_unlink(&ncreds_in);
+  Curl_creds_unlink(&ncreds_out);
+#endif
+  return result;
 }
 
 /*
  * Set the login details so they are available in the connection
  */
-static CURLcode set_login(struct Curl_easy *data,
-                          struct connectdata *conn)
+static CURLcode url_set_conn_login(struct Curl_easy *data,
+                                   struct connectdata *conn)
 {
-  CURLcode result = CURLE_OK;
-  const char *setuser = CURL_DEFAULT_USER;
-  const char *setpasswd = CURL_DEFAULT_PASSWORD;
-
   /* If our protocol needs a password and we have none, use the defaults */
-  if((conn->scheme->flags & PROTOPT_NEEDSPWD) && !data->state.aptr.user)
-    ;
-  else {
-    setuser = "";
-    setpasswd = "";
-  }
-  /* Store the default user */
-  if(!conn->user) {
-    conn->user = curlx_strdup(setuser);
-    if(!conn->user)
-      return CURLE_OUT_OF_MEMORY;
+  if((conn->scheme->flags & PROTOPT_NEEDSPWD) && !conn->creds) {
+    if(data->state.creds)
+      Curl_creds_link(&conn->creds, data->state.creds);
+    else
+      return Curl_creds_create(CURL_DEFAULT_USER, CURL_DEFAULT_PASSWORD,
+                               NULL, NULL, CREDS_NONE, &conn->creds);
   }
-
-  /* Store the default password */
-  if(!conn->passwd) {
-    conn->passwd = curlx_strdup(setpasswd);
-    if(!conn->passwd)
-      result = CURLE_OUT_OF_MEMORY;
+  else if(!(conn->scheme->flags & PROTOPT_CREDSPERREQUEST)) {
+    /* for protocols that do not handle credentials per request,
+     * the connection credentials are set by the initial transfer. */
+    Curl_creds_link(&conn->creds, data->state.creds);
   }
 
-  return result;
+  return CURLE_OK;
 }
 
 /*
@@ -2549,33 +2520,15 @@ static void url_conn_reuse_adjust(struct Curl_easy *data,
 
   /* get the user+password information from the needle since it may
    * be new for this request even when we reuse conn */
-  if(needle->user) {
+  if(needle->creds) {
     /* use the new username and password though */
-    curlx_free(conn->user);
-    curlx_free(conn->passwd);
-    conn->user = needle->user;
-    conn->passwd = needle->passwd;
-    needle->user = NULL;
-    needle->passwd = NULL;
+    Curl_creds_link(&conn->creds, needle->creds);
   }
 
 #ifndef CURL_DISABLE_PROXY
-  conn->bits.proxy_user_passwd = needle->bits.proxy_user_passwd;
-  if(conn->bits.proxy_user_passwd) {
-    /* use the new proxy username and proxy password though */
-    curlx_free(conn->http_proxy.user);
-    curlx_free(conn->socks_proxy.user);
-    curlx_free(conn->http_proxy.passwd);
-    curlx_free(conn->socks_proxy.passwd);
-    conn->http_proxy.user = needle->http_proxy.user;
-    conn->socks_proxy.user = needle->socks_proxy.user;
-    conn->http_proxy.passwd = needle->http_proxy.passwd;
-    conn->socks_proxy.passwd = needle->socks_proxy.passwd;
-    needle->http_proxy.user = NULL;
-    needle->socks_proxy.user = NULL;
-    needle->http_proxy.passwd = NULL;
-    needle->socks_proxy.passwd = NULL;
-  }
+  /* use the new proxy username and proxy password though */
+  Curl_creds_link(&conn->http_proxy.creds, needle->http_proxy.creds);
+  Curl_creds_link(&conn->socks_proxy.creds, needle->socks_proxy.creds);
 #endif
 
   /* Finding a connection for reuse in the cpool matches, among other
@@ -2686,29 +2639,13 @@ static CURLcode url_create_needle(struct Curl_easy *data,
   }
 #endif /* CURL_DISABLE_PROXY */
 
-  if(data->set.str[STRING_SASL_AUTHZID]) {
-    needle->sasl_authzid = curlx_strdup(data->set.str[STRING_SASL_AUTHZID]);
-    if(!needle->sasl_authzid) {
-      result = CURLE_OUT_OF_MEMORY;
-      goto out;
-    }
-  }
-
-  if(data->set.str[STRING_BEARER]) {
-    needle->oauth_bearer = curlx_strdup(data->set.str[STRING_BEARER]);
-    if(!needle->oauth_bearer) {
-      result = CURLE_OUT_OF_MEMORY;
-      goto out;
-    }
-  }
-
   /* Check for overridden login details and set them accordingly so that
      they are known when protocol->setup_connection is called! */
   result = override_login(data, needle);
   if(result)
     goto out;
 
-  result = set_login(data, needle); /* default credentials */
+  result = url_set_conn_login(data, needle); /* default credentials */
   if(result)
     goto out;
 
index 2889e936a4ae7fd7591bbdbc3ca7918043576cd5..6ad4666280d36b74695d19bc8f2fe8f3a0d63533 100644 (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
index 7976adec9c8fec28baaa8a9c42684677e7d20f28..ca0c9967ff9cd0c823144298b1e11f0afc5172d3 100644 (file)
  *
  * 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);
index d3f2d137b779607e37d9cc3453f7cb0bb2ffa8d3..023c31b58b67be3681de07edf501183566b4a6b5 100644 (file)
  * 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)
index 3c6f6e8e9559d86417eebe4223f2d5170559e522..f7080e2ece865c4d9c2e0ce88722808f1ca89743 100644 (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,
index f351a76986e22c9fa8288caccbd72ee3875f6289..31dfebfa5126dd83f42cdfcead47ada651b41931 100644 (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 */
index 958f4ffab746546fdb526ca82d6ade0589072d8d..3ea77eecd1b46c721d07b5eeea727c8fc9da748e 100644 (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));
index 64c735be582a8ab2cddfba3cf6d8e6630a8c252f..ad2c04facff8b2217fe37e42032ae3b2dc1c1011 100644 (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;
index e7491be022f86aa8f0e9e97e78298b6ff10c5278..dfac639bf9cab486665bd5bb88103d020e084c09 100644 (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;
 
index 1e485ed34d6f0a873b52a28fd003cb279d74d15a..bd914f3c8ce9e82760f64a1139b02e3873b010a1 100644 (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;
index 4c41eb21f4e652b403eecfab28c0e260a203fcd0..5fe78a622d7e7ba64659ef46c8e739c7541ecba0 100644 (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;
index 4541d1d551bb94f687eab71dff4658cade41d6ae..f597114638a5dade8bad27fbd8f323c6e87ab887 100644 (file)
  *
  * 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;
 
index 38bb4c1422c4a36c2faa742832ac0889fa5c2a86..631480fa7691b992b84f41667bd43c20fab213bd 100644 (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
index eeae0214841676c37e04c7afd4852f702f03f92a..ba4c4186a000c1a89ddb8db0bbc582d46af1a090 100644 (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;
 
index 81c29cd497d4c6cffb481424c2eae80db85e8703..76de85cb2844cdb7d5172b9a9face95137486b48 100644 (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
index 279da60be2cbabb41e27673ea3482b73b6c2962f..cdd64a1cfbd698cf47449ae0fe66f9f8c364bc8f 100644 (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,
index c6a6e0cfdfbe28aa3ecbe16daccb42ff22c80a24..49f9d3f93d2a4bf81c212c4b8b50bcc1e71580b7 100644 (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;
index 1f36934f6dda0b4ea6cb219da60d90735ee65190..118bc594f6415cd77bffdff547639c0203d1f038 100644 (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 */
 
index 4f3ef11fd064ec1834496d4f55ec6685b4c0f7a0..c13c5e863c8845b42b3393b04ac6ef027c6fab18 100644 (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);
 
index 72b2ab5a32f6f676ea9347ba9bad2ca070e7d29a..d66fe796e9529a44e4e90a612bd666fd90458225 100644 (file)
 
 #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