]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
vauth: move auth structs to conn meta data
authorStefan Eissing <stefan@eissing.org>
Mon, 9 Jun 2025 13:09:28 +0000 (15:09 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 10 Jun 2025 13:57:44 +0000 (15:57 +0200)
Remove structs for negotiate, krb5, ntlm and gsasl from connectdata and
store them as connection meta data with auto cleanup.

De-complexify sasl mech selection by moving code into static functions.

Closes #17557

16 files changed:
lib/cshutdn.c
lib/curl_ntlm_core.h
lib/curl_sasl.c
lib/curl_sasl.h
lib/http.c
lib/http_negotiate.c
lib/http_negotiate.h
lib/http_ntlm.c
lib/http_ntlm.h
lib/imap.c
lib/openldap.c
lib/pop3.c
lib/smtp.c
lib/urldata.h
lib/vauth/vauth.c
lib/vauth/vauth.h

index f05b87d277af8cc4d8a7e10f916cdbf8390e164f..be2561e719abdc88755d24be09cf50ee8a733a5e 100644 (file)
@@ -54,12 +54,6 @@ static void cshutdn_run_conn_handler(struct Curl_easy *data,
 {
   if(!conn->bits.shutdown_handler) {
 
-    /* Cleanup NTLM connection-related data */
-    Curl_http_auth_cleanup_ntlm(conn);
-
-    /* Cleanup NEGOTIATE connection-related data */
-    Curl_http_auth_cleanup_negotiate(conn);
-
     if(conn->handler && conn->handler->disconnect) {
       /* Some disconnect handlers do a blocking wait on server responses.
        * FTP/IMAP/SMTP and SFTP are among them. When using the internal
index e2e4b1bd43a12cf423a37849ddcdc5ece11c0105..7571ad5432f87419f44201bf5cca23bf61103890 100644 (file)
 
 #if defined(USE_CURL_NTLM_CORE)
 
+#include "vauth/vauth.h"
+
+struct ntlmdata;
+
 /* Helpers to generate function byte arguments in little endian order */
 #define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
 #define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
index 4fcbaac263bd9547ae47497af4a5e15a6139e989..f7118039049a12036d842f7c3e49694e91d9eafe 100644 (file)
@@ -76,44 +76,6 @@ static const struct {
   { ZERO_NULL,      0,  0 }
 };
 
-/*
- * Curl_sasl_cleanup()
- *
- * This is used to cleanup any libraries or curl modules used by the sasl
- * functions.
- *
- * Parameters:
- *
- * conn     [in]     - The connection data.
- * authused [in]     - The authentication mechanism used.
- */
-void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused)
-{
-  (void)conn;
-  (void)authused;
-
-#if defined(USE_KERBEROS5)
-  /* Cleanup the gssapi structure */
-  if(authused == SASL_MECH_GSSAPI) {
-    Curl_auth_cleanup_gssapi(&conn->krb5);
-  }
-#endif
-
-#if defined(USE_GSASL)
-  /* Cleanup the GSASL structure */
-  if(authused & (SASL_MECH_SCRAM_SHA_1 | SASL_MECH_SCRAM_SHA_256)) {
-    Curl_auth_gsasl_cleanup(&conn->gsasl);
-  }
-#endif
-
-#if defined(USE_NTLM)
-  /* Cleanup the NTLM structure */
-  if(authused == SASL_MECH_NTLM) {
-    Curl_auth_cleanup_ntlm(&conn->ntlm);
-  }
-#endif
-}
-
 /*
  * Curl_sasl_decode_mech()
  *
@@ -334,6 +296,241 @@ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
   return FALSE;
 }
 
+struct sasl_ctx {
+  struct SASL *sasl;
+  struct connectdata *conn;
+  const char *user;
+  unsigned short enabledmechs;
+  const char *mech;
+  saslstate state1;
+  saslstate state2;
+  struct bufref resp;
+  CURLcode result;
+};
+
+static bool sasl_choose_external(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  if((sctx->enabledmechs & SASL_MECH_EXTERNAL) && !sctx->conn->passwd[0]) {
+    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);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+#ifdef USE_KERBEROS5
+static bool sasl_choose_krb5(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  if(sctx->user &&
+     (sctx->enabledmechs & SASL_MECH_GSSAPI) &&
+     Curl_auth_is_gssapi_supported() &&
+     Curl_auth_user_contains_domain(sctx->conn->user)) {
+    const char *service = data->set.str[STRING_SERVICE_NAME] ?
+      data->set.str[STRING_SERVICE_NAME] :
+      sctx->sasl->params->service;
+
+    sctx->sasl->mutual_auth = FALSE;
+    sctx->mech = SASL_MECH_STRING_GSSAPI;
+    sctx->state1 = SASL_GSSAPI;
+    sctx->state2 = SASL_GSSAPI_TOKEN;
+    sctx->sasl->authused = SASL_MECH_GSSAPI;
+
+    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,
+                                             service, sctx->conn->host.name,
+                                             sctx->sasl->mutual_auth, NULL,
+                                             krb5, &sctx->resp);
+    }
+    return TRUE;
+  }
+  return FALSE;
+}
+#endif /* USE_KERBEROS5 */
+
+#ifdef USE_GSASL
+static bool sasl_choose_gsasl(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  struct gsasldata *gsasl;
+  struct bufref nullmsg;
+
+  if(sctx->user &&
+     (sctx->enabledmechs & (SASL_MECH_SCRAM_SHA_256|SASL_MECH_SCRAM_SHA_1))) {
+    gsasl = Curl_auth_gsasl_get(sctx->conn);
+    if(!gsasl) {
+      sctx->result = CURLE_OUT_OF_MEMORY;
+      return TRUE; /* attempted, but failed */
+    }
+
+    if((sctx->enabledmechs & SASL_MECH_SCRAM_SHA_256) &&
+      Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256,
+                                   gsasl)) {
+      sctx->mech = SASL_MECH_STRING_SCRAM_SHA_256;
+      sctx->sasl->authused = SASL_MECH_SCRAM_SHA_256;
+    }
+    else if((sctx->enabledmechs & SASL_MECH_SCRAM_SHA_1) &&
+      Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1,
+                                   gsasl)) {
+      sctx->mech = SASL_MECH_STRING_SCRAM_SHA_1;
+      sctx->sasl->authused = SASL_MECH_SCRAM_SHA_1;
+    }
+    else
+      return FALSE;
+
+    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);
+    if(!sctx->result && (sctx->sasl->force_ir || data->set.sasl_ir))
+      sctx->result = Curl_auth_gsasl_token(data, &nullmsg, gsasl, &sctx->resp);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+#endif /* USE_GSASL */
+
+#ifndef CURL_DISABLE_DIGEST_AUTH
+static bool sasl_choose_digest(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  (void)data;
+  if(!sctx->user)
+    return FALSE;
+  else if((sctx->enabledmechs & SASL_MECH_DIGEST_MD5) &&
+     Curl_auth_is_digest_supported()) {
+    sctx->mech = SASL_MECH_STRING_DIGEST_MD5;
+    sctx->state1 = SASL_DIGESTMD5;
+    sctx->sasl->authused = SASL_MECH_DIGEST_MD5;
+    return TRUE;
+  }
+  else if(sctx->enabledmechs & SASL_MECH_CRAM_MD5) {
+    sctx->mech = SASL_MECH_STRING_CRAM_MD5;
+    sctx->state1 = SASL_CRAMMD5;
+    sctx->sasl->authused = SASL_MECH_CRAM_MD5;
+    return TRUE;
+  }
+  return FALSE;
+}
+#endif /* !CURL_DISABLE_DIGEST_AUTH */
+
+#ifdef USE_NTLM
+static bool sasl_choose_ntlm(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  if(!sctx->user)
+    return FALSE;
+  else if((sctx->enabledmechs & SASL_MECH_NTLM) &&
+          Curl_auth_is_ntlm_supported()) {
+    const char *service = data->set.str[STRING_SERVICE_NAME] ?
+      data->set.str[STRING_SERVICE_NAME] :
+      sctx->sasl->params->service;
+    const char *hostname, *disp_hostname;
+    int port;
+
+    Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
+
+    sctx->mech = SASL_MECH_STRING_NTLM;
+    sctx->state1 = SASL_NTLM;
+    sctx->state2 = SASL_NTLM_TYPE2MSG;
+    sctx->sasl->authused = SASL_MECH_NTLM;
+
+    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,
+                                            service, hostname,
+                                            ntlm, &sctx->resp);
+    }
+    return TRUE;
+  }
+  return FALSE;
+}
+#endif /* USE_NTLM */
+
+static bool sasl_choose_oauth(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  const char *oauth_bearer = data->set.str[STRING_BEARER];
+
+  if(sctx->user && oauth_bearer &&
+     (sctx->enabledmechs & SASL_MECH_OAUTHBEARER)) {
+    const char *hostname, *disp_hostname;
+    int port;
+    Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
+
+    sctx->mech = SASL_MECH_STRING_OAUTHBEARER;
+    sctx->state1 = SASL_OAUTH2;
+    sctx->state2 = SASL_OAUTH2_RESP;
+    sctx->sasl->authused = SASL_MECH_OAUTHBEARER;
+
+    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);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static bool sasl_choose_oauth2(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  const char *oauth_bearer = data->set.str[STRING_BEARER];
+
+  if(sctx->user && oauth_bearer &&
+     (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);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static bool sasl_choose_plain(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  if(sctx->user && (sctx->enabledmechs & SASL_MECH_PLAIN)) {
+    sctx->mech = SASL_MECH_STRING_PLAIN;
+    sctx->state1 = SASL_PLAIN;
+    sctx->sasl->authused = SASL_MECH_PLAIN;
+
+    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);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static bool sasl_choose_login(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  if(sctx->user && (sctx->enabledmechs & SASL_MECH_LOGIN)) {
+    sctx->mech = SASL_MECH_STRING_LOGIN;
+    sctx->state1 = SASL_LOGIN;
+    sctx->state2 = SASL_LOGIN_PASSWD;
+    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);
+    return TRUE;
+  }
+  return FALSE;
+}
+
 /*
  * Curl_sasl_start()
  *
@@ -342,185 +539,66 @@ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
 CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
                          bool force_ir, saslprogress *progress)
 {
-  CURLcode result = CURLE_OK;
-  struct connectdata *conn = data->conn;
-  unsigned short enabledmechs;
-  const char *mech = NULL;
-  struct bufref resp;
-  saslstate state1 = SASL_STOP;
-  saslstate state2 = SASL_FINAL;
-  const char *hostname, *disp_hostname;
-  int port;
-#if defined(USE_KERBEROS5) || defined(USE_NTLM)
-  const char *service = data->set.str[STRING_SERVICE_NAME] ?
-    data->set.str[STRING_SERVICE_NAME] :
-    sasl->params->service;
-#endif
-  const char *oauth_bearer = data->set.str[STRING_BEARER];
-  struct bufref nullmsg;
+  struct sasl_ctx sctx;
 
-  Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
-  Curl_bufref_init(&nullmsg);
-  Curl_bufref_init(&resp);
   sasl->force_ir = force_ir;    /* Latch for future use */
   sasl->authused = 0;           /* No mechanism used yet */
-  enabledmechs = sasl->authmechs & sasl->prefmech;
   *progress = SASL_IDLE;
 
+  memset(&sctx, 0, sizeof(sctx));
+  sctx.sasl = sasl;
+  sctx.conn = data->conn;
+  sctx.user = data->state.aptr.user;
+  Curl_bufref_init(&sctx.resp);
+  sctx.enabledmechs = sasl->authmechs & sasl->prefmech;
+  sctx.state1 = SASL_STOP;
+  sctx.state2 = SASL_FINAL;
+
   /* Calculate the supported authentication mechanism, by decreasing order of
      security, as well as the initial response where appropriate */
-  if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) {
-    mech = SASL_MECH_STRING_EXTERNAL;
-    state1 = SASL_EXTERNAL;
-    sasl->authused = SASL_MECH_EXTERNAL;
-
-    if(force_ir || data->set.sasl_ir)
-      Curl_auth_create_external_message(conn->user, &resp);
-  }
-  else if(data->state.aptr.user) {
+  if(sasl_choose_external(data, &sctx) ||
 #if defined(USE_KERBEROS5)
-    if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() &&
-       Curl_auth_user_contains_domain(conn->user)) {
-      sasl->mutual_auth = FALSE;
-      mech = SASL_MECH_STRING_GSSAPI;
-      state1 = SASL_GSSAPI;
-      state2 = SASL_GSSAPI_TOKEN;
-      sasl->authused = SASL_MECH_GSSAPI;
-
-      if(force_ir || data->set.sasl_ir)
-        result = Curl_auth_create_gssapi_user_message(data, conn->user,
-                                                      conn->passwd,
-                                                      service,
-                                                      conn->host.name,
-                                                      sasl->mutual_auth,
-                                                      NULL, &conn->krb5,
-                                                      &resp);
-    }
-    else
+     sasl_choose_krb5(data, &sctx) ||
 #endif
 #ifdef USE_GSASL
-    if((enabledmechs & SASL_MECH_SCRAM_SHA_256) &&
-       Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256,
-                                    &conn->gsasl)) {
-      mech = SASL_MECH_STRING_SCRAM_SHA_256;
-      sasl->authused = SASL_MECH_SCRAM_SHA_256;
-      state1 = SASL_GSASL;
-      state2 = SASL_GSASL;
-
-      result = Curl_auth_gsasl_start(data, conn->user,
-                                     conn->passwd, &conn->gsasl);
-      if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
-        result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
-    }
-    else if((enabledmechs & SASL_MECH_SCRAM_SHA_1) &&
-            Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1,
-                                         &conn->gsasl)) {
-      mech = SASL_MECH_STRING_SCRAM_SHA_1;
-      sasl->authused = SASL_MECH_SCRAM_SHA_1;
-      state1 = SASL_GSASL;
-      state2 = SASL_GSASL;
-
-      result = Curl_auth_gsasl_start(data, conn->user,
-                                     conn->passwd, &conn->gsasl);
-      if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
-        result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
-    }
-    else
+     sasl_choose_gsasl(data, &sctx) ||
 #endif
 #ifndef CURL_DISABLE_DIGEST_AUTH
-    if((enabledmechs & SASL_MECH_DIGEST_MD5) &&
-       Curl_auth_is_digest_supported()) {
-      mech = SASL_MECH_STRING_DIGEST_MD5;
-      state1 = SASL_DIGESTMD5;
-      sasl->authused = SASL_MECH_DIGEST_MD5;
-    }
-    else if(enabledmechs & SASL_MECH_CRAM_MD5) {
-      mech = SASL_MECH_STRING_CRAM_MD5;
-      state1 = SASL_CRAMMD5;
-      sasl->authused = SASL_MECH_CRAM_MD5;
-    }
-    else
+     sasl_choose_digest(data, &sctx) ||
 #endif
 #ifdef USE_NTLM
-    if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) {
-      mech = SASL_MECH_STRING_NTLM;
-      state1 = SASL_NTLM;
-      state2 = SASL_NTLM_TYPE2MSG;
-      sasl->authused = SASL_MECH_NTLM;
-
-      if(force_ir || data->set.sasl_ir)
-        result = Curl_auth_create_ntlm_type1_message(data,
-                                                     conn->user, conn->passwd,
-                                                     service,
-                                                     hostname,
-                                                     &conn->ntlm, &resp);
-      }
-    else
+     sasl_choose_ntlm(data, &sctx) ||
 #endif
-    if((enabledmechs & SASL_MECH_OAUTHBEARER) && oauth_bearer) {
-      mech = SASL_MECH_STRING_OAUTHBEARER;
-      state1 = SASL_OAUTH2;
-      state2 = SASL_OAUTH2_RESP;
-      sasl->authused = SASL_MECH_OAUTHBEARER;
-
-      if(force_ir || data->set.sasl_ir)
-        result = Curl_auth_create_oauth_bearer_message(conn->user,
-                                                       hostname,
-                                                       port,
-                                                       oauth_bearer,
-                                                       &resp);
-    }
-    else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) {
-      mech = SASL_MECH_STRING_XOAUTH2;
-      state1 = SASL_OAUTH2;
-      sasl->authused = SASL_MECH_XOAUTH2;
-
-      if(force_ir || data->set.sasl_ir)
-        result = Curl_auth_create_xoauth_bearer_message(conn->user,
-                                                        oauth_bearer,
-                                                        &resp);
-    }
-    else if(enabledmechs & SASL_MECH_PLAIN) {
-      mech = SASL_MECH_STRING_PLAIN;
-      state1 = SASL_PLAIN;
-      sasl->authused = SASL_MECH_PLAIN;
-
-      if(force_ir || data->set.sasl_ir)
-        result = Curl_auth_create_plain_message(conn->sasl_authzid,
-                                                conn->user, conn->passwd,
-                                                &resp);
-    }
-    else if(enabledmechs & SASL_MECH_LOGIN) {
-      mech = SASL_MECH_STRING_LOGIN;
-      state1 = SASL_LOGIN;
-      state2 = SASL_LOGIN_PASSWD;
-      sasl->authused = SASL_MECH_LOGIN;
-
-      if(force_ir || data->set.sasl_ir)
-        Curl_auth_create_login_message(conn->user, &resp);
-    }
+     sasl_choose_oauth(data, &sctx) ||
+     sasl_choose_oauth2(data, &sctx) ||
+     sasl_choose_plain(data, &sctx) ||
+     sasl_choose_login(data, &sctx)) {
+    /* selected, either we have a mechanism or a failure */
+    DEBUGASSERT(sctx.mech || sctx.result);
   }
 
