SASL: common state engine for imap/pop3/smtp
This commit is contained in:
parent
e1ea18f90e
commit
79543caf90
331
lib/curl_sasl.c
331
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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
822
lib/imap.c
822
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,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,573 +964,40 @@ 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,
|
||||
/* 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);
|
||||
|
||||
result = Curl_sasl_continue(&imapc->sasl, conn, imapcode, &progress);
|
||||
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);
|
||||
}
|
||||
}
|
||||
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))
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* For LOGIN responses */
|
||||
static CURLcode imap_state_login_resp(struct connectdata *conn,
|
||||
int imapcode,
|
||||
@ -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 */
|
||||
|
15
lib/imap.h
15
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,
|
||||
|
825
lib/pop3.c
825
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,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;
|
||||
}
|
||||
|
||||
if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) {
|
||||
/* Calculate the SASL login details */
|
||||
if(pop3c->authtypes & POP3_TYPE_SASL)
|
||||
result = pop3_calc_sasl_details(conn, &mech, &initresp, &len, &state1,
|
||||
&state2);
|
||||
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,579 +804,46 @@ 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,
|
||||
/* 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);
|
||||
|
||||
result = Curl_sasl_continue(&pop3c->sasl, conn, pop3code, &progress);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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))
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_CRYPTO_AUTH
|
||||
/* For APOP responses */
|
||||
static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code,
|
||||
@ -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()
|
||||
|
15
lib/pop3.h
15
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,
|
||||
|
806
lib/smtp.c
806
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,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,
|
||||
/* 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);
|
||||
|
||||
result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress);
|
||||
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 {
|
||||
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
|
||||
|
15
lib/smtp.h
15
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 */
|
||||
|
Loading…
Reference in New Issue
Block a user