mirror of
https://github.com/curl/curl.git
synced 2026-04-11 12:01:42 +08:00
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:
parent
05ffeeda0c
commit
ab650379a8
@ -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
|
||||
|
||||
@ -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)), \
|
||||
|
||||
535
lib/curl_sasl.c
535
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
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
103
lib/urldata.h
103
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 <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
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user