-  if(!result && mech) {
-    sasl->curmech = mech;
-    if(Curl_bufref_ptr(&resp))
-      result = build_message(sasl, &resp);
+  if(!sctx.result && sctx.mech) {
+    sasl->curmech = sctx.mech;
+    if(Curl_bufref_ptr(&sctx.resp))
+      sctx.result = build_message(sasl, &sctx.resp);
 
     if(sasl->params->maxirlen &&
-       strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen)
-      Curl_bufref_free(&resp);
+       strlen(sctx.mech) + Curl_bufref_len(&sctx.resp) >
+         sasl->params->maxirlen)
+      Curl_bufref_free(&sctx.resp);
 
-    if(!result)
-      result = sasl->params->sendauth(data, mech, &resp);
+    if(!sctx.result)
+      sctx.result = sasl->params->sendauth(data, sctx.mech, &sctx.resp);
 
-    if(!result) {
+    if(!sctx.result) {
       *progress = SASL_INPROGRESS;
-      sasl_state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1);
+      sasl_state(sasl, data, Curl_bufref_ptr(&sctx.resp) ?
+                 sctx.state2 : sctx.state1);
     }
   }
 
-  Curl_bufref_free(&resp);
-  return result;
+  Curl_bufref_free(&sctx.resp);
+  return sctx.result;
 }
 
 /*
@@ -587,8 +665,11 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
 #ifdef USE_GSASL
   case SASL_GSASL:
     result = get_server_message(sasl, data, &serverdata);
-    if(!result)
-      result = Curl_auth_gsasl_token(data, &serverdata, &conn->gsasl, &resp);
+    if(!result) {
+      struct gsasldata *gsasl = Curl_auth_gsasl_get(conn);
+      result = !gsasl ? CURLE_OUT_OF_MEMORY :
+        Curl_auth_gsasl_token(data, &serverdata, gsasl, &resp);
+    }
     if(!result && Curl_bufref_len(&resp) > 0)
       newstate = SASL_GSASL;
     break;
@@ -615,50 +696,57 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
 #endif
 
 #ifdef USE_NTLM
-  case SASL_NTLM:
+  case SASL_NTLM: {
     /* Create the type-1 message */
