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
This commit is contained in:
Stefan Eissing 2025-06-09 15:09:28 +02:00 committed by Daniel Stenberg
parent 05ffeeda0c
commit ab650379a8
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
16 changed files with 598 additions and 396 deletions

View 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

View File

@ -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)), \

View 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

View 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);

View 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)

View File

@ -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 */

View 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 */

View 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 */

View 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 */

View 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;
}

View 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;
}

View 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);

View 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;
}

View 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

View 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 */

View File

@ -27,8 +27,10 @@
#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,