diff options
author | Patrick Monnerat <pm@datasphere.ch> | 2015-01-20 17:33:05 +0100 |
---|---|---|
committer | Patrick Monnerat <pm@datasphere.ch> | 2015-01-20 17:33:05 +0100 |
commit | 79543caf908118d056353714ba2cb5c5348e20c2 (patch) | |
tree | 3509da752a1a2be8b0c980bf6eae6637052e6777 /lib | |
parent | e1ea18f90e93d50fc999c46c53685fbdd9508659 (diff) |
SASL: common state engine for imap/pop3/smtp
Diffstat (limited to 'lib')
-rw-r--r-- | lib/curl_sasl.c | 331 | ||||
-rw-r--r-- | lib/curl_sasl.h | 54 | ||||
-rw-r--r-- | lib/imap.c | 838 | ||||
-rw-r--r-- | lib/imap.h | 15 | ||||
-rw-r--r-- | lib/pop3.c | 849 | ||||
-rw-r--r-- | lib/pop3.h | 15 | ||||
-rw-r--r-- | lib/smtp.c | 812 | ||||
-rw-r--r-- | lib/smtp.h | 15 |
8 files changed, 577 insertions, 2352 deletions
diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c index 7cb575b33..6a648f0ae 100644 --- a/lib/curl_sasl.c +++ b/lib/curl_sasl.c @@ -43,6 +43,7 @@ #include "strtok.h" #include "strequal.h" #include "rawstr.h" +#include "sendf.h" #include "non-ascii.h" /* included for Curl_convert_... prototypes */ #define _MPRINTF_REPLACE /* use our functions only */ @@ -1271,11 +1272,339 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, * * Initializes an SASL structure. */ -void Curl_sasl_init(struct SASL *sasl) +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->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) */ + sasl->force_ir = FALSE; /* Respect external option */ +} + +/* + * state() + * + * This is the ONLY way to change SASL state! + */ +static void state(struct SASL *sasl, + struct connectdata *conn, saslstate newstate) +{ +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ + static const char * const names[]={ + "STOP", + "PLAIN", + "LOGIN", + "LOGIN_PASSWD", + "CRAMMD5", + "DIGESTMD5", + "DIGESTMD5_RESP", + "NTLM", + "NTLM_TYPE2MSG", + "GSSAPI", + "GSSAPI_TOKEN", + "GSSAPI_NO_DATA", + "XOAUTH2", + "CANCEL", + "FINAL", + /* LAST */ + }; + + if(sasl->state != newstate) + infof(conn->data, "SASL %p state change from %s to %s\n", + (void *)sasl, names[sasl->state], names[newstate]); +#endif + + sasl->state = newstate; +} + +/* + * Curl_sasl_start() + * + * Calculate the required login details for SASL authentication. + */ +CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, + bool force_ir, saslprogress *progress) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + unsigned int enabledmechs; + const char *mech = NULL; + char *resp = NULL; + size_t len = 0; + saslstate state1 = SASL_STOP; + saslstate state2 = SASL_FINAL; + + sasl->force_ir = force_ir; /* Latch for future use */ + sasl->authused = 0; /* No mechanism used yet */ + enabledmechs = sasl->authmechs & sasl->prefmech; + *progress = SASL_IDLE; + + /* 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(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 +#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 +#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 = Curl_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 = Curl_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 = Curl_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 && + strlen(mech) + len > sasl->params->maxirlen) { + Curl_safefree(resp); + resp = NULL; + } + if(mech) { + result = sasl->params->sendauth(conn, mech, resp); + if(!result) { + *progress = SASL_INPROGRESS; + state(sasl, conn, resp? state2: state1); + } + } + } + + Curl_safefree(resp); + return result; +} + +/* + * Curl_sasl_continue() + * + * Continue an SASL authentication. + */ +CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, + int code, saslprogress *progress) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + saslstate newstate = SASL_FINAL; + char *chlg = NULL; + char *resp = NULL; + char *serverdata; + size_t len = 0; + size_t chlglen = 0; + + *progress = SASL_INPROGRESS; + + if(sasl->state == SASL_FINAL) { + if(code != sasl->params->finalcode) + result = CURLE_LOGIN_DENIED; + *progress = SASL_DONE; + state(sasl, conn, SASL_STOP); + return result; + } + + if(sasl->state != SASL_CANCEL && code != sasl->params->contcode) { + *progress = SASL_DONE; + state(sasl, conn, SASL_STOP); + return CURLE_LOGIN_DENIED; + } + + switch(sasl->state) { + case SASL_STOP: + *progress = SASL_DONE; + return result; + case SASL_PLAIN: + result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, + &resp, &len); + break; + case SASL_LOGIN: + result = Curl_sasl_create_login_message(data, conn->user, &resp, &len); + newstate = SASL_LOGIN_PASSWD; + break; + case SASL_LOGIN_PASSWD: + result = Curl_sasl_create_login_message(data, conn->passwd, &resp, &len); + break; + +#ifndef CURL_DISABLE_CRYPTO_AUTH + case SASL_CRAMMD5: + sasl->params->getmessage(data->state.buffer, &serverdata); + result = Curl_sasl_decode_cram_md5_message(serverdata, &chlg, &chlglen); + if(!result) + result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user, + conn->passwd, &resp, &len); + Curl_safefree(chlg); + break; + case SASL_DIGESTMD5: + sasl->params->getmessage(data->state.buffer, &serverdata); + result = Curl_sasl_create_digest_md5_message(data, serverdata, + conn->user, conn->passwd, + sasl->params->service, + &resp, &len); + newstate = SASL_DIGESTMD5_RESP; + break; + case SASL_DIGESTMD5_RESP: + if(!(resp = strdup(""))) + result = CURLE_OUT_OF_MEMORY; + break; +#endif + +#ifdef USE_NTLM + case SASL_NTLM: + /* Create the type-1 message */ + result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, + &conn->ntlm, + &resp, &len); + newstate = SASL_NTLM_TYPE2MSG; + break; + case SASL_NTLM_TYPE2MSG: + /* Decode the type-2 message */ + sasl->params->getmessage(data->state.buffer, &serverdata); + result = Curl_sasl_decode_ntlm_type2_message(data, + serverdata, &conn->ntlm); + if(!result) + result = Curl_sasl_create_ntlm_type3_message(data, conn->user, + conn->passwd, &conn->ntlm, + &resp, &len); + break; +#endif + +#if defined(USE_KERBEROS5) + case SASL_GSSAPI: + result = Curl_sasl_create_gssapi_user_message(data, conn->user, + conn->passwd, + sasl->params->service, + sasl->mutual_auth, NULL, + &conn->krb5, + &resp, &len); + newstate = SASL_GSSAPI_TOKEN; + break; + case SASL_GSSAPI_TOKEN: + sasl->params->getmessage(data->state.buffer, &serverdata); + if(sasl->mutual_auth) { + /* Decode the user token challenge and create the optional response + message */ + result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL, + sasl->mutual_auth, + serverdata, &conn->krb5, + &resp, &len); + newstate = SASL_GSSAPI_NO_DATA; + } + else + /* Decode the security challenge and create the response message */ + result = Curl_sasl_create_gssapi_security_message(data, serverdata, + &conn->krb5, + &resp, &len); + break; + case SASL_GSSAPI_NO_DATA: + sasl->params->getmessage(data->state.buffer, &serverdata); + /* Decode the security challenge and create the response message */ + result = Curl_sasl_create_gssapi_security_message(data, serverdata, + &conn->krb5, + &resp, &len); + break; +#endif + + case SASL_XOAUTH2: + /* Create the authorisation message */ + result = Curl_sasl_create_xoauth2_message(data, conn->user, + conn->xoauth2_bearer, + &resp, &len); + break; + case SASL_CANCEL: + /* Remove the offending mechanism from the supported list */ + sasl->authmechs ^= sasl->authused; + + /* Start an alternative SASL authentication */ + result = Curl_sasl_start(sasl, conn, sasl->force_ir, progress); + newstate = sasl->state; /* Use state from Curl_sasl_start() */ + break; + default: + failf(data, "Unsupported SASL authentication mechanism"); + result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */ + break; + } + + switch(result) { + case CURLE_BAD_CONTENT_ENCODING: + /* Cancel dialog */ + result = sasl->params->sendcont(conn, "*"); + newstate = SASL_CANCEL; + break; + case CURLE_OK: + if(resp) + result = sasl->params->sendcont(conn, resp); + break; + default: + newstate = SASL_STOP; /* Stop on error */ + *progress = SASL_DONE; + break; + } + + Curl_safefree(resp); + state(sasl, conn, newstate); + return result; } diff --git a/lib/curl_sasl.h b/lib/curl_sasl.h index e043449db..19fa239e4 100644 --- a/lib/curl_sasl.h +++ b/lib/curl_sasl.h @@ -68,13 +68,57 @@ enum { CURLDIGESTALGO_MD5SESS }; +/* SASL machine states */ +typedef enum { + SASL_STOP, + SASL_PLAIN, + SASL_LOGIN, + SASL_LOGIN_PASSWD, + SASL_CRAMMD5, + SASL_DIGESTMD5, + SASL_DIGESTMD5_RESP, + SASL_NTLM, + SASL_NTLM_TYPE2MSG, + SASL_GSSAPI, + SASL_GSSAPI_TOKEN, + SASL_GSSAPI_NO_DATA, + SASL_XOAUTH2, + SASL_CANCEL, + SASL_FINAL +} saslstate; + +/* Progress indicator */ +typedef enum { + SASL_IDLE, + SASL_INPROGRESS, + SASL_DONE +} saslprogress; + +/* Protocol dependent SASL parameters */ +struct SASLproto { + const char *service; /* The service name */ + int contcode; /* Code to receive when continuation is expected */ + int finalcode; /* Code to receive upon authentication success */ + size_t maxirlen; /* Maximum initial response length */ + CURLcode (*sendauth)(struct connectdata *conn, + const char *mech, const char *ir); + /* Send authentication command */ + CURLcode (*sendcont)(struct connectdata *conn, const char *contauth); + /* Send authentication continuation */ + void (*getmessage)(char *buffer, char **outptr); + /* Get SASL response message */ +}; + /* Per-connection parameters */ struct SASL { + const struct SASLproto *params; /* Protocol dependent parameters */ + saslstate state; /* Current machine state */ unsigned int authmechs; /* Accepted authentication mechanisms */ unsigned int prefmech; /* Preferred authentication mechanism */ unsigned int authused; /* Auth mechanism used for the connection */ bool resetprefs; /* For URL auth option parsing. */ bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */ + bool force_ir; /* Protocol always supports initial response */ }; /* This is used to test whether the line starts with the given mechanism */ @@ -211,6 +255,14 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, const char *value, size_t len); /* Initializes an SASL structure */ -void Curl_sasl_init(struct SASL *sasl); +void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params); + +/* Calculate the required login details for SASL authentication */ +CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, + bool force_ir, saslprogress *progress); + +/* Continue an SASL authentication */ +CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, + int code, saslprogress *progress); #endif /* HEADER_CURL_SASL_H */ diff --git a/lib/imap.c b/lib/imap.c index 965efdf8a..c5c8e4aea 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -105,10 +105,12 @@ static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...); static CURLcode imap_parse_url_options(struct connectdata *conn); static CURLcode imap_parse_url_path(struct connectdata *conn); static CURLcode imap_parse_custom_request(struct connectdata *conn); -static CURLcode imap_calc_sasl_details(struct connectdata *conn, - const char **mech, - char **initresp, size_t *len, - imapstate *state1, imapstate *state2); +static CURLcode imap_perform_authenticate(struct connectdata *conn, + const char *mech, + const char *initresp); +static CURLcode imap_continue_authenticate(struct connectdata *conn, + const char *resp); +static void imap_get_message(char *buffer, char** outptr); /* * IMAP protocol handler. @@ -213,6 +215,18 @@ static const struct Curl_handler Curl_handler_imaps_proxy = { #endif #endif +/* SASL parameters for the imap protocol */ +static const struct SASLproto saslimap = { + "imap", /* The service name */ + '+', /* Code received when continuation is expected */ + 'O', /* Code to receive upon authentication success */ + 0, /* Maximum initial response length (no max) */ + imap_perform_authenticate, /* Send authentication command */ + imap_continue_authenticate, /* Send authentication continuation */ + imap_get_message /* Get SASL response message */ +}; + + #ifdef USE_SSL static void imap_to_imaps(struct connectdata *conn) { @@ -353,16 +367,7 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len, (len >= 2 && !memcmp("+ ", line, 2))) { switch(imapc->state) { /* States which are interested in continuation responses */ - case IMAP_AUTHENTICATE_PLAIN: - case IMAP_AUTHENTICATE_LOGIN: - case IMAP_AUTHENTICATE_LOGIN_PASSWD: - case IMAP_AUTHENTICATE_CRAMMD5: - case IMAP_AUTHENTICATE_DIGESTMD5: - case IMAP_AUTHENTICATE_DIGESTMD5_RESP: - case IMAP_AUTHENTICATE_NTLM: - case IMAP_AUTHENTICATE_NTLM_TYPE2MSG: - case IMAP_AUTHENTICATE_XOAUTH2: - case IMAP_AUTHENTICATE_FINAL: + case IMAP_AUTHENTICATE: case IMAP_APPEND: *resp = '+'; break; @@ -425,20 +430,7 @@ static void state(struct connectdata *conn, imapstate newstate) "CAPABILITY", "STARTTLS", "UPGRADETLS", - "AUTHENTICATE_PLAIN", - "AUTHENTICATE_LOGIN", - "AUTHENTICATE_LOGIN_PASSWD", - "AUTHENTICATE_CRAMMD5", - "AUTHENTICATE_DIGESTMD5", - "AUTHENTICATE_DIGESTMD5_RESP", - "AUTHENTICATE_NTLM", - "AUTHENTICATE_NTLM_TYPE2MSG", - "AUTHENTICATE_GSSAPI", - "AUTHENTICATE_GSSAPI_TOKEN", - "AUTHENTICATE_GSSAPI_NO_DATA", - "AUTHENTICATE_XOAUTH2", - "AUTHENTICATE_CANCEL", - "AUTHENTICATE_FINAL", + "AUTHENTICATE", "LOGIN", "LIST", "SELECT", @@ -576,24 +568,17 @@ static CURLcode imap_perform_login(struct connectdata *conn) */ static CURLcode imap_perform_authenticate(struct connectdata *conn, const char *mech, - const char *initresp, - imapstate state1, imapstate state2) + const char *initresp) { CURLcode result = CURLE_OK; if(initresp) { /* Send the AUTHENTICATE command with the initial response */ result = imap_sendf(conn, "AUTHENTICATE %s %s", mech, initresp); - - if(!result) - state(conn, state2); } else { /* Send the AUTHENTICATE command */ result = imap_sendf(conn, "AUTHENTICATE %s", mech); - - if(!result) - state(conn, state1); } return result; @@ -601,6 +586,20 @@ static CURLcode imap_perform_authenticate(struct connectdata *conn, /*********************************************************************** * + * imap_continue_authenticate() + * + * Sends SASL continuation data or cancellation. + */ +static CURLcode imap_continue_authenticate(struct connectdata *conn, + const char *resp) +{ + struct imap_conn *imapc = &conn->proto.imapc; + + return Curl_pp_sendf(&imapc->pp, "%s", resp); +} + +/*********************************************************************** + * * imap_perform_authentication() * * Initiates the authentication sequence, with the appropriate SASL @@ -611,31 +610,22 @@ static CURLcode imap_perform_authentication(struct connectdata *conn) { CURLcode result = CURLE_OK; struct imap_conn *imapc = &conn->proto.imapc; - const char *mech = NULL; - char *initresp = NULL; - size_t len = 0; - imapstate state1 = IMAP_STOP; - imapstate state2 = IMAP_STOP; + saslprogress progress; /* Check we have a username and password to authenticate with and end the connect phase if we don't */ if(!conn->bits.user_passwd) { state(conn, IMAP_STOP); - return result; } /* Calculate the SASL login details */ - result = imap_calc_sasl_details(conn, &mech, &initresp, &len, &state1, - &state2); + result = Curl_sasl_start(&imapc->sasl, conn, imapc->ir_supported, &progress); if(!result) { - if(mech && (imapc->preftype & IMAP_TYPE_SASL)) { - /* Perform SASL based authentication */ - result = imap_perform_authenticate(conn, mech, initresp, state1, state2); - } - else if((!imapc->login_disabled) && - (imapc->preftype & IMAP_TYPE_CLEARTEXT)) + if(progress == SASL_INPROGRESS) + state(conn, IMAP_AUTHENTICATE); + else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT)) /* Perform clear text authentication */ result = imap_perform_login(conn); else { @@ -645,8 +635,6 @@ static CURLcode imap_perform_authentication(struct connectdata *conn) } } - Curl_safefree(initresp); - return result; } @@ -976,569 +964,36 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn, return result; } -/* For AUTHENTICATE PLAIN (without initial response) responses */ -static CURLcode imap_state_auth_plain_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *plainauth = NULL; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied. %c", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the authorisation message */ - result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, - &plainauth, &len); - if(!result && plainauth) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", plainauth); - - if(!result) - state(conn, IMAP_AUTHENTICATE_FINAL); - } - } - - Curl_safefree(plainauth); - - return result; -} - -/* For AUTHENTICATE LOGIN (without initial response) responses */ -static CURLcode imap_state_auth_login_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *authuser = NULL; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the user message */ - result = Curl_sasl_create_login_message(data, conn->user, - &authuser, &len); - if(!result && authuser) { - /* Send the user */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", authuser); - - if(!result) - state(conn, IMAP_AUTHENTICATE_LOGIN_PASSWD); - } - } - - Curl_safefree(authuser); - - return result; -} - -/* For AUTHENTICATE LOGIN user entry responses */ -static CURLcode imap_state_auth_login_password_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *authpasswd = NULL; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the password message */ - result = Curl_sasl_create_login_message(data, conn->passwd, - &authpasswd, &len); - if(!result && authpasswd) { - /* Send the password */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", authpasswd); - - if(!result) - state(conn, IMAP_AUTHENTICATE_FINAL); - } - } - - Curl_safefree(authpasswd); - - return result; -} - -#ifndef CURL_DISABLE_CRYPTO_AUTH -/* For AUTHENTICATE CRAM-MD5 responses */ -static CURLcode imap_state_auth_cram_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlg = NULL; - char *chlg64 = NULL; - char *rplyb64 = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - return CURLE_LOGIN_DENIED; - } - - /* Get the challenge message */ - imap_get_message(data->state.buffer, &chlg64); - - /* Decode the challenge message */ - result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len); - if(result) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "*"); - - if(!result) - state(conn, IMAP_AUTHENTICATE_CANCEL); - } - else { - /* Create the response message */ - result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user, - conn->passwd, &rplyb64, &len); - if(!result && rplyb64) { - /* Send the response */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", rplyb64); - - if(!result) - state(conn, IMAP_AUTHENTICATE_FINAL); - } - } - - Curl_safefree(chlg); - Curl_safefree(rplyb64); - - return result; -} - -/* For AUTHENTICATE DIGEST-MD5 challenge responses */ -static CURLcode imap_state_auth_digest_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlg64 = NULL; - char *rplyb64 = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - return CURLE_LOGIN_DENIED; - } - - /* Get the challenge message */ - imap_get_message(data->state.buffer, &chlg64); - - /* Create the response message */ - result = Curl_sasl_create_digest_md5_message(data, chlg64, - conn->user, conn->passwd, - "imap", &rplyb64, &len); - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "*"); - - if(!result) - state(conn, IMAP_AUTHENTICATE_CANCEL); - } - } - else { - /* Send the response */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", rplyb64); - - if(!result) - state(conn, IMAP_AUTHENTICATE_DIGESTMD5_RESP); - } - - Curl_safefree(rplyb64); - - return result; -} - -/* For AUTHENTICATE DIGEST-MD5 challenge-response responses */ -static CURLcode imap_state_auth_digest_resp_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Authentication failed: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Send an empty response */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", ""); - - if(!result) - state(conn, IMAP_AUTHENTICATE_FINAL); - } - - return result; -} -#endif - -#ifdef USE_NTLM -/* For AUTHENTICATE NTLM (without initial response) responses */ -static CURLcode imap_state_auth_ntlm_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *type1msg = NULL; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the type-1 message */ - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, - &type1msg, &len); - if(!result && type1msg) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", type1msg); - - if(!result) - state(conn, IMAP_AUTHENTICATE_NTLM_TYPE2MSG); - } - } - - Curl_safefree(type1msg); - - return result; -} - -/* For NTLM type-2 responses (sent in reponse to our type-1 message) */ -static CURLcode imap_state_auth_ntlm_type2msg_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *type2msg = NULL; - char *type3msg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the challenge message */ - imap_get_message(data->state.buffer, &type2msg); - - /* Decode the type-2 message */ - result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm); - if(result) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "*"); - - if(!result) - state(conn, IMAP_AUTHENTICATE_CANCEL); - } - else { - /* Create the type-3 message */ - result = Curl_sasl_create_ntlm_type3_message(data, conn->user, - conn->passwd, &conn->ntlm, - &type3msg, &len); - if(!result && type3msg) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", type3msg); - - if(!result) - state(conn, IMAP_AUTHENTICATE_FINAL); - } - } - } - - Curl_safefree(type3msg); - - return result; -} -#endif - -#if defined(USE_KERBEROS5) -/* For AUTHENTICATE GSSAPI (without initial response) responses */ -static CURLcode imap_state_auth_gssapi_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct imap_conn *imapc = &conn->proto.imapc; - size_t len = 0; - char *respmsg = NULL; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the initial response message */ - result = Curl_sasl_create_gssapi_user_message(data, conn->user, - conn->passwd, "imap", - imapc->sasl.mutual_auth, - NULL, &conn->krb5, - &respmsg, &len); - if(!result && respmsg) { - /* Send the message */ - result = Curl_pp_sendf(&imapc->pp, "%s", respmsg); - - if(!result) - state(conn, IMAP_AUTHENTICATE_GSSAPI_TOKEN); - } - } - - Curl_safefree(respmsg); - - return result; -} - -/* For AUTHENTICATE GSSAPI user token responses */ -static CURLcode imap_state_auth_gssapi_token_resp(struct connectdata *conn, - int imapcode, - imapstate instate) +/* For SASL authentication responses */ +static CURLcode imap_state_auth_resp(struct connectdata *conn, + int imapcode, + imapstate instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; struct imap_conn *imapc = &conn->proto.imapc; - char *chlgmsg = NULL; - char *respmsg = NULL; - size_t len = 0; + saslprogress progress; (void)instate; /* no use for this yet */ - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the challenge message */ - imap_get_message(data->state.buffer, &chlgmsg); - - if(imapc->sasl.mutual_auth) - /* Decode the user token challenge and create the optional response - message */ - result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL, - imapc->sasl.mutual_auth, - chlgmsg, &conn->krb5, - &respmsg, &len); - else - /* Decode the security challenge and create the response message */ - result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, - &conn->krb5, - &respmsg, &len); - - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&imapc->pp, "%s", "*"); - - if(!result) - state(conn, IMAP_AUTHENTICATE_CANCEL); - } - } - else { - /* Send the response */ - if(respmsg) - result = Curl_pp_sendf(&imapc->pp, "%s", respmsg); - else - result = Curl_pp_sendf(&imapc->pp, "%s", ""); - - if(!result) - state(conn, imapc->sasl.mutual_auth? IMAP_AUTHENTICATE_GSSAPI_NO_DATA: - IMAP_AUTHENTICATE_FINAL); - } - } - - Curl_safefree(respmsg); - - return result; -} - -/* For AUTHENTICATE GSSAPI no data responses */ -static CURLcode imap_state_auth_gssapi_no_data_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlgmsg = NULL; - char *respmsg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the challenge message */ - imap_get_message(data->state.buffer, &chlgmsg); - - /* Decode the security challenge and create the response message */ - result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, - &conn->krb5, - &respmsg, &len); - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "*"); - - if(!result) - state(conn, IMAP_AUTHENTICATE_CANCEL); - } - } - else { - /* Send the response */ - if(respmsg) { - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", respmsg); - - if(!result) - state(conn, IMAP_AUTHENTICATE_FINAL); + result = Curl_sasl_continue(&imapc->sasl, conn, imapcode, &progress); + if(!result) + switch(progress) { + case SASL_DONE: + state(conn, IMAP_STOP); /* Authenticated */ + break; + case SASL_IDLE: /* No mechanism left after cancellation */ + if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT)) + /* Perform clear text authentication */ + result = imap_perform_login(conn); + else { + failf(data, "Authentication cancelled"); + result = CURLE_LOGIN_DENIED; } + break; + default: + break; } - } - - Curl_safefree(respmsg); - - return result; -} -#endif - -/* For AUTHENTICATE XOAUTH2 (without initial response) responses */ -static CURLcode imap_state_auth_xoauth2_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *xoauth = NULL; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the authorisation message */ - result = Curl_sasl_create_xoauth2_message(conn->data, conn->user, - conn->xoauth2_bearer, - &xoauth, &len); - if(!result && xoauth) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", xoauth); - - if(!result) - state(conn, IMAP_AUTHENTICATE_FINAL); - } - } - - Curl_safefree(xoauth); - - return result; -} - -/* For AUTHENTICATE cancellation responses */ -static CURLcode imap_state_auth_cancel_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct imap_conn *imapc = &conn->proto.imapc; - const char *mech = NULL; - char *initresp = NULL; - size_t len = 0; - imapstate state1 = IMAP_STOP; - imapstate state2 = IMAP_STOP; - - (void)imapcode; - (void)instate; /* no use for this yet */ - - /* Remove the offending mechanism from the supported list */ - imapc->sasl.authmechs ^= imapc->sasl.authused; - - /* Calculate alternative SASL login details */ - result = imap_calc_sasl_details(conn, &mech, &initresp, &len, &state1, - &state2); - - if(!result) { - /* Do we have any mechanisms left or can we fallback to clear text? */ - if(mech) { - /* Retry SASL based authentication */ - result = imap_perform_authenticate(conn, mech, initresp, state1, state2); - - Curl_safefree(initresp); - } - else if((!imapc->login_disabled) && - (imapc->preftype & IMAP_TYPE_CLEARTEXT)) - /* Perform clear text authentication */ - result = imap_perform_login(conn); - else { - failf(data, "Authentication cancelled"); - - result = CURLE_LOGIN_DENIED; - } - } - - return result; -} - -/* For final responses in the AUTHENTICATE sequence */ -static CURLcode imap_state_auth_final_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(imapcode != 'O') { - failf(data, "Authentication failed: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else - /* End of connect phase */ - state(conn, IMAP_STOP); return result; } @@ -1862,69 +1317,8 @@ static CURLcode imap_statemach_act(struct connectdata *conn) result = imap_state_starttls_resp(conn, imapcode, imapc->state); break; - case IMAP_AUTHENTICATE_PLAIN: - result = imap_state_auth_plain_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_LOGIN: - result = imap_state_auth_login_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_LOGIN_PASSWD: - result = imap_state_auth_login_password_resp(conn, imapcode, - imapc->state); - break; - -#ifndef CURL_DISABLE_CRYPTO_AUTH - case IMAP_AUTHENTICATE_CRAMMD5: - result = imap_state_auth_cram_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_DIGESTMD5: - result = imap_state_auth_digest_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_DIGESTMD5_RESP: - result = imap_state_auth_digest_resp_resp(conn, imapcode, imapc->state); - break; -#endif - -#ifdef USE_NTLM - case IMAP_AUTHENTICATE_NTLM: - result = imap_state_auth_ntlm_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_NTLM_TYPE2MSG: - result = imap_state_auth_ntlm_type2msg_resp(conn, imapcode, - imapc->state); - break; -#endif - -#if defined(USE_KERBEROS5) - case IMAP_AUTHENTICATE_GSSAPI: - result = imap_state_auth_gssapi_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_GSSAPI_TOKEN: - result = imap_state_auth_gssapi_token_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_GSSAPI_NO_DATA: - result = imap_state_auth_gssapi_no_data_resp(conn, imapcode, - imapc->state); - break; -#endif - - case IMAP_AUTHENTICATE_XOAUTH2: - result = imap_state_auth_xoauth2_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_CANCEL: - result = imap_state_auth_cancel_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_FINAL: - result = imap_state_auth_final_resp(conn, imapcode, imapc->state); + case IMAP_AUTHENTICATE: + result = imap_state_auth_resp(conn, imapcode, imapc->state); break; case IMAP_LOGIN: @@ -2051,7 +1445,7 @@ static CURLcode imap_connect(struct connectdata *conn, bool *done) /* Set the default preferred authentication type and mechanism */ imapc->preftype = IMAP_TYPE_ANY; - Curl_sasl_init(&imapc->sasl); + Curl_sasl_init(&imapc->sasl, &saslimap); /* Initialise the pingpong layer */ Curl_pp_init(pp); @@ -2748,108 +2142,4 @@ static CURLcode imap_parse_custom_request(struct connectdata *conn) return result; } -/*********************************************************************** - * - * imap_calc_sasl_details() - * - * Calculate the required login details for SASL authentication. - */ -static CURLcode imap_calc_sasl_details(struct connectdata *conn, - const char **mech, - char **initresp, size_t *len, - imapstate *state1, imapstate *state2) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct imap_conn *imapc = &conn->proto.imapc; - - /* Calculate the supported authentication mechanism, by decreasing order of - security, as well as the initial response where appropriate */ -#if defined(USE_KERBEROS5) - if((imapc->sasl.authmechs & SASL_MECH_GSSAPI) && - (imapc->sasl.prefmech & SASL_MECH_GSSAPI)) { - imapc->sasl.mutual_auth = FALSE; /* TODO: Calculate mutual auth. */ - - *mech = SASL_MECH_STRING_GSSAPI; - *state1 = IMAP_AUTHENTICATE_GSSAPI; - *state2 = IMAP_AUTHENTICATE_GSSAPI_TOKEN; - imapc->sasl.authused = SASL_MECH_GSSAPI; - - if(imapc->ir_supported || data->set.sasl_ir) - result = Curl_sasl_create_gssapi_user_message(data, conn->user, - conn->passwd, "imap", - imapc->sasl.mutual_auth, - NULL, &conn->krb5, - initresp, len); - } - else -#endif -#ifndef CURL_DISABLE_CRYPTO_AUTH - if((imapc->sasl.authmechs & SASL_MECH_DIGEST_MD5) && - (imapc->sasl.prefmech & SASL_MECH_DIGEST_MD5)) { - *mech = SASL_MECH_STRING_DIGEST_MD5; - *state1 = IMAP_AUTHENTICATE_DIGESTMD5; - imapc->sasl.authused = SASL_MECH_DIGEST_MD5; - } - else if((imapc->sasl.authmechs & SASL_MECH_CRAM_MD5) && - (imapc->sasl.prefmech & SASL_MECH_CRAM_MD5)) { - *mech = SASL_MECH_STRING_CRAM_MD5; - *state1 = IMAP_AUTHENTICATE_CRAMMD5; - imapc->sasl.authused = SASL_MECH_CRAM_MD5; - } - else -#endif -#ifdef USE_NTLM - if((imapc->sasl.authmechs & SASL_MECH_NTLM) && - (imapc->sasl.prefmech & SASL_MECH_NTLM)) { - *mech = SASL_MECH_STRING_NTLM; - *state1 = IMAP_AUTHENTICATE_NTLM; - *state2 = IMAP_AUTHENTICATE_NTLM_TYPE2MSG; - imapc->sasl.authused = SASL_MECH_NTLM; - - if(imapc->ir_supported || data->set.sasl_ir) - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, - initresp, len); - } - else -#endif - if(((imapc->sasl.authmechs & SASL_MECH_XOAUTH2) && - (imapc->sasl.prefmech & SASL_MECH_XOAUTH2) && - (imapc->sasl.prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) { - *mech = SASL_MECH_STRING_XOAUTH2; - *state1 = IMAP_AUTHENTICATE_XOAUTH2; - *state2 = IMAP_AUTHENTICATE_FINAL; - imapc->sasl.authused = SASL_MECH_XOAUTH2; - - if(imapc->ir_supported || data->set.sasl_ir) - result = Curl_sasl_create_xoauth2_message(data, conn->user, - conn->xoauth2_bearer, - initresp, len); - } - else if((imapc->sasl.authmechs & SASL_MECH_LOGIN) && - (imapc->sasl.prefmech & SASL_MECH_LOGIN)) { - *mech = SASL_MECH_STRING_LOGIN; - *state1 = IMAP_AUTHENTICATE_LOGIN; - *state2 = IMAP_AUTHENTICATE_LOGIN_PASSWD; - imapc->sasl.authused = SASL_MECH_LOGIN; - - if(imapc->ir_supported || data->set.sasl_ir) - result = Curl_sasl_create_login_message(data, conn->user, initresp, len); - } - else if((imapc->sasl.authmechs & SASL_MECH_PLAIN) && - (imapc->sasl.prefmech & SASL_MECH_PLAIN)) { - *mech = SASL_MECH_STRING_PLAIN; - *state1 = IMAP_AUTHENTICATE_PLAIN; - *state2 = IMAP_AUTHENTICATE_FINAL; - imapc->sasl.authused = SASL_MECH_PLAIN; - - if(imapc->ir_supported || data->set.sasl_ir) - result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, - initresp, len); - } - - return result; -} - #endif /* CURL_DISABLE_IMAP */ diff --git a/lib/imap.h b/lib/imap.h index 22e6ada1c..3189daa3c 100644 --- a/lib/imap.h +++ b/lib/imap.h @@ -36,20 +36,7 @@ typedef enum { IMAP_STARTTLS, IMAP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS (multi mode only) */ - IMAP_AUTHENTICATE_PLAIN, - IMAP_AUTHENTICATE_LOGIN, - IMAP_AUTHENTICATE_LOGIN_PASSWD, - IMAP_AUTHENTICATE_CRAMMD5, - IMAP_AUTHENTICATE_DIGESTMD5, - IMAP_AUTHENTICATE_DIGESTMD5_RESP, - IMAP_AUTHENTICATE_NTLM, - IMAP_AUTHENTICATE_NTLM_TYPE2MSG, - IMAP_AUTHENTICATE_GSSAPI, - IMAP_AUTHENTICATE_GSSAPI_TOKEN, - IMAP_AUTHENTICATE_GSSAPI_NO_DATA, - IMAP_AUTHENTICATE_XOAUTH2, - IMAP_AUTHENTICATE_CANCEL, - IMAP_AUTHENTICATE_FINAL, + IMAP_AUTHENTICATE, IMAP_LOGIN, IMAP_LIST, IMAP_SELECT, diff --git a/lib/pop3.c b/lib/pop3.c index f5828e515..a7213a44e 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -106,10 +106,10 @@ static CURLcode pop3_setup_connection(struct connectdata *conn); static CURLcode pop3_parse_url_options(struct connectdata *conn); static CURLcode pop3_parse_url_path(struct connectdata *conn); static CURLcode pop3_parse_custom_request(struct connectdata *conn); -static CURLcode pop3_calc_sasl_details(struct connectdata *conn, - const char **mech, - char **initresp, size_t *len, - pop3state *state1, pop3state *state2); +static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech, + const char *initresp); +static CURLcode pop3_continue_auth(struct connectdata *conn, const char *resp); +static void pop3_get_message(char *buffer, char** outptr); /* * POP3 protocol handler. @@ -214,6 +214,17 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { #endif #endif +/* SASL parameters for the pop3 protocol */ +static const struct SASLproto saslpop3 = { + "pop", /* The service name */ + '+', /* Code received when continuation is expected */ + '+', /* Code to receive upon authentication success */ + 255 - 8, /* Maximum initial response length (no max) */ + pop3_perform_auth, /* Send authentication command */ + pop3_continue_auth, /* Send authentication continuation */ + pop3_get_message /* Get SASL response message */ +}; + #ifdef USE_SSL static void pop3_to_pop3s(struct connectdata *conn) { @@ -312,20 +323,7 @@ static void state(struct connectdata *conn, pop3state newstate) "CAPA", "STARTTLS", "UPGRADETLS", - "AUTH_PLAIN", - "AUTH_LOGIN", - "AUTH_LOGIN_PASSWD", - "AUTH_CRAMMD5", - "AUTH_DIGESTMD5", - "AUTH_DIGESTMD5_RESP", - "AUTH_NTLM", - "AUTH_NTLM_TYPE2MSG", - "AUTH_GSSAPI", - "AUTH_GSSAPI_TOKEN", - "AUTH_GSSAPI_NO_DATA", - "AUTH_XOAUTH2", - "AUTH_CANCEL", - "AUTH_FINAL", + "AUTH", "APOP", "USER", "PASS", @@ -500,25 +498,18 @@ static CURLcode pop3_perform_apop(struct connectdata *conn) */ static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech, - const char *initresp, size_t len, - pop3state state1, pop3state state2) + const char *initresp) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; - if(initresp && 8 + strlen(mech) + len <= 255) { /* AUTH <mech> ...<crlf> */ + if(initresp) { /* AUTH <mech> ...<crlf> */ /* Send the AUTH command with the initial response */ result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp); - - if(!result) - state(conn, state2); } else { /* Send the AUTH command */ result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech); - - if(!result) - state(conn, state1); } return result; @@ -526,6 +517,20 @@ static CURLcode pop3_perform_auth(struct connectdata *conn, /*********************************************************************** * + * pop3_continue_auth() + * + * Sends SASL continuation data or cancellation. + */ +static CURLcode pop3_continue_auth(struct connectdata *conn, + const char *resp) +{ + struct pop3_conn *pop3c = &conn->proto.pop3c; + + return Curl_pp_sendf(&pop3c->pp, "%s", resp); +} + +/*********************************************************************** + * * pop3_perform_authentication() * * Initiates the authentication sequence, with the appropriate SASL @@ -536,38 +541,32 @@ static CURLcode pop3_perform_authentication(struct connectdata *conn) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; - const char *mech = NULL; - char *initresp = NULL; - size_t len = 0; - pop3state state1 = POP3_STOP; - pop3state state2 = POP3_STOP; + saslprogress progress = SASL_IDLE; /* Check we have a username and password to authenticate with and end the connect phase if we don't */ if(!conn->bits.user_passwd) { state(conn, POP3_STOP); - return result; } - /* Calculate the SASL login details */ - if(pop3c->authtypes & POP3_TYPE_SASL) - result = pop3_calc_sasl_details(conn, &mech, &initresp, &len, &state1, - &state2); + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) { + /* Calculate the SASL login details */ + result = Curl_sasl_start(&pop3c->sasl, conn, FALSE, &progress); - if(!result) { - if(mech && (pop3c->preftype & POP3_TYPE_SASL)) { - /* Perform SASL based authentication */ - result = pop3_perform_auth(conn, mech, initresp, len, state1, state2); - } + if(!result) + if(progress == SASL_INPROGRESS) + state(conn, POP3_AUTH); + } + + if(!result && progress == SASL_IDLE) { #ifndef CURL_DISABLE_CRYPTO_AUTH - else if((pop3c->authtypes & POP3_TYPE_APOP) && - (pop3c->preftype & POP3_TYPE_APOP)) + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) /* Perform APOP authentication */ result = pop3_perform_apop(conn); + else #endif - else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) && - (pop3c->preftype & POP3_TYPE_CLEARTEXT)) + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) /* Perform clear text authentication */ result = pop3_perform_user(conn); else { @@ -577,8 +576,6 @@ static CURLcode pop3_perform_authentication(struct connectdata *conn) } } - Curl_safefree(initresp); - return result; } @@ -807,575 +804,42 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, return result; } -/* For AUTH PLAIN (without initial response) responses */ -static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *plainauth = NULL; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied. %c", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the authorisation message */ - result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, - &plainauth, &len); - if(!result && plainauth) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", plainauth); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - } - - Curl_safefree(plainauth); - - return result; -} - -/* For AUTH LOGIN (without initial response) responses */ -static CURLcode pop3_state_auth_login_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *authuser = NULL; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the user message */ - result = Curl_sasl_create_login_message(data, conn->user, - &authuser, &len); - if(!result && authuser) { - /* Send the user */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authuser); - - if(!result) - state(conn, POP3_AUTH_LOGIN_PASSWD); - } - } - - Curl_safefree(authuser); - - return result; -} - -/* For AUTH LOGIN user entry responses */ -static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *authpasswd = NULL; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the password message */ - result = Curl_sasl_create_login_message(data, conn->passwd, - &authpasswd, &len); - if(!result && authpasswd) { - /* Send the password */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authpasswd); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - } - - Curl_safefree(authpasswd); - - return result; -} - -#ifndef CURL_DISABLE_CRYPTO_AUTH -/* For AUTH CRAM-MD5 responses */ -static CURLcode pop3_state_auth_cram_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlg = NULL; - char *chlg64 = NULL; - char *rplyb64 = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - return CURLE_LOGIN_DENIED; - } - - /* Get the challenge message */ - pop3_get_message(data->state.buffer, &chlg64); - - /* Decode the challenge message */ - result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len); - if(result) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*"); - - if(!result) - state(conn, POP3_AUTH_CANCEL); - } - else { - /* Create the response message */ - result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user, - conn->passwd, &rplyb64, &len); - if(!result && rplyb64) { - /* Send the response */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - } - - Curl_safefree(chlg); - Curl_safefree(rplyb64); - - return result; -} - -/* For AUTH DIGEST-MD5 challenge responses */ -static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlg64 = NULL; - char *rplyb64 = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - return CURLE_LOGIN_DENIED; - } - - /* Get the challenge message */ - pop3_get_message(data->state.buffer, &chlg64); - - /* Create the response message */ - result = Curl_sasl_create_digest_md5_message(data, chlg64, - conn->user, conn->passwd, - "pop", &rplyb64, &len); - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*"); - - if(!result) - state(conn, POP3_AUTH_CANCEL); - } - } - else { - /* Send the response */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64); - - if(!result) - state(conn, POP3_AUTH_DIGESTMD5_RESP); - } - - Curl_safefree(rplyb64); - - return result; -} - -/* For AUTH DIGEST-MD5 challenge-response responses */ -static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Authentication failed: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Send an empty response */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", ""); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - - return result; -} -#endif - -#ifdef USE_NTLM -/* For AUTH NTLM (without initial response) responses */ -static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *type1msg = NULL; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the type-1 message */ - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, - &type1msg, &len); - if(!result && type1msg) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type1msg); - - if(!result) - state(conn, POP3_AUTH_NTLM_TYPE2MSG); - } - } - - Curl_safefree(type1msg); - - return result; -} - -/* For NTLM type-2 responses (sent in reponse to our type-1 message) */ -static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *type2msg = NULL; - char *type3msg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the type-2 message */ - pop3_get_message(data->state.buffer, &type2msg); - - /* Decode the type-2 message */ - result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm); - if(result) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*"); - - if(!result) - state(conn, POP3_AUTH_CANCEL); - } - else { - /* Create the type-3 message */ - result = Curl_sasl_create_ntlm_type3_message(data, conn->user, - conn->passwd, &conn->ntlm, - &type3msg, &len); - if(!result && type3msg) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type3msg); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - } - } - - Curl_safefree(type3msg); - - return result; -} -#endif - -#if defined(USE_KERBEROS5) -/* For AUTH GSSAPI (without initial response) responses */ -static CURLcode pop3_state_auth_gssapi_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct pop3_conn *pop3c = &conn->proto.pop3c; - size_t len = 0; - char *respmsg = NULL; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the initial response message */ - result = Curl_sasl_create_gssapi_user_message(data, conn->user, - conn->passwd, "pop", - pop3c->sasl.mutual_auth, - NULL, &conn->krb5, - &respmsg, &len); - if(!result && respmsg) { - /* Send the message */ - result = Curl_pp_sendf(&pop3c->pp, "%s", respmsg); - - if(!result) - state(conn, POP3_AUTH_GSSAPI_TOKEN); - } - } - - Curl_safefree(respmsg); - - return result; -} - -/* For AUTH GSSAPI user token responses */ -static CURLcode pop3_state_auth_gssapi_token_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct pop3_conn *pop3c = &conn->proto.pop3c; - char *chlgmsg = NULL; - char *respmsg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the challenge message */ - pop3_get_message(data->state.buffer, &chlgmsg); - - if(pop3c->sasl.mutual_auth) - /* Decode the user token challenge and create the optional response - message */ - result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL, - pop3c->sasl.mutual_auth, - chlgmsg, &conn->krb5, - &respmsg, &len); - else - /* Decode the security challenge and create the response message */ - result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, - &conn->krb5, - &respmsg, &len); - - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&pop3c->pp, "%s", "*"); - - if(!result) - state(conn, POP3_AUTH_CANCEL); - } - } - else { - /* Send the response */ - if(respmsg) - result = Curl_pp_sendf(&pop3c->pp, "%s", respmsg); - else - result = Curl_pp_sendf(&pop3c->pp, "%s", ""); - - if(!result) - state(conn, (pop3c->sasl.mutual_auth ? POP3_AUTH_GSSAPI_NO_DATA : - POP3_AUTH_FINAL)); - } - } - - Curl_safefree(respmsg); - - return result; -} - -/* For AUTH GSSAPI no data responses */ -static CURLcode pop3_state_auth_gssapi_no_data_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlgmsg = NULL; - char *respmsg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the challenge message */ - pop3_get_message(data->state.buffer, &chlgmsg); - - /* Decode the security challenge and create the security message */ - result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, - &conn->krb5, - &respmsg, &len); - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*"); - - if(!result) - state(conn, POP3_AUTH_CANCEL); - } - } - else { - /* Send the response */ - if(respmsg) { - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", respmsg); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - } - } - - Curl_safefree(respmsg); - - return result; -} -#endif - -/* For AUTH XOAUTH2 (without initial response) responses */ -static CURLcode pop3_state_auth_xoauth2_resp(struct connectdata *conn, - int pop3code, pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *xoauth = NULL; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the authorisation message */ - result = Curl_sasl_create_xoauth2_message(conn->data, conn->user, - conn->xoauth2_bearer, - &xoauth, &len); - if(!result && xoauth) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", xoauth); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - } - - Curl_safefree(xoauth); - - return result; -} - -/* For AUTH cancellation responses */ -static CURLcode pop3_state_auth_cancel_resp(struct connectdata *conn, - int pop3code, - pop3state instate) +/* For SASL authentication responses */ +static CURLcode pop3_state_auth_resp(struct connectdata *conn, + int pop3code, + pop3state instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; struct pop3_conn *pop3c = &conn->proto.pop3c; - const char *mech = NULL; - char *initresp = NULL; - size_t len = 0; - pop3state state1 = POP3_STOP; - pop3state state2 = POP3_STOP; + saslprogress progress; - (void)pop3code; (void)instate; /* no use for this yet */ - /* Remove the offending mechanism from the supported list */ - pop3c->sasl.authmechs ^= pop3c->sasl.authused; - - /* Calculate alternative SASL login details */ - result = pop3_calc_sasl_details(conn, &mech, &initresp, &len, &state1, - &state2); - - if(!result) { - /* Do we have any mechanisms left or can we fallback to another - authentication type? */ - if(mech) { - /* Retry SASL based authentication */ - result = pop3_perform_auth(conn, mech, initresp, len, state1, state2); - - Curl_safefree(initresp); - } + result = Curl_sasl_continue(&pop3c->sasl, conn, pop3code, &progress); + if(!result) + switch(progress) { + case SASL_DONE: + state(conn, POP3_STOP); /* Authenticated */ + break; + case SASL_IDLE: /* No mechanism left after cancellation */ #ifndef CURL_DISABLE_CRYPTO_AUTH - else if((pop3c->authtypes & POP3_TYPE_APOP) && - (pop3c->preftype & POP3_TYPE_APOP)) - /* Perform APOP authentication */ - result = pop3_perform_apop(conn); + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) + /* Perform APOP authentication */ + result = pop3_perform_apop(conn); + else #endif - else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) && - (pop3c->preftype & POP3_TYPE_CLEARTEXT)) - /* Perform clear text authentication */ - result = pop3_perform_user(conn); - else { - failf(data, "Authentication cancelled"); - - result = CURLE_LOGIN_DENIED; + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) + /* Perform clear text authentication */ + result = pop3_perform_user(conn); + else { + failf(data, "Authentication cancelled"); + result = CURLE_LOGIN_DENIED; + } + break; + default: + break; } - } - - return result; -} - -/* For final responses in the AUTH sequence */ -static CURLcode pop3_state_auth_final_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Authentication failed: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else - /* End of connect phase */ - state(conn, POP3_STOP); return result; } @@ -1542,69 +1006,8 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_starttls_resp(conn, pop3code, pop3c->state); break; - case POP3_AUTH_PLAIN: - result = pop3_state_auth_plain_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_LOGIN: - result = pop3_state_auth_login_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_LOGIN_PASSWD: - result = pop3_state_auth_login_password_resp(conn, pop3code, - pop3c->state); - break; - -#ifndef CURL_DISABLE_CRYPTO_AUTH - case POP3_AUTH_CRAMMD5: - result = pop3_state_auth_cram_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_DIGESTMD5: - result = pop3_state_auth_digest_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_DIGESTMD5_RESP: - result = pop3_state_auth_digest_resp_resp(conn, pop3code, pop3c->state); - break; -#endif - -#ifdef USE_NTLM - case POP3_AUTH_NTLM: - result = pop3_state_auth_ntlm_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_NTLM_TYPE2MSG: - result = pop3_state_auth_ntlm_type2msg_resp(conn, pop3code, - pop3c->state); - break; -#endif - -#if defined(USE_KERBEROS5) - case POP3_AUTH_GSSAPI: - result = pop3_state_auth_gssapi_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_GSSAPI_TOKEN: - result = pop3_state_auth_gssapi_token_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_GSSAPI_NO_DATA: - result = pop3_state_auth_gssapi_no_data_resp(conn, pop3code, - pop3c->state); - break; -#endif - - case POP3_AUTH_XOAUTH2: - result = pop3_state_auth_xoauth2_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_CANCEL: - result = pop3_state_auth_cancel_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_FINAL: - result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state); + case POP3_AUTH: + result = pop3_state_auth_resp(conn, pop3code, pop3c->state); break; #ifndef CURL_DISABLE_CRYPTO_AUTH @@ -1717,7 +1120,7 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done) /* Set the default preferred authentication type and mechanism */ pop3c->preftype = POP3_TYPE_ANY; - Curl_sasl_init(&pop3c->sasl); + Curl_sasl_init(&pop3c->sasl, &saslpop3); /* Initialise the pingpong layer */ Curl_pp_init(pp); @@ -2072,110 +1475,6 @@ static CURLcode pop3_parse_custom_request(struct connectdata *conn) /*********************************************************************** * - * pop3_calc_sasl_details() - * - * Calculate the required login details for SASL authentication. - */ -static CURLcode pop3_calc_sasl_details(struct connectdata *conn, - const char **mech, - char **initresp, size_t *len, - pop3state *state1, pop3state *state2) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct pop3_conn *pop3c = &conn->proto.pop3c; - - /* Calculate the supported authentication mechanism, by decreasing order of - security, as well as the initial response where appropriate */ -#if defined(USE_KERBEROS5) - if((pop3c->sasl.authmechs & SASL_MECH_GSSAPI) && - (pop3c->sasl.prefmech & SASL_MECH_GSSAPI)) { - pop3c->sasl.mutual_auth = FALSE; /* TODO: Calculate mutual auth. */ - - *mech = SASL_MECH_STRING_GSSAPI; - *state1 = POP3_AUTH_GSSAPI; - *state2 = POP3_AUTH_GSSAPI_TOKEN; - pop3c->sasl.authused = SASL_MECH_GSSAPI; - - if(data->set.sasl_ir) - result = Curl_sasl_create_gssapi_user_message(data, conn->user, - conn->passwd, "pop", - pop3c->sasl.mutual_auth, - NULL, &conn->krb5, - initresp, len); - } - else -#endif -#ifndef CURL_DISABLE_CRYPTO_AUTH - if((pop3c->sasl.authmechs & SASL_MECH_DIGEST_MD5) && - (pop3c->sasl.prefmech & SASL_MECH_DIGEST_MD5)) { - *mech = SASL_MECH_STRING_DIGEST_MD5; - *state1 = POP3_AUTH_DIGESTMD5; - pop3c->sasl.authused = SASL_MECH_DIGEST_MD5; - } - else if((pop3c->sasl.authmechs & SASL_MECH_CRAM_MD5) && - (pop3c->sasl.prefmech & SASL_MECH_CRAM_MD5)) { - *mech = SASL_MECH_STRING_CRAM_MD5; - *state1 = POP3_AUTH_CRAMMD5; - pop3c->sasl.authused = SASL_MECH_CRAM_MD5; - } - else -#endif -#ifdef USE_NTLM - if((pop3c->sasl.authmechs & SASL_MECH_NTLM) && - (pop3c->sasl.prefmech & SASL_MECH_NTLM)) { - *mech = SASL_MECH_STRING_NTLM; - *state1 = POP3_AUTH_NTLM; - *state2 = POP3_AUTH_NTLM_TYPE2MSG; - pop3c->sasl.authused = SASL_MECH_NTLM; - - if(data->set.sasl_ir) - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, - initresp, len); - } - else -#endif - if(((pop3c->sasl.authmechs & SASL_MECH_XOAUTH2) && - (pop3c->sasl.prefmech & SASL_MECH_XOAUTH2) && - (pop3c->sasl.prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) { - *mech = SASL_MECH_STRING_XOAUTH2; - *state1 = POP3_AUTH_XOAUTH2; - *state2 = POP3_AUTH_FINAL; - pop3c->sasl.authused = SASL_MECH_XOAUTH2; - - if(data->set.sasl_ir) - result = Curl_sasl_create_xoauth2_message(data, conn->user, - conn->xoauth2_bearer, - initresp, len); - } - else if((pop3c->sasl.authmechs & SASL_MECH_LOGIN) && - (pop3c->sasl.prefmech & SASL_MECH_LOGIN)) { - *mech = SASL_MECH_STRING_LOGIN; - *state1 = POP3_AUTH_LOGIN; - *state2 = POP3_AUTH_LOGIN_PASSWD; - pop3c->sasl.authused = SASL_MECH_LOGIN; - - if(data->set.sasl_ir) - result = Curl_sasl_create_login_message(data, conn->user, initresp, len); - } - else if((pop3c->sasl.authmechs & SASL_MECH_PLAIN) && - (pop3c->sasl.prefmech & SASL_MECH_PLAIN)) { - *mech = SASL_MECH_STRING_PLAIN; - *state1 = POP3_AUTH_PLAIN; - *state2 = POP3_AUTH_FINAL; - pop3c->sasl.authused = SASL_MECH_PLAIN; - - if(data->set.sasl_ir) - result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, - initresp, len); - } - - return result; -} - -/*********************************************************************** - * * Curl_pop3_write() * * This function scans the body after the end-of-body and writes everything diff --git a/lib/pop3.h b/lib/pop3.h index 0cb5852d8..7bc53aaf5 100644 --- a/lib/pop3.h +++ b/lib/pop3.h @@ -36,20 +36,7 @@ typedef enum { POP3_STARTTLS, POP3_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS (multi mode only) */ - POP3_AUTH_PLAIN, - POP3_AUTH_LOGIN, - POP3_AUTH_LOGIN_PASSWD, - POP3_AUTH_CRAMMD5, - POP3_AUTH_DIGESTMD5, - POP3_AUTH_DIGESTMD5_RESP, - POP3_AUTH_NTLM, - POP3_AUTH_NTLM_TYPE2MSG, - POP3_AUTH_GSSAPI, - POP3_AUTH_GSSAPI_TOKEN, - POP3_AUTH_GSSAPI_NO_DATA, - POP3_AUTH_XOAUTH2, - POP3_AUTH_CANCEL, - POP3_AUTH_FINAL, + POP3_AUTH, POP3_APOP, POP3_USER, POP3_PASS, diff --git a/lib/smtp.c b/lib/smtp.c index e5ddedb02..ca1ab2cec 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -105,10 +105,10 @@ static CURLcode smtp_setup_connection(struct connectdata *conn); static CURLcode smtp_parse_url_options(struct connectdata *conn); static CURLcode smtp_parse_url_path(struct connectdata *conn); static CURLcode smtp_parse_custom_request(struct connectdata *conn); -static CURLcode smtp_calc_sasl_details(struct connectdata *conn, - const char **mech, - char **initresp, size_t *len, - smtpstate *state1, smtpstate *state2); +static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech, + const char *initresp); +static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp); +static void smtp_get_message(char *buffer, char** outptr); /* * SMTP protocol handler. @@ -213,6 +213,17 @@ static const struct Curl_handler Curl_handler_smtps_proxy = { #endif #endif +/* SASL parameters for the smtp protocol */ +static const struct SASLproto saslsmtp = { + "smtp", /* The service name */ + 334, /* Code received when continuation is expected */ + 235, /* Code to receive upon authentication success */ + 512 - 8, /* Maximum initial response length (no max) */ + smtp_perform_auth, /* Send authentication command */ + smtp_continue_auth, /* Send authentication continuation */ + smtp_get_message /* Get SASL response message */ +}; + #ifdef USE_SSL static void smtp_to_smtps(struct connectdata *conn) { @@ -309,20 +320,7 @@ static void state(struct connectdata *conn, smtpstate newstate) "HELO", "STARTTLS", "UPGRADETLS", - "AUTH_PLAIN", - "AUTH_LOGIN", - "AUTH_LOGIN_PASSWD", - "AUTH_CRAMMD5", - "AUTH_DIGESTMD5", - "AUTH_DIGESTMD5_RESP", - "AUTH_NTLM", - "AUTH_NTLM_TYPE2MSG", - "AUTH_GSSAPI", - "AUTH_GSSAPI_TOKEN", - "AUTH_GSSAPI_NO_DATA", - "AUTH_XOAUTH2", - "AUTH_CANCEL", - "AUTH_FINAL", + "AUTH", "COMMAND", "MAIL", "RCPT", @@ -445,25 +443,18 @@ static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn) */ static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech, - const char *initresp, size_t len, - smtpstate state1, smtpstate state2) + const char *initresp) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; - if(initresp && 8 + strlen(mech) + len <= 512) { /* AUTH <mech> ...<crlf> */ + if(initresp) { /* AUTH <mech> ...<crlf> */ /* Send the AUTH command with the initial response */ result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp); - - if(!result) - state(conn, state2); } else { /* Send the AUTH command */ result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech); - - if(!result) - state(conn, state1); } return result; @@ -471,6 +462,19 @@ static CURLcode smtp_perform_auth(struct connectdata *conn, /*********************************************************************** * + * smtp_continue_auth() + * + * Sends SASL continuation data or cancellation. + */ +static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp) +{ + struct smtp_conn *smtpc = &conn->proto.smtpc; + + return Curl_pp_sendf(&smtpc->pp, "%s", resp); +} + +/*********************************************************************** + * * smtp_perform_authentication() * * Initiates the authentication sequence, with the appropriate SASL @@ -480,31 +484,21 @@ static CURLcode smtp_perform_authentication(struct connectdata *conn) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; - const char *mech = NULL; - char *initresp = NULL; - size_t len = 0; - smtpstate state1 = SMTP_STOP; - smtpstate state2 = SMTP_STOP; + saslprogress progress; /* Check we have a username and password to authenticate with, and the server supports authentiation, and end the connect phase if not */ if(!conn->bits.user_passwd || !smtpc->auth_supported) { state(conn, SMTP_STOP); - return result; } /* Calculate the SASL login details */ - result = smtp_calc_sasl_details(conn, &mech, &initresp, &len, &state1, - &state2); + result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress); if(!result) { - if(mech) { - /* Perform SASL based authentication */ - result = smtp_perform_auth(conn, mech, initresp, len, state1, state2); - - Curl_safefree(initresp); - } + if(progress == SASL_INPROGRESS) + state(conn, SMTP_AUTH); else { /* Other mechanisms not supported */ infof(conn->data, "No known authentication mechanisms supported!\n"); @@ -825,566 +819,31 @@ static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode, return result; } -/* For AUTH PLAIN (without initial response) responses */ -static CURLcode smtp_state_auth_plain_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *plainauth = NULL; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the authorisation message */ - result = Curl_sasl_create_plain_message(conn->data, conn->user, - conn->passwd, &plainauth, &len); - if(!result && plainauth) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth); - - if(!result) - state(conn, SMTP_AUTH_FINAL); - } - } - - Curl_safefree(plainauth); - - return result; -} - -/* For AUTH LOGIN (without initial response) responses */ -static CURLcode smtp_state_auth_login_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *authuser = NULL; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the user message */ - result = Curl_sasl_create_login_message(conn->data, conn->user, - &authuser, &len); - if(!result && authuser) { - /* Send the user */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser); - - if(!result) - state(conn, SMTP_AUTH_LOGIN_PASSWD); - } - } - - Curl_safefree(authuser); - - return result; -} - -/* For AUTH LOGIN user entry responses */ -static CURLcode smtp_state_auth_login_password_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *authpasswd = NULL; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the password message */ - result = Curl_sasl_create_login_message(conn->data, conn->passwd, - &authpasswd, &len); - if(!result && authpasswd) { - /* Send the password */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd); - - if(!result) - state(conn, SMTP_AUTH_FINAL); - } - } - - Curl_safefree(authpasswd); - - return result; -} - -#ifndef CURL_DISABLE_CRYPTO_AUTH -/* For AUTH CRAM-MD5 responses */ -static CURLcode smtp_state_auth_cram_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlg = NULL; - char *chlg64 = NULL; - char *rplyb64 = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - return CURLE_LOGIN_DENIED; - } - - /* Get the challenge message */ - smtp_get_message(data->state.buffer, &chlg64); - - /* Decode the challenge message */ - result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len); - if(result) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*"); - - if(!result) - state(conn, SMTP_AUTH_CANCEL); - } - else { - /* Create the response message */ - result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user, - conn->passwd, &rplyb64, &len); - if(!result && rplyb64) { - /* Send the response */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64); - - if(!result) - state(conn, SMTP_AUTH_FINAL); - } - } - - Curl_safefree(chlg); - Curl_safefree(rplyb64); - - return result; -} - -/* For AUTH DIGEST-MD5 challenge responses */ -static CURLcode smtp_state_auth_digest_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlg64 = NULL; - char *rplyb64 = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - return CURLE_LOGIN_DENIED; - } - - /* Get the challenge message */ - smtp_get_message(data->state.buffer, &chlg64); - - /* Create the response message */ - result = Curl_sasl_create_digest_md5_message(data, chlg64, - conn->user, conn->passwd, - "smtp", &rplyb64, &len); - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*"); - - if(!result) - state(conn, SMTP_AUTH_CANCEL); - } - } - else { - /* Send the response */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64); - - if(!result) - state(conn, SMTP_AUTH_DIGESTMD5_RESP); - } - - Curl_safefree(rplyb64); - - return result; -} - -/* For AUTH DIGEST-MD5 challenge-response responses */ -static CURLcode smtp_state_auth_digest_resp_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Authentication failed: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Send an empty response */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", ""); - - if(!result) - state(conn, SMTP_AUTH_FINAL); - } - - return result; -} - -#endif - -#ifdef USE_NTLM -/* For AUTH NTLM (without initial response) responses */ -static CURLcode smtp_state_auth_ntlm_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *type1msg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the type-1 message */ - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, - &type1msg, &len); - if(!result && type1msg) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type1msg); - - if(!result) - state(conn, SMTP_AUTH_NTLM_TYPE2MSG); - } - } - - Curl_safefree(type1msg); - - return result; -} - -/* For NTLM type-2 responses (sent in reponse to our type-1 message) */ -static CURLcode smtp_state_auth_ntlm_type2msg_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *type2msg = NULL; - char *type3msg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the type-2 message */ - smtp_get_message(data->state.buffer, &type2msg); - - /* Decode the type-2 message */ - result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm); - if(result) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*"); - - if(!result) - state(conn, SMTP_AUTH_CANCEL); - } - else { - /* Create the type-3 message */ - result = Curl_sasl_create_ntlm_type3_message(data, conn->user, - conn->passwd, &conn->ntlm, - &type3msg, &len); - if(!result && type3msg) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type3msg); - - if(!result) - state(conn, SMTP_AUTH_FINAL); - } - } - } - - Curl_safefree(type3msg); - - return result; -} -#endif - -#if defined(USE_KERBEROS5) -/* For AUTH GSSAPI (without initial response) responses */ -static CURLcode smtp_state_auth_gssapi_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct smtp_conn *smtpc = &conn->proto.smtpc; - char *respmsg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the initial response message */ - result = Curl_sasl_create_gssapi_user_message(data, conn->user, - conn->passwd, "smtp", - smtpc->sasl.mutual_auth, - NULL, - &conn->krb5, - &respmsg, &len); - if(!result && respmsg) { - /* Send the message */ - result = Curl_pp_sendf(&smtpc->pp, "%s", respmsg); - - if(!result) - state(conn, SMTP_AUTH_GSSAPI_TOKEN); - } - } - - Curl_safefree(respmsg); - - return result; -} - -/* For AUTH GSSAPI user token responses */ -static CURLcode smtp_state_auth_gssapi_token_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct smtp_conn *smtpc = &conn->proto.smtpc; - char *chlgmsg = NULL; - char *respmsg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the challenge message */ - smtp_get_message(data->state.buffer, &chlgmsg); - - if(smtpc->sasl.mutual_auth) - /* Decode the user token challenge and create the optional response - message */ - result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL, - smtpc->sasl.mutual_auth, - chlgmsg, &conn->krb5, - &respmsg, &len); - else - /* Decode the security challenge and create the response message */ - result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, - &conn->krb5, - &respmsg, &len); - - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&smtpc->pp, "%s", "*"); - - if(!result) - state(conn, SMTP_AUTH_CANCEL); - } - } - else { - /* Send the response */ - if(respmsg) - result = Curl_pp_sendf(&smtpc->pp, "%s", respmsg); - else - result = Curl_pp_sendf(&smtpc->pp, "%s", ""); - - if(!result) - state(conn, (smtpc->sasl.mutual_auth ? SMTP_AUTH_GSSAPI_NO_DATA : - SMTP_AUTH_FINAL)); - } - } - - Curl_safefree(respmsg); - - return result; -} - -/* For AUTH GSSAPI no data responses */ -static CURLcode smtp_state_auth_gssapi_no_data_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlgmsg = NULL; - char *respmsg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the challenge message */ - smtp_get_message(data->state.buffer, &chlgmsg); - - /* Decode the security challenge and create the response message */ - result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, - &conn->krb5, - &respmsg, &len); - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*"); - - if(!result) - state(conn, SMTP_AUTH_CANCEL); - } - } - else { - /* Send the response */ - if(respmsg) { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", respmsg); - - if(!result) - state(conn, SMTP_AUTH_FINAL); - } - } - } - - Curl_safefree(respmsg); - - return result; -} -#endif - -/* For AUTH XOAUTH2 (without initial response) responses */ -static CURLcode smtp_state_auth_xoauth2_resp(struct connectdata *conn, - int smtpcode, smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *xoauth = NULL; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the authorisation message */ - result = Curl_sasl_create_xoauth2_message(conn->data, conn->user, - conn->xoauth2_bearer, - &xoauth, &len); - if(!result && xoauth) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", xoauth); - - if(!result) - state(conn, SMTP_AUTH_FINAL); - } - } - - Curl_safefree(xoauth); - - return result; -} - -/* For AUTH cancellation responses */ -static CURLcode smtp_state_auth_cancel_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) +/* For SASL authentication responses */ +static CURLcode smtp_state_auth_resp(struct connectdata *conn, + int smtpcode, + smtpstate instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; struct smtp_conn *smtpc = &conn->proto.smtpc; - const char *mech = NULL; - char *initresp = NULL; - size_t len = 0; - smtpstate state1 = SMTP_STOP; - smtpstate state2 = SMTP_STOP; + saslprogress progress; - (void)smtpcode; (void)instate; /* no use for this yet */ - /* Remove the offending mechanism from the supported list */ - smtpc->sasl.authmechs ^= smtpc->sasl.authused; - - /* Calculate alternative SASL login details */ - result = smtp_calc_sasl_details(conn, &mech, &initresp, &len, &state1, - &state2); - - if(!result) { - /* Do we have any mechanisms left? */ - if(mech) { - /* Retry SASL based authentication */ - result = smtp_perform_auth(conn, mech, initresp, len, state1, state2); - - Curl_safefree(initresp); - } - else { + result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress); + if(!result) + switch(progress) { + case SASL_DONE: + state(conn, SMTP_STOP); /* Authenticated */ + break; + case SASL_IDLE: /* No mechanism left after cancellation */ failf(data, "Authentication cancelled"); - result = CURLE_LOGIN_DENIED; + break; + default: + break; } - } - - return result; -} - -/* For final responses in the AUTH sequence */ -static CURLcode smtp_state_auth_final_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 235) { - failf(data, "Authentication failed: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else - /* End of connect phase */ - state(conn, SMTP_STOP); return result; } @@ -1582,69 +1041,8 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state); break; - case SMTP_AUTH_PLAIN: - result = smtp_state_auth_plain_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_LOGIN: - result = smtp_state_auth_login_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_LOGIN_PASSWD: - result = smtp_state_auth_login_password_resp(conn, smtpcode, - smtpc->state); - break; - -#ifndef CURL_DISABLE_CRYPTO_AUTH - case SMTP_AUTH_CRAMMD5: - result = smtp_state_auth_cram_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_DIGESTMD5: - result = smtp_state_auth_digest_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_DIGESTMD5_RESP: - result = smtp_state_auth_digest_resp_resp(conn, smtpcode, smtpc->state); - break; -#endif - -#ifdef USE_NTLM - case SMTP_AUTH_NTLM: - result = smtp_state_auth_ntlm_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_NTLM_TYPE2MSG: - result = smtp_state_auth_ntlm_type2msg_resp(conn, smtpcode, - smtpc->state); - break; -#endif - -#if defined(USE_KERBEROS5) - case SMTP_AUTH_GSSAPI: - result = smtp_state_auth_gssapi_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_GSSAPI_TOKEN: - result = smtp_state_auth_gssapi_token_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_GSSAPI_NO_DATA: - result = smtp_state_auth_gssapi_no_data_resp(conn, smtpcode, - smtpc->state); - break; -#endif - - case SMTP_AUTH_XOAUTH2: - result = smtp_state_auth_xoauth2_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_CANCEL: - result = smtp_state_auth_cancel_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_FINAL: - result = smtp_state_auth_final_resp(conn, smtpcode, smtpc->state); + case SMTP_AUTH: + result = smtp_state_auth_resp(conn, smtpcode, smtpc->state); break; case SMTP_COMMAND: @@ -1758,7 +1156,7 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done) pp->conn = conn; /* Initialize the SASL storage */ - Curl_sasl_init(&smtpc->sasl); + Curl_sasl_init(&smtpc->sasl, &saslsmtp); /* Initialise the pingpong layer */ Curl_pp_init(pp); @@ -2172,110 +1570,6 @@ static CURLcode smtp_parse_custom_request(struct connectdata *conn) return result; } -/*********************************************************************** - * - * smtp_calc_sasl_details() - * - * Calculate the required login details for SASL authentication. - */ -static CURLcode smtp_calc_sasl_details(struct connectdata *conn, - const char **mech, - char **initresp, size_t *len, - smtpstate *state1, smtpstate *state2) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct smtp_conn *smtpc = &conn->proto.smtpc; - - /* Calculate the supported authentication mechanism, by decreasing order of - security, as well as the initial response where appropriate */ -#if defined(USE_KERBEROS5) - if((smtpc->sasl.authmechs & SASL_MECH_GSSAPI) && - (smtpc->sasl.prefmech & SASL_MECH_GSSAPI)) { - smtpc->sasl.mutual_auth = FALSE; /* TODO: Calculate mutual auth. */ - - *mech = SASL_MECH_STRING_GSSAPI; - *state1 = SMTP_AUTH_GSSAPI; - *state2 = SMTP_AUTH_GSSAPI_TOKEN; - smtpc->sasl.authused = SASL_MECH_GSSAPI; - - if(data->set.sasl_ir) - result = Curl_sasl_create_gssapi_user_message(data, conn->user, - conn->passwd, "smtp", - smtpc->sasl.mutual_auth, - NULL, &conn->krb5, - initresp, len); - } - else -#endif -#ifndef CURL_DISABLE_CRYPTO_AUTH - if((smtpc->sasl.authmechs & SASL_MECH_DIGEST_MD5) && - (smtpc->sasl.prefmech & SASL_MECH_DIGEST_MD5)) { - *mech = SASL_MECH_STRING_DIGEST_MD5; - *state1 = SMTP_AUTH_DIGESTMD5; - smtpc->sasl.authused = SASL_MECH_DIGEST_MD5; - } - else if((smtpc->sasl.authmechs & SASL_MECH_CRAM_MD5) && - (smtpc->sasl.prefmech & SASL_MECH_CRAM_MD5)) { - *mech = SASL_MECH_STRING_CRAM_MD5; - *state1 = SMTP_AUTH_CRAMMD5; - smtpc->sasl.authused = SASL_MECH_CRAM_MD5; - } - else -#endif -#ifdef USE_NTLM - if((smtpc->sasl.authmechs & SASL_MECH_NTLM) && - (smtpc->sasl.prefmech & SASL_MECH_NTLM)) { - *mech = SASL_MECH_STRING_NTLM; - *state1 = SMTP_AUTH_NTLM; - *state2 = SMTP_AUTH_NTLM_TYPE2MSG; - smtpc->sasl.authused = SASL_MECH_NTLM; - - if(data->set.sasl_ir) - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, - initresp, len); - } - else -#endif - if(((smtpc->sasl.authmechs & SASL_MECH_XOAUTH2) && - (smtpc->sasl.prefmech & SASL_MECH_XOAUTH2) && - (smtpc->sasl.prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) { - *mech = SASL_MECH_STRING_XOAUTH2; - *state1 = SMTP_AUTH_XOAUTH2; - *state2 = SMTP_AUTH_FINAL; - smtpc->sasl.authused = SASL_MECH_XOAUTH2; - - if(data->set.sasl_ir) - result = Curl_sasl_create_xoauth2_message(data, conn->user, - conn->xoauth2_bearer, - initresp, len); - } - else if((smtpc->sasl.authmechs & SASL_MECH_LOGIN) && - (smtpc->sasl.prefmech & SASL_MECH_LOGIN)) { - *mech = SASL_MECH_STRING_LOGIN; - *state1 = SMTP_AUTH_LOGIN; - *state2 = SMTP_AUTH_LOGIN_PASSWD; - smtpc->sasl.authused = SASL_MECH_LOGIN; - - if(data->set.sasl_ir) - result = Curl_sasl_create_login_message(data, conn->user, initresp, len); - } - else if((smtpc->sasl.authmechs & SASL_MECH_PLAIN) && - (smtpc->sasl.prefmech & SASL_MECH_PLAIN)) { - *mech = SASL_MECH_STRING_PLAIN; - *state1 = SMTP_AUTH_PLAIN; - *state2 = SMTP_AUTH_FINAL; - smtpc->sasl.authused = SASL_MECH_PLAIN; - - if(data->set.sasl_ir) - result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, - initresp, len); - } - - return result; -} - CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread) { /* When sending a SMTP payload we must detect CRLF. sequences making sure diff --git a/lib/smtp.h b/lib/smtp.h index a237d3e5c..9fbe0c5bf 100644 --- a/lib/smtp.h +++ b/lib/smtp.h @@ -37,20 +37,7 @@ typedef enum { SMTP_STARTTLS, SMTP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS (multi mode only) */ - SMTP_AUTH_PLAIN, - SMTP_AUTH_LOGIN, - SMTP_AUTH_LOGIN_PASSWD, - SMTP_AUTH_CRAMMD5, - SMTP_AUTH_DIGESTMD5, - SMTP_AUTH_DIGESTMD5_RESP, - SMTP_AUTH_NTLM, - SMTP_AUTH_NTLM_TYPE2MSG, - SMTP_AUTH_GSSAPI, - SMTP_AUTH_GSSAPI_TOKEN, - SMTP_AUTH_GSSAPI_NO_DATA, - SMTP_AUTH_XOAUTH2, - SMTP_AUTH_CANCEL, - SMTP_AUTH_FINAL, + SMTP_AUTH, SMTP_COMMAND, /* VRFY, EXPN, NOOP, RSET and HELP */ SMTP_MAIL, /* MAIL FROM */ SMTP_RCPT, /* RCPT TO */ |