-    result = Curl_auth_create_ntlm_type1_message(data,
-                                                 conn->user, conn->passwd,
-                                                 service, hostname,
-                                                 &conn->ntlm, &resp);
+    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,
+                                          service, hostname,
+                                          ntlm, &resp);
     newstate = SASL_NTLM_TYPE2MSG;
     break;
-  case SASL_NTLM_TYPE2MSG:
+  }
+  case SASL_NTLM_TYPE2MSG: {
     /* Decode the type-2 message */
-    result = get_server_message(sasl, data, &serverdata);
+    struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, FALSE);
+    result = !ntlm ? CURLE_FAILED_INIT :
+      get_server_message(sasl, data, &serverdata);
     if(!result)
-      result = Curl_auth_decode_ntlm_type2_message(data, &serverdata,
-                                                   &conn->ntlm);
+      result = Curl_auth_decode_ntlm_type2_message(data, &serverdata, ntlm);
     if(!result)
       result = Curl_auth_create_ntlm_type3_message(data, conn->user,
-                                                   conn->passwd, &conn->ntlm,
+                                                   conn->passwd, ntlm,
                                                    &resp);
     break;
+  }
 #endif
 
 #if defined(USE_KERBEROS5)
-  case SASL_GSSAPI:
-    result = Curl_auth_create_gssapi_user_message(data, conn->user,
-                                                  conn->passwd,
-                                                  service,
-                                                  conn->host.name,
+  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,
+                                                  service, conn->host.name,
                                                   sasl->mutual_auth, NULL,
-                                                  &conn->krb5,
-                                                  &resp);
+                                                  krb5, &resp);
     newstate = SASL_GSSAPI_TOKEN;
     break;
