SASL: common state engine for imap/pop3/smtp

This commit is contained in:
Patrick Monnerat 2015-01-20 17:33:05 +01:00
parent e1ea18f90e
commit 79543caf90
8 changed files with 577 additions and 2352 deletions

View File

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

View File

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

View File

@ -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,29 +568,36 @@ 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;
}
/***********************************************************************
*
* 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()
@ -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)
/* 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;
size_t len = 0;
char *respmsg = NULL;
saslprogress progress;
(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)
{
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;
(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);
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;
}
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);
}
}
}
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 */

View File

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

View File

@ -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,30 +498,37 @@ 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;
}
/***********************************************************************
*
* 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()
@ -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)
/* 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;
size_t len = 0;
char *plainauth = NULL;
struct pop3_conn *pop3c = &conn->proto.pop3c;
saslprogress progress;
(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;
}
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
/* 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);
if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
/* Perform APOP authentication */
result = pop3_perform_apop(conn);
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);
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;
}
}
Curl_safefree(xoauth);
return result;
}
/* For AUTH cancellation responses */
static CURLcode pop3_state_auth_cancel_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;
(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);
}
#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);
#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;
}
}
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);
@ -2070,110 +1473,6 @@ static CURLcode pop3_parse_custom_request(struct connectdata *conn)
return result;
}
/***********************************************************************
*
* 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()

View File

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

View File

@ -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,30 +443,36 @@ 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;
}
/***********************************************************************
*
* 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()
@ -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)
/* 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;
char *respmsg = NULL;
size_t len = 0;
saslprogress progress;
(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)
{
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;
(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

View File

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