mirror of
https://github.com/moparisthebest/curl
synced 2024-12-21 23:58:49 -05:00
sasl: implement EXTERNAL authentication mechanism.
Its use is only enabled by explicit requirement in URL (;AUTH=EXTERNAL) and by not setting the password.
This commit is contained in:
parent
e1bb13c09f
commit
0d24f64473
180
lib/curl_sasl.c
180
lib/curl_sasl.c
@ -368,6 +368,30 @@ static CURLcode sasl_create_login_message(struct SessionHandle *data,
|
|||||||
return Curl_base64_encode(data, valuep, vlen, outptr, outlen);
|
return Curl_base64_encode(data, valuep, vlen, outptr, outlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* sasl_create_external_message()
|
||||||
|
*
|
||||||
|
* This is used to generate an already encoded EXTERNAL message containing
|
||||||
|
* the user name ready for sending to the recipient.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
*
|
||||||
|
* data [in] - The session handle.
|
||||||
|
* user [in] - The user name.
|
||||||
|
* outptr [in/out] - The address where a pointer to newly allocated memory
|
||||||
|
* holding the result will be stored upon completion.
|
||||||
|
* outlen [out] - The length of the output message.
|
||||||
|
*
|
||||||
|
* Returns CURLE_OK on success.
|
||||||
|
*/
|
||||||
|
static CURLcode sasl_create_external_message(struct SessionHandle *data,
|
||||||
|
const char *user, char **outptr,
|
||||||
|
size_t *outlen)
|
||||||
|
{
|
||||||
|
/* This is the same formatting as the login message. */
|
||||||
|
return sasl_create_login_message(data, user, outptr, outlen);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef CURL_DISABLE_CRYPTO_AUTH
|
#ifndef CURL_DISABLE_CRYPTO_AUTH
|
||||||
/*
|
/*
|
||||||
* sasl_decode_cram_md5_message()
|
* sasl_decode_cram_md5_message()
|
||||||
@ -1257,7 +1281,7 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(strnequal(value, "*", len))
|
if(strnequal(value, "*", len))
|
||||||
sasl->prefmech = SASL_AUTH_ANY;
|
sasl->prefmech = SASL_AUTH_DEFAULT;
|
||||||
else if((mechbit = Curl_sasl_decode_mech(value, len, &mechlen)) &&
|
else if((mechbit = Curl_sasl_decode_mech(value, len, &mechlen)) &&
|
||||||
mechlen == len)
|
mechlen == len)
|
||||||
sasl->prefmech |= mechbit;
|
sasl->prefmech |= mechbit;
|
||||||
@ -1277,7 +1301,7 @@ void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params)
|
|||||||
sasl->params = params; /* Set protocol dependent parameters */
|
sasl->params = params; /* Set protocol dependent parameters */
|
||||||
sasl->state = SASL_STOP; /* Not yet running */
|
sasl->state = SASL_STOP; /* Not yet running */
|
||||||
sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */
|
sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */
|
||||||
sasl->prefmech = SASL_AUTH_ANY; /* Prefer all mechanisms */
|
sasl->prefmech = SASL_AUTH_DEFAULT; /* Prefer all mechanisms */
|
||||||
sasl->authused = SASL_AUTH_NONE; /* No the authentication mechanism used */
|
sasl->authused = SASL_AUTH_NONE; /* No the authentication mechanism used */
|
||||||
sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */
|
sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */
|
||||||
sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */
|
sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */
|
||||||
@ -1299,6 +1323,7 @@ static void state(struct SASL *sasl,
|
|||||||
"PLAIN",
|
"PLAIN",
|
||||||
"LOGIN",
|
"LOGIN",
|
||||||
"LOGIN_PASSWD",
|
"LOGIN_PASSWD",
|
||||||
|
"EXTERNAL",
|
||||||
"CRAMMD5",
|
"CRAMMD5",
|
||||||
"DIGESTMD5",
|
"DIGESTMD5",
|
||||||
"DIGESTMD5_RESP",
|
"DIGESTMD5_RESP",
|
||||||
@ -1321,6 +1346,23 @@ static void state(struct SASL *sasl,
|
|||||||
sasl->state = newstate;
|
sasl->state = newstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Curl_sasl_can_authenticate()
|
||||||
|
*
|
||||||
|
* Check if we have enough auth data and capabilities to authenticate.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn)
|
||||||
|
{
|
||||||
|
if(conn->bits.user_passwd)
|
||||||
|
return TRUE; /* Credentials provided */
|
||||||
|
|
||||||
|
if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL)
|
||||||
|
return TRUE; /* Can authenticate without password */
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Curl_sasl_start()
|
* Curl_sasl_start()
|
||||||
*
|
*
|
||||||
@ -1345,80 +1387,89 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
|
|||||||
|
|
||||||
/* Calculate the supported authentication mechanism, by decreasing order of
|
/* Calculate the supported authentication mechanism, by decreasing order of
|
||||||
* security, as well as the initial response where appropriate */
|
* security, as well as the initial response where appropriate */
|
||||||
#if defined(USE_KERBEROS5)
|
if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) {
|
||||||
if(enabledmechs & SASL_MECH_GSSAPI) {
|
mech = SASL_MECH_STRING_EXTERNAL;
|
||||||
sasl->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */
|
state1 = SASL_EXTERNAL;
|
||||||
mech = SASL_MECH_STRING_GSSAPI;
|
sasl->authused = SASL_MECH_EXTERNAL;
|
||||||
state1 = SASL_GSSAPI;
|
|
||||||
state2 = SASL_GSSAPI_TOKEN;
|
|
||||||
sasl->authused = SASL_MECH_GSSAPI;
|
|
||||||
|
|
||||||
if(force_ir || data->set.sasl_ir)
|
if(force_ir || data->set.sasl_ir)
|
||||||
result = Curl_sasl_create_gssapi_user_message(data, conn->user,
|
result = sasl_create_external_message(data, conn->user, &resp, &len);
|
||||||
conn->passwd,
|
|
||||||
sasl->params->service,
|
|
||||||
sasl->mutual_auth,
|
|
||||||
NULL, &conn->krb5,
|
|
||||||
&resp, &len);
|
|
||||||
}
|
}
|
||||||
else
|
else if(conn->bits.user_passwd) {
|
||||||
|
#if defined(USE_KERBEROS5)
|
||||||
|
if(enabledmechs & SASL_MECH_GSSAPI) {
|
||||||
|
sasl->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */
|
||||||
|
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_sasl_create_gssapi_user_message(data, conn->user,
|
||||||
|
conn->passwd,
|
||||||
|
sasl->params->service,
|
||||||
|
sasl->mutual_auth,
|
||||||
|
NULL, &conn->krb5,
|
||||||
|
&resp, &len);
|
||||||
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
#ifndef CURL_DISABLE_CRYPTO_AUTH
|
#ifndef CURL_DISABLE_CRYPTO_AUTH
|
||||||
if(enabledmechs & SASL_MECH_DIGEST_MD5) {
|
if(enabledmechs & SASL_MECH_DIGEST_MD5) {
|
||||||
mech = SASL_MECH_STRING_DIGEST_MD5;
|
mech = SASL_MECH_STRING_DIGEST_MD5;
|
||||||
state1 = SASL_DIGESTMD5;
|
state1 = SASL_DIGESTMD5;
|
||||||
sasl->authused = SASL_MECH_DIGEST_MD5;
|
sasl->authused = SASL_MECH_DIGEST_MD5;
|
||||||
}
|
}
|
||||||
else if(enabledmechs & SASL_MECH_CRAM_MD5) {
|
else if(enabledmechs & SASL_MECH_CRAM_MD5) {
|
||||||
mech = SASL_MECH_STRING_CRAM_MD5;
|
mech = SASL_MECH_STRING_CRAM_MD5;
|
||||||
state1 = SASL_CRAMMD5;
|
state1 = SASL_CRAMMD5;
|
||||||
sasl->authused = SASL_MECH_CRAM_MD5;
|
sasl->authused = SASL_MECH_CRAM_MD5;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_NTLM
|
#ifdef USE_NTLM
|
||||||
if(enabledmechs & SASL_MECH_NTLM) {
|
if(enabledmechs & SASL_MECH_NTLM) {
|
||||||
mech = SASL_MECH_STRING_NTLM;
|
mech = SASL_MECH_STRING_NTLM;
|
||||||
state1 = SASL_NTLM;
|
state1 = SASL_NTLM;
|
||||||
state2 = SASL_NTLM_TYPE2MSG;
|
state2 = SASL_NTLM_TYPE2MSG;
|
||||||
sasl->authused = SASL_MECH_NTLM;
|
sasl->authused = SASL_MECH_NTLM;
|
||||||
|
|
||||||
if(force_ir || data->set.sasl_ir)
|
if(force_ir || data->set.sasl_ir)
|
||||||
result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
|
result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
|
||||||
&conn->ntlm, &resp, &len);
|
&conn->ntlm, &resp, &len);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
if((((enabledmechs & SASL_MECH_XOAUTH2) &&
|
if((((enabledmechs & SASL_MECH_XOAUTH2) &&
|
||||||
sasl->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
|
sasl->prefmech != SASL_AUTH_DEFAULT)) || conn->xoauth2_bearer) {
|
||||||
mech = SASL_MECH_STRING_XOAUTH2;
|
mech = SASL_MECH_STRING_XOAUTH2;
|
||||||
state1 = SASL_XOAUTH2;
|
state1 = SASL_XOAUTH2;
|
||||||
sasl->authused = SASL_MECH_XOAUTH2;
|
sasl->authused = SASL_MECH_XOAUTH2;
|
||||||
|
|
||||||
if(force_ir || data->set.sasl_ir)
|
if(force_ir || data->set.sasl_ir)
|
||||||
result = sasl_create_xoauth2_message(data, conn->user,
|
result = sasl_create_xoauth2_message(data, conn->user,
|
||||||
conn->xoauth2_bearer, &resp, &len);
|
conn->xoauth2_bearer,
|
||||||
}
|
&resp, &len);
|
||||||
else if(enabledmechs & SASL_MECH_LOGIN) {
|
}
|
||||||
mech = SASL_MECH_STRING_LOGIN;
|
else if(enabledmechs & SASL_MECH_LOGIN) {
|
||||||
state1 = SASL_LOGIN;
|
mech = SASL_MECH_STRING_LOGIN;
|
||||||
state2 = SASL_LOGIN_PASSWD;
|
state1 = SASL_LOGIN;
|
||||||
sasl->authused = SASL_MECH_LOGIN;
|
state2 = SASL_LOGIN_PASSWD;
|
||||||
|
sasl->authused = SASL_MECH_LOGIN;
|
||||||
|
|
||||||
if(force_ir || data->set.sasl_ir)
|
if(force_ir || data->set.sasl_ir)
|
||||||
result = sasl_create_login_message(data, conn->user, &resp, &len);
|
result = sasl_create_login_message(data, conn->user, &resp, &len);
|
||||||
}
|
}
|
||||||
else if(enabledmechs & SASL_MECH_PLAIN) {
|
else if(enabledmechs & SASL_MECH_PLAIN) {
|
||||||
mech = SASL_MECH_STRING_PLAIN;
|
mech = SASL_MECH_STRING_PLAIN;
|
||||||
state1 = SASL_PLAIN;
|
state1 = SASL_PLAIN;
|
||||||
sasl->authused = SASL_MECH_PLAIN;
|
sasl->authused = SASL_MECH_PLAIN;
|
||||||
|
|
||||||
if(force_ir || data->set.sasl_ir)
|
if(force_ir || data->set.sasl_ir)
|
||||||
result = sasl_create_plain_message(data, conn->user, conn->passwd,
|
result = sasl_create_plain_message(data, conn->user, conn->passwd,
|
||||||
&resp, &len);
|
&resp, &len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
state2 = SASL_STOP; /* No authentication started */
|
|
||||||
|
|
||||||
if(!result) {
|
if(!result) {
|
||||||
if(resp && sasl->params->maxirlen &&
|
if(resp && sasl->params->maxirlen &&
|
||||||
@ -1490,6 +1541,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
|
|||||||
case SASL_LOGIN_PASSWD:
|
case SASL_LOGIN_PASSWD:
|
||||||
result = sasl_create_login_message(data, conn->passwd, &resp, &len);
|
result = sasl_create_login_message(data, conn->passwd, &resp, &len);
|
||||||
break;
|
break;
|
||||||
|
case SASL_EXTERNAL:
|
||||||
|
result = sasl_create_external_message(data, conn->user, &resp, &len);
|
||||||
|
break;
|
||||||
|
|
||||||
#ifndef CURL_DISABLE_CRYPTO_AUTH
|
#ifndef CURL_DISABLE_CRYPTO_AUTH
|
||||||
case SASL_CRAMMD5:
|
case SASL_CRAMMD5:
|
||||||
|
@ -39,10 +39,6 @@ struct ntlmdata;
|
|||||||
struct kerberos5data;
|
struct kerberos5data;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Authentication mechanism values */
|
|
||||||
#define SASL_AUTH_NONE 0
|
|
||||||
#define SASL_AUTH_ANY ~0U
|
|
||||||
|
|
||||||
/* Authentication mechanism flags */
|
/* Authentication mechanism flags */
|
||||||
#define SASL_MECH_LOGIN (1 << 0)
|
#define SASL_MECH_LOGIN (1 << 0)
|
||||||
#define SASL_MECH_PLAIN (1 << 1)
|
#define SASL_MECH_PLAIN (1 << 1)
|
||||||
@ -53,6 +49,11 @@ struct kerberos5data;
|
|||||||
#define SASL_MECH_NTLM (1 << 6)
|
#define SASL_MECH_NTLM (1 << 6)
|
||||||
#define SASL_MECH_XOAUTH2 (1 << 7)
|
#define SASL_MECH_XOAUTH2 (1 << 7)
|
||||||
|
|
||||||
|
/* Authentication mechanism values */
|
||||||
|
#define SASL_AUTH_NONE 0
|
||||||
|
#define SASL_AUTH_ANY ~0U
|
||||||
|
#define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL)
|
||||||
|
|
||||||
/* Authentication mechanism strings */
|
/* Authentication mechanism strings */
|
||||||
#define SASL_MECH_STRING_LOGIN "LOGIN"
|
#define SASL_MECH_STRING_LOGIN "LOGIN"
|
||||||
#define SASL_MECH_STRING_PLAIN "PLAIN"
|
#define SASL_MECH_STRING_PLAIN "PLAIN"
|
||||||
@ -74,6 +75,7 @@ typedef enum {
|
|||||||
SASL_PLAIN,
|
SASL_PLAIN,
|
||||||
SASL_LOGIN,
|
SASL_LOGIN,
|
||||||
SASL_LOGIN_PASSWD,
|
SASL_LOGIN_PASSWD,
|
||||||
|
SASL_EXTERNAL,
|
||||||
SASL_CRAMMD5,
|
SASL_CRAMMD5,
|
||||||
SASL_DIGESTMD5,
|
SASL_DIGESTMD5,
|
||||||
SASL_DIGESTMD5_RESP,
|
SASL_DIGESTMD5_RESP,
|
||||||
@ -228,6 +230,9 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
|
|||||||
/* Initializes an SASL structure */
|
/* Initializes an SASL structure */
|
||||||
void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params);
|
void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params);
|
||||||
|
|
||||||
|
/* Check if we have enough auth data and capabilities to authenticate */
|
||||||
|
bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn);
|
||||||
|
|
||||||
/* Calculate the required login details for SASL authentication */
|
/* Calculate the required login details for SASL authentication */
|
||||||
CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
|
CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
|
||||||
bool force_ir, saslprogress *progress);
|
bool force_ir, saslprogress *progress);
|
||||||
|
@ -612,9 +612,9 @@ static CURLcode imap_perform_authentication(struct connectdata *conn)
|
|||||||
struct imap_conn *imapc = &conn->proto.imapc;
|
struct imap_conn *imapc = &conn->proto.imapc;
|
||||||
saslprogress progress;
|
saslprogress progress;
|
||||||
|
|
||||||
/* Check we have a username and password to authenticate with and end the
|
/* Check we have enough data to authenticate with and end the
|
||||||
connect phase if we don't */
|
connect phase if we don't */
|
||||||
if(!conn->bits.user_passwd) {
|
if(!Curl_sasl_can_authenticate(&imapc->sasl, conn)) {
|
||||||
state(conn, IMAP_STOP);
|
state(conn, IMAP_STOP);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1962,7 +1962,7 @@ static CURLcode imap_parse_url_options(struct connectdata *conn)
|
|||||||
case SASL_AUTH_NONE:
|
case SASL_AUTH_NONE:
|
||||||
imapc->preftype = IMAP_TYPE_NONE;
|
imapc->preftype = IMAP_TYPE_NONE;
|
||||||
break;
|
break;
|
||||||
case SASL_AUTH_ANY:
|
case SASL_AUTH_DEFAULT:
|
||||||
imapc->preftype = IMAP_TYPE_ANY;
|
imapc->preftype = IMAP_TYPE_ANY;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -543,9 +543,9 @@ static CURLcode pop3_perform_authentication(struct connectdata *conn)
|
|||||||
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||||
saslprogress progress = SASL_IDLE;
|
saslprogress progress = SASL_IDLE;
|
||||||
|
|
||||||
/* Check we have a username and password to authenticate with and end the
|
/* Check we have enough data to authenticate with and end the
|
||||||
connect phase if we don't */
|
connect phase if we don't */
|
||||||
if(!conn->bits.user_passwd) {
|
if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) {
|
||||||
state(conn, POP3_STOP);
|
state(conn, POP3_STOP);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1425,7 +1425,7 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn)
|
|||||||
case SASL_AUTH_NONE:
|
case SASL_AUTH_NONE:
|
||||||
pop3c->preftype = POP3_TYPE_NONE;
|
pop3c->preftype = POP3_TYPE_NONE;
|
||||||
break;
|
break;
|
||||||
case SASL_AUTH_ANY:
|
case SASL_AUTH_DEFAULT:
|
||||||
pop3c->preftype = POP3_TYPE_ANY;
|
pop3c->preftype = POP3_TYPE_ANY;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -486,9 +486,10 @@ static CURLcode smtp_perform_authentication(struct connectdata *conn)
|
|||||||
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||||
saslprogress progress;
|
saslprogress progress;
|
||||||
|
|
||||||
/* Check we have a username and password to authenticate with, and the
|
/* Check we have enough data to authenticate with, and the
|
||||||
server supports authentiation, and end the connect phase if not */
|
server supports authentiation, and end the connect phase if not */
|
||||||
if(!conn->bits.user_passwd || !smtpc->auth_supported) {
|
if(!smtpc->auth_supported ||
|
||||||
|
!Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
|
||||||
state(conn, SMTP_STOP);
|
state(conn, SMTP_STOP);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user