+  }
   case SASL_GSSAPI_TOKEN:
     result = get_server_message(sasl, data, &serverdata);
     if(!result) {
-      if(sasl->mutual_auth) {
+      struct kerberos5data *krb5 = Curl_auth_krb5_get(conn);
+      if(!krb5)
+        result = CURLE_OUT_OF_MEMORY;
+      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,
                                                       NULL, NULL,
                                                       sasl->mutual_auth,
                                                       &serverdata,
-                                                      &conn->krb5,
-                                                      &resp);
+                                                      krb5, &resp);
         newstate = SASL_GSSAPI_NO_DATA;
       }
       else
@@ -666,19 +754,22 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
         result = Curl_auth_create_gssapi_security_message(data,
                                                           conn->sasl_authzid,
                                                           &serverdata,
-                                                          &conn->krb5,
-                                                          &resp);
+                                                          krb5, &resp);
     }
     break;
   case SASL_GSSAPI_NO_DATA:
     /* Decode the security challenge and create the response message */
     result = get_server_message(sasl, data, &serverdata);
-    if(!result)
-      result = Curl_auth_create_gssapi_security_message(data,
-                                                        conn->sasl_authzid,
-                                                        &serverdata,
-                                                        &conn->krb5,
-                                                        &resp);
+    if(!result) {
+      struct kerberos5data *krb5 = Curl_auth_krb5_get(conn);
+      if(!krb5)
+        result = CURLE_OUT_OF_MEMORY;
+      else
+        result = Curl_auth_create_gssapi_security_message(data,
+                                                          conn->sasl_authzid,
+                                                          &serverdata,
+                                                          krb5, &resp);
+    }
     break;
 #endif
 
index 59983f7c669dad2d557a3b5314fcf8cdfebe2720..0674d56f86500310567f2463278bbe81d119cc61 100644 (file)
@@ -135,10 +135,6 @@ struct SASL {
   (wordlen == (sizeof(mech) - 1) / sizeof(char) && \
    !memcmp(line, mech, wordlen))
 
-/* This is used to cleanup any libraries or curl modules used by the sasl
-   functions */
-void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused);
-
 /* Convert a mechanism name to a token */
 unsigned short Curl_sasl_decode_mech(const char *ptr,
                                      size_t maxlen, size_t *len);
index 5942d313b87a2fe624d1fc45d80620630c070f13..45fbc250eade0064d783b9511424a9c81f050e7c 100644 (file)
@@ -3221,8 +3221,10 @@ static CURLcode http_header(struct Curl_easy *data,
     }
 #ifdef USE_SPNEGO
     if(HD_IS(hd, hdlen, "Persistent-Auth:")) {
-      struct negotiatedata *negdata = &conn->negotiate;
+      struct negotiatedata *negdata = Curl_auth_nego_get(conn, FALSE);
       struct auth *authp = &data->state.authhost;
+      if(!negdata)
+        return CURLE_OUT_OF_MEMORY;
       if(authp->picked == CURLAUTH_NEGOTIATE) {
         char *persistentauth = Curl_copy_header_value(hd);
         if(!persistentauth)
index 5bec3b39ff5bd9fe5e8b87cd493d0414d3b68ad0..2c0b7e16d76ac23668b7a6b4c1abaa63ae760010 100644 (file)
 #include "curl_memory.h"
 #include "memdebug.h"
 
+
+static void http_auth_nego_reset(struct connectdata *conn,
+                                 struct negotiatedata *neg_ctx,
+                                 bool proxy)
+{
+  if(proxy)
+    conn->proxy_negotiate_state = GSS_AUTHNONE;
+  else
+    conn->http_negotiate_state = GSS_AUTHNONE;
+  if(neg_ctx)
+    Curl_auth_cleanup_spnego(neg_ctx);
+}
+
+
 CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
                               bool proxy, const char *header)
 {
@@ -62,7 +76,6 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
     service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
               data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
     host = conn->http_proxy.host.name;
-    neg_ctx = &conn->proxyneg;
     state = conn->proxy_negotiate_state;
 #else
     return CURLE_NOT_BUILT_IN;
@@ -74,10 +87,13 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
     service = data->set.str[STRING_SERVICE_NAME] ?
               data->set.str[STRING_SERVICE_NAME] : "HTTP";
     host = conn->host.name;
-    neg_ctx = &conn->negotiate;
     state = conn->http_negotiate_state;
   }
 
+  neg_ctx = Curl_auth_nego_get(conn, proxy);
+  if(!neg_ctx)
+    return CURLE_OUT_OF_MEMORY;
+
   /* Not set means empty */
   if(!userp)
     userp = "";
@@ -94,12 +110,12 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
   if(!len) {
     if(state == GSS_AUTHSUCC) {
       infof(data, "Negotiate auth restarted");
-      Curl_http_auth_cleanup_negotiate(conn);
+      http_auth_nego_reset(conn, neg_ctx, proxy);
     }
     else if(state != GSS_AUTHNONE) {
       /* The server rejected our authentication and has not supplied any more
       negotiation mechanisms */
-      Curl_http_auth_cleanup_negotiate(conn);
+      http_auth_nego_reset(conn, neg_ctx, proxy);
       return CURLE_LOGIN_DENIED;
     }
   }
@@ -116,7 +132,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
     result = Curl_ssl_get_channel_binding(
       data, FIRSTSOCKET, &neg_ctx->channel_binding_data);
     if(result) {
-      Curl_http_auth_cleanup_negotiate(conn);
+      http_auth_nego_reset(conn, neg_ctx, proxy);
       return result;
     }
   }
