diff options
Diffstat (limited to 'libs/libcurl/src/pop3.c')
-rw-r--r-- | libs/libcurl/src/pop3.c | 1129 |
1 files changed, 335 insertions, 794 deletions
diff --git a/libs/libcurl/src/pop3.c b/libs/libcurl/src/pop3.c index a771933840..5792a4a6fd 100644 --- a/libs/libcurl/src/pop3.c +++ b/libs/libcurl/src/pop3.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -27,8 +27,10 @@ * RFC2831 DIGEST-MD5 authentication * RFC4422 Simple Authentication and Security Layer (SASL) * RFC4616 PLAIN authentication + * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism * RFC5034 POP3 SASL Authentication Mechanism * RFC6749 OAuth 2.0 Authorization Framework + * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt> * ***************************************************************************/ @@ -61,7 +63,6 @@ #include <curl/curl.h> #include "urldata.h" #include "sendf.h" -#include "if2ip.h" #include "hostip.h" #include "progress.h" #include "transfer.h" @@ -69,25 +70,20 @@ #include "http.h" /* for HTTP proxy tunnel stuff */ #include "socks.h" #include "pop3.h" - #include "strtoofft.h" -#include "strequal.h" -#include "sslgen.h" +#include "strcase.h" +#include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" -#include "rawstr.h" #include "curl_sasl.h" #include "curl_md5.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* Local API functions */ @@ -105,6 +101,10 @@ static CURLcode pop3_setup_connection(struct connectdata *conn); static CURLcode pop3_parse_url_options(struct connectdata *conn); static CURLcode pop3_parse_url_path(struct connectdata *conn); static CURLcode pop3_parse_custom_request(struct connectdata *conn); +static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech, + const char *initresp); +static CURLcode pop3_continue_auth(struct connectdata *conn, const char *resp); +static void pop3_get_message(char *buffer, char **outptr); /* * POP3 protocol handler. @@ -125,9 +125,11 @@ const struct Curl_handler Curl_handler_pop3 = { ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_POP3, /* defport */ CURLPROTO_POP3, /* protocol */ - PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ + PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ + PROTOPT_URLOPTIONS }; #ifdef USE_SSL @@ -150,69 +152,33 @@ const struct Curl_handler Curl_handler_pop3s = { ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_POP3S, /* defport */ - CURLPROTO_POP3 | CURLPROTO_POP3S, /* protocol */ + CURLPROTO_POP3S, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_SSL - | PROTOPT_NOURLQUERY /* flags */ + | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */ }; #endif -#ifndef CURL_DISABLE_HTTP -/* - * HTTP-proxyed POP3 protocol handler. - */ - -static const struct Curl_handler Curl_handler_pop3_proxy = { - "POP3", /* scheme */ - Curl_http_setup_conn, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - PORT_POP3, /* defport */ - CURLPROTO_HTTP, /* protocol */ - PROTOPT_NONE /* flags */ +/* SASL parameters for the pop3 protocol */ +static const struct SASLproto saslpop3 = { + "pop", /* The service name */ + '*', /* Code received when continuation is expected */ + '+', /* Code to receive upon authentication success */ + 255 - 8, /* Maximum initial response length (no max) */ + pop3_perform_auth, /* Send authentication command */ + pop3_continue_auth, /* Send authentication continuation */ + pop3_get_message /* Get SASL response message */ }; #ifdef USE_SSL -/* - * HTTP-proxyed POP3S protocol handler. - */ - -static const struct Curl_handler Curl_handler_pop3s_proxy = { - "POP3S", /* scheme */ - Curl_http_setup_conn, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - PORT_POP3S, /* defport */ - CURLPROTO_HTTP, /* protocol */ - PROTOPT_NONE /* flags */ -}; -#endif -#endif - -#ifdef USE_SSL static void pop3_to_pop3s(struct connectdata *conn) { + /* Change the connection handler */ conn->handler = &Curl_handler_pop3s; + + /* Set the connection's upgraded to TLS flag */ + conn->tls_upgraded = TRUE; } #else #define pop3_to_pop3s(x) Curl_nop_stmt @@ -231,8 +197,6 @@ static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len, int *resp) { struct pop3_conn *pop3c = &conn->proto.pop3c; - size_t wordlen; - size_t i; /* Do we have an error response? */ if(len >= 4 && !memcmp("-ERR", line, 4)) { @@ -241,112 +205,63 @@ static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len, return TRUE; } - /* Are we processing servergreet responses? */ - if(pop3c->state == POP3_SERVERGREET) { - /* Look for the APOP timestamp */ - if(len >= 3 && line[len - 3] == '>') { - for(i = 0; i < len - 3; ++i) { - if(line[i] == '<') { - /* Calculate the length of the timestamp */ - size_t timestamplen = len - 2 - i; - - /* Allocate some memory for the timestamp */ - pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1); - - if(!pop3c->apoptimestamp) - break; - - /* Copy the timestamp */ - memcpy(pop3c->apoptimestamp, line + i, timestamplen); - pop3c->apoptimestamp[timestamplen] = '\0'; - break; - } - } - } - } /* Are we processing CAPA command responses? */ - else if(pop3c->state == POP3_CAPA) { + if(pop3c->state == POP3_CAPA) { /* Do we have the terminating line? */ - if(len >= 1 && !memcmp(line, ".", 1)) { + if(len >= 1 && !memcmp(line, ".", 1)) + /* Treat the response as a success */ *resp = '+'; + else + /* Treat the response as an untagged continuation */ + *resp = '*'; - return TRUE; - } - - /* Does the server support the STLS capability? */ - if(len >= 4 && !memcmp(line, "STLS", 4)) - pop3c->tls_supported = TRUE; - - /* Does the server support clear text authentication? */ - else if(len >= 4 && !memcmp(line, "USER", 4)) - pop3c->authtypes |= POP3_TYPE_CLEARTEXT; - - /* Does the server support APOP authentication? */ - else if(len >= 4 && !memcmp(line, "APOP", 4)) - pop3c->authtypes |= POP3_TYPE_APOP; - - /* Does the server support SASL based authentication? */ - else if(len >= 5 && !memcmp(line, "SASL ", 5)) { - pop3c->authtypes |= POP3_TYPE_SASL; - - /* Advance past the SASL keyword */ - line += 5; - len -= 5; + return TRUE; + } - /* Loop through the data line */ - for(;;) { - while(len && - (*line == ' ' || *line == '\t' || - *line == '\r' || *line == '\n')) { + /* Do we have a success response? */ + if(len >= 3 && !memcmp("+OK", line, 3)) { + *resp = '+'; - line++; - len--; - } + return TRUE; + } - if(!len) - break; + /* Do we have a continuation response? */ + if(len >= 1 && !memcmp("+", line, 1)) { + *resp = '*'; - /* Extract the word */ - for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && - line[wordlen] != '\t' && line[wordlen] != '\r' && - line[wordlen] != '\n';) - wordlen++; + return TRUE; + } - /* Test the word for a matching authentication mechanism */ - if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN)) - pop3c->authmechs |= SASL_MECH_LOGIN; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN)) - pop3c->authmechs |= SASL_MECH_PLAIN; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5)) - pop3c->authmechs |= SASL_MECH_CRAM_MD5; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5)) - pop3c->authmechs |= SASL_MECH_DIGEST_MD5; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI)) - pop3c->authmechs |= SASL_MECH_GSSAPI; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL)) - pop3c->authmechs |= SASL_MECH_EXTERNAL; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM)) - pop3c->authmechs |= SASL_MECH_NTLM; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2)) - pop3c->authmechs |= SASL_MECH_XOAUTH2; + return FALSE; /* Nothing for us */ +} - line += wordlen; - len -= wordlen; - } - } +/*********************************************************************** + * + * pop3_get_message() + * + * Gets the authentication message from the response buffer. + */ +static void pop3_get_message(char *buffer, char **outptr) +{ + size_t len = 0; + char *message = NULL; - return FALSE; - } + /* Find the start of the message */ + for(message = buffer + 2; *message == ' ' || *message == '\t'; message++) + ; - /* Do we have a command or continuation response? */ - if((len >= 3 && !memcmp("+OK", line, 3)) || - (len >= 1 && !memcmp("+", line, 1))) { - *resp = '+'; + /* Find the end of the message */ + for(len = strlen(message); len--;) + if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && + message[len] != '\t') + break; - return TRUE; + /* Terminate the message */ + if(++len) { + message[len] = '\0'; } - return FALSE; /* Nothing for us */ + *outptr = message; } /*********************************************************************** @@ -366,16 +281,7 @@ static void state(struct connectdata *conn, pop3state newstate) "CAPA", "STARTTLS", "UPGRADETLS", - "AUTH_PLAIN", - "AUTH_LOGIN", - "AUTH_LOGIN_PASSWD", - "AUTH_CRAMMD5", - "AUTH_DIGESTMD5", - "AUTH_DIGESTMD5_RESP", - "AUTH_NTLM", - "AUTH_NTLM_TYPE2MSG", - "AUTH_XOAUTH2", - "AUTH_FINAL", + "AUTH", "APOP", "USER", "PASS", @@ -404,9 +310,9 @@ static CURLcode pop3_perform_capa(struct connectdata *conn) CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; - pop3c->authmechs = 0; /* No known authentication mechanisms yet */ - pop3c->authused = 0; /* Clear the authentication mechanism used */ - pop3c->tls_supported = FALSE; /* Clear the TLS capability */ + pop3c->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */ + pop3c->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */ + pop3c->tls_supported = FALSE; /* Clear the TLS capability */ /* Send the CAPA command */ result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA"); @@ -543,131 +449,82 @@ static CURLcode pop3_perform_apop(struct connectdata *conn) /*********************************************************************** * - * pop3_perform_authenticate() + * pop3_perform_auth() + * + * Sends an AUTH command allowing the client to login with the given SASL + * authentication mechanism. + */ +static CURLcode pop3_perform_auth(struct connectdata *conn, + const char *mech, + const char *initresp) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + + if(initresp) { /* AUTH <mech> ...<crlf> */ + /* Send the AUTH command with the initial response */ + result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp); + } + else { + /* Send the AUTH command */ + result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech); + } + + return result; +} + +/*********************************************************************** * - * Sends an AUTH command allowing the client to login with the appropriate - * SASL authentication mechanism. + * pop3_continue_auth() * - * Additionally, the function will perform fallback to APOP and USER commands - * should a common mechanism not be available between the client and server. + * Sends SASL continuation data or cancellation. */ -static CURLcode pop3_perform_authenticate(struct connectdata *conn) +static CURLcode pop3_continue_auth(struct connectdata *conn, + const char *resp) +{ + struct pop3_conn *pop3c = &conn->proto.pop3c; + + return Curl_pp_sendf(&pop3c->pp, "%s", resp); +} + +/*********************************************************************** + * + * pop3_perform_authentication() + * + * Initiates the authentication sequence, with the appropriate SASL + * authentication mechanism, falling back to APOP and clear text should a + * common mechanism not be available between the client and server. + */ +static CURLcode pop3_perform_authentication(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; struct pop3_conn *pop3c = &conn->proto.pop3c; - const char *mech = NULL; - char *initresp = NULL; - size_t len = 0; - pop3state state1 = POP3_STOP; - pop3state state2 = POP3_STOP; + saslprogress progress = SASL_IDLE; - /* Check we have a username and password to authenticate with and end the + /* Check we have enough data to authenticate with and end the connect phase if we don't */ - if(!conn->bits.user_passwd) { + if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) { state(conn, POP3_STOP); - return result; } - /* Calculate the supported authentication mechanism by decreasing order of - security */ - if(pop3c->authtypes & POP3_TYPE_SASL) { -#ifndef CURL_DISABLE_CRYPTO_AUTH - if((pop3c->authmechs & SASL_MECH_DIGEST_MD5) && - (pop3c->prefmech & SASL_MECH_DIGEST_MD5)) { - mech = SASL_MECH_STRING_DIGEST_MD5; - state1 = POP3_AUTH_DIGESTMD5; - pop3c->authused = SASL_MECH_DIGEST_MD5; - } - else if((pop3c->authmechs & SASL_MECH_CRAM_MD5) && - (pop3c->prefmech & SASL_MECH_CRAM_MD5)) { - mech = SASL_MECH_STRING_CRAM_MD5; - state1 = POP3_AUTH_CRAMMD5; - pop3c->authused = SASL_MECH_CRAM_MD5; - } - else -#endif -#ifdef USE_NTLM - if((pop3c->authmechs & SASL_MECH_NTLM) && - (pop3c->prefmech & SASL_MECH_NTLM)) { - mech = SASL_MECH_STRING_NTLM; - state1 = POP3_AUTH_NTLM; - state2 = POP3_AUTH_NTLM_TYPE2MSG; - pop3c->authused = SASL_MECH_NTLM; - - if(data->set.sasl_ir) - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, - &initresp, &len); - } - else -#endif - if(((pop3c->authmechs & SASL_MECH_XOAUTH2) && - (pop3c->prefmech & SASL_MECH_XOAUTH2) && - (pop3c->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) { - mech = SASL_MECH_STRING_XOAUTH2; - state1 = POP3_AUTH_XOAUTH2; - state2 = POP3_AUTH_FINAL; - pop3c->authused = SASL_MECH_XOAUTH2; - - if(data->set.sasl_ir) - result = Curl_sasl_create_xoauth2_message(conn->data, conn->user, - conn->xoauth2_bearer, - &initresp, &len); - } - else if((pop3c->authmechs & SASL_MECH_LOGIN) && - (pop3c->prefmech & SASL_MECH_LOGIN)) { - mech = SASL_MECH_STRING_LOGIN; - state1 = POP3_AUTH_LOGIN; - state2 = POP3_AUTH_LOGIN_PASSWD; - pop3c->authused = SASL_MECH_LOGIN; - - if(data->set.sasl_ir) - result = Curl_sasl_create_login_message(conn->data, conn->user, - &initresp, &len); - } - else if((pop3c->authmechs & SASL_MECH_PLAIN) && - (pop3c->prefmech & SASL_MECH_PLAIN)) { - mech = SASL_MECH_STRING_PLAIN; - state1 = POP3_AUTH_PLAIN; - state2 = POP3_AUTH_FINAL; - pop3c->authused = SASL_MECH_PLAIN; - - if(data->set.sasl_ir) - result = Curl_sasl_create_plain_message(conn->data, conn->user, - conn->passwd, &initresp, - &len); - } - } - - if(!result) { - if(mech && (pop3c->preftype & POP3_TYPE_SASL)) { - /* Perform SASL based authentication */ - if(initresp && - 8 + strlen(mech) + len <= 255) { /* AUTH <mech> ...<crlf> */ - result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp); - - if(!result) - state(conn, state2); - } - else { - result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech); + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) { + /* Calculate the SASL login details */ + result = Curl_sasl_start(&pop3c->sasl, conn, FALSE, &progress); - if(!result) - state(conn, state1); - } + if(!result) + if(progress == SASL_INPROGRESS) + state(conn, POP3_AUTH); + } - Curl_safefree(initresp); - } + if(!result && progress == SASL_IDLE) { #ifndef CURL_DISABLE_CRYPTO_AUTH - else if((pop3c->authtypes & POP3_TYPE_APOP) && - (pop3c->preftype & POP3_TYPE_APOP)) + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) /* Perform APOP authentication */ result = pop3_perform_apop(conn); + else #endif - else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) && - (pop3c->preftype & POP3_TYPE_CLEARTEXT)) + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) /* Perform clear text authentication */ result = pop3_perform_user(conn); else { @@ -689,7 +546,7 @@ static CURLcode pop3_perform_authenticate(struct connectdata *conn) static CURLcode pop3_perform_command(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; const char *command = NULL; @@ -745,442 +602,202 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Got unexpected pop3-server response"); - result = CURLE_FTP_WEIRD_SERVER_REPLY; - } - else - result = pop3_perform_capa(conn); - - return result; -} - -/* For CAPA responses */ -static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct pop3_conn *pop3c = &conn->proto.pop3c; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') - result = pop3_perform_user(conn); - else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { - /* We don't have a SSL/TLS connection yet, but SSL is requested */ - if(pop3c->tls_supported) - /* Switch to TLS connection now */ - result = pop3_perform_starttls(conn); - else if(data->set.use_ssl == CURLUSESSL_TRY) - /* Fallback and carry on with authentication */ - result = pop3_perform_authenticate(conn); - else { - failf(data, "STLS not supported."); - result = CURLE_USE_SSL_FAILED; - } - } - else - result = pop3_perform_authenticate(conn); - - return result; -} - -/* For STARTTLS responses */ -static CURLcode pop3_state_starttls_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - if(data->set.use_ssl != CURLUSESSL_TRY) { - failf(data, "STARTTLS denied. %c", pop3code); - result = CURLE_USE_SSL_FAILED; - } - else - result = pop3_perform_authenticate(conn); - } - else - result = pop3_perform_upgrade_tls(conn); - - return result; -} - -/* For AUTH PLAIN (without initial response) responses */ -static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *plainauth = NULL; + const char *line = data->state.buffer; + size_t len = strlen(line); + size_t i; (void)instate; /* no use for this yet */ if(pop3code != '+') { - failf(data, "Access denied. %c", pop3code); - result = CURLE_LOGIN_DENIED; + failf(data, "Got unexpected pop3-server response"); + result = CURLE_WEIRD_SERVER_REPLY; } else { - /* Create the authorisation message */ - result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, - &plainauth, &len); - - /* Send the message */ - if(!result) { - if(plainauth) { - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", plainauth); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - - Curl_safefree(plainauth); - } - } - - return result; -} - -/* For AUTH LOGIN (without initial response) responses */ -static CURLcode pop3_state_auth_login_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *authuser = NULL; + /* Does the server support APOP authentication? */ + if(len >= 4 && line[len - 2] == '>') { + /* Look for the APOP timestamp */ + for(i = 3; i < len - 2; ++i) { + if(line[i] == '<') { + /* Calculate the length of the timestamp */ + size_t timestamplen = len - 1 - i; + if(!timestamplen) + break; - (void)instate; /* no use for this yet */ + /* Allocate some memory for the timestamp */ + pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1); - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the user message */ - result = Curl_sasl_create_login_message(data, conn->user, - &authuser, &len); + if(!pop3c->apoptimestamp) + break; - /* Send the user */ - if(!result) { - if(authuser) { - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authuser); + /* Copy the timestamp */ + memcpy(pop3c->apoptimestamp, line + i, timestamplen); + pop3c->apoptimestamp[timestamplen] = '\0'; - if(!result) - state(conn, POP3_AUTH_LOGIN_PASSWD); + /* Store the APOP capability */ + pop3c->authtypes |= POP3_TYPE_APOP; + break; + } } - - Curl_safefree(authuser); } - } - return result; -} - -/* For AUTH LOGIN user entry responses */ -static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *authpasswd = NULL; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the password message */ - result = Curl_sasl_create_login_message(data, conn->passwd, - &authpasswd, &len); - - /* Send the password */ - if(!result) { - if(authpasswd) { - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authpasswd); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - - Curl_safefree(authpasswd); - } + result = pop3_perform_capa(conn); } return result; } -#ifndef CURL_DISABLE_CRYPTO_AUTH -/* For AUTH CRAM-MD5 responses */ -static CURLcode pop3_state_auth_cram_resp(struct connectdata *conn, - int pop3code, - pop3state instate) +/* For CAPA responses */ +static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code, + pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlg64 = data->state.buffer; - size_t len = 0; - char *rplyb64 = NULL; + struct Curl_easy *data = conn->data; + struct pop3_conn *pop3c = &conn->proto.pop3c; + const char *line = data->state.buffer; + size_t len = strlen(line); + size_t wordlen; (void)instate; /* no use for this yet */ - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - return CURLE_LOGIN_DENIED; - } - - /* Get the challenge */ - for(chlg64 += 2; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++) - ; - - /* Terminate the challenge */ - if(*chlg64 != '=') { - for(len = strlen(chlg64); len--;) - if(chlg64[len] != '\r' && chlg64[len] != '\n' && chlg64[len] != ' ' && - chlg64[len] != '\t') - break; - - if(++len) { - chlg64[len] = '\0'; - } - } - - /* Create the response message */ - result = Curl_sasl_create_cram_md5_message(data, chlg64, conn->user, - conn->passwd, &rplyb64, &len); - - /* Send the response */ - if(!result) { - if(rplyb64) { - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64); + /* Do we have a untagged continuation response? */ + if(pop3code == '*') { + /* Does the server support the STLS capability? */ + if(len >= 4 && !memcmp(line, "STLS", 4)) + pop3c->tls_supported = TRUE; - if(!result) - state(conn, POP3_AUTH_FINAL); - } + /* Does the server support clear text authentication? */ + else if(len >= 4 && !memcmp(line, "USER", 4)) + pop3c->authtypes |= POP3_TYPE_CLEARTEXT; - Curl_safefree(rplyb64); - } + /* Does the server support SASL based authentication? */ + else if(len >= 5 && !memcmp(line, "SASL ", 5)) { + pop3c->authtypes |= POP3_TYPE_SASL; - return result; -} + /* Advance past the SASL keyword */ + line += 5; + len -= 5; -/* For AUTH DIGEST-MD5 challenge responses */ -static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlg64 = data->state.buffer; - size_t len = 0; - char *rplyb64 = NULL; + /* Loop through the data line */ + for(;;) { + size_t llen; + unsigned int mechbit; - (void)instate; /* no use for this yet */ + while(len && + (*line == ' ' || *line == '\t' || + *line == '\r' || *line == '\n')) { - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - return CURLE_LOGIN_DENIED; - } + line++; + len--; + } - /* Get the challenge */ - for(chlg64 += 2; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++) - ; + if(!len) + break; - /* Create the response message */ - result = Curl_sasl_create_digest_md5_message(data, chlg64, conn->user, - conn->passwd, "pop", - &rplyb64, &len); + /* Extract the word */ + for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && + line[wordlen] != '\t' && line[wordlen] != '\r' && + line[wordlen] != '\n';) + wordlen++; - /* Send the response */ - if(!result) { - if(rplyb64) { - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64); + /* Test the word for a matching authentication mechanism */ + mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); + if(mechbit && llen == wordlen) + pop3c->sasl.authmechs |= mechbit; - if(!result) - state(conn, POP3_AUTH_DIGESTMD5_RESP); + line += wordlen; + len -= wordlen; + } } - - Curl_safefree(rplyb64); } - - return result; -} - -/* For AUTH DIGEST-MD5 challenge-response responses */ -static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Authentication failed: %d", pop3code); - result = CURLE_LOGIN_DENIED; + else if(pop3code == '+') { + if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { + /* We don't have a SSL/TLS connection yet, but SSL is requested */ + if(pop3c->tls_supported) + /* Switch to TLS connection now */ + result = pop3_perform_starttls(conn); + else if(data->set.use_ssl == CURLUSESSL_TRY) + /* Fallback and carry on with authentication */ + result = pop3_perform_authentication(conn); + else { + failf(data, "STLS not supported."); + result = CURLE_USE_SSL_FAILED; + } + } + else + result = pop3_perform_authentication(conn); } else { - /* Send an empty response */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", ""); + /* Clear text is supported when CAPA isn't recognised */ + pop3c->authtypes |= POP3_TYPE_CLEARTEXT; - if(!result) - state(conn, POP3_AUTH_FINAL); + result = pop3_perform_authentication(conn); } return result; } -#endif -#ifdef USE_NTLM -/* For AUTH NTLM (without initial response) responses */ -static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn, - int pop3code, - pop3state instate) +/* For STARTTLS responses */ +static CURLcode pop3_state_starttls_resp(struct connectdata *conn, + int pop3code, + pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *type1msg = NULL; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the type-1 message */ - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, - &type1msg, &len); - - /* Send the message */ - if(!result) { - if(type1msg) { - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type1msg); - - if(!result) - state(conn, POP3_AUTH_NTLM_TYPE2MSG); - } - - Curl_safefree(type1msg); + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied"); + result = CURLE_USE_SSL_FAILED; } + else + result = pop3_perform_authentication(conn); } + else + result = pop3_perform_upgrade_tls(conn); return result; } -/* For NTLM type-2 responses (sent in reponse to our type-1 message) */ -static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn, - int pop3code, - pop3state instate) +/* For SASL authentication responses */ +static CURLcode pop3_state_auth_resp(struct connectdata *conn, + int pop3code, + pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *type3msg = NULL; + struct Curl_easy *data = conn->data; + struct pop3_conn *pop3c = &conn->proto.pop3c; + saslprogress progress; (void)instate; /* no use for this yet */ - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the type-3 message */ - result = Curl_sasl_create_ntlm_type3_message(data, - data->state.buffer + 2, - conn->user, conn->passwd, - &conn->ntlm, - &type3msg, &len); - - /* Send the message */ - if(!result) { - if(type3msg) { - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type3msg); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - - Curl_safefree(type3msg); - } - } - - return result; -} + result = Curl_sasl_continue(&pop3c->sasl, conn, pop3code, &progress); + if(!result) + switch(progress) { + case SASL_DONE: + state(conn, POP3_STOP); /* Authenticated */ + break; + case SASL_IDLE: /* No mechanism left after cancellation */ +#ifndef CURL_DISABLE_CRYPTO_AUTH + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) + /* Perform APOP authentication */ + result = pop3_perform_apop(conn); + else #endif - -/* For AUTH XOAUTH2 (without initial response) responses */ -static CURLcode pop3_state_auth_xoauth2_resp(struct connectdata *conn, - int pop3code, pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *xoauth = NULL; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the authorisation message */ - result = Curl_sasl_create_xoauth2_message(conn->data, conn->user, - conn->xoauth2_bearer, - &xoauth, &len); - - /* Send the message */ - if(!result) { - if(xoauth) { - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", xoauth); - - if(!result) - state(conn, POP3_AUTH_FINAL); + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) + /* Perform clear text authentication */ + result = pop3_perform_user(conn); + else { + failf(data, "Authentication cancelled"); + result = CURLE_LOGIN_DENIED; } - - Curl_safefree(xoauth); + break; + default: + break; } - } - - return result; -} - -/* For final responses to the AUTH sequence */ -static CURLcode pop3_state_auth_final_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Authentication failed: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else - /* End of connect phase */ - state(conn, POP3_STOP); return result; } @@ -1191,7 +808,7 @@ static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -1212,7 +829,7 @@ static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -1235,7 +852,7 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -1256,7 +873,7 @@ static CURLcode pop3_state_command_resp(struct connectdata *conn, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; struct pop3_conn *pop3c = &conn->proto.pop3c; struct pingpong *pp = &pop3c->pp; @@ -1324,12 +941,15 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) if(pp->sendleft) return Curl_pp_flushsend(pp); - /* Read the response from the server */ - result = Curl_pp_readresp(sock, pp, &pop3code, &nread); - if(result) - return result; + do { + /* Read the response from the server */ + result = Curl_pp_readresp(sock, pp, &pop3code, &nread); + if(result) + return result; + + if(!pop3code) + break; - if(pop3code) { /* We have now received a full POP3 server response */ switch(pop3c->state) { case POP3_SERVERGREET: @@ -1344,50 +964,8 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_starttls_resp(conn, pop3code, pop3c->state); break; - case POP3_AUTH_PLAIN: - result = pop3_state_auth_plain_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_LOGIN: - result = pop3_state_auth_login_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_LOGIN_PASSWD: - result = pop3_state_auth_login_password_resp(conn, pop3code, - pop3c->state); - break; - -#ifndef CURL_DISABLE_CRYPTO_AUTH - case POP3_AUTH_CRAMMD5: - result = pop3_state_auth_cram_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_DIGESTMD5: - result = pop3_state_auth_digest_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_DIGESTMD5_RESP: - result = pop3_state_auth_digest_resp_resp(conn, pop3code, pop3c->state); - break; -#endif - -#ifdef USE_NTLM - case POP3_AUTH_NTLM: - result = pop3_state_auth_ntlm_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_NTLM_TYPE2MSG: - result = pop3_state_auth_ntlm_type2msg_resp(conn, pop3code, - pop3c->state); - break; -#endif - - case POP3_AUTH_XOAUTH2: - result = pop3_state_auth_xoauth2_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_FINAL: - result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state); + case POP3_AUTH: + result = pop3_state_auth_resp(conn, pop3code, pop3c->state); break; #ifndef CURL_DISABLE_CRYPTO_AUTH @@ -1415,7 +993,7 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) state(conn, POP3_STOP); break; } - } + } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp)); return result; } @@ -1449,12 +1027,12 @@ static CURLcode pop3_block_statemach(struct connectdata *conn) return result; } -/* Allocate and initialize the POP3 struct for the current SessionHandle if +/* Allocate and initialize the POP3 struct for the current Curl_easy if required */ static CURLcode pop3_init(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3; pop3 = data->req.protop = calloc(sizeof(struct POP3), 1); @@ -1490,7 +1068,7 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done) *done = FALSE; /* default to not done yet */ /* We always support persistent connections in POP3 */ - conn->bits.close = FALSE; + connkeep(conn, "POP3 default"); /* Set the default response time-out */ pp->response_time = RESP_TIMEOUT; @@ -1500,7 +1078,7 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done) /* Set the default preferred authentication type and mechanism */ pop3c->preftype = POP3_TYPE_ANY; - pop3c->prefmech = SASL_AUTH_ANY; + Curl_sasl_init(&pop3c->sasl, &saslpop3); /* Initialise the pingpong layer */ Curl_pp_init(pp); @@ -1531,20 +1109,16 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, bool premature) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; (void)premature; if(!pop3) - /* When the easy handle is removed from the multi interface while libcurl - is still trying to resolve the host name, the POP3 struct is not yet - initialized. However, the removal action calls Curl_done() which in - turn calls this function, so we simply return success. */ return CURLE_OK; if(status) { - conn->bits.close = TRUE; /* marked for closure */ + connclose(conn, "POP3 done with bad status"); result = status; /* use the already set error code */ } @@ -1570,12 +1144,12 @@ static CURLcode pop3_perform(struct connectdata *conn, bool *connected, { /* This is POP3 and no proxy */ CURLcode result = CURLE_OK; + struct POP3 *pop3 = conn->data->req.protop; DEBUGF(infof(conn->data, "DO phase starts\n")); if(conn->data->set.opt_no_body) { /* Requested no body means no transfer */ - struct POP3 *pop3 = conn->data->req.protop; pop3->transfer = FTPTRANSFER_INFO; } @@ -1634,8 +1208,7 @@ static CURLcode pop3_do(struct connectdata *conn, bool *done) * Disconnect from an POP3 server. Cleanup protocol-specific per-connection * resources. BLOCKING. */ -static CURLcode pop3_disconnect(struct connectdata *conn, - bool dead_connection) +static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection) { struct pop3_conn *pop3c = &conn->proto.pop3c; @@ -1645,7 +1218,7 @@ static CURLcode pop3_disconnect(struct connectdata *conn, /* The POP3 session may or may not have been allocated/setup at this point! */ - if(!dead_connection && pop3c->pp.conn) + if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart) if(!pop3_perform_quit(conn)) (void)pop3_block_statemach(conn); /* ignore errors on QUIT */ @@ -1653,7 +1226,7 @@ static CURLcode pop3_disconnect(struct connectdata *conn, Curl_pp_disconnect(&pop3c->pp); /* Cleanup the SASL module */ - Curl_sasl_cleanup(conn, pop3c->authused); + Curl_sasl_cleanup(conn, pop3c->sasl.authused); /* Cleanup our connection based variables */ Curl_safefree(pop3c->apoptimestamp); @@ -1700,7 +1273,7 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn, { CURLcode result = CURLE_OK; bool connected = FALSE; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Make sure size is unknown at this point */ data->req.size = -1; @@ -1708,8 +1281,8 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn, /* Set the progress data */ Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); - Curl_pgrsSetUploadSize(data, 0); - Curl_pgrsSetDownloadSize(data, 0); + Curl_pgrsSetUploadSize(data, -1); + Curl_pgrsSetDownloadSize(data, -1); /* Carry out the perform */ result = pop3_perform(conn, &connected, dophase_done); @@ -1723,36 +1296,15 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn, static CURLcode pop3_setup_connection(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Initialise the POP3 layer */ CURLcode result = pop3_init(conn); if(result) return result; - if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { - /* Unless we have asked to tunnel POP3 operations through the proxy, we - switch and use HTTP operations only */ -#ifndef CURL_DISABLE_HTTP - if(conn->handler == &Curl_handler_pop3) - conn->handler = &Curl_handler_pop3_proxy; - else { -#ifdef USE_SSL - conn->handler = &Curl_handler_pop3s_proxy; -#else - failf(data, "POP3S not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - - /* set it up as an HTTP connection instead */ - return conn->handler->setup_connection(conn); -#else - failf(data, "POP3 over http proxy requires HTTP support built-in!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - + /* Clear the TLS upgraded flag */ + conn->tls_upgraded = FALSE; data->state.path++; /* don't include the initial slash */ return CURLE_OK; @@ -1768,63 +1320,52 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; - const char *options = conn->options; - const char *ptr = options; + const char *ptr = conn->options; + + pop3c->sasl.resetprefs = TRUE; - if(options) { + while(!result && ptr && *ptr) { const char *key = ptr; + const char *value; while(*ptr && *ptr != '=') ptr++; - if(strnequal(key, "AUTH", 4)) { - const char *value = ptr + 1; + value = ptr + 1; - if(strequal(value, "*")) { - pop3c->preftype = POP3_TYPE_ANY; - pop3c->prefmech = SASL_AUTH_ANY; - } - else if(strequal(value, "+APOP")) { + while(*ptr && *ptr != ';') + ptr++; + + if(strncasecompare(key, "AUTH=", 5)) { + result = Curl_sasl_parse_url_auth_option(&pop3c->sasl, + value, ptr - value); + + if(result && strncasecompare(value, "+APOP", ptr - value)) { pop3c->preftype = POP3_TYPE_APOP; - pop3c->prefmech = SASL_AUTH_NONE; - } - else if(strequal(value, SASL_MECH_STRING_LOGIN)) { - pop3c->preftype = POP3_TYPE_SASL; - pop3c->prefmech = SASL_MECH_LOGIN; - } - else if(strequal(value, SASL_MECH_STRING_PLAIN)) { - pop3c->preftype = POP3_TYPE_SASL; - pop3c->prefmech = SASL_MECH_PLAIN; - } - else if(strequal(value, SASL_MECH_STRING_CRAM_MD5)) { - pop3c->preftype = POP3_TYPE_SASL; - pop3c->prefmech = SASL_MECH_CRAM_MD5; - } - else if(strequal(value, SASL_MECH_STRING_DIGEST_MD5)) { - pop3c->preftype = POP3_TYPE_SASL; - pop3c->prefmech = SASL_MECH_DIGEST_MD5; - } - else if(strequal(value, SASL_MECH_STRING_GSSAPI)) { - pop3c->preftype = POP3_TYPE_SASL; - pop3c->prefmech = SASL_MECH_GSSAPI; - } - else if(strequal(value, SASL_MECH_STRING_NTLM)) { - pop3c->preftype = POP3_TYPE_SASL; - pop3c->prefmech = SASL_MECH_NTLM; - } - else if(strequal(value, SASL_MECH_STRING_XOAUTH2)) { - pop3c->preftype = POP3_TYPE_SASL; - pop3c->prefmech = SASL_MECH_XOAUTH2; - } - else { - pop3c->preftype = POP3_TYPE_NONE; - pop3c->prefmech = SASL_AUTH_NONE; + pop3c->sasl.prefmech = SASL_AUTH_NONE; + result = CURLE_OK; } } else result = CURLE_URL_MALFORMAT; + + if(*ptr == ';') + ptr++; } + if(pop3c->preftype != POP3_TYPE_APOP) + switch(pop3c->sasl.prefmech) { + case SASL_AUTH_NONE: + pop3c->preftype = POP3_TYPE_NONE; + break; + case SASL_AUTH_DEFAULT: + pop3c->preftype = POP3_TYPE_ANY; + break; + default: + pop3c->preftype = POP3_TYPE_SASL; + break; + } + return result; } @@ -1837,7 +1378,7 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn) static CURLcode pop3_parse_url_path(struct connectdata *conn) { /* The POP3 struct is already initialised in pop3_connect() */ - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; const char *path = data->state.path; @@ -1854,7 +1395,7 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn) static CURLcode pop3_parse_custom_request(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; const char *custom = data->set.str[STRING_CUSTOMREQUEST]; @@ -1876,7 +1417,7 @@ CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread) { /* This code could be made into a special function in the handler struct */ CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SingleRequest *k = &data->req; struct pop3_conn *pop3c = &conn->proto.pop3c; @@ -1957,7 +1498,7 @@ CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread) if(prev) { /* If the partial match was the CRLF and dot then only write the CRLF as the server would have inserted the dot */ - result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB, + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, strip_dot ? prev - 1 : prev); if(result) |