sasl: binary messages

Capabilities of sasl module are extended to exchange messages in binary
as an alternative to base64.

If http authentication flags have been set, those are used as sasl
default preferred mechanisms.

Closes #6930
This commit is contained in:
Patrick Monnerat 2021-10-02 18:05:26 +02:00 committed by Daniel Stenberg
parent e12dc2dd97
commit 3e2c1dcda8
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
6 changed files with 305 additions and 231 deletions

View File

@ -133,7 +133,6 @@
16. SASL 16. SASL
16.1 Other authentication mechanisms 16.1 Other authentication mechanisms
16.2 Add QOP support to GSSAPI authentication 16.2 Add QOP support to GSSAPI authentication
16.3 Support binary messages (i.e.: non-base64)
17. SSH protocols 17. SSH protocols
17.1 Multiplexing 17.1 Multiplexing
@ -902,10 +901,6 @@
with integrity protection) and auth-conf (Authentication with integrity and with integrity protection) and auth-conf (Authentication with integrity and
privacy protection). privacy protection).
16.3 Support binary messages (i.e.: non-base64)
Mandatory to support LDAP SASL authentication.
17. SSH protocols 17. SSH protocols

View File

@ -56,8 +56,8 @@
/* Supported mechanisms */ /* Supported mechanisms */
static const struct { static const struct {
const char *name; /* Name */ const char *name; /* Name */
size_t len; /* Name length */ size_t len; /* Name length */
unsigned short bit; /* Flag bit */ unsigned short bit; /* Flag bit */
} mechtable[] = { } mechtable[] = {
{ "LOGIN", 5, SASL_MECH_LOGIN }, { "LOGIN", 5, SASL_MECH_LOGIN },
@ -85,8 +85,11 @@ static const struct {
* conn [in] - The connection data. * conn [in] - The connection data.
* authused [in] - The authentication mechanism used. * authused [in] - The authentication mechanism used.
*/ */
void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused) void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused)
{ {
(void)conn;
(void)authused;
#if defined(USE_KERBEROS5) #if defined(USE_KERBEROS5)
/* Cleanup the gssapi structure */ /* Cleanup the gssapi structure */
if(authused == SASL_MECH_GSSAPI) { if(authused == SASL_MECH_GSSAPI) {
@ -107,12 +110,6 @@ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
Curl_auth_cleanup_ntlm(&conn->ntlm); Curl_auth_cleanup_ntlm(&conn->ntlm);
} }
#endif #endif
#if !defined(USE_KERBEROS5) && !defined(USE_NTLM)
/* Reserved for future use */
(void)conn;
(void)authused;
#endif
} }
/* /*
@ -189,16 +186,35 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
* *
* Initializes the SASL structure. * Initializes the SASL structure.
*/ */
void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params) void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
const struct SASLproto *params)
{ {
unsigned long auth = data->set.httpauth;
sasl->params = params; /* Set protocol dependent parameters */ sasl->params = params; /* Set protocol dependent parameters */
sasl->state = SASL_STOP; /* Not yet running */ sasl->state = SASL_STOP; /* Not yet running */
sasl->curmech = NULL; /* No mechanism yet. */
sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */ sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */
sasl->prefmech = SASL_AUTH_DEFAULT; /* Prefer all mechanisms */ sasl->prefmech = params->defmechs; /* Default preferred mechanisms */
sasl->authused = SASL_AUTH_NONE; /* No the authentication mechanism used */ sasl->authused = SASL_AUTH_NONE; /* The authentication mechanism used */
sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */ sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */
sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */ sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */
sasl->force_ir = FALSE; /* Respect external option */ sasl->force_ir = FALSE; /* Respect external option */
if(auth != CURLAUTH_BASIC) {
sasl->resetprefs = FALSE;
sasl->prefmech = SASL_AUTH_NONE;
if(auth & CURLAUTH_BASIC)
sasl->prefmech |= SASL_MECH_PLAIN | SASL_MECH_LOGIN;
if(auth & CURLAUTH_DIGEST)
sasl->prefmech |= SASL_MECH_DIGEST_MD5;
if(auth & CURLAUTH_NTLM)
sasl->prefmech |= SASL_MECH_NTLM;
if(auth & CURLAUTH_BEARER)
sasl->prefmech |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2;
if(auth & CURLAUTH_GSSAPI)
sasl->prefmech |= SASL_MECH_GSSAPI;
}
} }
/* /*
@ -247,40 +263,45 @@ static void state(struct SASL *sasl, struct Curl_easy *data,
static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data, static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
struct bufref *out) struct bufref *out)
{ {
unsigned char *msg;
size_t msglen;
char *serverdata = NULL;
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
sasl->params->getmessage(data->state.buffer, &serverdata); result = sasl->params->getmessage(data, out);
if(!serverdata) if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) {
result = CURLE_BAD_CONTENT_ENCODING; unsigned char *msg;
else if(!*serverdata || *serverdata == '=') size_t msglen;
Curl_bufref_set(out, NULL, 0, NULL); const char *serverdata = (const char *) Curl_bufref_ptr(out);
else {
result = Curl_base64_decode(serverdata, &msg, &msglen); if(!*serverdata || *serverdata == '=')
if(!result) Curl_bufref_set(out, NULL, 0, NULL);
Curl_bufref_set(out, msg, msglen, curl_free); else {
result = Curl_base64_decode(serverdata, &msg, &msglen);
if(!result)
Curl_bufref_set(out, msg, msglen, curl_free);
}
} }
return result; return result;
} }
/* Encode the outgoing SASL message. */ /* Encode the outgoing SASL message. */
static CURLcode build_message(struct Curl_easy *data, struct bufref *msg) static CURLcode build_message(struct SASL *sasl, struct Curl_easy *data,
struct bufref *msg)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
char *base64;
size_t base64len;
if(!Curl_bufref_ptr(msg)) /* Empty message. */ if(sasl->params->flags & SASL_FLAG_BASE64) {
Curl_bufref_set(msg, "", 0, NULL); if(!Curl_bufref_ptr(msg)) /* Empty message. */
else if(!Curl_bufref_len(msg)) /* Explicit empty response. */ Curl_bufref_set(msg, "", 0, NULL);
Curl_bufref_set(msg, "=", 1, NULL); else if(!Curl_bufref_len(msg)) /* Explicit empty response. */
else { Curl_bufref_set(msg, "=", 1, NULL);
result = Curl_base64_encode(data, (const char *) Curl_bufref_ptr(msg), else {
Curl_bufref_len(msg), &base64, &base64len); char *base64;
if(!result) size_t base64len;
Curl_bufref_set(msg, base64, base64len, curl_free);
result = Curl_base64_encode(data, (const char *) Curl_bufref_ptr(msg),
Curl_bufref_len(msg), &base64, &base64len);
if(!result)
Curl_bufref_set(msg, base64, base64len, curl_free);
}
} }
return result; return result;
@ -310,11 +331,11 @@ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn)
* Calculate the required login details for SASL authentication. * Calculate the required login details for SASL authentication.
*/ */
CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
struct connectdata *conn,
bool force_ir, saslprogress *progress) bool force_ir, saslprogress *progress)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
unsigned int enabledmechs; struct connectdata *conn = data->conn;
unsigned short enabledmechs;
const char *mech = NULL; const char *mech = NULL;
struct bufref resp; struct bufref resp;
saslstate state1 = SASL_STOP; saslstate state1 = SASL_STOP;
@ -471,16 +492,16 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
} }
if(!result && mech) { if(!result && mech) {
sasl->curmech = mech;
if(Curl_bufref_ptr(&resp)) if(Curl_bufref_ptr(&resp))
result = build_message(data, &resp); result = build_message(sasl, data, &resp);
if(sasl->params->maxirlen && if(sasl->params->maxirlen &&
strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen) strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen)
Curl_bufref_free(&resp); Curl_bufref_free(&resp);
if(!result) if(!result)
result = sasl->params->sendauth(data, conn, mech, result = sasl->params->sendauth(data, mech, &resp);
(const char *) Curl_bufref_ptr(&resp));
if(!result) { if(!result) {
*progress = SASL_INPROGRESS; *progress = SASL_INPROGRESS;
@ -498,10 +519,10 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
* Continue the authentication. * Continue the authentication.
*/ */
CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
struct connectdata *conn,
int code, saslprogress *progress) int code, saslprogress *progress)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
saslstate newstate = SASL_FINAL; saslstate newstate = SASL_FINAL;
struct bufref resp; struct bufref resp;
const char * const hostname = SSL_HOST_NAME(); const char * const hostname = SSL_HOST_NAME();
@ -574,7 +595,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
result = Curl_auth_create_digest_md5_message(data, &serverdata, result = Curl_auth_create_digest_md5_message(data, &serverdata,
conn->user, conn->passwd, conn->user, conn->passwd,
service, &resp); service, &resp);
newstate = SASL_DIGESTMD5_RESP; if(!result && (sasl->params->flags & SASL_FLAG_BASE64))
newstate = SASL_DIGESTMD5_RESP;
break; break;
case SASL_DIGESTMD5_RESP: case SASL_DIGESTMD5_RESP:
/* Keep response NULL to output an empty line. */ /* Keep response NULL to output an empty line. */
@ -691,7 +713,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
sasl->authmechs ^= sasl->authused; sasl->authmechs ^= sasl->authused;
/* Start an alternative SASL authentication */ /* Start an alternative SASL authentication */
return Curl_sasl_start(sasl, data, conn, sasl->force_ir, progress); return Curl_sasl_start(sasl, data, sasl->force_ir, progress);
default: default:
failf(data, "Unsupported SASL authentication mechanism"); failf(data, "Unsupported SASL authentication mechanism");
result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */ result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */
@ -703,14 +725,13 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
switch(result) { switch(result) {
case CURLE_BAD_CONTENT_ENCODING: case CURLE_BAD_CONTENT_ENCODING:
/* Cancel dialog */ /* Cancel dialog */
result = sasl->params->sendcont(data, conn, "*"); result = sasl->params->cancelauth(data, sasl->curmech);
newstate = SASL_CANCEL; newstate = SASL_CANCEL;
break; break;
case CURLE_OK: case CURLE_OK:
result = build_message(data, &resp); result = build_message(sasl, data, &resp);
if(!result) if(!result)
result = sasl->params->sendcont(data, conn, result = sasl->params->contauth(data, sasl->curmech, &resp);
(const char *) Curl_bufref_ptr(&resp));
break; break;
default: default:
newstate = SASL_STOP; /* Stop on error */ newstate = SASL_STOP; /* Stop on error */

View File

@ -24,6 +24,8 @@
#include <curl/curl.h> #include <curl/curl.h>
#include "bufref.h"
struct Curl_easy; struct Curl_easy;
struct connectdata; struct connectdata;
@ -46,17 +48,20 @@ struct connectdata;
#define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL) #define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL)
/* Authentication mechanism strings */ /* Authentication mechanism strings */
#define SASL_MECH_STRING_LOGIN "LOGIN" #define SASL_MECH_STRING_LOGIN "LOGIN"
#define SASL_MECH_STRING_PLAIN "PLAIN" #define SASL_MECH_STRING_PLAIN "PLAIN"
#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5" #define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5"
#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5" #define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5"
#define SASL_MECH_STRING_GSSAPI "GSSAPI" #define SASL_MECH_STRING_GSSAPI "GSSAPI"
#define SASL_MECH_STRING_EXTERNAL "EXTERNAL" #define SASL_MECH_STRING_EXTERNAL "EXTERNAL"
#define SASL_MECH_STRING_NTLM "NTLM" #define SASL_MECH_STRING_NTLM "NTLM"
#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2" #define SASL_MECH_STRING_XOAUTH2 "XOAUTH2"
#define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER" #define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER"
#define SASL_MECH_STRING_SCRAM_SHA_1 "SCRAM-SHA-1" #define SASL_MECH_STRING_SCRAM_SHA_1 "SCRAM-SHA-1"
#define SASL_MECH_STRING_SCRAM_SHA_256 "SCRAM-SHA-256" #define SASL_MECH_STRING_SCRAM_SHA_256 "SCRAM-SHA-256"
/* SASL flags */
#define SASL_FLAG_BASE64 0x0001 /* Messages are base64-encoded */
/* SASL machine states */ /* SASL machine states */
typedef enum { typedef enum {
@ -90,30 +95,37 @@ typedef enum {
/* Protocol dependent SASL parameters */ /* Protocol dependent SASL parameters */
struct SASLproto { struct SASLproto {
const char *service; /* The service name */ const char *service; /* The service name */
CURLcode (*sendauth)(struct Curl_easy *data, const char *mech,
const struct bufref *ir);
/* Send authentication command */
CURLcode (*contauth)(struct Curl_easy *data, const char *mech,
const struct bufref *contauth);
/* Send authentication continuation */
CURLcode (*cancelauth)(struct Curl_easy *data, const char *mech);
/* Cancel authentication. */
CURLcode (*getmessage)(struct Curl_easy *data, struct bufref *out);
/* Get SASL response message */
size_t maxirlen; /* Maximum initial response + mechanism length,
or zero if no max. This is normally the max
command length - other characters count.
This has to be zero for non-base64 protocols. */
int contcode; /* Code to receive when continuation is expected */ int contcode; /* Code to receive when continuation is expected */
int finalcode; /* Code to receive upon authentication success */ int finalcode; /* Code to receive upon authentication success */
size_t maxirlen; /* Maximum initial response length */ unsigned short defmechs; /* Mechanisms enabled by default */
CURLcode (*sendauth)(struct Curl_easy *data, unsigned short flags; /* Configuration flags. */
struct connectdata *conn,
const char *mech, const char *ir);
/* Send authentication command */
CURLcode (*sendcont)(struct Curl_easy *data,
struct connectdata *conn, const char *contauth);
/* Send authentication continuation */
void (*getmessage)(char *buffer, char **outptr);
/* Get SASL response message */
}; };
/* Per-connection parameters */ /* Per-connection parameters */
struct SASL { struct SASL {
const struct SASLproto *params; /* Protocol dependent parameters */ const struct SASLproto *params; /* Protocol dependent parameters */
saslstate state; /* Current machine state */ saslstate state; /* Current machine state */
const char *curmech; /* Current mechanism id. */
unsigned short authmechs; /* Accepted authentication mechanisms */ unsigned short authmechs; /* Accepted authentication mechanisms */
unsigned short prefmech; /* Preferred authentication mechanism */ unsigned short prefmech; /* Preferred authentication mechanism */
unsigned short authused; /* Auth mechanism used for the connection */ unsigned short authused; /* Auth mechanism used for the connection */
bool resetprefs; /* For URL auth option parsing. */ bool resetprefs; /* For URL auth option parsing. */
bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */ bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */
bool force_ir; /* Protocol always supports initial response */ bool force_ir; /* Protocol always supports initial response */
}; };
/* This is used to test whether the line starts with the given mechanism */ /* This is used to test whether the line starts with the given mechanism */
@ -123,7 +135,7 @@ struct SASL {
/* This is used to cleanup any libraries or curl modules used by the sasl /* This is used to cleanup any libraries or curl modules used by the sasl
functions */ functions */
void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused); void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused);
/* Convert a mechanism name to a token */ /* Convert a mechanism name to a token */
unsigned short Curl_sasl_decode_mech(const char *ptr, unsigned short Curl_sasl_decode_mech(const char *ptr,
@ -134,19 +146,18 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
const char *value, size_t len); const char *value, size_t len);
/* Initializes an SASL structure */ /* Initializes an SASL structure */
void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params); void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
const struct SASLproto *params);
/* Check if we have enough auth data and capabilities to authenticate */ /* Check if we have enough auth data and capabilities to authenticate */
bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn); bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn);
/* Calculate the required login details for SASL authentication */ /* Calculate the required login details for SASL authentication */
CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
struct connectdata *conn,
bool force_ir, saslprogress *progress); bool force_ir, saslprogress *progress);
/* Continue an SASL authentication */ /* Continue an SASL authentication */
CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
struct connectdata *conn,
int code, saslprogress *progress); int code, saslprogress *progress);
#endif /* HEADER_CURL_SASL_H */ #endif /* HEADER_CURL_SASL_H */