@@ -134,7 +150,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
 #endif
 
   if(result)
-    Curl_http_auth_cleanup_negotiate(conn);
+    http_auth_nego_reset(conn, neg_ctx, proxy);
 
   return result;
 }
@@ -152,7 +168,6 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
 
   if(proxy) {
 #ifndef CURL_DISABLE_PROXY
-    neg_ctx = &conn->proxyneg;
     authp = &data->state.authproxy;
     state = &conn->proxy_negotiate_state;
 #else
@@ -160,10 +175,12 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
 #endif
   }
   else {
-    neg_ctx = &conn->negotiate;
     authp = &data->state.authhost;
     state = &conn->http_negotiate_state;
   }
+  neg_ctx = Curl_auth_nego_get(conn, proxy);
+  if(!neg_ctx)
+    return CURLE_OUT_OF_MEMORY;
 
   authp->done = FALSE;
 
@@ -184,7 +201,7 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
     if(neg_ctx->noauthpersist && *state == GSS_AUTHSUCC) {
       infof(data, "Curl_output_negotiate, "
             "no persistent authentication: cleanup existing context");
-      Curl_http_auth_cleanup_negotiate(conn);
+      http_auth_nego_reset(conn, neg_ctx, proxy);
     }
     if(!neg_ctx->context) {
       result = Curl_input_negotiate(data, conn, proxy, "Negotiate");
@@ -249,13 +266,4 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
   return CURLE_OK;
 }
 
-void Curl_http_auth_cleanup_negotiate(struct connectdata *conn)
-{
-  conn->http_negotiate_state = GSS_AUTHNONE;
-  conn->proxy_negotiate_state = GSS_AUTHNONE;
-
-  Curl_auth_cleanup_spnego(&conn->negotiate);
-  Curl_auth_cleanup_spnego(&conn->proxyneg);
-}
-
 #endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */
index 76d8356132d8b7c1364bb2c6b3e4c343bfaf076c..ad7c43d833ea5df4f23a0d6620767f387006992d 100644 (file)
@@ -34,10 +34,6 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
 CURLcode Curl_output_negotiate(struct Curl_easy *data,
                                struct connectdata *conn, bool proxy);
 
-void Curl_http_auth_cleanup_negotiate(struct connectdata *conn);
-
-#else /* !CURL_DISABLE_HTTP && USE_SPNEGO */
-#define Curl_http_auth_cleanup_negotiate(x)
 #endif
 
 #endif /* HEADER_CURL_HTTP_NEGOTIATE_H */
index e6a3b175a776a4447fc959b687d3dcaca0401093..cd8e321e7eb0c1a8d6f904a09345958f83761aee 100644 (file)
@@ -60,17 +60,18 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data,
                                                 header */
 {
   /* point to the correct struct with this */
-  struct ntlmdata *ntlm;
   curlntlm *state;
   CURLcode result = CURLE_OK;
   struct connectdata *conn = data->conn;
 
-  ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
   state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
 
   if(checkprefix("NTLM", header)) {
-    header += strlen("NTLM");
+    struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, proxy);
+    if(!ntlm)
+      return CURLE_FAILED_INIT;
 
+    header += strlen("NTLM");
     curlx_str_passblanks(&header);
     if(*header) {
       unsigned char *hdr;
@@ -93,11 +94,11 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data,
     else {
       if(*state == NTLMSTATE_LAST) {
         infof(data, "NTLM auth restarted");
-        Curl_http_auth_cleanup_ntlm(conn);
+        Curl_auth_ntlm_remove(conn, proxy);
       }
       else if(*state == NTLMSTATE_TYPE3) {
         infof(data, "NTLM handshake rejected");
-        Curl_http_auth_cleanup_ntlm(conn);
+        Curl_auth_ntlm_remove(conn, proxy);
         *state = NTLMSTATE_NONE;
         return CURLE_REMOTE_ACCESS_DENIED;
       }
@@ -150,7 +151,6 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
     service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
       data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
     hostname = conn->http_proxy.host.name;
-    ntlm = &conn->proxyntlm;
     state = &conn->proxy_ntlm_state;
     authp = &data->state.authproxy;
 #else
@@ -164,10 +164,10 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
     service = data->set.str[STRING_SERVICE_NAME] ?
       data->set.str[STRING_SERVICE_NAME] : "HTTP";
     hostname = conn->host.name;
-    ntlm = &conn->ntlm;
     state = &conn->http_ntlm_state;
     authp = &data->state.authhost;
   }
+  ntlm = Curl_auth_ntlm_get(conn, proxy);
   authp->done = FALSE;
 
   /* not set means empty */
@@ -200,9 +200,9 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
   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, hostname,
-                                                 ntlm, &ntlmmsg);
+    result = !ntlm ? CURLE_OUT_OF_MEMORY :
+      Curl_auth_create_ntlm_type1_message(data, userp, passwdp, service,
+                                          hostname, ntlm, &ntlmmsg);
     if(!result) {
       DEBUGASSERT(Curl_bufref_len(&ntlmmsg) != 0);
       result = curlx_base64_encode((const char *) Curl_bufref_ptr(&ntlmmsg),
@@ -258,10 +258,4 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
   return result;
 }
 
-void Curl_http_auth_cleanup_ntlm(struct connectdata *conn)
-{
-  Curl_auth_cleanup_ntlm(&conn->ntlm);
-  Curl_auth_cleanup_ntlm(&conn->proxyntlm);
-}
-
 #endif /* !CURL_DISABLE_HTTP && USE_NTLM */
index c1cf05701f4812e0447d1d3512ebd116ed727e39..b38ff82dba3cc61fb74488f97a5e4a8536691c9c 100644 (file)
@@ -35,10 +35,6 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data, bool proxy,
 /* this is for creating NTLM header output */
 CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy);
 
-void Curl_http_auth_cleanup_ntlm(struct connectdata *conn);
-
-#else /* !CURL_DISABLE_HTTP && USE_NTLM */
-#define Curl_http_auth_cleanup_ntlm(x)
 #endif
 
 #endif /* HEADER_CURL_HTTP_NTLM_H */
index fa17b77151b5c7d114420c6ef04a73cbd21bde6d..4e6c01475c3ddb04b160bcca09f39188dd526af5 100644 (file)
@@ -1788,9 +1788,6 @@ static CURLcode imap_disconnect(struct Curl_easy *data,
       if(!imap_perform_logout(data, imapc))
         (void)imap_block_statemach(data, imapc, TRUE); /* ignore errors */
     }
-
-    /* Cleanup the SASL module */
-    Curl_sasl_cleanup(conn, imapc->sasl.authused);
   }
   return CURLE_OK;
 }
