From 0d24f644735924524bcffff75ace4bd7b7a2e05a Mon Sep 17 00:00:00 2001 From: Patrick Monnerat Date: Tue, 27 Jan 2015 17:24:55 +0100 Subject: sasl: implement EXTERNAL authentication mechanism. Its use is only enabled by explicit requirement in URL (;AUTH=EXTERNAL) and by not setting the password. --- lib/curl_sasl.c | 188 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 121 insertions(+), 67 deletions(-) (limited to 'lib/curl_sasl.c') diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c index 347f1a302..2d55836cd 100644 --- a/lib/curl_sasl.c +++ b/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); } +/* + * 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 /* * sasl_decode_cram_md5_message() @@ -1257,7 +1281,7 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, } if(strnequal(value, "*", len)) - sasl->prefmech = SASL_AUTH_ANY; + sasl->prefmech = SASL_AUTH_DEFAULT; else if((mechbit = Curl_sasl_decode_mech(value, len, &mechlen)) && mechlen == len) 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->state = SASL_STOP; /* Not yet running */ 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->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */ sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */ @@ -1299,6 +1323,7 @@ static void state(struct SASL *sasl, "PLAIN", "LOGIN", "LOGIN_PASSWD", + "EXTERNAL", "CRAMMD5", "DIGESTMD5", "DIGESTMD5_RESP", @@ -1321,6 +1346,23 @@ static void state(struct SASL *sasl, 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() * @@ -1345,80 +1387,89 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, /* Calculate the supported authentication mechanism, by decreasing order of * security, as well as the initial response where appropriate */ -#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((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) - result = Curl_sasl_create_gssapi_user_message(data, conn->user, - conn->passwd, - sasl->params->service, - sasl->mutual_auth, - NULL, &conn->krb5, - &resp, &len); + result = sasl_create_external_message(data, conn->user, &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 #ifndef CURL_DISABLE_CRYPTO_AUTH - if(enabledmechs & SASL_MECH_DIGEST_MD5) { - 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 + if(enabledmechs & SASL_MECH_DIGEST_MD5) { + 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 #endif #ifdef USE_NTLM - if(enabledmechs & SASL_MECH_NTLM) { - 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_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, &resp, &len); - } - else + if(enabledmechs & SASL_MECH_NTLM) { + 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_sasl_create_ntlm_type1_message(conn->user, conn->passwd, + &conn->ntlm, &resp, &len); + } + else #endif - if((((enabledmechs & SASL_MECH_XOAUTH2) && - sasl->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) { - mech = SASL_MECH_STRING_XOAUTH2; - state1 = SASL_XOAUTH2; - sasl->authused = SASL_MECH_XOAUTH2; - - if(force_ir || data->set.sasl_ir) - result = sasl_create_xoauth2_message(data, conn->user, - conn->xoauth2_bearer, &resp, &len); - } - 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) - result = sasl_create_login_message(data, conn->user, &resp, &len); - } - 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 = sasl_create_plain_message(data, conn->user, conn->passwd, - &resp, &len); + if((((enabledmechs & SASL_MECH_XOAUTH2) && + sasl->prefmech != SASL_AUTH_DEFAULT)) || conn->xoauth2_bearer) { + mech = SASL_MECH_STRING_XOAUTH2; + state1 = SASL_XOAUTH2; + sasl->authused = SASL_MECH_XOAUTH2; + + if(force_ir || data->set.sasl_ir) + result = sasl_create_xoauth2_message(data, conn->user, + conn->xoauth2_bearer, + &resp, &len); + } + 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) + result = sasl_create_login_message(data, conn->user, &resp, &len); + } + 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 = sasl_create_plain_message(data, conn->user, conn->passwd, + &resp, &len); + } } - else - state2 = SASL_STOP; /* No authentication started */ if(!result) { if(resp && sasl->params->maxirlen && @@ -1490,6 +1541,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, case SASL_LOGIN_PASSWD: result = sasl_create_login_message(data, conn->passwd, &resp, &len); break; + case SASL_EXTERNAL: + result = sasl_create_external_message(data, conn->user, &resp, &len); + break; #ifndef CURL_DISABLE_CRYPTO_AUTH case SASL_CRAMMD5: -- cgit v1.2.3