From: Stefan Eissing Date: Mon, 9 Jun 2025 13:09:28 +0000 (+0200) Subject: vauth: move auth structs to conn meta data X-Git-Tag: curl-8_15_0~307 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ab650379a8c25ca952f651476d25b4cdd77bb3fc;p=thirdparty%2Fcurl.git vauth: move auth structs to conn meta data 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 --- diff --git a/lib/cshutdn.c b/lib/cshutdn.c index f05b87d277..be2561e719 100644 --- a/lib/cshutdn.c +++ b/lib/cshutdn.c @@ -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 diff --git a/lib/curl_ntlm_core.h b/lib/curl_ntlm_core.h index e2e4b1bd43..7571ad5432 100644 --- a/lib/curl_ntlm_core.h +++ b/lib/curl_ntlm_core.h @@ -28,6 +28,10 @@ #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)), \ diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c index 4fcbaac263..f711803904 100644 --- a/lib/curl_sasl.c +++ b/lib/curl_sasl.c @@ -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 diff --git a/lib/curl_sasl.h b/lib/curl_sasl.h index 59983f7c66..0674d56f86 100644 --- a/lib/curl_sasl.h +++ b/lib/curl_sasl.h @@ -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); diff --git a/lib/http.c b/lib/http.c index 5942d313b8..45fbc250ea 100644 --- a/lib/http.c +++ b/lib/http.c @@ -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) diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c index 5bec3b39ff..2c0b7e16d7 100644 --- a/lib/http_negotiate.c +++ b/lib/http_negotiate.c @@ -39,6 +39,20 @@ #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 */ diff --git a/lib/http_negotiate.h b/lib/http_negotiate.h index 76d8356132..ad7c43d833 100644 --- a/lib/http_negotiate.h +++ b/lib/http_negotiate.h @@ -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 */ diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c index e6a3b175a7..cd8e321e7e 100644 --- a/lib/http_ntlm.c +++ b/lib/http_ntlm.c @@ -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 */ diff --git a/lib/http_ntlm.h b/lib/http_ntlm.h index c1cf05701f..b38ff82dba 100644 --- a/lib/http_ntlm.h +++ b/lib/http_ntlm.h @@ -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 */ diff --git a/lib/imap.c b/lib/imap.c index fa17b77151..4e6c01475c 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -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; } diff --git a/lib/openldap.c b/lib/openldap.c index 6343c40c09..6cde41120f 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -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; } diff --git a/lib/pop3.c b/lib/pop3.c index 3e3070e333..db3f1fb5ac 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -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); diff --git a/lib/smtp.c b/lib/smtp.c index 99a348e234..d313f088fb 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -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; } diff --git a/lib/urldata.h b/lib/urldata.h index 45052e84b1..d7fff0b2fa 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -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 -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 diff --git a/lib/vauth/vauth.c b/lib/vauth/vauth.c index e2872b2522..c907ddcfaa 100644 --- a/lib/vauth/vauth.c +++ b/lib/vauth/vauth.c @@ -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 */ diff --git a/lib/vauth/vauth.h b/lib/vauth/vauth.h index 58b13f582c..ab54e35f34 100644 --- a/lib/vauth/vauth.h +++ b/lib/vauth/vauth.h @@ -27,8 +27,10 @@ #include #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 +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 +# elif defined HAVE_GSSAPI_GSSAPI_H +# include +# else +# include +# endif +# ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H +# include +# 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,