index 6343c40c094af6e1c40e79575c4793a391ac38ad..6cde41120f2568187d563a93c278ad88b2447dcf 100644 (file)
@@ -941,7 +941,6 @@ static CURLcode oldap_disconnect(struct Curl_easy *data,
       ldap_unbind_ext(li->ld, NULL, NULL);
       li->ld = NULL;
     }
-    Curl_sasl_cleanup(conn, li->sasl.authused);
   }
   return CURLE_OK;
 }
index 3e3070e333a8eed2c64a317308e8d19590e06e7b..db3f1fb5ac04771118f7515eb68e92401e91c127 100644 (file)
@@ -1459,9 +1459,6 @@ static CURLcode pop3_disconnect(struct Curl_easy *data,
   /* Disconnect from the server */
   Curl_pp_disconnect(&pop3c->pp);
 
-  /* Cleanup the SASL module */
-  Curl_sasl_cleanup(conn, pop3c->sasl.authused);
-
   /* Cleanup our connection based variables */
   Curl_safefree(pop3c->apoptimestamp);
 
index 99a348e2346dc41fdad38ef124641189876e01fe..d313f088fb84a47283c1ab2aa3180fa481038244 100644 (file)
@@ -1631,8 +1631,6 @@ static CURLcode smtp_disconnect(struct Curl_easy *data,
       (void)smtp_block_statemach(data, smtpc, TRUE); /* ignore on QUIT */
   }
 
-  /* Cleanup the SASL module */
-  Curl_sasl_cleanup(conn, smtpc->sasl.authused);
   CURL_TRC_SMTP(data, "smtp_disconnect(), finished");
   return CURLE_OK;
 }
index 45052e84b18bf8436f266d60076ec5824d186032..d7fff0b2fa98655a6bc818738cbaa71960a9ddcd 100644 (file)
@@ -357,93 +357,6 @@ typedef enum {
   GSS_AUTHSUCC
 } curlnegotiate;
 
-/* Struct used for GSSAPI (Kerberos V5) authentication */
-#if defined(USE_KERBEROS5)
-struct kerberos5data {
-#if defined(USE_WINDOWS_SSPI)
-  CredHandle *credentials;
-  CtxtHandle *context;
-  TCHAR *spn;
-  SEC_WINNT_AUTH_IDENTITY identity;
-  SEC_WINNT_AUTH_IDENTITY *p_identity;
-  size_t token_max;
-  BYTE *output_token;
-#else
-  gss_ctx_id_t context;
-  gss_name_t spn;
-#endif
-};
-#endif
-
-/* Struct used for SCRAM-SHA-1 authentication */
-#ifdef USE_GSASL
-#include <gsasl.h>
-struct gsasldata {
-  Gsasl *ctx;
-  Gsasl_session *client;
-};
-#endif
-
-/* Struct used for NTLM challenge-response authentication */
-#if defined(USE_NTLM)
-struct ntlmdata {
-#ifdef USE_WINDOWS_SSPI
-/* The sslContext is used for the Schannel bindings. The
- * api is available on the Windows 7 SDK and later.
- */
-#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
-  CtxtHandle *sslContext;
-#endif
-  CredHandle *credentials;
-  CtxtHandle *context;
-  SEC_WINNT_AUTH_IDENTITY identity;
-  SEC_WINNT_AUTH_IDENTITY *p_identity;
-  size_t token_max;
-  BYTE *output_token;
-  BYTE *input_token;
-  size_t input_token_len;
-  TCHAR *spn;
-#else
-  unsigned int flags;
-  unsigned char nonce[8];
-  unsigned int target_info_len;
-  void *target_info; /* TargetInfo received in the NTLM type-2 message */
-#endif
-};
-#endif
-
-/* Struct used for Negotiate (SPNEGO) authentication */
-#ifdef USE_SPNEGO
-struct negotiatedata {
-#ifdef HAVE_GSSAPI
-  OM_uint32 status;
-  gss_ctx_id_t context;
-  gss_name_t spn;
-  gss_buffer_desc output_token;
-  struct dynbuf channel_binding_data;
-#else
-#ifdef USE_WINDOWS_SSPI
-#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
-  CtxtHandle *sslContext;
-#endif
-  DWORD status;
-  CredHandle *credentials;
-  CtxtHandle *context;
-  SEC_WINNT_AUTH_IDENTITY identity;
-  SEC_WINNT_AUTH_IDENTITY *p_identity;
-  TCHAR *spn;
-  size_t token_max;
-  BYTE *output_token;
-  size_t output_token_length;
-#endif
-#endif
-  BIT(noauthpersist);
-  BIT(havenoauthpersist);
-  BIT(havenegdata);
-  BIT(havemultiplerequests);
-};
-#endif
-
 #ifdef CURL_DISABLE_PROXY
 #define CONN_IS_PROXIED(x) 0
 #else
