diff options
-rw-r--r-- | docs/TODO | 5 | ||||
-rw-r--r-- | lib/curl_sasl.c | 117 | ||||
-rw-r--r-- | lib/curl_sasl.h | 67 | ||||
-rw-r--r-- | lib/imap.c | 154 | ||||
-rw-r--r-- | lib/pop3.c | 96 | ||||
-rw-r--r-- | lib/smtp.c | 95 |
6 files changed, 304 insertions, 230 deletions
@@ -133,7 +133,6 @@ 16. SASL 16.1 Other authentication mechanisms 16.2 Add QOP support to GSSAPI authentication - 16.3 Support binary messages (i.e.: non-base64) 17. SSH protocols 17.1 Multiplexing @@ -902,10 +901,6 @@ with integrity protection) and auth-conf (Authentication with integrity and privacy protection). -16.3 Support binary messages (i.e.: non-base64) - - Mandatory to support LDAP SASL authentication. - 17. SSH protocols diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c index a5ee8bbe2..8d39e4f81 100644 --- a/lib/curl_sasl.c +++ b/lib/curl_sasl.c @@ -56,8 +56,8 @@ /* Supported mechanisms */ static const struct { - const char *name; /* Name */ - size_t len; /* Name length */ + const char *name; /* Name */ + size_t len; /* Name length */ unsigned short bit; /* Flag bit */ } mechtable[] = { { "LOGIN", 5, SASL_MECH_LOGIN }, @@ -85,8 +85,11 @@ static const struct { * conn [in] - The connection data. * 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) /* Cleanup the gssapi structure */ 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); } #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. */ -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->state = SASL_STOP; /* Not yet running */ + sasl->curmech = NULL; /* No mechanism yet. */ sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */ - sasl->prefmech = SASL_AUTH_DEFAULT; /* Prefer all mechanisms */ - sasl->authused = SASL_AUTH_NONE; /* No the authentication mechanism used */ + sasl->prefmech = params->defmechs; /* Default preferred mechanisms */ + sasl->authused = SASL_AUTH_NONE; /* 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 */ + + 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, struct bufref *out) { - unsigned char *msg; - size_t msglen; - char *serverdata = NULL; CURLcode result = CURLE_OK; - sasl->params->getmessage(data->state.buffer, &serverdata); - if(!serverdata) - result = CURLE_BAD_CONTENT_ENCODING; - else if(!*serverdata || *serverdata == '=') - Curl_bufref_set(out, NULL, 0, NULL); - else { - result = Curl_base64_decode(serverdata, &msg, &msglen); - if(!result) - Curl_bufref_set(out, msg, msglen, curl_free); + result = sasl->params->getmessage(data, out); + if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) { + unsigned char *msg; + size_t msglen; + const char *serverdata = (const char *) Curl_bufref_ptr(out); + + if(!*serverdata || *serverdata == '=') + Curl_bufref_set(out, NULL, 0, NULL); + else { + result = Curl_base64_decode(serverdata, &msg, &msglen); + if(!result) + Curl_bufref_set(out, msg, msglen, curl_free); + } } return result; } /* 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; - char *base64; - size_t base64len; - if(!Curl_bufref_ptr(msg)) /* Empty message. */ - Curl_bufref_set(msg, "", 0, NULL); - else if(!Curl_bufref_len(msg)) /* Explicit empty response. */ - Curl_bufref_set(msg, "=", 1, NULL); - else { - 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); + if(sasl->params->flags & SASL_FLAG_BASE64) { + if(!Curl_bufref_ptr(msg)) /* Empty message. */ + Curl_bufref_set(msg, "", 0, NULL); + else if(!Curl_bufref_len(msg)) /* Explicit empty response. */ + Curl_bufref_set(msg, "=", 1, NULL); + else { + char *base64; + size_t base64len; + + 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; @@ -310,11 +331,11 @@ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn) * Calculate the required login details for SASL authentication. */ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, - struct connectdata *conn, bool force_ir, saslprogress *progress) { CURLcode result = CURLE_OK; - unsigned int enabledmechs; + struct connectdata *conn = data->conn; + unsigned short enabledmechs; const char *mech = NULL; struct bufref resp; saslstate state1 = SASL_STOP; @@ -471,16 +492,16 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, } if(!result && mech) { + sasl->curmech = mech; if(Curl_bufref_ptr(&resp)) - result = build_message(data, &resp); + result = build_message(sasl, data, &resp); if(sasl->params->maxirlen && strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen) Curl_bufref_free(&resp); if(!result) - result = sasl->params->sendauth(data, conn, mech, - (const char *) Curl_bufref_ptr(&resp)); + result = sasl->params->sendauth(data, mech, &resp); if(!result) { *progress = SASL_INPROGRESS; @@ -498,10 +519,10 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, * Continue the authentication. */ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, - struct connectdata *conn, int code, saslprogress *progress) { CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; saslstate newstate = SASL_FINAL; struct bufref resp; 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, conn->user, conn->passwd, service, &resp); - newstate = SASL_DIGESTMD5_RESP; + if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) + newstate = SASL_DIGESTMD5_RESP; break; case SASL_DIGESTMD5_RESP: /* 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; /* 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: failf(data, "Unsupported SASL authentication mechanism"); result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */ @@ -703,14 +725,13 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, switch(result) { case CURLE_BAD_CONTENT_ENCODING: /* Cancel dialog */ - result = sasl->params->sendcont(data, conn, "*"); + result = sasl->params->cancelauth(data, sasl->curmech); newstate = SASL_CANCEL; break; case CURLE_OK: - result = build_message(data, &resp); + result = build_message(sasl, data, &resp); if(!result) - result = sasl->params->sendcont(data, conn, - (const char *) Curl_bufref_ptr(&resp)); + result = sasl->params->contauth(data, sasl->curmech, &resp); break; default: newstate = SASL_STOP; /* Stop on error */ diff --git a/lib/curl_sasl.h b/lib/curl_sasl.h index e17d323eb..91458c74a 100644 --- a/lib/curl_sasl.h +++ b/lib/curl_sasl.h @@ -24,6 +24,8 @@ #include <curl/curl.h> +#include "bufref.h" + struct Curl_easy; struct connectdata; @@ -46,17 +48,20 @@ struct connectdata; #define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL) /* Authentication mechanism strings */ -#define SASL_MECH_STRING_LOGIN "LOGIN" -#define SASL_MECH_STRING_PLAIN "PLAIN" -#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5" -#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5" -#define SASL_MECH_STRING_GSSAPI "GSSAPI" -#define SASL_MECH_STRING_EXTERNAL "EXTERNAL" -#define SASL_MECH_STRING_NTLM "NTLM" -#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2" -#define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER" -#define SASL_MECH_STRING_SCRAM_SHA_1 "SCRAM-SHA-1" -#define SASL_MECH_STRING_SCRAM_SHA_256 "SCRAM-SHA-256" +#define SASL_MECH_STRING_LOGIN "LOGIN" +#define SASL_MECH_STRING_PLAIN "PLAIN" +#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5" +#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5" +#define SASL_MECH_STRING_GSSAPI "GSSAPI" +#define SASL_MECH_STRING_EXTERNAL "EXTERNAL" +#define SASL_MECH_STRING_NTLM "NTLM" +#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2" +#define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER" +#define SASL_MECH_STRING_SCRAM_SHA_1 "SCRAM-SHA-1" +#define SASL_MECH_STRING_SCRAM_SHA_256 "SCRAM-SHA-256" + +/* SASL flags */ +#define SASL_FLAG_BASE64 0x0001 /* Messages are base64-encoded */ /* SASL machine states */ typedef enum { @@ -90,30 +95,37 @@ typedef enum { /* 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 Curl_easy *data, - struct connectdata *conn, - const char *mech, const char *ir); + CURLcode (*sendauth)(struct Curl_easy *data, const char *mech, + const struct bufref *ir); /* Send authentication command */ - CURLcode (*sendcont)(struct Curl_easy *data, - struct connectdata *conn, const char *contauth); + CURLcode (*contauth)(struct Curl_easy *data, const char *mech, + const struct bufref *contauth); /* Send authentication continuation */ - void (*getmessage)(char *buffer, char **outptr); + 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 finalcode; /* Code to receive upon authentication success */ + unsigned short defmechs; /* Mechanisms enabled by default */ + unsigned short flags; /* Configuration flags. */ }; /* Per-connection parameters */ struct SASL { 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 prefmech; /* Preferred authentication mechanism */ unsigned short 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 */ + 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 */ @@ -123,7 +135,7 @@ struct SASL { /* This is used to cleanup any libraries or curl modules used by the sasl 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 */ 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); /* 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 */ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn); /* Calculate the required login details for SASL authentication */ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, - struct connectdata *conn, bool force_ir, saslprogress *progress); /* Continue an SASL authentication */ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, - struct connectdata *conn, int code, saslprogress *progress); #endif /* HEADER_CURL_SASL_H */ diff --git a/lib/imap.c b/lib/imap.c index 6163899bb..e1704b299 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -78,6 +78,7 @@ #include "multiif.h" #include "url.h" #include "strcase.h" +#include "bufref.h" #include "curl_sasl.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, struct connectdata *conn); static char *imap_atom(const char *str, bool escape_only); -static CURLcode imap_sendf(struct Curl_easy *data, - struct connectdata *conn, const char *fmt, ...); +static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...); static CURLcode imap_parse_url_options(struct connectdata *conn); static CURLcode imap_parse_url_path(struct Curl_easy *data); static CURLcode imap_parse_custom_request(struct Curl_easy *data); static CURLcode imap_perform_authenticate(struct Curl_easy *data, - struct connectdata *conn, const char *mech, - const char *initresp); + const struct bufref *initresp); static CURLcode imap_continue_authenticate(struct Curl_easy *data, - struct connectdata *conn, - const char *resp); -static void imap_get_message(char *buffer, char **outptr); + const char *mech, + const struct bufref *resp); +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. @@ -180,12 +181,15 @@ const struct Curl_handler Curl_handler_imaps = { /* SASL parameters for the imap protocol */ static const struct SASLproto saslimap = { "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_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. */ -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 = NULL; + char *message = data->state.buffer; + size_t len = strlen(message); if(len > 2) { /* Find the start of the message */ len -= 2; - for(message = buffer + 2; *message == ' ' || *message == '\t'; - message++, len--) + for(message += 2; *message == ' ' || *message == '\t'; message++, len--) ; /* Find the end of the message */ - for(; len--;) + while(len--) if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && message[len] != '\t') break; /* Terminate the message */ - if(++len) { - message[len] = '\0'; - } + message[++len] = '\0'; + Curl_bufref_set(out, message, len, NULL); } else /* 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 */ /* Send the CAPABILITY command */ - result = imap_sendf(data, conn, "CAPABILITY"); + result = imap_sendf(data, "CAPABILITY"); if(!result) 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. */ -static CURLcode imap_perform_starttls(struct Curl_easy *data, - struct connectdata *conn) +static CURLcode imap_perform_starttls(struct Curl_easy *data) { /* Send the STARTTLS command */ - CURLcode result = imap_sendf(data, conn, "STARTTLS"); + CURLcode result = imap_sendf(data, "STARTTLS"); if(!result) state(data, IMAP_STARTTLS); @@ -516,7 +517,7 @@ static CURLcode imap_perform_login(struct Curl_easy *data, passwd = imap_atom(conn->passwd, false); /* 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 : ""); free(user); @@ -536,20 +537,19 @@ static CURLcode imap_perform_login(struct Curl_easy *data, * SASL authentication mechanism. */ static CURLcode imap_perform_authenticate(struct Curl_easy *data, - struct connectdata *conn, const char *mech, - const char *initresp) + const struct bufref *initresp) { 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 */ - result = imap_sendf(data, conn, "AUTHENTICATE %s %s", mech, initresp); + result = imap_sendf(data, "AUTHENTICATE %s %s", mech, ir); } else { /* Send the AUTHENTICATE command */ - result = imap_sendf(data, conn, "AUTHENTICATE %s", mech); + result = imap_sendf(data, "AUTHENTICATE %s", mech); } return result; @@ -559,15 +559,34 @@ static CURLcode imap_perform_authenticate(struct Curl_easy *data, * * imap_continue_authenticate() * - * Sends SASL continuation data or cancellation. + * Sends SASL continuation data. */ static CURLcode imap_continue_authenticate(struct Curl_easy *data, - struct connectdata *conn, - const char *resp) + const char *mech, + const struct bufref *resp) { - struct imap_conn *imapc = &conn->proto.imapc; + struct imap_conn *imapc = &data->conn->proto.imapc; + + (void)mech; - return Curl_pp_sendf(data, &imapc->pp, "%s", resp); + 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 */ - result = Curl_sasl_start(&imapc->sasl, data, conn, - imapc->ir_supported, &progress); + result = Curl_sasl_start(&imapc->sasl, data, imapc->ir_supported, &progress); if(!result) { 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) { CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; struct IMAP *imap = data->req.p.imap; if(imap->custom) /* 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 : ""); else { /* 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; /* Send the LIST command */ - result = imap_sendf(data, conn, "LIST \"%s\" *", mailbox); + result = imap_sendf(data, "LIST \"%s\" *", mailbox); free(mailbox); } @@ -678,7 +695,7 @@ static CURLcode imap_perform_select(struct Curl_easy *data) return CURLE_OUT_OF_MEMORY; /* Send the SELECT command */ - result = imap_sendf(data, conn, "SELECT %s", mailbox); + result = imap_sendf(data, "SELECT %s", 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. */ -static CURLcode imap_perform_fetch(struct Curl_easy *data, - struct connectdata *conn) +static CURLcode imap_perform_fetch(struct Curl_easy *data) { CURLcode result = CURLE_OK; struct IMAP *imap = data->req.p.imap; @@ -704,21 +720,21 @@ static CURLcode imap_perform_fetch(struct Curl_easy *data, /* Send the FETCH command */ 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->partial); 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 : ""); } else if(imap->mindex) { /* Send the FETCH command */ 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->partial); else - result = imap_sendf(data, conn, "FETCH %s BODY[%s]", + result = imap_sendf(data, "FETCH %s BODY[%s]", imap->mindex, imap->section ? imap->section : ""); } else { @@ -740,7 +756,6 @@ static CURLcode imap_perform_fetch(struct Curl_easy *data, static CURLcode imap_perform_append(struct Curl_easy *data) { CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; struct IMAP *imap = data->req.p.imap; char *mailbox; @@ -791,7 +806,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data) return CURLE_OUT_OF_MEMORY; /* Send the APPEND command */ - result = imap_sendf(data, conn, + result = imap_sendf(data, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}", mailbox, data->state.infilesize); @@ -809,8 +824,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data) * * Sends a SEARCH command. */ -static CURLcode imap_perform_search(struct Curl_easy *data, - struct connectdata *conn) +static CURLcode imap_perform_search(struct Curl_easy *data) { CURLcode result = CURLE_OK; struct IMAP *imap = data->req.p.imap; @@ -822,7 +836,7 @@ static CURLcode imap_perform_search(struct Curl_easy *data, } /* Send the SEARCH command */ - result = imap_sendf(data, conn, "SEARCH %s", imap->query); + result = imap_sendf(data, "SEARCH %s", imap->query); if(!result) 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. */ -static CURLcode imap_perform_logout(struct Curl_easy *data, - struct connectdata *conn) +static CURLcode imap_perform_logout(struct Curl_easy *data) { /* Send the LOGOUT command */ - CURLcode result = imap_sendf(data, conn, "LOGOUT"); + CURLcode result = imap_sendf(data, "LOGOUT"); if(!result) state(data, IMAP_LOGOUT); @@ -938,7 +951,7 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data, /* PREAUTH is not compatible with STARTTLS. */ if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) { /* Switch to TLS connection now */ - result = imap_perform_starttls(data, conn); + result = imap_perform_starttls(data); } else if(data->set.use_ssl <= CURLUSESSL_TRY) 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 */ - result = Curl_sasl_continue(&imapc->sasl, data, conn, imapcode, &progress); + result = Curl_sasl_continue(&imapc->sasl, data, imapcode, &progress); if(!result) switch(progress) { case SASL_DONE: @@ -1094,9 +1107,9 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode, if(imap->custom) result = imap_perform_list(data); else if(imap->query) - result = imap_perform_search(data, conn); + result = imap_perform_search(data); else - result = imap_perform_fetch(data, conn); + result = imap_perform_fetch(data); } } else { @@ -1441,7 +1454,7 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done) /* Set the default preferred authentication type and mechanism */ 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); /* Initialise the pingpong layer */ @@ -1568,10 +1581,10 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected, result = imap_perform_list(data); else if(!imap->custom && selected && (imap->uid || imap->mindex)) /* FETCH from the same mailbox */ - result = imap_perform_fetch(data, conn); + result = imap_perform_fetch(data); else if(!imap->custom && selected && imap->query) /* SEARCH the current mailbox */ - result = imap_perform_search(data, conn); + result = imap_perform_search(data); else if(imap->mailbox && !selected && (imap->custom || imap->uid || imap->mindex || imap->query)) /* 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 point! */ 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 */ } @@ -1747,17 +1760,16 @@ static CURLcode imap_setup_connection(struct Curl_easy *data, * * Designed to never block. */ -static CURLcode imap_sendf(struct Curl_easy *data, - struct connectdata *conn, const char *fmt, ...) +static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...) { CURLcode result = CURLE_OK; - struct imap_conn *imapc = &conn->proto.imapc; + struct imap_conn *imapc = &data->conn->proto.imapc; DEBUGASSERT(fmt); /* Calculate the tag based on the connection ID and command ID */ 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); /* 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; const char *ptr = conn->options; - imapc->sasl.resetprefs = TRUE; - while(!result && ptr && *ptr) { const char *key = ptr; const char *value; diff --git a/lib/pop3.c b/lib/pop3.c index 57296cf9b..d4ca67877 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -78,6 +78,7 @@ #include "select.h" #include "multiif.h" #include "url.h" +#include "bufref.h" #include "curl_sasl.h" #include "curl_md5.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_path(struct Curl_easy *data); static CURLcode pop3_parse_custom_request(struct Curl_easy *data); -static CURLcode pop3_perform_auth(struct Curl_easy *data, - struct connectdata *conn, const char *mech, - const char *initresp); -static CURLcode pop3_continue_auth(struct Curl_easy *data, - struct connectdata *conn, const char *resp); -static void pop3_get_message(char *buffer, char **outptr); +static CURLcode pop3_perform_auth(struct Curl_easy *data, const char *mech, + const struct bufref *initresp); +static CURLcode pop3_continue_auth(struct Curl_easy *data, const char *mech, + const struct bufref *resp); +static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech); +static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out); /* * POP3 protocol handler. @@ -170,13 +171,16 @@ const struct Curl_handler Curl_handler_pop3s = { /* 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 */ + "pop", /* The service name */ + pop3_perform_auth, /* Send authentication command */ + pop3_continue_auth, /* Send authentication continuation */ + pop3_cancel_auth, /* Send authentication cancellation */ + pop3_get_message, /* Get SASL response message */ + 255 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */ + '*', /* 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 @@ -250,34 +254,32 @@ static bool pop3_endofresp(struct Curl_easy *data, struct connectdata *conn, * * 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 = NULL; + char *message = data->state.buffer; + size_t len = strlen(message); if(len > 2) { /* Find the start of the message */ len -= 2; - for(message = buffer + 2; *message == ' ' || *message == '\t'; - message++, len--) + for(message += 2; *message == ' ' || *message == '\t'; message++, len--) ; /* Find the end of the message */ - for(; len--;) + while(len--) if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && message[len] != '\t') break; /* Terminate the message */ - if(++len) { - message[len] = '\0'; - } + message[++len] = '\0'; + Curl_bufref_set(out, message, len, NULL); } else /* 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. */ static CURLcode pop3_perform_auth(struct Curl_easy *data, - struct connectdata *conn, const char *mech, - const char *initresp) + const struct bufref *initresp) { 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 */ - 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 { /* Send the AUTH command */ @@ -497,15 +499,33 @@ static CURLcode pop3_perform_auth(struct Curl_easy *data, * * pop3_continue_auth() * - * Sends SASL continuation data or cancellation. + * Sends SASL continuation data. */ static CURLcode pop3_continue_auth(struct Curl_easy *data, - struct connectdata *conn, - const char *resp) + const char *mech, + const struct bufref *resp) { - struct pop3_conn *pop3c = &conn->proto.pop3c; + struct pop3_conn *pop3c = &data->conn->proto.pop3c; + + (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; - return Curl_pp_sendf(data, &pop3c->pp, "%s", resp); + (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) { /* 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(progress == SASL_INPROGRESS) @@ -801,7 +821,7 @@ static CURLcode pop3_state_auth_resp(struct Curl_easy *data, (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) switch(progress) { 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 */ pop3c->preftype = POP3_TYPE_ANY; - Curl_sasl_init(&pop3c->sasl, &saslpop3); + Curl_sasl_init(&pop3c->sasl, data, &saslpop3); /* Initialise the pingpong layer */ Curl_pp_setup(pp); @@ -1345,8 +1365,6 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn) struct pop3_conn *pop3c = &conn->proto.pop3c; const char *ptr = conn->options; - pop3c->sasl.resetprefs = TRUE; - while(!result && ptr && *ptr) { const char *key = ptr; const char *value; diff --git a/lib/smtp.c b/lib/smtp.c index 02ddaca0a..fdacefe55 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -82,6 +82,7 @@ #include "multiif.h" #include "url.h" #include "curl_gethostname.h" +#include "bufref.h" #include "curl_sasl.h" #include "warnless.h" /* 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_address(struct Curl_easy *data, const char *fqma, char **address, struct hostname *host); -static CURLcode smtp_perform_auth(struct Curl_easy *data, - struct connectdata *conn, const char *mech, - const char *initresp); -static CURLcode smtp_continue_auth(struct Curl_easy *data, - struct connectdata *conn, const char *resp); -static void smtp_get_message(char *buffer, char **outptr); +static CURLcode smtp_perform_auth(struct Curl_easy *data, const char *mech, + const struct bufref *initresp); +static CURLcode smtp_continue_auth(struct Curl_easy *data, const char *mech, + const struct bufref *resp); +static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech); +static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out); /* * SMTP protocol handler. @@ -175,13 +176,16 @@ const struct Curl_handler Curl_handler_smtps = { /* 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 */ + "smtp", /* The service name */ + smtp_perform_auth, /* Send authentication command */ + smtp_continue_auth, /* Send authentication continuation */ + smtp_cancel_auth, /* Cancel authentication */ + smtp_get_message, /* Get SASL response message */ + 512 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */ + 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 @@ -248,34 +252,32 @@ static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn, * * 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 = NULL; + char *message = data->state.buffer; + size_t len = strlen(message); if(len > 4) { /* Find the start of the message */ len -= 4; - for(message = buffer + 4; *message == ' ' || *message == '\t'; - message++, len--) + for(message += 4; *message == ' ' || *message == '\t'; message++, len--) ; /* Find the end of the message */ - for(; len--;) + while(len--) if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && message[len] != '\t') break; /* Terminate the message */ - if(++len) { - message[len] = '\0'; - } + message[++len] = '\0'; + Curl_bufref_set(out, message, len, NULL); } else /* 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. */ static CURLcode smtp_perform_auth(struct Curl_easy *data, - struct connectdata *conn, const char *mech, - const char *initresp) + const struct bufref *initresp) { 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 */ - 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 { /* Send the AUTH command */ @@ -444,14 +446,33 @@ static CURLcode smtp_perform_auth(struct Curl_easy *data, * * smtp_continue_auth() * - * Sends SASL continuation data or cancellation. + * Sends SASL continuation 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; + + (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; - return Curl_pp_sendf(data, &smtpc->pp, "%s", resp); + (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 */ - result = Curl_sasl_start(&smtpc->sasl, data, conn, FALSE, &progress); + result = Curl_sasl_start(&smtpc->sasl, data, FALSE, &progress); if(!result) { 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 */ - result = Curl_sasl_continue(&smtpc->sasl, data, conn, smtpcode, &progress); + result = Curl_sasl_continue(&smtpc->sasl, data, smtpcode, &progress); if(!result) switch(progress) { case SASL_DONE: @@ -1333,7 +1354,7 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done) PINGPONG_SETUP(pp, smtp_statemachine, smtp_endofresp); /* Initialize the SASL storage */ - Curl_sasl_init(&smtpc->sasl, &saslsmtp); + Curl_sasl_init(&smtpc->sasl, data, &saslsmtp); /* Initialise the pingpong layer */ Curl_pp_setup(pp); @@ -1655,8 +1676,6 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn) struct smtp_conn *smtpc = &conn->proto.smtpc; const char *ptr = conn->options; - smtpc->sasl.resetprefs = TRUE; - while(!result && ptr && *ptr) { const char *key = ptr; const char *value; |