View File

@ -78,6 +78,7 @@
#include "multiif.h" #include "multiif.h"
#include "url.h" #include "url.h"
#include "strcase.h" #include "strcase.h"
#include "bufref.h"
#include "curl_sasl.h" #include "curl_sasl.h"
#include "warnless.h" #include "warnless.h"
@ -101,19 +102,19 @@ static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done);
static CURLcode imap_setup_connection(struct Curl_easy *data, static CURLcode imap_setup_connection(struct Curl_easy *data,
struct connectdata *conn); struct connectdata *conn);
static char *imap_atom(const char *str, bool escape_only); static char *imap_atom(const char *str, bool escape_only);
static CURLcode imap_sendf(struct Curl_easy *data, static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...);
struct connectdata *conn, const char *fmt, ...);
static CURLcode imap_parse_url_options(struct connectdata *conn); static CURLcode imap_parse_url_options(struct connectdata *conn);
static CURLcode imap_parse_url_path(struct Curl_easy *data); static CURLcode imap_parse_url_path(struct Curl_easy *data);
static CURLcode imap_parse_custom_request(struct Curl_easy *data); static CURLcode imap_parse_custom_request(struct Curl_easy *data);
static CURLcode imap_perform_authenticate(struct Curl_easy *data, static CURLcode imap_perform_authenticate(struct Curl_easy *data,
struct connectdata *conn,
const char *mech, const char *mech,
const char *initresp); const struct bufref *initresp);
static CURLcode imap_continue_authenticate(struct Curl_easy *data, static CURLcode imap_continue_authenticate(struct Curl_easy *data,
struct connectdata *conn, const char *mech,
const char *resp); const struct bufref *resp);
static void imap_get_message(char *buffer, char **outptr); static CURLcode imap_cancel_authenticate(struct Curl_easy *data,
const char *mech);
static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out);
/* /*
* IMAP protocol handler. * IMAP protocol handler.
@ -180,12 +181,15 @@ const struct Curl_handler Curl_handler_imaps = {
/* SASL parameters for the imap protocol */ /* SASL parameters for the imap protocol */
static const struct SASLproto saslimap = { static const struct SASLproto saslimap = {
"imap", /* The service name */ "imap", /* The service name */
'+', /* Code received when continuation is expected */
IMAP_RESP_OK, /* Code to receive upon authentication success */
0, /* Maximum initial response length (no max) */
imap_perform_authenticate, /* Send authentication command */ imap_perform_authenticate, /* Send authentication command */
imap_continue_authenticate, /* Send authentication continuation */ imap_continue_authenticate, /* Send authentication continuation */
imap_get_message /* Get SASL response message */ imap_cancel_authenticate, /* Send authentication cancellation */
imap_get_message, /* Get SASL response message */
0, /* No maximum initial response length */
'+', /* Code received when continuation is expected */
IMAP_RESP_OK, /* Code to receive upon authentication success */
SASL_AUTH_DEFAULT, /* Default mechanisms */
SASL_FLAG_BASE64 /* Configuration flags */
}; };
@ -352,34 +356,32 @@ static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn,
* *
* Gets the authentication message from the response buffer. * Gets the authentication message from the response buffer.
*/ */
static void imap_get_message(char *buffer, char **outptr) static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out)
{ {
size_t len = strlen(buffer); char *message = data->state.buffer;
char *message = NULL; size_t len = strlen(message);
if(len > 2) { if(len > 2) {
/* Find the start of the message */ /* Find the start of the message */
len -= 2; len -= 2;
for(message = buffer + 2; *message == ' ' || *message == '\t'; for(message += 2; *message == ' ' || *message == '\t'; message++, len--)
message++, len--)
; ;
/* Find the end of the message */ /* Find the end of the message */
for(; len--;) while(len--)
if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
message[len] != '\t') message[len] != '\t')
break; break;
/* Terminate the message */ /* Terminate the message */
if(++len) { message[++len] = '\0';
message[len] = '\0'; Curl_bufref_set(out, message, len, NULL);
}
} }
else else
/* junk input => zero length output */ /* junk input => zero length output */
message = &buffer[len]; Curl_bufref_set(out, "", 0, NULL);
*outptr = message; return CURLE_OK;
} }
/*********************************************************************** /***********************************************************************
@ -437,7 +439,7 @@ static CURLcode imap_perform_capability(struct Curl_easy *data,
imapc->tls_supported = FALSE; /* Clear the TLS capability */ imapc->tls_supported = FALSE; /* Clear the TLS capability */
/* Send the CAPABILITY command */ /* Send the CAPABILITY command */
result = imap_sendf(data, conn, "CAPABILITY"); result = imap_sendf(data, "CAPABILITY");
if(!result) if(!result)
state(data, IMAP_CAPABILITY); state(data, IMAP_CAPABILITY);
@ -451,11 +453,10 @@ static CURLcode imap_perform_capability(struct Curl_easy *data,
* *
* Sends the STARTTLS command to start the upgrade to TLS. * Sends the STARTTLS command to start the upgrade to TLS.
*/ */
static CURLcode imap_perform_starttls(struct Curl_easy *data, static CURLcode imap_perform_starttls(struct Curl_easy *data)
struct connectdata *conn)
{ {
/* Send the STARTTLS command */ /* Send the STARTTLS command */
CURLcode result = imap_sendf(data, conn, "STARTTLS"); CURLcode result = imap_sendf(data, "STARTTLS");
if(!result) if(!result)
state(data, IMAP_STARTTLS); state(data, IMAP_STARTTLS);
@ -516,7 +517,7 @@ static CURLcode imap_perform_login(struct Curl_easy *data,
passwd = imap_atom(conn->passwd, false); passwd = imap_atom(conn->passwd, false);
/* Send the LOGIN command */ /* Send the LOGIN command */
result = imap_sendf(data, conn, "LOGIN %s %s", user ? user : "", result = imap_sendf(data, "LOGIN %s %s", user ? user : "",
passwd ? passwd : ""); passwd ? passwd : "");
free(user); free(user);
@ -536,20 +537,19 @@ static CURLcode imap_perform_login(struct Curl_easy *data,
* SASL authentication mechanism. * SASL authentication mechanism.
*/ */
static CURLcode imap_perform_authenticate(struct Curl_easy *data, static CURLcode imap_perform_authenticate(struct Curl_easy *data,
struct connectdata *conn,
const char *mech, const char *mech,
const char *initresp) const struct bufref *initresp)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
(void)data; const char *ir = (const char *) Curl_bufref_ptr(initresp);
if(initresp) { if(ir) {
/* Send the AUTHENTICATE command with the initial response */ /* Send the AUTHENTICATE command with the initial response */
result = imap_sendf(data, conn, "AUTHENTICATE %s %s", mech, initresp); result = imap_sendf(data, "AUTHENTICATE %s %s", mech, ir);
} }
else { else {
/* Send the AUTHENTICATE command */ /* Send the AUTHENTICATE command */
result = imap_sendf(data, conn, "AUTHENTICATE %s", mech); result = imap_sendf(data, "AUTHENTICATE %s", mech);
} }
return result; return result;
@ -559,15 +559,34 @@ static CURLcode imap_perform_authenticate(struct Curl_easy *data,
* *
* imap_continue_authenticate() * imap_continue_authenticate()
* *
* Sends SASL continuation data or cancellation. * Sends SASL continuation data.
*/ */
static CURLcode imap_continue_authenticate(struct Curl_easy *data, static CURLcode imap_continue_authenticate(struct Curl_easy *data,
struct connectdata *conn, const char *mech,
const char *resp) const struct bufref *resp)
{ {
struct imap_conn *imapc = &conn->proto.imapc; struct imap_conn *imapc = &data->conn->proto.imapc;
return Curl_pp_sendf(data, &imapc->pp, "%s", resp); (void)mech;
return Curl_pp_sendf(data, &imapc->pp,
"%s", (const char *) Curl_bufref_ptr(resp));
}
/***********************************************************************
*
* imap_cancel_authenticate()
*
* Sends SASL cancellation.
*/
static CURLcode imap_cancel_authenticate(struct Curl_easy *data,
const char *mech)
{
struct imap_conn *imapc = &data->conn->proto.imapc;
(void)mech;
return Curl_pp_sendf(data, &imapc->pp, "*");
} }
/*********************************************************************** /***********************************************************************
@ -594,8 +613,7 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data,
} }
/* Calculate the SASL login details */ /* Calculate the SASL login details */
result = Curl_sasl_start(&imapc->sasl, data, conn, result = Curl_sasl_start(&imapc->sasl, data, imapc->ir_supported, &progress);
imapc->ir_supported, &progress);
if(!result) { if(!result) {
if(progress == SASL_INPROGRESS) if(progress == SASL_INPROGRESS)
@ -622,12 +640,11 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data,
static CURLcode imap_perform_list(struct Curl_easy *data) static CURLcode imap_perform_list(struct Curl_easy *data)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct IMAP *imap = data->req.p.imap; struct IMAP *imap = data->req.p.imap;
if(imap->custom) if(imap->custom)
/* Send the custom request */ /* Send the custom request */
result = imap_sendf(data, conn, "%s%s", imap->custom, result = imap_sendf(data, "%s%s", imap->custom,
imap->custom_params ? imap->custom_params : ""); imap->custom_params ? imap->custom_params : "");
else { else {
/* Make sure the mailbox is in the correct atom format if necessary */ /* Make sure the mailbox is in the correct atom format if necessary */
@ -637,7 +654,7 @@ static CURLcode imap_perform_list(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
/* Send the LIST command */ /* Send the LIST command */
result = imap_sendf(data, conn, "LIST \"%s\" *", mailbox); result = imap_sendf(data, "LIST \"%s\" *", mailbox);
free(mailbox); free(mailbox);
} }
@ -678,7 +695,7 @@ static CURLcode imap_perform_select(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
/* Send the SELECT command */ /* Send the SELECT command */
result = imap_sendf(data, conn, "SELECT %s", mailbox); result = imap_sendf(data, "SELECT %s", mailbox);
free(mailbox); free(mailbox);
@ -694,8 +711,7 @@ static CURLcode imap_perform_select(struct Curl_easy *data)
* *
* Sends a FETCH command to initiate the download of a message. * Sends a FETCH command to initiate the download of a message.
*/ */
static CURLcode imap_perform_fetch(struct Curl_easy *data, static CURLcode imap_perform_fetch(struct Curl_easy *data)
struct connectdata *conn)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct IMAP *imap = data->req.p.imap; struct IMAP *imap = data->req.p.imap;
@ -704,21 +720,21 @@ static CURLcode imap_perform_fetch(struct Curl_easy *data,
/* Send the FETCH command */ /* Send the FETCH command */
if(imap->partial) if(imap->partial)
result = imap_sendf(data, conn, "UID FETCH %s BODY[%s]<%s>", result = imap_sendf(data, "UID FETCH %s BODY[%s]<%s>",
imap->uid, imap->section ? imap->section : "", imap->uid, imap->section ? imap->section : "",
imap->partial); imap->partial);
else else
result = imap_sendf(data, conn, "UID FETCH %s BODY[%s]", result = imap_sendf(data, "UID FETCH %s BODY[%s]",
imap->uid, imap->section ? imap->section : ""); imap->uid, imap->section ? imap->section : "");
} }
else if(imap->mindex) { else if(imap->mindex) {
/* Send the FETCH command */ /* Send the FETCH command */
if(imap->partial) if(imap->partial)
result = imap_sendf(data, conn, "FETCH %s BODY[%s]<%s>", result = imap_sendf(data, "FETCH %s BODY[%s]<%s>",
imap->mindex, imap->section ? imap->section : "", imap->mindex, imap->section ? imap->section : "",
imap->partial); imap->partial);
else else
result = imap_sendf(data, conn, "FETCH %s BODY[%s]", result = imap_sendf(data, "FETCH %s BODY[%s]",
imap->mindex, imap->section ? imap->section : ""); imap->mindex, imap->section ? imap->section : "");
} }
else { else {
@ -740,7 +756,6 @@ static CURLcode imap_perform_fetch(struct Curl_easy *data,
static CURLcode imap_perform_append(struct Curl_easy *data) static CURLcode imap_perform_append(struct Curl_easy *data)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct IMAP *imap = data->req.p.imap; struct IMAP *imap = data->req.p.imap;
char *mailbox; char *mailbox;
@ -791,7 +806,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
/* Send the APPEND command */ /* Send the APPEND command */
result = imap_sendf(data, conn, result = imap_sendf(data,
"APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}", "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
mailbox, data->state.infilesize); mailbox, data->state.infilesize);
@ -809,8 +824,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
* *
* Sends a SEARCH command. * Sends a SEARCH command.
*/ */
static CURLcode imap_perform_search(struct Curl_easy *data, static CURLcode imap_perform_search(struct Curl_easy *data)
struct connectdata *conn)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct IMAP *imap = data->req.p.imap; struct IMAP *imap = data->req.p.imap;
@ -822,7 +836,7 @@ static CURLcode imap_perform_search(struct Curl_easy *data,
} }
/* Send the SEARCH command */ /* Send the SEARCH command */
result = imap_sendf(data, conn, "SEARCH %s", imap->query); result = imap_sendf(data, "SEARCH %s", imap->query);
if(!result) if(!result)
state(data, IMAP_SEARCH); state(data, IMAP_SEARCH);
@ -836,11 +850,10 @@ static CURLcode imap_perform_search(struct Curl_easy *data,
* *
* Performs the logout action prior to sclose() being called. * Performs the logout action prior to sclose() being called.
*/ */
static CURLcode imap_perform_logout(struct Curl_easy *data, static CURLcode imap_perform_logout(struct Curl_easy *data)
struct connectdata *conn)
{ {
/* Send the LOGOUT command */ /* Send the LOGOUT command */
CURLcode result = imap_sendf(data, conn, "LOGOUT"); CURLcode result = imap_sendf(data, "LOGOUT");
if(!result) if(!result)
state(data, IMAP_LOGOUT); state(data, IMAP_LOGOUT);
@ -938,7 +951,7 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data,
/* PREAUTH is not compatible with STARTTLS. */ /* PREAUTH is not compatible with STARTTLS. */
if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) { if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) {
/* Switch to TLS connection now */ /* Switch to TLS connection now */
result = imap_perform_starttls(data, conn); result = imap_perform_starttls(data);
} }
else if(data->set.use_ssl <= CURLUSESSL_TRY) else if(data->set.use_ssl <= CURLUSESSL_TRY)
result = imap_perform_authentication(data, conn); result = imap_perform_authentication(data, conn);
@ -993,7 +1006,7 @@ static CURLcode imap_state_auth_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */ (void)instate; /* no use for this yet */
result = Curl_sasl_continue(&imapc->sasl, data, conn, imapcode, &progress); result = Curl_sasl_continue(&imapc->sasl, data, imapcode, &progress);
if(!result) if(!result)
switch(progress) { switch(progress) {
case SASL_DONE: case SASL_DONE:
@ -1094,9 +1107,9 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode,
if(imap->custom) if(imap->custom)
result = imap_perform_list(data); result = imap_perform_list(data);
else if(imap->query) else if(imap->query)
result = imap_perform_search(data, conn); result = imap_perform_search(data);
else else
result = imap_perform_fetch(data, conn); result = imap_perform_fetch(data);
} }
} }
else { else {
@ -1441,7 +1454,7 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done)
/* Set the default preferred authentication type and mechanism */ /* Set the default preferred authentication type and mechanism */
imapc->preftype = IMAP_TYPE_ANY; imapc->preftype = IMAP_TYPE_ANY;
Curl_sasl_init(&imapc->sasl, &saslimap); Curl_sasl_init(&imapc->sasl, data, &saslimap);
Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD); Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD);
/* Initialise the pingpong layer */ /* Initialise the pingpong layer */
@ -1568,10 +1581,10 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
result = imap_perform_list(data); result = imap_perform_list(data);
else if(!imap->custom && selected && (imap->uid || imap->mindex)) else if(!imap->custom && selected && (imap->uid || imap->mindex))
/* FETCH from the same mailbox */ /* FETCH from the same mailbox */
result = imap_perform_fetch(data, conn); result = imap_perform_fetch(data);
else if(!imap->custom && selected && imap->query) else if(!imap->custom && selected && imap->query)
/* SEARCH the current mailbox */ /* SEARCH the current mailbox */
result = imap_perform_search(data, conn); result = imap_perform_search(data);
else if(imap->mailbox && !selected && else if(imap->mailbox && !selected &&
(imap->custom || imap->uid || imap->mindex || imap->query)) (imap->custom || imap->uid || imap->mindex || imap->query))
/* SELECT the mailbox */ /* SELECT the mailbox */
@ -1643,7 +1656,7 @@ static CURLcode imap_disconnect(struct Curl_easy *data,
/* The IMAP session may or may not have been allocated/setup at this /* The IMAP session may or may not have been allocated/setup at this
point! */ point! */
if(!dead_connection && conn->bits.protoconnstart) { if(!dead_connection && conn->bits.protoconnstart) {
if(!imap_perform_logout(data, conn)) if(!imap_perform_logout(data))
(void)imap_block_statemach(data, conn, TRUE); /* ignore errors */ (void)imap_block_statemach(data, conn, TRUE); /* ignore errors */
} }
@ -1747,17 +1760,16 @@ static CURLcode imap_setup_connection(struct Curl_easy *data,
* *
* Designed to never block. * Designed to never block.
*/ */
static CURLcode imap_sendf(struct Curl_easy *data, static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...)
struct connectdata *conn, const char *fmt, ...)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct imap_conn *imapc = &conn->proto.imapc; struct imap_conn *imapc = &data->conn->proto.imapc;
DEBUGASSERT(fmt); DEBUGASSERT(fmt);
/* Calculate the tag based on the connection ID and command ID */ /* Calculate the tag based on the connection ID and command ID */
msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d", msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
'A' + curlx_sltosi(conn->connection_id % 26), 'A' + curlx_sltosi(data->conn->connection_id % 26),
(++imapc->cmdid)%1000); (++imapc->cmdid)%1000);
/* start with a blank buffer */ /* start with a blank buffer */
@ -1911,8 +1923,6 @@ static CURLcode imap_parse_url_options(struct connectdata *conn)
struct imap_conn *imapc = &conn->proto.imapc; struct imap_conn *imapc = &conn->proto.imapc;
const char *ptr = conn->options; const char *ptr = conn->options;
imapc->sasl.resetprefs = TRUE;
while(!result && ptr && *ptr) { while(!result && ptr && *ptr) {
const char *key = ptr; const char *key = ptr;
const char *value; const char *value;

View File

@ -78,6 +78,7 @@
#include "select.h" #include "select.h"
#include "multiif.h" #include "multiif.h"
#include "url.h" #include "url.h"
#include "bufref.h"
#include "curl_sasl.h" #include "curl_sasl.h"
#include "curl_md5.h" #include "curl_md5.h"
#include "warnless.h" #include "warnless.h"
@ -103,12 +104,12 @@ static CURLcode pop3_setup_connection(struct Curl_easy *data,
static CURLcode pop3_parse_url_options(struct connectdata *conn); static CURLcode pop3_parse_url_options(struct connectdata *conn);
static CURLcode pop3_parse_url_path(struct Curl_easy *data); static CURLcode pop3_parse_url_path(struct Curl_easy *data);
static CURLcode pop3_parse_custom_request(struct Curl_easy *data); static CURLcode pop3_parse_custom_request(struct Curl_easy *data);
static CURLcode pop3_perform_auth(struct Curl_easy *data, static CURLcode pop3_perform_auth(struct Curl_easy *data, const char *mech,
struct connectdata *conn, const char *mech, const struct bufref *initresp);
const char *initresp); static CURLcode pop3_continue_auth(struct Curl_easy *data, const char *mech,
static CURLcode pop3_continue_auth(struct Curl_easy *data, const struct bufref *resp);
struct connectdata *conn, const char *resp); static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech);
static void pop3_get_message(char *buffer, char **outptr); static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out);
/* /*
* POP3 protocol handler. * POP3 protocol handler.
@ -170,13 +171,16 @@ const struct Curl_handler Curl_handler_pop3s = {
/* SASL parameters for the pop3 protocol */ /* SASL parameters for the pop3 protocol */
static const struct SASLproto saslpop3 = { static const struct SASLproto saslpop3 = {
"pop", /* The service name */ "pop", /* The service name */
'*', /* Code received when continuation is expected */ pop3_perform_auth, /* Send authentication command */
'+', /* Code to receive upon authentication success */ pop3_continue_auth, /* Send authentication continuation */
255 - 8, /* Maximum initial response length (no max) */ pop3_cancel_auth, /* Send authentication cancellation */
pop3_perform_auth, /* Send authentication command */ pop3_get_message, /* Get SASL response message */
pop3_continue_auth, /* Send authentication continuation */ 255 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */
pop3_get_message /* Get SASL response message */ '*', /* Code received when continuation is expected */
'+', /* Code to receive upon authentication success */
SASL_AUTH_DEFAULT, /* Default mechanisms */
SASL_FLAG_BASE64 /* Configuration flags */
}; };
#ifdef USE_SSL #ifdef USE_SSL
@ -250,34 +254,32 @@ static bool pop3_endofresp(struct Curl_easy *data, struct connectdata *conn,
* *
* Gets the authentication message from the response buffer. * Gets the authentication message from the response buffer.
*/ */
static void pop3_get_message(char *buffer, char **outptr) static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out)
{ {
size_t len = strlen(buffer); char *message = data->state.buffer;
char *message = NULL; size_t len = strlen(message);
if(len > 2) { if(len > 2) {
/* Find the start of the message */ /* Find the start of the message */
len -= 2; len -= 2;
for(message = buffer + 2; *message == ' ' || *message == '\t'; for(message += 2; *message == ' ' || *message == '\t'; message++, len--)
message++, len--)
; ;
/* Find the end of the message */ /* Find the end of the message */
for(; len--;) while(len--)
if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
message[len] != '\t') message[len] != '\t')
break; break;
/* Terminate the message */ /* Terminate the message */
if(++len) { message[++len] = '\0';
message[len] = '\0'; Curl_bufref_set(out, message, len, NULL);
}
} }
else else
/* junk input => zero length output */ /* junk input => zero length output */
message = &buffer[len]; Curl_bufref_set(out, "", 0, NULL);
*outptr = message; return CURLE_OK;
} }
/*********************************************************************** /***********************************************************************
@ -474,16 +476,16 @@ static CURLcode pop3_perform_apop(struct Curl_easy *data,
* authentication mechanism. * authentication mechanism.
*/ */
static CURLcode pop3_perform_auth(struct Curl_easy *data, static CURLcode pop3_perform_auth(struct Curl_easy *data,
struct connectdata *conn,
const char *mech, const char *mech,
const char *initresp) const struct bufref *initresp)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct pop3_conn *pop3c = &conn->proto.pop3c; struct pop3_conn *pop3c = &data->conn->proto.pop3c;
const char *ir = (const char *) Curl_bufref_ptr(initresp);
if(initresp) { /* AUTH <mech> ...<crlf> */ if(ir) { /* AUTH <mech> ...<crlf> */
/* Send the AUTH command with the initial response */ /* Send the AUTH command with the initial response */
result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s %s", mech, initresp); result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s %s", mech, ir);
} }
else { else {
/* Send the AUTH command */ /* Send the AUTH command */
@ -497,15 +499,33 @@ static CURLcode pop3_perform_auth(struct Curl_easy *data,
* *
* pop3_continue_auth() * pop3_continue_auth()
* *
* Sends SASL continuation data or cancellation. * Sends SASL continuation data.
*/ */
static CURLcode pop3_continue_auth(struct Curl_easy *data, static CURLcode pop3_continue_auth(struct Curl_easy *data,
struct connectdata *conn, const char *mech,
const char *resp) const struct bufref *resp)
{ {
struct pop3_conn *pop3c = &conn->proto.pop3c; struct pop3_conn *pop3c = &data->conn->proto.pop3c;
return Curl_pp_sendf(data, &pop3c->pp, "%s", resp); (void)mech;
return Curl_pp_sendf(data, &pop3c->pp,
"%s", (const char *) Curl_bufref_ptr(resp));
}
/***********************************************************************
*
* pop3_cancel_auth()
*
* Sends SASL cancellation.
*/
static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech)
{
struct pop3_conn *pop3c = &data->conn->proto.pop3c;
(void)mech;
return Curl_pp_sendf(data, &pop3c->pp, "*");
} }
/*********************************************************************** /***********************************************************************
@ -532,7 +552,7 @@ static CURLcode pop3_perform_authentication(struct Curl_easy *data,
if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) { if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) {
/* Calculate the SASL login details */ /* Calculate the SASL login details */
result = Curl_sasl_start(&pop3c->sasl, data, conn, FALSE, &progress); result = Curl_sasl_start(&pop3c->sasl, data, FALSE, &progress);
if(!result) if(!result)
if(progress == SASL_INPROGRESS) if(progress == SASL_INPROGRESS)
@ -801,7 +821,7 @@ static CURLcode pop3_state_auth_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */ (void)instate; /* no use for this yet */
result = Curl_sasl_continue(&pop3c->sasl, data, conn, pop3code, &progress); result = Curl_sasl_continue(&pop3c->sasl, data, pop3code, &progress);
if(!result) if(!result)
switch(progress) { switch(progress) {
case SASL_DONE: case SASL_DONE:
@ -1104,7 +1124,7 @@ static CURLcode pop3_connect(struct Curl_easy *data, bool *done)
/* Set the default preferred authentication type and mechanism */ /* Set the default preferred authentication type and mechanism */
pop3c->preftype = POP3_TYPE_ANY; pop3c->preftype = POP3_TYPE_ANY;
Curl_sasl_init(&pop3c->sasl, &saslpop3); Curl_sasl_init(&pop3c->sasl, data, &saslpop3);
/* Initialise the pingpong layer */ /* Initialise the pingpong layer */
Curl_pp_setup(pp); Curl_pp_setup(pp);
@ -1345,8 +1365,6 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn)
struct pop3_conn *pop3c = &conn->proto.pop3c; struct pop3_conn *pop3c = &conn->proto.pop3c;
const char *ptr = conn->options; const char *ptr = conn->options;
pop3c->sasl.resetprefs = TRUE;
while(!result && ptr && *ptr) { while(!result && ptr && *ptr) {
const char *key = ptr; const char *key = ptr;
const char *value; const char *value;

View File

@ -82,6 +82,7 @@
#include "multiif.h" #include "multiif.h"
#include "url.h" #include "url.h"
#include "curl_gethostname.h" #include "curl_gethostname.h"
#include "bufref.h"
#include "curl_sasl.h" #include "curl_sasl.h"
#include "warnless.h" #include "warnless.h"
/* The last 3 #include files should be in this order */ /* The last 3 #include files should be in this order */
@ -108,12 +109,12 @@ static CURLcode smtp_parse_url_path(struct Curl_easy *data);
static CURLcode smtp_parse_custom_request(struct Curl_easy *data); static CURLcode smtp_parse_custom_request(struct Curl_easy *data);
static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma, static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma,
char **address, struct hostname *host); char **address, struct hostname *host);
static CURLcode smtp_perform_auth(struct Curl_easy *data, static CURLcode smtp_perform_auth(struct Curl_easy *data, const char *mech,
struct connectdata *conn, const char *mech, const struct bufref *initresp);
const char *initresp); static CURLcode smtp_continue_auth(struct Curl_easy *data, const char *mech,
static CURLcode smtp_continue_auth(struct Curl_easy *data, const struct bufref *resp);
struct connectdata *conn, const char *resp); static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech);
static void smtp_get_message(char *buffer, char **outptr); static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out);
/* /*
* SMTP protocol handler. * SMTP protocol handler.
@ -175,13 +176,16 @@ const struct Curl_handler Curl_handler_smtps = {
/* SASL parameters for the smtp protocol */ /* SASL parameters for the smtp protocol */
static const struct SASLproto saslsmtp = { static const struct SASLproto saslsmtp = {
"smtp", /* The service name */ "smtp", /* The service name */
334, /* Code received when continuation is expected */ smtp_perform_auth, /* Send authentication command */
235, /* Code to receive upon authentication success */ smtp_continue_auth, /* Send authentication continuation */
512 - 8, /* Maximum initial response length (no max) */ smtp_cancel_auth, /* Cancel authentication */
smtp_perform_auth, /* Send authentication command */ smtp_get_message, /* Get SASL response message */
smtp_continue_auth, /* Send authentication continuation */ 512 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */
smtp_get_message /* Get SASL response message */ 334, /* Code received when continuation is expected */
235, /* Code to receive upon authentication success */
SASL_AUTH_DEFAULT, /* Default mechanisms */
SASL_FLAG_BASE64 /* Configuration flags */
}; };
#ifdef USE_SSL #ifdef USE_SSL
@ -248,34 +252,32 @@ static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn,
* *
* Gets the authentication message from the response buffer. * Gets the authentication message from the response buffer.
*/ */
static void smtp_get_message(char *buffer, char **outptr) static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out)
{ {
size_t len = strlen(buffer); char *message = data->state.buffer;
char *message = NULL; size_t len = strlen(message);
if(len > 4) { if(len > 4) {
/* Find the start of the message */ /* Find the start of the message */
len -= 4; len -= 4;
for(message = buffer + 4; *message == ' ' || *message == '\t'; for(message += 4; *message == ' ' || *message == '\t'; message++, len--)
message++, len--)
; ;
/* Find the end of the message */ /* Find the end of the message */
for(; len--;) while(len--)
if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
message[len] != '\t') message[len] != '\t')
break; break;
/* Terminate the message */ /* Terminate the message */
if(++len) { message[++len] = '\0';
message[len] = '\0'; Curl_bufref_set(out, message, len, NULL);
}
} }
else else
/* junk input => zero length output */ /* junk input => zero length output */
message = &buffer[len]; Curl_bufref_set(out, "", 0, NULL);
*outptr = message; return CURLE_OK;
} }
/*********************************************************************** /***********************************************************************
@ -421,16 +423,16 @@ static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data)
* authentication mechanism. * authentication mechanism.
*/ */
static CURLcode smtp_perform_auth(struct Curl_easy *data, static CURLcode smtp_perform_auth(struct Curl_easy *data,
struct connectdata *conn,
const char *mech, const char *mech,
const char *initresp) const struct bufref *initresp)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct smtp_conn *smtpc = &conn->proto.smtpc; struct smtp_conn *smtpc = &data->conn->proto.smtpc;
const char *ir = (const char *) Curl_bufref_ptr(initresp);
if(initresp) { /* AUTH <mech> ...<crlf> */ if(ir) { /* AUTH <mech> ...<crlf> */
/* Send the AUTH command with the initial response */ /* Send the AUTH command with the initial response */
result = Curl_pp_sendf(data, &smtpc->pp, "AUTH %s %s", mech, initresp); result = Curl_pp_sendf(data, &smtpc->pp, "AUTH %s %s", mech, ir);
} }
else { else {
/* Send the AUTH command */ /* Send the AUTH command */
@ -444,14 +446,33 @@ static CURLcode smtp_perform_auth(struct Curl_easy *data,
* *
* smtp_continue_auth() * smtp_continue_auth()
* *
* Sends SASL continuation data or cancellation. * Sends SASL continuation data.
*/ */
static CURLcode smtp_continue_auth(struct Curl_easy *data, static CURLcode smtp_continue_auth(struct Curl_easy *data,
struct connectdata *conn, const char *resp) const char *mech,
const struct bufref *resp)
{ {
struct smtp_conn *smtpc = &conn->proto.smtpc; struct smtp_conn *smtpc = &data->conn->proto.smtpc;
return Curl_pp_sendf(data, &smtpc->pp, "%s", resp); (void)mech;
return Curl_pp_sendf(data, &smtpc->pp,
"%s", (const char *) Curl_bufref_ptr(resp));
}
/***********************************************************************
*
* smtp_cancel_auth()
*
* Sends SASL cancellation.
*/
static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech)
{
struct smtp_conn *smtpc = &data->conn->proto.smtpc;
(void)mech;
return Curl_pp_sendf(data, &smtpc->pp, "*");
} }
/*********************************************************************** /***********************************************************************
@ -477,7 +498,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data)
} }
/* Calculate the SASL login details */ /* Calculate the SASL login details */
result = Curl_sasl_start(&smtpc->sasl, data, conn, FALSE, &progress); result = Curl_sasl_start(&smtpc->sasl, data, FALSE, &progress);
if(!result) { if(!result) {
if(progress == SASL_INPROGRESS) if(progress == SASL_INPROGRESS)
@ -985,7 +1006,7 @@ static CURLcode smtp_state_auth_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */ (void)instate; /* no use for this yet */
result = Curl_sasl_continue(&smtpc->sasl, data, conn, smtpcode, &progress); result = Curl_sasl_continue(&smtpc->sasl, data, smtpcode, &progress);
if(!result) if(!result)
switch(progress) { switch(progress) {
case SASL_DONE: case SASL_DONE:
@ -1333,7 +1354,7 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done)
PINGPONG_SETUP(pp, smtp_statemachine, smtp_endofresp); PINGPONG_SETUP(pp, smtp_statemachine, smtp_endofresp);
/* Initialize the SASL storage */ /* Initialize the SASL storage */
Curl_sasl_init(&smtpc->sasl, &saslsmtp); Curl_sasl_init(&smtpc->sasl, data, &saslsmtp);
/* Initialise the pingpong layer */ /* Initialise the pingpong layer */
Curl_pp_setup(pp); Curl_pp_setup(pp);
@ -1655,8 +1676,6 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn)
struct smtp_conn *smtpc = &conn->proto.smtpc; struct smtp_conn *smtpc = &conn->proto.smtpc;
const char *ptr = conn->options; const char *ptr = conn->options;
smtpc->sasl.resetprefs = TRUE;
while(!result && ptr && *ptr) { while(!result && ptr && *ptr) {
const char *key = ptr; const char *key = ptr;
const char *value; const char *value;