@@ -823,10 +736,6 @@ struct connectdata {
   struct sockaddr_in local_addr;
 #endif
 
-#if defined(USE_KERBEROS5)    /* Consider moving some of the above GSS-API */
-  struct kerberos5data krb5;  /* variables into the structure definition, */
-#endif                        /* however, some of them are ftp specific. */
-
   struct uint_spbset xfers_attached; /* mids of attached transfers */
   /* A connection cache from a SHARE might be used in several multi handles.
    * We MUST not reuse connections that are running in another multi,
@@ -841,26 +750,14 @@ struct connectdata {
   CtxtHandle *sslContext;
 #endif
 
-#ifdef USE_GSASL
-  struct gsasldata gsasl;
-#endif
-
 #if defined(USE_NTLM)
   curlntlm http_ntlm_state;
   curlntlm proxy_ntlm_state;
-
-  struct ntlmdata ntlm;     /* NTLM differs from other authentication schemes
-                               because it authenticates connections, not
-                               single requests! */
-  struct ntlmdata proxyntlm; /* NTLM data for proxy */
 #endif
 
 #ifdef USE_SPNEGO
   curlnegotiate http_negotiate_state;
   curlnegotiate proxy_negotiate_state;
-
-  struct negotiatedata negotiate; /* state data for host Negotiate auth */
-  struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */
 #endif
 
 #ifdef USE_UNIX_SOCKETS
index e2872b2522a5cd95fa48be531027d334af8dc045..c907ddcfaa503505f2f7c3a54cbd21af60c35cf0 100644 (file)
@@ -31,6 +31,7 @@
 #include "../strcase.h"
 #include "../curlx/multibyte.h"
 #include "../curl_printf.h"
+#include "../url.h"
 
 /* The last #include files should be: */
 #include "../curl_memory.h"
@@ -160,3 +161,117 @@ bool Curl_auth_allowed_to_host(struct Curl_easy *data)
           (data->state.first_remote_port == conn->remote_port) &&
           (data->state.first_remote_protocol == conn->handler->protocol));
 }
+
+#ifdef USE_NTLM
+
+static void ntlm_conn_dtor(void *key, size_t klen, void *entry)
+{
+  struct ntlmdata *ntlm = entry;
+  (void)key;
+  (void)klen;
+  DEBUGASSERT(ntlm);
+  Curl_auth_cleanup_ntlm(ntlm);
+  free(ntlm);
+}
+
+struct ntlmdata *Curl_auth_ntlm_get(struct connectdata *conn, bool proxy)
+{
+  const char *key = proxy ? CURL_META_NTLM_PROXY_CONN :
+                    CURL_META_NTLM_CONN;
+  struct ntlmdata *ntlm = Curl_conn_meta_get(conn, key);
+  if(!ntlm) {
+    ntlm = calloc(1, sizeof(*ntlm));
+    if(!ntlm ||
+       Curl_conn_meta_set(conn, key, ntlm, ntlm_conn_dtor))
+      return NULL;
+  }
+  return ntlm;
+}
+
+void Curl_auth_ntlm_remove(struct connectdata *conn, bool proxy)
+{
+  Curl_conn_meta_remove(conn, proxy ?
+    CURL_META_NTLM_PROXY_CONN : CURL_META_NTLM_CONN);
+}
+
+#endif /* USE_NTLM */
+
+#ifdef USE_KERBEROS5
+
+static void krb5_conn_dtor(void *key, size_t klen, void *entry)
+{
+  struct kerberos5data *krb5 = entry;
+  (void)key;
+  (void)klen;
+  DEBUGASSERT(krb5);
+  Curl_auth_cleanup_gssapi(krb5);
+  free(krb5);
+}
+
+struct kerberos5data *Curl_auth_krb5_get(struct connectdata *conn)
+{
+  struct kerberos5data *krb5 = Curl_conn_meta_get(conn, CURL_META_KRB5_CONN);
+  if(!krb5) {
+    krb5 = calloc(1, sizeof(*krb5));
+    if(!krb5 ||
+       Curl_conn_meta_set(conn, CURL_META_KRB5_CONN, krb5, krb5_conn_dtor))
+      return NULL;
+  }
+  return krb5;
+}
+
+#endif /* USE_KERBEROS5 */
+
+#ifdef USE_GSASL
+
+static void gsasl_conn_dtor(void *key, size_t klen, void *entry)
+{
+  struct gsasldata *gsasl = entry;
+  (void)key;
+  (void)klen;
+  DEBUGASSERT(gsasl);
+  Curl_auth_gsasl_cleanup(gsasl);
+  free(gsasl);
+}
+
+struct gsasldata *Curl_auth_gsasl_get(struct connectdata *conn)
+{
+  struct gsasldata *gsasl = Curl_conn_meta_get(conn, CURL_META_GSASL_CONN);
+  if(!gsasl) {
+    gsasl = calloc(1, sizeof(*gsasl));
+    if(!gsasl ||
+       Curl_conn_meta_set(conn, CURL_META_GSASL_CONN, gsasl, gsasl_conn_dtor))
+      return NULL;
+  }
+  return gsasl;
+}
+
+#endif /* USE_GSASL */
+
+#ifdef USE_SPNEGO
+
+static void nego_conn_dtor(void *key, size_t klen, void *entry)
+{
+  struct negotiatedata *nego = entry;
+  (void)key;
+  (void)klen;
+  DEBUGASSERT(nego);
+  Curl_auth_cleanup_spnego(nego);
+  free(nego);
+}
+
+struct negotiatedata *Curl_auth_nego_get(struct connectdata *conn, bool proxy)
+{
+  const char *key = proxy ? CURL_META_NEGO_PROXY_CONN :
+                    CURL_META_NEGO_CONN;
+  struct negotiatedata *nego = Curl_conn_meta_get(conn, key);
+  if(!nego) {
+    nego = calloc(1, sizeof(*nego));
+    if(!nego ||
+       Curl_conn_meta_set(conn, key, nego, nego_conn_dtor))
+      return NULL;
+  }
+  return nego;
+}
+
+#endif /* USE_SPNEGO */
index 58b13f582c7b147ff4d4d9efd85e62cc60f928f7..ab54e35f347d921695e2b18189257c67793e0b7f 100644 (file)
 #include <curl/curl.h>
 
 #include "../bufref.h"
+#include "../curlx/dynbuf.h"
 
 struct Curl_easy;
+struct connectdata;
 
 #if !defined(CURL_DISABLE_DIGEST_AUTH)
 struct digestdata;
@@ -38,10 +40,6 @@ struct digestdata;
 struct ntlmdata;
 #endif
 
-#if defined(USE_KERBEROS5)
-struct kerberos5data;
-#endif
-
 #if (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) && defined(USE_SPNEGO)
 struct negotiatedata;
 #endif
@@ -50,7 +48,8 @@ struct negotiatedata;
 struct gsasldata;
 #endif
 
-#if defined(USE_WINDOWS_SSPI)
+#ifdef USE_WINDOWS_SSPI
+#include "../curl_sspi.h"
 #define GSS_ERROR(status) ((status) & 0x80000000)
 #endif
 
@@ -120,6 +119,18 @@ void Curl_auth_digest_cleanup(struct digestdata *digest);
 #endif /* !CURL_DISABLE_DIGEST_AUTH */
 
 #ifdef USE_GSASL
+
+/* meta key for storing GSASL meta at connection */
+#define CURL_META_GSASL_CONN   "meta:auth:gsasl:conn"
+
+#include <gsasl.h>
+struct gsasldata {
+  Gsasl *ctx;
+  Gsasl_session *client;
+};
+
+struct gsasldata *Curl_auth_gsasl_get(struct connectdata *conn);
+
 /* This is used to evaluate if MECH is supported by gsasl */
 bool Curl_auth_gsasl_is_supported(struct Curl_easy *data,
                                   const char *mech,
@@ -141,9 +152,46 @@ void Curl_auth_gsasl_cleanup(struct gsasldata *digest);
 #endif
 
 #if defined(USE_NTLM)
+
+/* meta key for storing NTML meta at connection */
+#define CURL_META_NTLM_CONN   "meta:auth:ntml:conn"
+/* meta key for storing NTML-PROXY meta at connection */
+#define CURL_META_NTLM_PROXY_CONN   "meta:auth:ntml-proxy:conn"
+
+struct ntlmdata {
+#ifdef USE_WINDOWS_SSPI
+/* The sslContext is used for the Schannel bindings. The
+ * api is available on the Windows 7 SDK and later.
+ */
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+  CtxtHandle *sslContext;
+#endif
+  CredHandle *credentials;
+  CtxtHandle *context;
+  SEC_WINNT_AUTH_IDENTITY identity;
+  SEC_WINNT_AUTH_IDENTITY *p_identity;
+  size_t token_max;
+  BYTE *output_token;
+  BYTE *input_token;
+  size_t input_token_len;
+  TCHAR *spn;
+#else
+  unsigned int flags;
+  unsigned char nonce[8];
+  unsigned int target_info_len;
+  void *target_info; /* TargetInfo received in the NTLM type-2 message */
+#endif
+};
+
 /* This is used to evaluate if NTLM is supported */
 bool Curl_auth_is_ntlm_supported(void);
 
+struct ntlmdata *Curl_auth_ntlm_get(struct connectdata *conn, bool proxy);
+void Curl_auth_ntlm_remove(struct connectdata *conn, bool proxy);
+
+/* This is used to clean up the NTLM specific data */
+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,
@@ -165,8 +213,6 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
                                              struct ntlmdata *ntlm,
                                              struct bufref *out);
 
-/* This is used to clean up the NTLM specific data */
-void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm);
 #else
 #define Curl_auth_is_ntlm_supported()     FALSE
 #endif /* USE_NTLM */
@@ -184,6 +230,40 @@ CURLcode Curl_auth_create_xoauth_bearer_message(const char *user,
                                                 struct bufref *out);
 
 #if defined(USE_KERBEROS5)
+
+#ifdef HAVE_GSSAPI
+# ifdef HAVE_GSSGNU
+#  include <gss.h>
+# elif defined HAVE_GSSAPI_GSSAPI_H
+#  include <gssapi/gssapi.h>
+# else
+#  include <gssapi.h>
+# endif
+# ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H
+#  include <gssapi/gssapi_generic.h>
+# endif
+#endif
+
+/* meta key for storing KRB5 meta at connection */
+#define CURL_META_KRB5_CONN   "meta:auth:krb5:conn"
+
+struct kerberos5data {
+#if defined(USE_WINDOWS_SSPI)
+  CredHandle *credentials;
+  CtxtHandle *context;
+  TCHAR *spn;
+  SEC_WINNT_AUTH_IDENTITY identity;
+  SEC_WINNT_AUTH_IDENTITY *p_identity;
+  size_t token_max;
+  BYTE *output_token;
+#else
+  gss_ctx_id_t context;
+  gss_name_t spn;
+#endif
+};
+
+struct kerberos5data *Curl_auth_krb5_get(struct connectdata *conn);
+
 /* This is used to evaluate if GSSAPI (Kerberos V5) is supported */
 bool Curl_auth_is_gssapi_supported(void);
 
@@ -213,10 +293,48 @@ void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5);
 #define Curl_auth_is_gssapi_supported()       FALSE
 #endif /* USE_KERBEROS5 */
 
-#if defined(USE_SPNEGO)
-/* This is used to evaluate if SPNEGO (Negotiate) is supported */
+#ifdef USE_SPNEGO
+
 bool Curl_auth_is_spnego_supported(void);
 
+/* meta key for storing NEGO meta at connection */
+#define CURL_META_NEGO_CONN         "meta:auth:nego:conn"
+/* meta key for storing NEGO PROXY meta at connection */
+#define CURL_META_NEGO_PROXY_CONN   "meta:auth:nego-proxy:conn"
+
+/* Struct used for Negotiate (SPNEGO) authentication */
+struct negotiatedata {
+#ifdef HAVE_GSSAPI
+  OM_uint32 status;
+  gss_ctx_id_t context;
+  gss_name_t spn;
+  gss_buffer_desc output_token;
+  struct dynbuf channel_binding_data;
+#else
+#ifdef USE_WINDOWS_SSPI
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+  CtxtHandle *sslContext;
+#endif
+  DWORD status;
+  CredHandle *credentials;
+  CtxtHandle *context;
+  SEC_WINNT_AUTH_IDENTITY identity;
+  SEC_WINNT_AUTH_IDENTITY *p_identity;
+  TCHAR *spn;
+  size_t token_max;
+  BYTE *output_token;
+  size_t output_token_length;
+#endif
+#endif
+  BIT(noauthpersist);
+  BIT(havenoauthpersist);
+  BIT(havenegdata);
+  BIT(havemultiplerequests);
+};
+
+struct negotiatedata *
+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,