From ec3bb8f727405642a471b4b1b9eb0118fc003104 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 12 Dec 2009 21:54:01 +0000 Subject: introducing IMAP, POP3 and SMTP support (still lots of polish left to do) --- lib/pop3.c | 961 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 961 insertions(+) create mode 100644 lib/pop3.c (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c new file mode 100644 index 000000000..cf4fd1c02 --- /dev/null +++ b/lib/pop3.c @@ -0,0 +1,961 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2009, Daniel Stenberg, , 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. + * + * 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 + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * RFC1939 POP3 protocol + * RFC2384 POP URL Scheme + * RFC2595 Using TLS with IMAP, POP3 and ACAP + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifndef CURL_DISABLE_POP3 +#include +#include +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_UTSNAME_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef VMS +#include +#include +#endif + +#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) +#undef in_addr_t +#define in_addr_t unsigned long +#endif + +#include +#include "urldata.h" +#include "sendf.h" +#include "easyif.h" /* for Curl_convert_... prototypes */ + +#include "if2ip.h" +#include "hostip.h" +#include "progress.h" +#include "transfer.h" +#include "escape.h" +#include "http.h" /* for HTTP proxy tunnel stuff */ +#include "socks.h" +#include "pop3.h" + +#include "strtoofft.h" +#include "strequal.h" +#include "sslgen.h" +#include "connect.h" +#include "strerror.h" +#include "select.h" +#include "multiif.h" +#include "url.h" +#include "rawstr.h" +#include "strtoofft.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* Local API functions */ +static CURLcode pop3_parse_url_path(struct connectdata *conn); +static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done); +static CURLcode pop3_do(struct connectdata *conn, bool *done); +static CURLcode pop3_done(struct connectdata *conn, + CURLcode, bool premature); +static CURLcode pop3_connect(struct connectdata *conn, bool *done); +static CURLcode pop3_disconnect(struct connectdata *conn); +static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done); +static int pop3_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks); +static CURLcode pop3_doing(struct connectdata *conn, + bool *dophase_done); +static CURLcode pop3_setup_connection(struct connectdata * conn); + +/* + * POP3 protocol handler. + */ + +const struct Curl_handler Curl_handler_pop3 = { + "POP3", /* scheme */ + pop3_setup_connection, /* setup_connection */ + pop3_do, /* do_it */ + pop3_done, /* done */ + ZERO_NULL, /* do_more */ + pop3_connect, /* connect_it */ + pop3_multi_statemach, /* connecting */ + pop3_doing, /* doing */ + pop3_getsock, /* proto_getsock */ + pop3_getsock, /* doing_getsock */ + ZERO_NULL, /* perform_getsock */ + pop3_disconnect, /* disconnect */ + PORT_POP3, /* defport */ + PROT_POP3 /* protocol */ +}; + + +#ifdef USE_SSL +/* + * POP3S protocol handler. + */ + +const struct Curl_handler Curl_handler_pop3s = { + "POP3S", /* scheme */ + pop3_setup_connection, /* setup_connection */ + pop3_do, /* do_it */ + pop3_done, /* done */ + ZERO_NULL, /* do_more */ + pop3_connect, /* connect_it */ + pop3_multi_statemach, /* connecting */ + pop3_doing, /* doing */ + pop3_getsock, /* proto_getsock */ + pop3_getsock, /* doing_getsock */ + ZERO_NULL, /* perform_getsock */ + pop3_disconnect, /* disconnect */ + PORT_POP3S, /* defport */ + PROT_POP3 | PROT_POP3S | PROT_SSL /* protocol */ +}; +#endif + +#ifndef CURL_DISABLE_HTTP +/* + * HTTP-proxyed POP3 protocol handler. + */ + +const struct Curl_handler Curl_handler_pop3_proxy = { + "POP3", /* scheme */ + ZERO_NULL, /* 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, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + PORT_POP3, /* defport */ + PROT_HTTP /* protocol */ +}; + + +#ifdef USE_SSL +/* + * HTTP-proxyed POP3S protocol handler. + */ + +const struct Curl_handler Curl_handler_pop3s_proxy = { + "POP3S", /* scheme */ + ZERO_NULL, /* 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, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + PORT_POP3S, /* defport */ + PROT_HTTP /* protocol */ +}; +#endif +#endif + + +/* function that checks for a pop3 status code at the start of the given + string */ +static int pop3_endofresp(struct pingpong *pp, + int *resp) +{ + char *line = pp->linestart_resp; + size_t len = pp->nread_resp; + + if( ((len >= 3) && !memcmp("+OK", line, 3)) || + ((len >= 4) && !memcmp("-ERR", line, 4)) ) { + *resp=line[1]; /* O or E */ + return TRUE; + } + + return FALSE; /* nothing for us */ +} + +/* This is the ONLY way to change POP3 state! */ +static void state(struct connectdata *conn, + pop3state newstate) +{ +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ + static const char * const names[]={ + "STOP", + "SERVERGREET", + "USER", + "PASS", + "STARTTLS", + "RETR", + "QUIT", + /* LAST */ + }; +#endif + struct pop3_conn *pop3c = &conn->proto.pop3c; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + if(pop3c->state != newstate) + infof(conn->data, "POP3 %p state change from %s to %s\n", + pop3c, names[pop3c->state], names[newstate]); +#endif + pop3c->state = newstate; +} + +static CURLcode pop3_state_user(struct connectdata *conn) +{ + CURLcode result; + struct FTP *pop3 = conn->data->state.proto.pop3; + + /* send USER */ + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s", + pop3->user?pop3->user:""); + if(result) + return result; + + state(conn, POP3_USER); + + return CURLE_OK; +} + +/* For the POP3 "protocol connect" and "doing" phases only */ +static int pop3_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) +{ + return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks); +} + +/* 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 != 'O') { + failf(data, "STARTTLS denied. %c", pop3code); + result = CURLE_LOGIN_DENIED; + } + else { + /* Curl_ssl_connect is BLOCKING */ + result = Curl_ssl_connect(conn, FIRSTSOCKET); + if(CURLE_OK == result) { + conn->protocol |= PROT_POP3S; + result = pop3_state_user(conn); + } + } + state(conn, POP3_STOP); + return result; +} + +/* for USER responses */ +static CURLcode pop3_state_user_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct FTP *pop3 = data->state.proto.pop3; + + (void)instate; /* no use for this yet */ + + if(pop3code != 'O') { + failf(data, "Access denied. %c", pop3code); + result = CURLE_LOGIN_DENIED; + } + + /* send PASS */ + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s", + pop3->passwd?pop3->passwd:""); + if(result) + return result; + + state(conn, POP3_PASS); + return result; +} + +/* for PASS responses */ +static CURLcode pop3_state_pass_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 != 'O') { + failf(data, "Access denied. %c", pop3code); + result = CURLE_LOGIN_DENIED; + } + + state(conn, POP3_STOP); + return result; +} + +/* for the retr response */ +static CURLcode pop3_state_retr_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct FTP *pop3 = data->state.proto.pop3; + struct pop3_conn *pop3c = &conn->proto.pop3c; + struct pingpong *pp = &pop3c->pp; + + (void)instate; /* no use for this yet */ + + if('O' != pop3code) { + state(conn, POP3_STOP); + return CURLE_RECV_ERROR; + } + + /* POP3 download */ + result=Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, + pop3->bytecountp, + -1, NULL); /* no upload here */ + + if(pp->cache) { + /* At this point there is a bunch of data in the header "cache" that is + actually body content, send it as body and then skip it. Do note + that there may even be additional "headers" after the body. */ + + /* we may get the EOB already here! */ + result = Curl_pop3_write(conn, pp->cache, pp->cache_size); + if(result) + return result; + + /* cache is drained */ + free(pp->cache); + pp->cache = NULL; + pp->cache_size = 0; + } + + state(conn, POP3_STOP); + return result; +} + +/* start the DO phase */ +static CURLcode pop3_retr(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "RETR %s", pop3c->mailbox); + if(result) + return result; + + state(conn, POP3_RETR); + return result; +} + +static CURLcode pop3_statemach_act(struct connectdata *conn) +{ + CURLcode result; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + struct SessionHandle *data=conn->data; + int pop3code; + struct pop3_conn *pop3c = &conn->proto.pop3c; + struct pingpong *pp = &pop3c->pp; + size_t nread = 0; + + if(pp->sendleft) + return Curl_pp_flushsend(pp); + + /* we read a piece of response */ + result = Curl_pp_readresp(sock, pp, &pop3code, &nread); + if(result) + return result; + + if(pop3code) { + /* we have now received a full POP3 server response */ + switch(pop3c->state) { + case POP3_SERVERGREET: + if(pop3code != 'O') { + failf(data, "Got unexpected pop3-server response"); + return CURLE_FTP_WEIRD_SERVER_REPLY; + } + + if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) { + /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch + to TLS connection now */ + const char *str; + + result = Curl_pp_sendf(&pop3c->pp, "STARTTLS", str); + state(conn, POP3_STARTTLS); + } + else + result = pop3_state_user(conn); + if(result) + return result; + break; + + case POP3_USER: + result = pop3_state_user_resp(conn, pop3code, pop3c->state); + break; + + case POP3_PASS: + result = pop3_state_pass_resp(conn, pop3code, pop3c->state); + break; + + case POP3_STARTTLS: + result = pop3_state_starttls_resp(conn, pop3code, pop3c->state); + break; + + case POP3_RETR: + result = pop3_state_retr_resp(conn, pop3code, pop3c->state); + break; + + case POP3_QUIT: + /* fallthrough, just stop! */ + default: + /* internal error */ + state(conn, POP3_STOP); + break; + } + } + return result; +} + +/* called repeatedly until done from multi.c */ +static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done) +{ + struct pop3_conn *pop3c = &conn->proto.pop3c; + CURLcode result = Curl_pp_multi_statemach(&pop3c->pp); + + *done = (bool)(pop3c->state == POP3_STOP); + + return result; +} + +static CURLcode pop3_easy_statemach(struct connectdata *conn) +{ + struct pop3_conn *pop3c = &conn->proto.pop3c; + struct pingpong *pp = &pop3c->pp; + CURLcode result = CURLE_OK; + + while(pop3c->state != POP3_STOP) { + result = Curl_pp_easy_statemach(pp); + if(result) + break; + } + + return result; +} + +/* + * Allocate and initialize the struct POP3 for the current SessionHandle. If + * need be. + */ +static CURLcode pop3_init(struct connectdata *conn) +{ + struct SessionHandle *data = conn->data; + struct FTP *pop3 = data->state.proto.pop3; + if(!pop3) { + pop3 = data->state.proto.pop3 = calloc(sizeof(struct FTP), 1); + if(!pop3) + return CURLE_OUT_OF_MEMORY; + } + + /* get some initial data into the pop3 struct */ + pop3->bytecountp = &data->req.bytecount; + + /* No need to duplicate user+password, the connectdata struct won't change + during a session, but we re-init them here since on subsequent inits + since the conn struct may have changed or been replaced. + */ + pop3->user = conn->user; + pop3->passwd = conn->passwd; + + return CURLE_OK; +} + +/* + * pop3_connect() should do everything that is to be considered a part of + * the connection phase. + * + * The variable 'done' points to will be TRUE if the protocol-layer connect + * phase is done when this function returns, or FALSE is not. When called as + * a part of the easy interface, it will always be TRUE. + */ +static CURLcode pop3_connect(struct connectdata *conn, + bool *done) /* see description above */ +{ + CURLcode result; + struct pop3_conn *pop3c = &conn->proto.pop3c; + struct SessionHandle *data=conn->data; + struct pingpong *pp = &pop3c->pp; + + *done = FALSE; /* default to not done yet */ + + /* If there already is a protocol-specific struct allocated for this + sessionhandle, deal with it */ + Curl_reset_reqproto(conn); + + result = pop3_init(conn); + if(CURLE_OK != result) + return result; + + /* We always support persistant connections on pop3 */ + conn->bits.close = FALSE; + + pp->response_time = RESP_TIMEOUT; /* set default response time-out */ + pp->statemach_act = pop3_statemach_act; + pp->endofresp = pop3_endofresp; + pp->conn = conn; + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY) + if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { + /* for POP3 over HTTP proxy */ + struct HTTP http_proxy; + struct FTP *pop3_save; + + /* BLOCKING */ + /* We want "seamless" POP3 operations through HTTP proxy tunnel */ + + /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member + * conn->proto.http; we want POP3 through HTTP and we have to change the + * member temporarily for connecting to the HTTP proxy. After + * Curl_proxyCONNECT we have to set back the member to the original struct + * POP3 pointer + */ + pop3_save = data->state.proto.pop3; + memset(&http_proxy, 0, sizeof(http_proxy)); + data->state.proto.http = &http_proxy; + + result = Curl_proxyCONNECT(conn, FIRSTSOCKET, + conn->host.name, conn->remote_port); + + data->state.proto.pop3 = pop3_save; + + if(CURLE_OK != result) + return result; + } +#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */ + + if(conn->protocol & PROT_POP3S) { + /* BLOCKING */ + /* POP3S is simply pop3 with SSL for the control channel */ + /* now, perform the SSL initialization for this socket */ + result = Curl_ssl_connect(conn, FIRSTSOCKET); + if(result) + return result; + } + + Curl_pp_init(pp); /* init the response reader stuff */ + + /* When we connect, we start in the state where we await the server greet + response */ + state(conn, POP3_SERVERGREET); + + if(data->state.used_interface == Curl_if_multi) + result = pop3_multi_statemach(conn, done); + else { + result = pop3_easy_statemach(conn); + if(!result) + *done = TRUE; + } + + return result; +} + +/*********************************************************************** + * + * pop3_done() + * + * The DONE function. This does what needs to be done after a single DO has + * performed. + * + * Input argument is already checked for validity. + */ +static CURLcode pop3_done(struct connectdata *conn, CURLcode status, + bool premature) +{ + struct SessionHandle *data = conn->data; + struct FTP *pop3 = data->state.proto.pop3; + CURLcode result=CURLE_OK; + (void)premature; + + if(!pop3) + /* When the easy handle is removed from the multi while libcurl is still + * trying to resolve the host name, it seems that the pop3 struct is not + * yet initialized, but the removal action calls Curl_done() which calls + * this function. So we simply return success if no pop3 pointer is set. + */ + return CURLE_OK; + + if(status) { + conn->bits.close = TRUE; /* marked for closure */ + result = status; /* use the already set error code */ + } + + /* clear these for next connection */ + pop3->transfer = FTPTRANSFER_BODY; + + return result; +} + +/*********************************************************************** + * + * pop3_perform() + * + * This is the actual DO function for POP3. Get a file/directory according to + * the options previously setup. + */ + +static +CURLcode pop3_perform(struct connectdata *conn, + bool *connected, /* connect status after PASV / PORT */ + bool *dophase_done) +{ + /* this is POP3 and no proxy */ + CURLcode result=CURLE_OK; + + DEBUGF(infof(conn->data, "DO phase starts\n")); + + if(conn->data->set.opt_no_body) { + /* requested no body means no transfer... */ + struct FTP *pop3 = conn->data->state.proto.pop3; + pop3->transfer = FTPTRANSFER_INFO; + } + + *dophase_done = FALSE; /* not done yet */ + + /* start the first command in the DO phase */ + result = pop3_retr(conn); + if(result) + return result; + + /* run the state-machine */ + if(conn->data->state.used_interface == Curl_if_multi) + result = pop3_multi_statemach(conn, dophase_done); + else { + result = pop3_easy_statemach(conn); + *dophase_done = TRUE; /* with the easy interface we are done here */ + } + *connected = conn->bits.tcpconnect; + + if(*dophase_done) + DEBUGF(infof(conn->data, "DO phase is complete\n")); + + return result; +} + +/*********************************************************************** + * + * pop3_do() + * + * This function is registered as 'curl_do' function. It decodes the path + * parts etc as a wrapper to the actual DO function (pop3_perform). + * + * The input argument is already checked for validity. + */ +static CURLcode pop3_do(struct connectdata *conn, bool *done) +{ + CURLcode retcode = CURLE_OK; + + *done = FALSE; /* default to false */ + + /* + Since connections can be re-used between SessionHandles, this might be a + connection already existing but on a fresh SessionHandle struct so we must + make sure we have a good 'struct POP3' to play with. For new connections, + the struct POP3 is allocated and setup in the pop3_connect() function. + */ + Curl_reset_reqproto(conn); + retcode = pop3_init(conn); + if(retcode) + return retcode; + + retcode = pop3_parse_url_path(conn); + if(retcode) + return retcode; + + retcode = pop3_regular_transfer(conn, done); + + return retcode; +} + +/*********************************************************************** + * + * pop3_quit() + * + * This should be called before calling sclose(). We should then wait for the + * response from the server before returning. The calling code should then try + * to close the connection. + * + */ +static CURLcode pop3_quit(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "QUIT", NULL); + if(result) + return result; + state(conn, POP3_QUIT); + + result = pop3_easy_statemach(conn); + + return result; +} + +/*********************************************************************** + * + * pop3_disconnect() + * + * Disconnect from an POP3 server. Cleanup protocol-specific per-connection + * resources. BLOCKING. + */ +static CURLcode pop3_disconnect(struct connectdata *conn) +{ + struct pop3_conn *pop3c= &conn->proto.pop3c; + + /* We cannot send quit unconditionally. If this connection is stale or + bad in any way, sending quit and waiting around here will make the + disconnect wait in vain and cause more problems than we need to. + */ + + /* The POP3 session may or may not have been allocated/setup at this + point! */ + (void)pop3_quit(conn); /* ignore errors on the LOGOUT */ + + + Curl_pp_disconnect(&pop3c->pp); + + return CURLE_OK; +} + +/*********************************************************************** + * + * pop3_parse_url_path() + * + * Parse the URL path into separate path components. + * + */ +static CURLcode pop3_parse_url_path(struct connectdata *conn) +{ + /* the pop3 struct is already inited in pop3_connect() */ + struct pop3_conn *pop3c = &conn->proto.pop3c; + struct SessionHandle *data = conn->data; + const char *path = data->state.path; + int len; + + if(!*path) + path = "INBOX"; + + /* url decode the path and use this mailbox */ + pop3c->mailbox = curl_easy_unescape(data, path, 0, &len); + + return CURLE_OK; +} + +/* call this when the DO phase has completed */ +static CURLcode pop3_dophase_done(struct connectdata *conn, + bool connected) +{ + CURLcode result = CURLE_OK; + struct FTP *pop3 = conn->data->state.proto.pop3; + struct pop3_conn *pop3c = &conn->proto.pop3c; + (void)connected; + + if(pop3->transfer != FTPTRANSFER_BODY) + /* no data to transfer */ + result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + + free(pop3c->mailbox); + + return result; +} + +/* called from multi.c while DOing */ +static CURLcode pop3_doing(struct connectdata *conn, + bool *dophase_done) +{ + CURLcode result; + result = pop3_multi_statemach(conn, dophase_done); + + if(*dophase_done) { + result = pop3_dophase_done(conn, FALSE /* not connected */); + + DEBUGF(infof(conn->data, "DO phase is complete\n")); + } + return result; +} + +/*********************************************************************** + * + * pop3_regular_transfer() + * + * The input argument is already checked for validity. + * + * Performs all commands done before a regular transfer between a local and a + * remote host. + * + */ +static +CURLcode pop3_regular_transfer(struct connectdata *conn, + bool *dophase_done) +{ + CURLcode result=CURLE_OK; + bool connected=FALSE; + struct SessionHandle *data = conn->data; + data->req.size = -1; /* make sure this is unknown at this point */ + + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + Curl_pgrsSetUploadSize(data, 0); + Curl_pgrsSetDownloadSize(data, 0); + + result = pop3_perform(conn, + &connected, /* have we connected after PASV/PORT */ + dophase_done); /* all commands in the DO-phase done? */ + + if(CURLE_OK == result) { + + if(!*dophase_done) + /* the DO phase has not completed yet */ + return CURLE_OK; + + result = pop3_dophase_done(conn, connected); + if(result) + return result; + } + + return result; +} + +static CURLcode pop3_setup_connection(struct connectdata * conn) +{ + struct SessionHandle *data = conn->data; + + 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 + } + /* + * We explicitly mark this connection as persistent here as we're doing + * POP3 over HTTP and thus we accidentally avoid setting this value + * otherwise. + */ + conn->bits.close = FALSE; +#else + failf(data, "POP3 over http proxy requires HTTP support built-in!"); + return CURLE_UNSUPPORTED_PROTOCOL; +#endif + } + + data->state.path++; /* don't include the initial slash */ + + return CURLE_OK; +} + +/* this is the 5-bytes End-Of-Body marker for POP3 */ +#define POP3_EOB "\x0d\x0a\x2e\x0d\x0a" +#define POP3_EOB_LEN 5 + +/* + * This function scans the body after the end-of-body and writes everything + * until the end is found. + */ +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; + struct SessionHandle *data = conn->data; + struct SingleRequest *k = &data->req; + + /* Detect the end-of-body marker, which is 5 bytes: + 0d 0a 2e 0d 0a. This marker can of course be spread out + over up to 5 different data chunks. Deal with it! */ + struct pop3_conn *pop3c = &conn->proto.pop3c; + int checkmax = (nread >= POP3_EOB_LEN?POP3_EOB_LEN:nread); + int checkleft = POP3_EOB_LEN-pop3c->eob; + int check = checkmax>= checkleft?checkleft:checkmax; + + if(!memcmp(POP3_EOB, &str[nread - check], check)) { + /* substring match */ + pop3c->eob += check; + if(pop3c->eob == POP3_EOB_LEN) { + /* full match, the transfer is done! */ + nread -= check; + k->keepon &= ~KEEP_RECV; + pop3c->eob = 0; + } + } + else if(pop3c->eob) { + /* not a match, but we matched a piece before so we must now + send that part as body first, before we move on and send + this buffer */ + result = Curl_client_write(conn, CLIENTWRITE_BODY, + (char *)POP3_EOB, pop3c->eob); + if(result) + return result; + pop3c->eob = 0; + } + + result = Curl_client_write(conn, CLIENTWRITE_BODY, str, nread); + + return result; +} + +#endif /* CURL_DISABLE_POP3 */ -- cgit v1.2.1 From b0f548fb56d61a44a1f689b25955140c01e1821b Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Mon, 14 Dec 2009 14:02:43 +0000 Subject: Fix compiler warnings --- lib/pop3.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index cf4fd1c02..43549f791 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -427,9 +427,7 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) { /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch to TLS connection now */ - const char *str; - - result = Curl_pp_sendf(&pop3c->pp, "STARTTLS", str); + result = Curl_pp_sendf(&pop3c->pp, "STARTTLS", NULL); state(conn, POP3_STARTTLS); } else @@ -930,7 +928,7 @@ CURLcode Curl_pop3_write(struct connectdata *conn, struct pop3_conn *pop3c = &conn->proto.pop3c; int checkmax = (nread >= POP3_EOB_LEN?POP3_EOB_LEN:nread); int checkleft = POP3_EOB_LEN-pop3c->eob; - int check = checkmax>= checkleft?checkleft:checkmax; + int check = (checkmax >= checkleft?checkleft:checkmax); if(!memcmp(POP3_EOB, &str[nread - check], check)) { /* substring match */ -- cgit v1.2.1 From 3184a91ec86b2f35f16a8e11e2daa03fac8e91b6 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Wed, 30 Dec 2009 17:59:56 +0000 Subject: VMS specific preprocessor symbol checking adjustments --- lib/pop3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 43549f791..24354504f 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -53,7 +53,7 @@ #ifdef HAVE_NETDB_H #include #endif -#ifdef VMS +#ifdef __VMS #include #include #endif -- cgit v1.2.1 From 340ab2f87f22a22a9a7c92391e1a1a62c61b5bb2 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Mon, 25 Jan 2010 23:41:02 +0000 Subject: make Curl_handler_*_proxy definition static --- lib/pop3.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 24354504f..bb3781ef3 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -161,7 +161,7 @@ const struct Curl_handler Curl_handler_pop3s = { * HTTP-proxyed POP3 protocol handler. */ -const struct Curl_handler Curl_handler_pop3_proxy = { +static const struct Curl_handler Curl_handler_pop3_proxy = { "POP3", /* scheme */ ZERO_NULL, /* setup_connection */ Curl_http, /* do_it */ @@ -184,7 +184,7 @@ const struct Curl_handler Curl_handler_pop3_proxy = { * HTTP-proxyed POP3S protocol handler. */ -const struct Curl_handler Curl_handler_pop3s_proxy = { +static const struct Curl_handler Curl_handler_pop3s_proxy = { "POP3S", /* scheme */ ZERO_NULL, /* setup_connection */ Curl_http, /* do_it */ -- cgit v1.2.1 From 715e3a806f333320f3d8a1172d7f000db59edcf6 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Sat, 30 Jan 2010 05:22:30 +0000 Subject: Make Curl_pop3_write() additionally truncate trailing POP3_EOB from received string buffer, otherwise Curl_client_write() call with zero size would write to the end of string buffer including matched POP3_EOB. --- lib/pop3.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index bb3781ef3..f94035faa 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -935,6 +935,7 @@ CURLcode Curl_pop3_write(struct connectdata *conn, pop3c->eob += check; if(pop3c->eob == POP3_EOB_LEN) { /* full match, the transfer is done! */ + str[nread - check] = '\0'; nread -= check; k->keepon &= ~KEEP_RECV; pop3c->eob = 0; -- cgit v1.2.1 From 2309b4e330b96bc2e1f8e36b6184015e59544037 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 24 Mar 2010 11:02:54 +0100 Subject: remove the CVSish $Id$ lines --- lib/pop3.c | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index f94035faa..320f75644 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -22,7 +22,6 @@ * RFC2384 POP URL Scheme * RFC2595 Using TLS with IMAP, POP3 and ACAP * - * $Id$ ***************************************************************************/ #include "setup.h" -- cgit v1.2.1 From 69ccc9f8610694134a3a33206f86d14c0f4a2bf9 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Sun, 28 Mar 2010 23:49:00 +0200 Subject: pop3: Get message listing if no mailbox in URL If you pass a URL to pop3 that does not contain a message ID as part of the URL, it will currently ask for 'INBOX' which just causes the pop3 server to return an error. The change makes libcurl treat en empty message ID as a request for LIST (list of pop3 message IDs). User's code could then parse this and download individual messages as desired. --- lib/pop3.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 5 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 320f75644..ff929b09c 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -232,6 +232,7 @@ static void state(struct connectdata *conn, "USER", "PASS", "STARTTLS", + "LIST", "RETR", "QUIT", /* LAST */ @@ -382,7 +383,49 @@ static CURLcode pop3_state_retr_resp(struct connectdata *conn, return result; } -/* start the DO phase */ + +/* for the list response */ +static CURLcode pop3_state_list_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct FTP *pop3 = data->state.proto.pop3; + struct pop3_conn *pop3c = &conn->proto.pop3c; + struct pingpong *pp = &pop3c->pp; + + (void)instate; /* no use for this yet */ + + if('O' != pop3code) { + state(conn, POP3_STOP); + return CURLE_RECV_ERROR; + } + + /* POP3 download */ + result=Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, + pop3->bytecountp, + -1, NULL); /* no upload here */ + + if(pp->cache) { + /* cache holds the email ID listing */ + + /* we may get the EOB already here! */ + result = Curl_pop3_write(conn, pp->cache, pp->cache_size); + if(result) + return result; + + /* cache is drained */ + free(pp->cache); + pp->cache = NULL; + pp->cache_size = 0; + } + + state(conn, POP3_STOP); + return result; +} + +/* start the DO phase for RETR */ static CURLcode pop3_retr(struct connectdata *conn) { CURLcode result = CURLE_OK; @@ -396,6 +439,20 @@ static CURLcode pop3_retr(struct connectdata *conn) return result; } +/* start the DO phase for LIST */ +static CURLcode pop3_list(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST %s", pop3c->mailbox); + if(result) + return result; + + state(conn, POP3_LIST); + return result; +} + static CURLcode pop3_statemach_act(struct connectdata *conn) { CURLcode result; @@ -451,6 +508,10 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_retr_resp(conn, pop3code, pop3c->state); break; + case POP3_LIST: + result = pop3_state_list_resp(conn, pop3code, pop3c->state); + break; + case POP3_QUIT: /* fallthrough, just stop! */ default: @@ -655,6 +716,7 @@ CURLcode pop3_perform(struct connectdata *conn, { /* this is POP3 and no proxy */ CURLcode result=CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; DEBUGF(infof(conn->data, "DO phase starts\n")); @@ -667,7 +729,13 @@ CURLcode pop3_perform(struct connectdata *conn, *dophase_done = FALSE; /* not done yet */ /* start the first command in the DO phase */ - result = pop3_retr(conn); + /* If mailbox is empty, then assume user wants listing for mail IDs, + * otherwise, attempt to retrieve the mail-id stored in mailbox + */ + if (strlen(pop3c->mailbox)) + result = pop3_retr(conn); + else + result = pop3_list(conn); if(result) return result; @@ -785,9 +853,6 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn) const char *path = data->state.path; int len; - if(!*path) - path = "INBOX"; - /* url decode the path and use this mailbox */ pop3c->mailbox = curl_easy_unescape(data, path, 0, &len); -- cgit v1.2.1 From d1837ad90a31bb70be4d44b4f745ae696e21e972 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 29 Mar 2010 16:30:35 +0200 Subject: use (s)size_t for string lengths to fix compiler warns --- lib/pop3.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index ff929b09c..4894f3c44 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -990,9 +990,9 @@ CURLcode Curl_pop3_write(struct connectdata *conn, 0d 0a 2e 0d 0a. This marker can of course be spread out over up to 5 different data chunks. Deal with it! */ struct pop3_conn *pop3c = &conn->proto.pop3c; - int checkmax = (nread >= POP3_EOB_LEN?POP3_EOB_LEN:nread); - int checkleft = POP3_EOB_LEN-pop3c->eob; - int check = (checkmax >= checkleft?checkleft:checkmax); + size_t checkmax = (nread >= POP3_EOB_LEN?POP3_EOB_LEN:nread); + size_t checkleft = POP3_EOB_LEN-pop3c->eob; + size_t check = (checkmax >= checkleft?checkleft:checkmax); if(!memcmp(POP3_EOB, &str[nread - check], check)) { /* substring match */ -- cgit v1.2.1 From fa7341143a4bb5c1c1a2d43375bbc9a2157938ec Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 16 Apr 2010 22:56:13 +0200 Subject: POP3: when USER command fails, don't even try PASS --- lib/pop3.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 4894f3c44..34c6fdfb1 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -311,10 +311,10 @@ static CURLcode pop3_state_user_resp(struct connectdata *conn, failf(data, "Access denied. %c", pop3code); result = CURLE_LOGIN_DENIED; } - - /* send PASS */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s", - pop3->passwd?pop3->passwd:""); + else + /* send PASS */ + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s", + pop3->passwd?pop3->passwd:""); if(result) return result; -- cgit v1.2.1 From c0111460b0689d74731cc56ff019cc869a0d16a8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 16 Apr 2010 23:43:04 +0200 Subject: Curl_setup_transfer: no longer returns anything This function could only return CURLE_OK and by changing it to a void instead, we can simplify code all over. --- lib/pop3.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 34c6fdfb1..4d79eebb2 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -359,9 +359,8 @@ static CURLcode pop3_state_retr_resp(struct connectdata *conn, } /* POP3 download */ - result=Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, - pop3->bytecountp, - -1, NULL); /* no upload here */ + Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, + pop3->bytecountp, -1, NULL); /* no upload here */ if(pp->cache) { /* At this point there is a bunch of data in the header "cache" that is @@ -403,9 +402,8 @@ static CURLcode pop3_state_list_resp(struct connectdata *conn, } /* POP3 download */ - result=Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, - pop3->bytecountp, - -1, NULL); /* no upload here */ + Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, pop3->bytecountp, + -1, NULL); /* no upload here */ if(pp->cache) { /* cache holds the email ID listing */ @@ -863,18 +861,17 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn) static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected) { - CURLcode result = CURLE_OK; struct FTP *pop3 = conn->data->state.proto.pop3; struct pop3_conn *pop3c = &conn->proto.pop3c; - (void)connected; + (void)connected; if(pop3->transfer != FTPTRANSFER_BODY) /* no data to transfer */ - result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); free(pop3c->mailbox); - return result; + return CURLE_OK; } /* called from multi.c while DOing */ -- cgit v1.2.1 From 04cfef24a113e1477ccfafa633c468f0055a42c5 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Wed, 19 May 2010 12:18:06 -0700 Subject: Fixed some memory leaks in the POP3 torture tests --- lib/pop3.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 4d79eebb2..9609b6249 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -828,7 +828,8 @@ static CURLcode pop3_disconnect(struct connectdata *conn) /* The POP3 session may or may not have been allocated/setup at this point! */ - (void)pop3_quit(conn); /* ignore errors on the LOGOUT */ + if(pop3c->pp.conn) + (void)pop3_quit(conn); /* ignore errors on the LOGOUT */ Curl_pp_disconnect(&pop3c->pp); @@ -849,10 +850,11 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn) struct pop3_conn *pop3c = &conn->proto.pop3c; struct SessionHandle *data = conn->data; const char *path = data->state.path; - int len; /* url decode the path and use this mailbox */ - pop3c->mailbox = curl_easy_unescape(data, path, 0, &len); + pop3c->mailbox = curl_easy_unescape(data, path, 0, NULL); + if (!pop3c->mailbox) + return CURLE_OUT_OF_MEMORY; return CURLE_OK; } -- cgit v1.2.1 From 5c7c9a768d009319520142fcaee1dea33625060f Mon Sep 17 00:00:00 2001 From: Kamil Dudka Date: Fri, 19 Nov 2010 13:43:20 +0100 Subject: url: provide dead_connection flag in Curl_handler::disconnect It helps to prevent a hangup with some FTP servers in case idle session timeout has exceeded. But it may be useful also for other protocols that send any quit message on disconnect. Currently used by FTP, POP3, IMAP and SMTP. --- lib/pop3.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 9609b6249..9f6744363 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -101,7 +101,7 @@ static CURLcode pop3_do(struct connectdata *conn, bool *done); static CURLcode pop3_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode pop3_connect(struct connectdata *conn, bool *done); -static CURLcode pop3_disconnect(struct connectdata *conn); +static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection); static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done); static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks, @@ -817,7 +817,7 @@ static CURLcode pop3_quit(struct connectdata *conn) * Disconnect from an POP3 server. Cleanup protocol-specific per-connection * resources. BLOCKING. */ -static CURLcode pop3_disconnect(struct connectdata *conn) +static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection) { struct pop3_conn *pop3c= &conn->proto.pop3c; @@ -828,7 +828,7 @@ static CURLcode pop3_disconnect(struct connectdata *conn) /* The POP3 session may or may not have been allocated/setup at this point! */ - if(pop3c->pp.conn) + if(!dead_connection && pop3c->pp.conn) (void)pop3_quit(conn); /* ignore errors on the LOGOUT */ -- cgit v1.2.1 From 8831000bc07de463d277975a3ddfb6a31dcf14b4 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 14 Mar 2011 22:22:22 +0100 Subject: protocol handler: added flags field The protocol handler struct got a 'flags' field for special information and characteristics of the given protocol. This now enables us to move away central protocol information such as CLOSEACTION and DUALCHANNEL from single defines in a central place, out to each protocol's definition. It also made us stop abusing the protocol field for other info than the protocol, and we could start cleaning up other protocol-specific things by adding flags bits to set in the handler struct. The "protocol" field connectdata struct was removed as well and the code now refers directly to the conn->handler->protocol field instead. To make things work properly, the code now always store a conn->given pointer that points out the original handler struct so that the code can learn details from the original protocol even if conn->handler is modified along the way - for example when switching to go over a HTTP proxy. --- lib/pop3.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 9f6744363..2c1cc00c3 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -128,7 +128,8 @@ const struct Curl_handler Curl_handler_pop3 = { ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ PORT_POP3, /* defport */ - PROT_POP3 /* protocol */ + PROT_POP3, /* protocol */ + PROTOPT_CLOSEACTION /* flags */ }; @@ -151,7 +152,8 @@ const struct Curl_handler Curl_handler_pop3s = { ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ PORT_POP3S, /* defport */ - PROT_POP3 | PROT_POP3S | PROT_SSL /* protocol */ + PROT_POP3 | PROT_POP3S, /* protocol */ + PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */ }; #endif @@ -174,7 +176,8 @@ static const struct Curl_handler Curl_handler_pop3_proxy = { ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ PORT_POP3, /* defport */ - PROT_HTTP /* protocol */ + PROT_HTTP, /* protocol */ + PROTOPT_NONE /* flags */ }; @@ -197,7 +200,8 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ PORT_POP3S, /* defport */ - PROT_HTTP /* protocol */ + PROT_HTTP, /* protocol */ + PROTOPT_NONE /* flags */ }; #endif #endif @@ -288,7 +292,7 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, /* Curl_ssl_connect is BLOCKING */ result = Curl_ssl_connect(conn, FIRSTSOCKET); if(CURLE_OK == result) { - conn->protocol |= PROT_POP3S; + conn->handler = &Curl_handler_pop3s; result = pop3_state_user(conn); } } @@ -637,7 +641,7 @@ static CURLcode pop3_connect(struct connectdata *conn, } #endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */ - if(conn->protocol & PROT_POP3S) { + if(conn->handler->protocol & PROT_POP3S) { /* BLOCKING */ /* POP3S is simply pop3 with SSL for the control channel */ /* now, perform the SSL initialization for this socket */ -- cgit v1.2.1 From 13b64d75589647f8d151e035bd2c5d340a1c37ee Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 14 Mar 2011 22:52:14 +0100 Subject: protocols: use CURLPROTO_ internally The PROT_* set of internal defines for the protocols is no longer used. We now use the same bits internally as we have defined in the public header using the CURLPROTO_ prefix. This is for simplicity and because the PROT_* prefix was already used duplicated internally for a set of KRB4 values. The PROTOPT_* defines were moved up to just below the struct definition within which they are used. --- lib/pop3.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 2c1cc00c3..a5447e4f3 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -128,7 +128,7 @@ const struct Curl_handler Curl_handler_pop3 = { ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ PORT_POP3, /* defport */ - PROT_POP3, /* protocol */ + CURLPROTO_POP3, /* protocol */ PROTOPT_CLOSEACTION /* flags */ }; @@ -152,7 +152,7 @@ const struct Curl_handler Curl_handler_pop3s = { ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ PORT_POP3S, /* defport */ - PROT_POP3 | PROT_POP3S, /* protocol */ + CURLPROTO_POP3 | CURLPROTO_POP3S, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */ }; #endif @@ -176,7 +176,7 @@ static const struct Curl_handler Curl_handler_pop3_proxy = { ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ PORT_POP3, /* defport */ - PROT_HTTP, /* protocol */ + CURLPROTO_HTTP, /* protocol */ PROTOPT_NONE /* flags */ }; @@ -200,7 +200,7 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ PORT_POP3S, /* defport */ - PROT_HTTP, /* protocol */ + CURLPROTO_HTTP, /* protocol */ PROTOPT_NONE /* flags */ }; #endif @@ -641,7 +641,7 @@ static CURLcode pop3_connect(struct connectdata *conn, } #endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */ - if(conn->handler->protocol & PROT_POP3S) { + if(conn->handler->protocol & CURLPROTO_POP3S) { /* BLOCKING */ /* POP3S is simply pop3 with SSL for the control channel */ /* now, perform the SSL initialization for this socket */ -- cgit v1.2.1 From cc228ea6f61a4543cbec3568b37bf881ab1010ac Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 15 Mar 2011 10:02:05 +0100 Subject: protocol handler cleanup: SSL awareness As a follow-up to commit 8831000bc0: don't assume that the SSL powered protocol alternatives are available. --- lib/pop3.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index a5447e4f3..d6e63035b 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -275,6 +275,15 @@ static int pop3_getsock(struct connectdata *conn, return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks); } +#ifdef USE_SSL +static void pop3_to_pop3s(struct connectdata *conn) +{ + conn->handler = &Curl_handler_pop3s; +} +#else +#define pop3_to_pop3s(x) +#endif + /* for STARTTLS responses */ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, int pop3code, @@ -292,7 +301,7 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, /* Curl_ssl_connect is BLOCKING */ result = Curl_ssl_connect(conn, FIRSTSOCKET); if(CURLE_OK == result) { - conn->handler = &Curl_handler_pop3s; + pop3_to_pop3s(conn); result = pop3_state_user(conn); } } -- cgit v1.2.1 From 409867e62bf1b12e0fa0d39007256b5807a60cea Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Thu, 17 Mar 2011 16:28:12 -0700 Subject: pop3: fixed memory leak in an error retrieval case --- lib/pop3.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index d6e63035b..65169cff5 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -690,6 +690,7 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, { struct SessionHandle *data = conn->data; struct FTP *pop3 = data->state.proto.pop3; + struct pop3_conn *pop3c = &conn->proto.pop3c; CURLcode result=CURLE_OK; (void)premature; @@ -706,6 +707,9 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, result = status; /* use the already set error code */ } + free(pop3c->mailbox); + pop3c->mailbox = NULL; + /* clear these for next connection */ pop3->transfer = FTPTRANSFER_BODY; @@ -884,8 +888,6 @@ static CURLcode pop3_dophase_done(struct connectdata *conn, /* no data to transfer */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - free(pop3c->mailbox); - return CURLE_OK; } -- cgit v1.2.1 From ef1c18b952de0763037b7c940cc6960bbf990912 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Thu, 17 Mar 2011 16:59:30 -0700 Subject: Added support for LISTing a single POP3 message Added tests for a number of POP3 LIST operations, including one that shows a curl problem when listing no messages, so is disabled. --- lib/pop3.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 65169cff5..e48c9b4f8 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -436,6 +436,24 @@ static CURLcode pop3_state_list_resp(struct connectdata *conn, return result; } +/* for LIST response with a given message */ +static CURLcode pop3_state_list_single_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 != 'O') { + failf(data, "Invalid message. %c", pop3code); + result = CURLE_REMOTE_FILE_NOT_FOUND; + } + + state(conn, POP3_STOP); + return result; +} + /* start the DO phase for RETR */ static CURLcode pop3_retr(struct connectdata *conn) { @@ -460,7 +478,10 @@ static CURLcode pop3_list(struct connectdata *conn) if(result) return result; - state(conn, POP3_LIST); + if (strlen(pop3c->mailbox)) + state(conn, POP3_LIST_SINGLE); + else + state(conn, POP3_LIST); return result; } @@ -523,6 +544,10 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_list_resp(conn, pop3code, pop3c->state); break; + case POP3_LIST_SINGLE: + result = pop3_state_list_single_resp(conn, pop3code, pop3c->state); + break; + case POP3_QUIT: /* fallthrough, just stop! */ default: @@ -747,7 +772,7 @@ CURLcode pop3_perform(struct connectdata *conn, /* If mailbox is empty, then assume user wants listing for mail IDs, * otherwise, attempt to retrieve the mail-id stored in mailbox */ - if (strlen(pop3c->mailbox)) + if (strlen(pop3c->mailbox) && !conn->data->set.ftp_list_only) result = pop3_retr(conn); else result = pop3_list(conn); -- cgit v1.2.1 From 0c05ee3a33d4d767b28000b9e72ca51ed1b90fc6 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 18 Mar 2011 09:18:22 +0100 Subject: pop3: remove unused variable --- lib/pop3.c | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index e48c9b4f8..03ea7efaf 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -906,7 +906,6 @@ static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected) { struct FTP *pop3 = conn->data->state.proto.pop3; - struct pop3_conn *pop3c = &conn->proto.pop3c; (void)connected; if(pop3->transfer != FTPTRANSFER_BODY) -- cgit v1.2.1 From 663a52c2f88637c773f610d0e8e610de0ad65425 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Fri, 18 Mar 2011 11:20:24 -0700 Subject: pop3: use Curl_safefree() to allow torture tests to succeed --- lib/pop3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 03ea7efaf..8da045e48 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -732,7 +732,7 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, result = status; /* use the already set error code */ } - free(pop3c->mailbox); + Curl_safefree(pop3c->mailbox); pop3c->mailbox = NULL; /* clear these for next connection */ -- cgit v1.2.1 From 3a87dd8b207444d768fa6a839f79cb16c06e7f90 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 19 Mar 2011 11:05:45 +0100 Subject: pop3: add state name in debug array We have an array with the state names only built and used when built debug enabled and this need to list all the states from the .h --- lib/pop3.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 8da045e48..7f97722a8 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -237,6 +237,7 @@ static void state(struct connectdata *conn, "PASS", "STARTTLS", "LIST", + "LIST_SINGLE", "RETR", "QUIT", /* LAST */ -- cgit v1.2.1 From 02dbfa21921aded6bba292b99dd224fe450e7254 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 4 Apr 2011 16:24:37 +0200 Subject: http-proxy: move proxy code to http_proxy.c The new http_proxy.* files now host HTTP proxy specific code (500+ lines moved out from http.c), and as a consequence there is a macro introduced for the Curl_proxyCONNECT() function so that code can use it without actually supporting proxy (or HTTP) in builds. --- lib/pop3.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 7f97722a8..a7657171c 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -86,6 +86,7 @@ #include "url.h" #include "rawstr.h" #include "strtoofft.h" +#include "http_proxy.h" #define _MPRINTF_REPLACE /* use our functions only */ #include @@ -647,7 +648,6 @@ static CURLcode pop3_connect(struct connectdata *conn, pp->endofresp = pop3_endofresp; pp->conn = conn; -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY) if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { /* for POP3 over HTTP proxy */ struct HTTP http_proxy; @@ -674,7 +674,6 @@ static CURLcode pop3_connect(struct connectdata *conn, if(CURLE_OK != result) return result; } -#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */ if(conn->handler->protocol & CURLPROTO_POP3S) { /* BLOCKING */ -- cgit v1.2.1 From e7837bfd03c117aa8d4f0a1c5018e2d08119c4af Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 17 Mar 2011 22:35:18 +0100 Subject: [pop3 starttls] the command to send is STLS, not STARTTLS. --- lib/pop3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index a7657171c..ba13e7d6b 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -517,7 +517,7 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) { /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch to TLS connection now */ - result = Curl_pp_sendf(&pop3c->pp, "STARTTLS", NULL); + result = Curl_pp_sendf(&pop3c->pp, "STLS"); state(conn, POP3_STARTTLS); } else -- cgit v1.2.1 From db59b6202d8eb15b8c2cb41a52d0675832182976 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 17 Mar 2011 23:07:56 +0100 Subject: [pop3 starttls] PASS command was not sent after upgrade to TLS. --- lib/pop3.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index ba13e7d6b..79af8fc0c 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -298,6 +298,7 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, if(pop3code != 'O') { failf(data, "STARTTLS denied. %c", pop3code); result = CURLE_LOGIN_DENIED; + state(conn, POP3_STOP); } else { /* Curl_ssl_connect is BLOCKING */ @@ -306,8 +307,10 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, pop3_to_pop3s(conn); result = pop3_state_user(conn); } + else { + state(conn, POP3_STOP); + } } - state(conn, POP3_STOP); return result; } -- cgit v1.2.1 From c828646f60b5bffb2bfcf924eba36da767bf08bf Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 20 Apr 2011 00:48:20 +0200 Subject: CURL_DOES_CONVERSIONS: cleanup Massively reduce #ifdefs all over (23 #ifdef lines less so far) Moved conversion-specific code to non-ascii.c --- lib/pop3.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 79af8fc0c..8f37c1fe6 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -65,8 +65,6 @@ #include #include "urldata.h" #include "sendf.h" -#include "easyif.h" /* for Curl_convert_... prototypes */ - #include "if2ip.h" #include "hostip.h" #include "progress.h" -- cgit v1.2.1 From 1702a2c08d3a0ed5945f34e6cd38436611f65164 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Tue, 19 Apr 2011 15:54:13 +0200 Subject: Fix a couple of spelling errors in lib/ Found with codespell. --- lib/pop3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 8f37c1fe6..d0aba352b 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -641,7 +641,7 @@ static CURLcode pop3_connect(struct connectdata *conn, if(CURLE_OK != result) return result; - /* We always support persistant connections on pop3 */ + /* We always support persistent connections on pop3 */ conn->bits.close = FALSE; pp->response_time = RESP_TIMEOUT; /* set default response time-out */ -- cgit v1.2.1 From b903186fa0189ff241d756d25d07fdfe9885ae49 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 20 Apr 2011 15:17:42 +0200 Subject: source cleanup: unify look, style and indent levels By the use of a the new lib/checksrc.pl script that checks that our basic source style rules are followed. --- lib/pop3.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index d0aba352b..e4fd03b45 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -100,7 +100,7 @@ static CURLcode pop3_do(struct connectdata *conn, bool *done); static CURLcode pop3_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode pop3_connect(struct connectdata *conn, bool *done); -static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection); +static CURLcode pop3_disconnect(struct connectdata *conn, bool dead); static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done); static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks, @@ -481,7 +481,7 @@ static CURLcode pop3_list(struct connectdata *conn) if(result) return result; - if (strlen(pop3c->mailbox)) + if(strlen(pop3c->mailbox)) state(conn, POP3_LIST_SINGLE); else state(conn, POP3_LIST); @@ -773,7 +773,7 @@ CURLcode pop3_perform(struct connectdata *conn, /* If mailbox is empty, then assume user wants listing for mail IDs, * otherwise, attempt to retrieve the mail-id stored in mailbox */ - if (strlen(pop3c->mailbox) && !conn->data->set.ftp_list_only) + if(strlen(pop3c->mailbox) && !conn->data->set.ftp_list_only) result = pop3_retr(conn); else result = pop3_list(conn); @@ -896,7 +896,7 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn) /* url decode the path and use this mailbox */ pop3c->mailbox = curl_easy_unescape(data, path, 0, NULL); - if (!pop3c->mailbox) + if(!pop3c->mailbox) return CURLE_OUT_OF_MEMORY; return CURLE_OK; -- cgit v1.2.1 From 889d1e973fb718a77c5000141d724ce03863af23 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 22 Apr 2011 23:01:30 +0200 Subject: whitespace cleanup: no space first in conditionals "if(a)" is our style, not "if( a )" --- lib/pop3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index e4fd03b45..6d5afa876 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -214,8 +214,8 @@ static int pop3_endofresp(struct pingpong *pp, char *line = pp->linestart_resp; size_t len = pp->nread_resp; - if( ((len >= 3) && !memcmp("+OK", line, 3)) || - ((len >= 4) && !memcmp("-ERR", line, 4)) ) { + if(((len >= 3) && !memcmp("+OK", line, 3)) || + ((len >= 4) && !memcmp("-ERR", line, 4))) { *resp=line[1]; /* O or E */ return TRUE; } -- cgit v1.2.1 From e34131db783336aa17fa0aa664635867459b2a85 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 5 May 2011 15:49:43 +0200 Subject: SSL: check for SSL, not specific protocols Code cleanup to check less for protocols and more for the specific relevant feature. Like if SSL is required. --- lib/pop3.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 6d5afa876..f53661285 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -676,10 +676,8 @@ static CURLcode pop3_connect(struct connectdata *conn, return result; } - if(conn->handler->protocol & CURLPROTO_POP3S) { + if(conn->handler->flags & PROTOPT_SSL) { /* BLOCKING */ - /* POP3S is simply pop3 with SSL for the control channel */ - /* now, perform the SSL initialization for this socket */ result = Curl_ssl_connect(conn, FIRSTSOCKET); if(result) return result; -- cgit v1.2.1 From f0612f166a5fa51d09498baa19a327c5cf36941f Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 5 May 2011 16:27:03 +0200 Subject: RTSP: convert protocol-specific checks to generic Add a 'readwrite' function to the protocol handler struct and use that for the extra readwrite functionality RTSP needs. --- lib/pop3.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index f53661285..0581c58b0 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -126,6 +126,7 @@ const struct Curl_handler Curl_handler_pop3 = { pop3_getsock, /* doing_getsock */ ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_POP3, /* defport */ CURLPROTO_POP3, /* protocol */ PROTOPT_CLOSEACTION /* flags */ @@ -150,6 +151,7 @@ const struct Curl_handler Curl_handler_pop3s = { pop3_getsock, /* doing_getsock */ ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_POP3S, /* defport */ CURLPROTO_POP3 | CURLPROTO_POP3S, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */ @@ -174,6 +176,7 @@ static const struct Curl_handler Curl_handler_pop3_proxy = { ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_POP3, /* defport */ CURLPROTO_HTTP, /* protocol */ PROTOPT_NONE /* flags */ @@ -198,6 +201,7 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_POP3S, /* defport */ CURLPROTO_HTTP, /* protocol */ PROTOPT_NONE /* flags */ -- cgit v1.2.1 From af6dcc92d56c8913a49a4c8b776f65c717f242d6 Mon Sep 17 00:00:00 2001 From: Ori Avtalion Date: Tue, 21 Jun 2011 01:33:32 +0300 Subject: [pop3] remove extra space in LIST command Some servers, e.g. mail.bezeqint.net:110, consider it a syntax error --- lib/pop3.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 0581c58b0..dc5a1c2fa 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -481,11 +481,14 @@ static CURLcode pop3_list(struct connectdata *conn) CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST %s", pop3c->mailbox); + if(pop3c->mailbox[0] != '\0') + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST %s", pop3c->mailbox); + else + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST"); if(result) return result; - if(strlen(pop3c->mailbox)) + if(pop3c->mailbox[0] != '\0') state(conn, POP3_LIST_SINGLE); else state(conn, POP3_LIST); -- cgit v1.2.1 From f1586cb4775681810afd8e6626e7842d459f3b85 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Tue, 26 Jul 2011 17:23:27 +0200 Subject: stdio.h, stdlib.h, string.h, stdarg.h and ctype.h inclusion done in setup_once.h --- lib/pop3.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index dc5a1c2fa..30766711c 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -27,11 +27,6 @@ #include "setup.h" #ifndef CURL_DISABLE_POP3 -#include -#include -#include -#include -#include #ifdef HAVE_UNISTD_H #include -- cgit v1.2.1 From 2d7c79af76ea9c35d0ec9512da2211d7aedf2878 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Aug 2011 23:38:45 +0200 Subject: tcpconnect: follow-up commit after b998d95b As I modified conn->bits.tcpconnect to become an array that holds one bool for each potential connection all uses of that struct field must index it correctly. --- lib/pop3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 30766711c..42f6c1dbf 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -787,7 +787,7 @@ CURLcode pop3_perform(struct connectdata *conn, result = pop3_easy_statemach(conn); *dophase_done = TRUE; /* with the easy interface we are done here */ } - *connected = conn->bits.tcpconnect; + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); -- cgit v1.2.1 From 6b75d2c2df7209919a70a29a4479625b62fb3c28 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Sat, 3 Sep 2011 16:06:10 +0200 Subject: fix a bunch of MSVC compiler warnings --- lib/pop3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 42f6c1dbf..ff71ed663 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -280,7 +280,7 @@ static void pop3_to_pop3s(struct connectdata *conn) conn->handler = &Curl_handler_pop3s; } #else -#define pop3_to_pop3s(x) +#define pop3_to_pop3s(x) Curl_nop_stmt #endif /* for STARTTLS responses */ -- cgit v1.2.1 From a50210710ab6fd772e2762ed36602c15adfb49e1 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Mon, 5 Sep 2011 20:46:09 +0200 Subject: fix bool variables checking and assignment --- lib/pop3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index ff71ed663..c5a0f5b9b 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -570,7 +570,7 @@ static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done) struct pop3_conn *pop3c = &conn->proto.pop3c; CURLcode result = Curl_pp_multi_statemach(&pop3c->pp); - *done = (bool)(pop3c->state == POP3_STOP); + *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE; return result; } -- cgit v1.2.1 From d7934b8bd49114cbb54f7401742f7fb088e2f796 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 21 Oct 2011 23:36:54 +0200 Subject: curl_multi_fdset: correct fdset with FTP PORT use After a PORT has been issued, and the multi handle would switch to the CURLM_STATE_DO_MORE state (which is unique for FTP), libcurl would return the wrong fdset to wait for when curl_multi_fdset() is called. The code would blindly assume that it was waiting for a connect of the second connection, while that isn't true immediately after the PORT command. Also, the function multi.c:domore_getsock() was highly FTP-centric and therefore ugly to keep in protocol-agnostic code. I solved this problem by introducing a new function pointer in the Curl_handler struct called domore_getsock() which is only called during the DOMORE state for protocols that set that pointer. The new ftp.c:ftp_domore_getsock() function now returns fdset info about the control connection's command/response handling while such a state is in use, and goes over to waiting for a writable second connection first once the commands are done. The original problem could be seen by running test 525 and checking the time stamps in the FTP server log. I can verify that this fix at least fixes this problem. Bug: http://curl.haxx.se/mail/lib-2011-10/0250.html Reported by: Gokhan Sengun --- lib/pop3.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index c5a0f5b9b..cb70679c5 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -119,6 +119,7 @@ const struct Curl_handler Curl_handler_pop3 = { pop3_doing, /* doing */ pop3_getsock, /* proto_getsock */ pop3_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -144,6 +145,7 @@ const struct Curl_handler Curl_handler_pop3s = { pop3_doing, /* doing */ pop3_getsock, /* proto_getsock */ pop3_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -169,6 +171,7 @@ static const struct Curl_handler Curl_handler_pop3_proxy = { 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 */ @@ -194,6 +197,7 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { 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 */ -- cgit v1.2.1 From 93e57d0628aad62330dc62ff809752a0478824c4 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 3 Nov 2011 09:54:12 +0100 Subject: rename ftp_ssl: the struct field is used for many protocols Now called 'use_ssl' instead, which better matches the current CURLOPT name and since the option is used for all pingpong protocols (at least) it makes sense to not use 'ftp' in the name. --- lib/pop3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index cb70679c5..6cda3bc5a 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -521,7 +521,7 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) return CURLE_FTP_WEIRD_SERVER_REPLY; } - if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) { + if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch to TLS connection now */ result = Curl_pp_sendf(&pop3c->pp, "STLS"); -- cgit v1.2.1 From 2c905fd1f8200349667dc990a17daf37214700bf Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Thu, 24 Nov 2011 23:28:54 +0100 Subject: query-part: ignore the URI part for given protocols By setting PROTOPT_NOURLQUERY in the protocol handler struct, the protocol will get the "query part" of the URL cut off before the data is handled by the protocol-specific code. This makes libcurl adhere to RFC3986 section 2.2. Test 1220 is added to verify a file:// URL with query-part. --- lib/pop3.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 6cda3bc5a..8fd8ab01f 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -125,7 +125,7 @@ const struct Curl_handler Curl_handler_pop3 = { ZERO_NULL, /* readwrite */ PORT_POP3, /* defport */ CURLPROTO_POP3, /* protocol */ - PROTOPT_CLOSEACTION /* flags */ + PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ }; @@ -151,7 +151,8 @@ const struct Curl_handler Curl_handler_pop3s = { ZERO_NULL, /* readwrite */ PORT_POP3S, /* defport */ CURLPROTO_POP3 | CURLPROTO_POP3S, /* protocol */ - PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */ + PROTOPT_CLOSEACTION | PROTOPT_SSL + | PROTOPT_NOURLQUERY /* flags */ }; #endif -- cgit v1.2.1 From dda815b77680af1492c962e729f1bb90a48f65a4 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 28 Nov 2011 23:02:35 +0100 Subject: POP3: fix end of body detection Curl_pop3_write() now has a state machine that scans for the end of a POP3 body so that the CR LF '.' CR LF sequence can come in everything from one up to five subsequent packets. Test case 810 is modified to use SLOWDOWN which makes the server pause between each single byte and thus makes the POP3 body get sent to curl basically one byte at a time. --- lib/pop3.c | 72 +++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 19 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 8fd8ab01f..a47717a71 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -1032,33 +1032,67 @@ CURLcode Curl_pop3_write(struct connectdata *conn, /* Detect the end-of-body marker, which is 5 bytes: 0d 0a 2e 0d 0a. This marker can of course be spread out - over up to 5 different data chunks. Deal with it! */ + over up to 5 different data chunks. + */ struct pop3_conn *pop3c = &conn->proto.pop3c; - size_t checkmax = (nread >= POP3_EOB_LEN?POP3_EOB_LEN:nread); - size_t checkleft = POP3_EOB_LEN-pop3c->eob; - size_t check = (checkmax >= checkleft?checkleft:checkmax); + unsigned int i; + + /* since the EOB string must be within the last 5 bytes, get the index + position of where to start to scan for it */ + size_t checkstart = (nread>POP3_EOB_LEN)?nread-POP3_EOB_LEN:0; + + if(checkstart) { + /* write out the first piece, if any */ + result = Curl_client_write(conn, CLIENTWRITE_BODY, str, checkstart); + if(result) + return result; + pop3c->eob=0; + } - if(!memcmp(POP3_EOB, &str[nread - check], check)) { - /* substring match */ - pop3c->eob += check; + for(i=checkstart; ieob; + switch(str[i]) { + case 0x0d: + if((pop3c->eob == 0) || (pop3c->eob == 3)) + pop3c->eob++; + else + /* if it wasn't 0 or 3, it restarts the pattern match again */ + pop3c->eob=1; + break; + case 0x0a: + if((pop3c->eob == 1) || (pop3c->eob == 4)) + pop3c->eob++; + else + pop3c->eob=0; + break; + case 0x2e: + if(pop3c->eob == 2) + pop3c->eob++; + else + pop3c->eob=0; + break; + default: + pop3c->eob=0; + break; + } if(pop3c->eob == POP3_EOB_LEN) { /* full match, the transfer is done! */ - str[nread - check] = '\0'; - nread -= check; k->keepon &= ~KEEP_RECV; pop3c->eob = 0; + return CURLE_OK; + } + else if(prev && (prev >= pop3c->eob)) { + /* write out the body part that didn't match */ + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB, + prev); + if(result) + return result; } } - else if(pop3c->eob) { - /* not a match, but we matched a piece before so we must now - send that part as body first, before we move on and send - this buffer */ - result = Curl_client_write(conn, CLIENTWRITE_BODY, - (char *)POP3_EOB, pop3c->eob); - if(result) - return result; - pop3c->eob = 0; - } + + if(pop3c->eob) + /* while EOB is matching, don't output it! */ + return CURLE_OK; result = Curl_client_write(conn, CLIENTWRITE_BODY, str, nread); -- cgit v1.2.1 From af6466643416fd36fea4205d2d7a02a9292e2858 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 29 Nov 2011 13:43:46 +0100 Subject: POP3: detect when LIST returns no mails By making sure the function can detect an "end of body" sequence immediately on the first line, test 811 is now enabled. --- lib/pop3.c | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index a47717a71..5d06dfcb5 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -421,6 +421,16 @@ static CURLcode pop3_state_list_resp(struct connectdata *conn, return CURLE_RECV_ERROR; } + /* This 'OK' line ends with a CR LF pair which is the two first bytes of the + EOB string so count this is two matching bytes. This is necessary to make + the code detect the EOB if the only data than comes now is %2e CR LF like + when there is no body to return. */ + pop3c->eob = 2; + + /* But since this initial CR LF pair is not part of the actual body, we set + the strip counter here so that these bytes won't be delivered. */ + pop3c->strip = 2; + /* POP3 download */ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, pop3->bytecountp, -1, NULL); /* no upload here */ @@ -1082,11 +1092,22 @@ CURLcode Curl_pop3_write(struct connectdata *conn, return CURLE_OK; } else if(prev && (prev >= pop3c->eob)) { - /* write out the body part that didn't match */ - result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB, - prev); - if(result) - return result; + + /* strip can only be non-zero for the very first mismatch after CRLF and + then both prev and strip are equal and nothing will be output + below */ + while(prev && pop3c->strip) { + prev--; + pop3c->strip--; + } + + if(prev) { + /* write out the body part that didn't match */ + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB, + prev); + if(result) + return result; + } } } @@ -1094,7 +1115,15 @@ CURLcode Curl_pop3_write(struct connectdata *conn, /* while EOB is matching, don't output it! */ return CURLE_OK; - result = Curl_client_write(conn, CLIENTWRITE_BODY, str, nread); + while(nread && pop3c->strip) { + nread--; + pop3c->strip--; + str++; + } + + if(nread) { + result = Curl_client_write(conn, CLIENTWRITE_BODY, str, nread); + } return result; } -- cgit v1.2.1 From 1038d0aa16d10582258e5702ee3637fb0c17bbfa Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Tue, 29 Nov 2011 20:28:49 +0100 Subject: pop3.c: fix compiler warning --- lib/pop3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 5d06dfcb5..cf439c87a 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -1045,7 +1045,7 @@ CURLcode Curl_pop3_write(struct connectdata *conn, over up to 5 different data chunks. */ struct pop3_conn *pop3c = &conn->proto.pop3c; - unsigned int i; + size_t i; /* since the EOB string must be within the last 5 bytes, get the index position of where to start to scan for it */ -- cgit v1.2.1 From bdb647814ebf0b19e9e97507e3f99b3b4bbbf8be Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Wed, 30 Nov 2011 18:23:09 +0000 Subject: POP3: fixed escaped dot not being striped out Changed the eob detection to work across the whole of the buffer so that lines that begin with a dot (which the server will have escaped) are passed to the client application correctly. --- lib/pop3.c | 109 ++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 65 insertions(+), 44 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index cf439c87a..2252c57f8 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -1040,61 +1040,75 @@ CURLcode Curl_pop3_write(struct connectdata *conn, struct SessionHandle *data = conn->data; struct SingleRequest *k = &data->req; - /* Detect the end-of-body marker, which is 5 bytes: - 0d 0a 2e 0d 0a. This marker can of course be spread out - over up to 5 different data chunks. - */ struct pop3_conn *pop3c = &conn->proto.pop3c; + bool strip_dot = FALSE; + size_t last = 0; size_t i; - /* since the EOB string must be within the last 5 bytes, get the index - position of where to start to scan for it */ - size_t checkstart = (nread>POP3_EOB_LEN)?nread-POP3_EOB_LEN:0; - - if(checkstart) { - /* write out the first piece, if any */ - result = Curl_client_write(conn, CLIENTWRITE_BODY, str, checkstart); - if(result) - return result; - pop3c->eob=0; - } - - for(i=checkstart; ieob; + switch(str[i]) { case 0x0d: - if((pop3c->eob == 0) || (pop3c->eob == 3)) + if(pop3c->eob == 0) { + pop3c->eob++; + + if(i) { + /* Write out the body part that didn't match */ + result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last], + i - last); + + if(result) + return result; + + last = i; + } + } + else if(pop3c->eob == 3) pop3c->eob++; else - /* if it wasn't 0 or 3, it restarts the pattern match again */ - pop3c->eob=1; + /* If the character match wasn't at position 0 or 3 then restart the + pattern matching */ + pop3c->eob = 1; break; + case 0x0a: - if((pop3c->eob == 1) || (pop3c->eob == 4)) + if(pop3c->eob == 1 || pop3c->eob == 4) pop3c->eob++; else - pop3c->eob=0; + /* If the character match wasn't at position 1 or 4 then start the + search again */ + pop3c->eob = 0; break; + case 0x2e: if(pop3c->eob == 2) pop3c->eob++; + else if(pop3c->eob == 3) { + /* We have an extra dot after the CRLF which we need to strip off */ + strip_dot = TRUE; + pop3c->eob = 0; + } else - pop3c->eob=0; + /* If the character match wasn't at position 2 then start the search + again */ + pop3c->eob = 0; break; + default: - pop3c->eob=0; - break; - } - if(pop3c->eob == POP3_EOB_LEN) { - /* full match, the transfer is done! */ - k->keepon &= ~KEEP_RECV; pop3c->eob = 0; - return CURLE_OK; + break; } - else if(prev && (prev >= pop3c->eob)) { - /* strip can only be non-zero for the very first mismatch after CRLF and - then both prev and strip are equal and nothing will be output + /* Did we have a partial match which has subsequently failed? */ + if(prev && prev >= pop3c->eob) { + /* Strip can only be non-zero for the very first mismatch after CRLF + and then both prev and strip are equal and nothing will be output below */ while(prev && pop3c->strip) { prev--; @@ -1102,27 +1116,34 @@ CURLcode Curl_pop3_write(struct connectdata *conn, } if(prev) { - /* write out the body part that didn't match */ + /* 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, - prev); + strip_dot ? prev - 1 : prev); + if(result) return result; + + last = i; + strip_dot = FALSE; } } } - if(pop3c->eob) - /* while EOB is matching, don't output it! */ + if(pop3c->eob == POP3_EOB_LEN) { + /* We have a full match so the transfer is done! */ + k->keepon &= ~KEEP_RECV; + pop3c->eob = 0; return CURLE_OK; - - while(nread && pop3c->strip) { - nread--; - pop3c->strip--; - str++; } - if(nread) { - result = Curl_client_write(conn, CLIENTWRITE_BODY, str, nread); + if(pop3c->eob) + /* While EOB is matching nothing should be output */ + return CURLE_OK; + + if(nread - last) { + result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last], + nread - last); } return result; -- cgit v1.2.1 From b9b772fefe5f9e3ab90640f4536ab4c172658407 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Tue, 13 Dec 2011 15:58:02 +0100 Subject: pop3.c: fix compiler warning variable may be used uninitialized --- lib/pop3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 2252c57f8..6796cf76f 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -1036,7 +1036,7 @@ CURLcode Curl_pop3_write(struct connectdata *conn, size_t nread) { /* This code could be made into a special function in the handler struct. */ - CURLcode result; + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; struct SingleRequest *k = &data->req; -- cgit v1.2.1 From 277022b2e48e338ca85adc4321f0cf5661df4713 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Tue, 3 Jan 2012 23:01:51 +0000 Subject: Fixed incorrect error code being returned in STARTTLS The STARTTLS response code in SMTP, POP3 and IMAP would return CURLE_LOGIN_DENIED rather than CURLE_USE_SSL_FAILED when SSL/TLS was not available on the server. Reported by: Gokhan Sengun Bug: http://curl.haxx.se/mail/lib-2012-01/0018.html --- lib/pop3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 6796cf76f..283025120 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -299,7 +299,7 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, if(pop3code != 'O') { failf(data, "STARTTLS denied. %c", pop3code); - result = CURLE_LOGIN_DENIED; + result = CURLE_USE_SSL_FAILED; state(conn, POP3_STOP); } else { -- cgit v1.2.1 From db4f69ef0630001e6d566b949d86d1739bdd85b3 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Tue, 3 Jan 2012 23:17:08 +0000 Subject: Fixed use of CURLUSESSL_TRY for POP3 and IMAP based connections. Fixed a problem in POP3 and IMAP where a connection would fail when CURLUSESSL_TRY was specified for a server that didn't support SSL/TLS connections rather than continuing. --- lib/pop3.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 283025120..b7781109b 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -298,9 +298,13 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, (void)instate; /* no use for this yet */ if(pop3code != 'O') { - failf(data, "STARTTLS denied. %c", pop3code); - result = CURLE_USE_SSL_FAILED; - state(conn, POP3_STOP); + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied. %c", pop3code); + result = CURLE_USE_SSL_FAILED; + state(conn, POP3_STOP); + } + else + result = pop3_state_user(conn); } else { /* Curl_ssl_connect is BLOCKING */ -- cgit v1.2.1 From 75ca568fa1c19de4c5358fed246686de8467c238 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 23 Dec 2011 13:24:16 +0100 Subject: URL sanitize: reject URLs containing bad data Protocols (IMAP, POP3 and SMTP) that use the path part of a URL in a decoded manner now use the new Curl_urldecode() function to reject URLs with embedded control codes (anything that is or decodes to a byte value less than 32). URLs containing such codes could easily otherwise be used to do harm and allow users to do unintended actions with otherwise innocent tools and applications. Like for example using a URL like pop3://pop3.example.com/1%0d%0aDELE%201 when the app wants a URL to get a mail and instead this would delete one. This flaw is considered a security vulnerability: CVE-2012-0036 Security advisory at: http://curl.haxx.se/docs/adv_20120124.html Reported by: Dan Fandrich --- lib/pop3.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index b7781109b..cc360b8b9 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -914,11 +914,7 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn) const char *path = data->state.path; /* url decode the path and use this mailbox */ - pop3c->mailbox = curl_easy_unescape(data, path, 0, NULL); - if(!pop3c->mailbox) - return CURLE_OUT_OF_MEMORY; - - return CURLE_OK; + return Curl_urldecode(data, path, 0, &pop3c->mailbox, NULL, TRUE); } /* call this when the DO phase has completed */ -- cgit v1.2.1 From 035ef06bda7fbe9ae1934f9dee008b61ad623ac1 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sat, 18 Feb 2012 22:57:13 +0000 Subject: pop3.c: Fixed drop of final CRLF in EOB checking Curl_pop3_write() would drop the final CRLF of a message as it was considered part of the EOB as opposed to part of the message. Whilst the EOB sequence needs to be searched for by the function only the final 3 characters should be removed as per RFC-1939 section 3. Reported by: Rich Gray Bug: http://curl.haxx.se/mail/lib-2012-02/0051.html --- lib/pop3.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index cc360b8b9..b9201e474 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -755,7 +755,7 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, Curl_safefree(pop3c->mailbox); pop3c->mailbox = NULL; - /* clear these for next connection */ + /* Clear the transfer mode for the next connection */ pop3->transfer = FTPTRANSFER_BODY; return result; @@ -1035,7 +1035,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. */ + /* This code could be made into a special function in the handler struct */ CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; struct SingleRequest *k = &data->req; @@ -1131,10 +1131,15 @@ CURLcode Curl_pop3_write(struct connectdata *conn, } if(pop3c->eob == POP3_EOB_LEN) { - /* We have a full match so the transfer is done! */ + /* We have a full match so the transfer is done, however we must transfer + the CRLF at the start of the EOB as this is considered to be part of the + message as per RFC-1939, sect. 3 */ + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB, 2); + k->keepon &= ~KEEP_RECV; pop3c->eob = 0; - return CURLE_OK; + + return result; } if(pop3c->eob) -- cgit v1.2.1 From 41b02378342322aa8e264260057502f4d7493239 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 8 Mar 2012 23:31:38 +0100 Subject: CONNECT: made generically not per-protocol Curl_protocol_connect() now does the tunneling through the HTTP proxy if requested instead of letting each protocol specific connection function do it. --- lib/pop3.c | 27 --------------------------- 1 file changed, 27 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index b9201e474..4009a1fd7 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -670,33 +670,6 @@ static CURLcode pop3_connect(struct connectdata *conn, pp->endofresp = pop3_endofresp; pp->conn = conn; - if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { - /* for POP3 over HTTP proxy */ - struct HTTP http_proxy; - struct FTP *pop3_save; - - /* BLOCKING */ - /* We want "seamless" POP3 operations through HTTP proxy tunnel */ - - /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member - * conn->proto.http; we want POP3 through HTTP and we have to change the - * member temporarily for connecting to the HTTP proxy. After - * Curl_proxyCONNECT we have to set back the member to the original struct - * POP3 pointer - */ - pop3_save = data->state.proto.pop3; - memset(&http_proxy, 0, sizeof(http_proxy)); - data->state.proto.http = &http_proxy; - - result = Curl_proxyCONNECT(conn, FIRSTSOCKET, - conn->host.name, conn->remote_port); - - data->state.proto.pop3 = pop3_save; - - if(CURLE_OK != result) - return result; - } - if(conn->handler->flags & PROTOPT_SSL) { /* BLOCKING */ result = Curl_ssl_connect(conn, FIRSTSOCKET); -- cgit v1.2.1 From 2764bf2c5b4076f25e76dd8e64bf52f226ee7c5f Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 9 Mar 2012 00:05:24 +0100 Subject: includes: remove inclusion of unused file http_proxy.h --- lib/pop3.c | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 4009a1fd7..4cddba25d 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -79,7 +79,6 @@ #include "url.h" #include "rawstr.h" #include "strtoofft.h" -#include "http_proxy.h" #define _MPRINTF_REPLACE /* use our functions only */ #include -- cgit v1.2.1 From 602a8a565cf8661a85b74f23e14449ff04b9f543 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sat, 24 Mar 2012 00:09:38 +0000 Subject: pop3.c: Fixed body data being written when CURLOPT_NOBODY is specified Body data would be forwarded to the client application in both the RETR and LIST commands even if CURLOPT_NOBODY was specified. --- lib/pop3.c | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 4cddba25d..c95f45e19 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -382,30 +382,32 @@ static CURLcode pop3_state_retr_resp(struct connectdata *conn, } /* POP3 download */ - Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, - pop3->bytecountp, -1, NULL); /* no upload here */ + Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, pop3->bytecountp, + -1, NULL); /* no upload here */ if(pp->cache) { - /* At this point there is a bunch of data in the header "cache" that is - actually body content, send it as body and then skip it. Do note - that there may even be additional "headers" after the body. */ + /* The header "cache" contains a bunch of data that is actually body + content so send it as such. Note that there may even be additional + "headers" after the body */ - /* we may get the EOB already here! */ - result = Curl_pop3_write(conn, pp->cache, pp->cache_size); - if(result) - return result; + if(!data->set.opt_no_body) { + result = Curl_pop3_write(conn, pp->cache, pp->cache_size); + if(result) + return result; + } - /* cache is drained */ - free(pp->cache); - pp->cache = NULL; + /* Free the cache */ + Curl_safefree(pp->cache); + + /* Reset the cache size */ pp->cache_size = 0; } state(conn, POP3_STOP); + return result; } - /* for the list response */ static CURLcode pop3_state_list_resp(struct connectdata *conn, int pop3code, @@ -439,20 +441,24 @@ static CURLcode pop3_state_list_resp(struct connectdata *conn, -1, NULL); /* no upload here */ if(pp->cache) { - /* cache holds the email ID listing */ + /* The header "cache" contains a bunch of data that is actually list data + so send it as such */ - /* we may get the EOB already here! */ - result = Curl_pop3_write(conn, pp->cache, pp->cache_size); - if(result) - return result; + if(!data->set.opt_no_body) { + result = Curl_pop3_write(conn, pp->cache, pp->cache_size); + if(result) + return result; + } - /* cache is drained */ - free(pp->cache); - pp->cache = NULL; + /* Free the cache */ + Curl_safefree(pp->cache); + + /* Reset the cache size */ pp->cache_size = 0; } state(conn, POP3_STOP); + return result; } -- cgit v1.2.1 From 5c62a551c431e05ab7a80cf48985870ee54c1a68 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sat, 24 Mar 2012 11:55:34 +0000 Subject: email: Moved server greeting responses into separate functions Moved the server greeting response handling code from the statemach_act functions to separate response functions. This makes the code simpler to follow and provides consistency with the other responses that are handled here. --- lib/pop3.c | 50 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 16 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index c95f45e19..6b7e01a60 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -287,6 +287,34 @@ static void pop3_to_pop3s(struct connectdata *conn) #define pop3_to_pop3s(x) Curl_nop_stmt #endif +/* for the initial server greeting */ +static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct pop3_conn *pop3c = &conn->proto.pop3c; + + (void)instate; /* no use for this yet */ + + if(pop3code != 'O') { + failf(data, "Got unexpected pop3-server response"); + return CURLE_FTP_WEIRD_SERVER_REPLY; + } + + if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { + /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch + to TLS connection now */ + result = Curl_pp_sendf(&pop3c->pp, "STLS"); + state(conn, POP3_STARTTLS); + } + else + result = pop3_state_user(conn); + + return result; +} + /* for STARTTLS responses */ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, int pop3code, @@ -294,6 +322,7 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; + (void)instate; /* no use for this yet */ if(pop3code != 'O') { @@ -316,6 +345,7 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, state(conn, POP3_STOP); } } + return result; } @@ -342,6 +372,7 @@ static CURLcode pop3_state_user_resp(struct connectdata *conn, return result; state(conn, POP3_PASS); + return result; } @@ -360,6 +391,7 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, } state(conn, POP3_STOP); + return result; } @@ -518,7 +550,6 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) { CURLcode result; curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct SessionHandle *data=conn->data; int pop3code; struct pop3_conn *pop3c = &conn->proto.pop3c; struct pingpong *pp = &pop3c->pp; @@ -536,21 +567,7 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) /* we have now received a full POP3 server response */ switch(pop3c->state) { case POP3_SERVERGREET: - if(pop3code != 'O') { - failf(data, "Got unexpected pop3-server response"); - return CURLE_FTP_WEIRD_SERVER_REPLY; - } - - if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { - /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch - to TLS connection now */ - result = Curl_pp_sendf(&pop3c->pp, "STLS"); - state(conn, POP3_STARTTLS); - } - else - result = pop3_state_user(conn); - if(result) - return result; + result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state); break; case POP3_USER: @@ -585,6 +602,7 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) break; } } + return result; } -- cgit v1.2.1 From 2da89708ecea44b15c2ed9642b391e33f5188e91 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sat, 24 Mar 2012 12:28:11 +0000 Subject: pop3.c: Code policing and tidy up Corrected character and line spacing and re-ordered list and retr functions based on the order of their state machines. --- lib/pop3.c | 130 +++++++++++++++++++++++++++++++------------------------------ 1 file changed, 66 insertions(+), 64 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 6b7e01a60..e3f31c893 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -127,7 +127,6 @@ const struct Curl_handler Curl_handler_pop3 = { PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ }; - #ifdef USE_SSL /* * POP3S protocol handler. @@ -180,7 +179,6 @@ static const struct Curl_handler Curl_handler_pop3_proxy = { PROTOPT_NONE /* flags */ }; - #ifdef USE_SSL /* * HTTP-proxyed POP3S protocol handler. @@ -208,7 +206,6 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { #endif #endif - /* function that checks for a pop3 status code at the start of the given string */ static int pop3_endofresp(struct pingpong *pp, @@ -219,7 +216,7 @@ static int pop3_endofresp(struct pingpong *pp, if(((len >= 3) && !memcmp("+OK", line, 3)) || ((len >= 4) && !memcmp("-ERR", line, 4))) { - *resp=line[1]; /* O or E */ + *resp = line[1]; /* O or E */ return TRUE; } @@ -383,6 +380,7 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; + (void)instate; /* no use for this yet */ if(pop3code != 'O') { @@ -395,8 +393,8 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, return result; } -/* for the retr response */ -static CURLcode pop3_state_retr_resp(struct connectdata *conn, +/* for the list response */ +static CURLcode pop3_state_list_resp(struct connectdata *conn, int pop3code, pop3state instate) { @@ -413,14 +411,23 @@ static CURLcode pop3_state_retr_resp(struct connectdata *conn, return CURLE_RECV_ERROR; } + /* This 'OK' line ends with a CR LF pair which is the two first bytes of the + EOB string so count this is two matching bytes. This is necessary to make + the code detect the EOB if the only data than comes now is %2e CR LF like + when there is no body to return. */ + pop3c->eob = 2; + + /* But since this initial CR LF pair is not part of the actual body, we set + the strip counter here so that these bytes won't be delivered. */ + pop3c->strip = 2; + /* POP3 download */ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, pop3->bytecountp, -1, NULL); /* no upload here */ if(pp->cache) { - /* The header "cache" contains a bunch of data that is actually body - content so send it as such. Note that there may even be additional - "headers" after the body */ + /* The header "cache" contains a bunch of data that is actually list data + so send it as such */ if(!data->set.opt_no_body) { result = Curl_pop3_write(conn, pp->cache, pp->cache_size); @@ -440,8 +447,28 @@ static CURLcode pop3_state_retr_resp(struct connectdata *conn, return result; } -/* for the list response */ -static CURLcode pop3_state_list_resp(struct connectdata *conn, +/* for LIST response with a given message */ +static CURLcode pop3_state_list_single_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 != 'O') { + failf(data, "Invalid message. %c", pop3code); + result = CURLE_REMOTE_FILE_NOT_FOUND; + } + + state(conn, POP3_STOP); + + return result; +} + +/* for the retr response */ +static CURLcode pop3_state_retr_resp(struct connectdata *conn, int pop3code, pop3state instate) { @@ -458,23 +485,14 @@ static CURLcode pop3_state_list_resp(struct connectdata *conn, return CURLE_RECV_ERROR; } - /* This 'OK' line ends with a CR LF pair which is the two first bytes of the - EOB string so count this is two matching bytes. This is necessary to make - the code detect the EOB if the only data than comes now is %2e CR LF like - when there is no body to return. */ - pop3c->eob = 2; - - /* But since this initial CR LF pair is not part of the actual body, we set - the strip counter here so that these bytes won't be delivered. */ - pop3c->strip = 2; - /* POP3 download */ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, pop3->bytecountp, -1, NULL); /* no upload here */ if(pp->cache) { - /* The header "cache" contains a bunch of data that is actually list data - so send it as such */ + /* The header "cache" contains a bunch of data that is actually body + content so send it as such. Note that there may even be additional + "headers" after the body */ if(!data->set.opt_no_body) { result = Curl_pop3_write(conn, pp->cache, pp->cache_size); @@ -494,21 +512,24 @@ static CURLcode pop3_state_list_resp(struct connectdata *conn, return result; } -/* for LIST response with a given message */ -static CURLcode pop3_state_list_single_resp(struct connectdata *conn, - int pop3code, - pop3state instate) +/* start the DO phase for LIST */ +static CURLcode pop3_list(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - (void)instate; /* no use for this yet */ + struct pop3_conn *pop3c = &conn->proto.pop3c; - if(pop3code != 'O') { - failf(data, "Invalid message. %c", pop3code); - result = CURLE_REMOTE_FILE_NOT_FOUND; - } + if(pop3c->mailbox[0] != '\0') + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST %s", pop3c->mailbox); + else + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST"); + if(result) + return result; + + if(pop3c->mailbox[0] != '\0') + state(conn, POP3_LIST_SINGLE); + else + state(conn, POP3_LIST); - state(conn, POP3_STOP); return result; } @@ -523,26 +544,7 @@ static CURLcode pop3_retr(struct connectdata *conn) return result; state(conn, POP3_RETR); - return result; -} - -/* start the DO phase for LIST */ -static CURLcode pop3_list(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; - if(pop3c->mailbox[0] != '\0') - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST %s", pop3c->mailbox); - else - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST"); - if(result) - return result; - - if(pop3c->mailbox[0] != '\0') - state(conn, POP3_LIST_SINGLE); - else - state(conn, POP3_LIST); return result; } @@ -582,10 +584,6 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_starttls_resp(conn, pop3code, pop3c->state); break; - case POP3_RETR: - result = pop3_state_retr_resp(conn, pop3code, pop3c->state); - break; - case POP3_LIST: result = pop3_state_list_resp(conn, pop3code, pop3c->state); break; @@ -594,6 +592,10 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_list_single_resp(conn, pop3code, pop3c->state); break; + case POP3_RETR: + result = pop3_state_retr_resp(conn, pop3code, pop3c->state); + break; + case POP3_QUIT: /* fallthrough, just stop! */ default: @@ -668,7 +670,7 @@ static CURLcode pop3_init(struct connectdata *conn) * a part of the easy interface, it will always be TRUE. */ static CURLcode pop3_connect(struct connectdata *conn, - bool *done) /* see description above */ + bool *done) /* see description above */ { CURLcode result; struct pop3_conn *pop3c = &conn->proto.pop3c; @@ -732,7 +734,8 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, struct SessionHandle *data = conn->data; struct FTP *pop3 = data->state.proto.pop3; struct pop3_conn *pop3c = &conn->proto.pop3c; - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; + (void)premature; if(!pop3) @@ -749,7 +752,6 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, } Curl_safefree(pop3c->mailbox); - pop3c->mailbox = NULL; /* Clear the transfer mode for the next connection */ pop3->transfer = FTPTRANSFER_BODY; @@ -861,6 +863,7 @@ static CURLcode pop3_quit(struct connectdata *conn) result = Curl_pp_sendf(&conn->proto.pop3c.pp, "QUIT", NULL); if(result) return result; + state(conn, POP3_QUIT); result = pop3_easy_statemach(conn); @@ -889,7 +892,6 @@ static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection) if(!dead_connection && pop3c->pp.conn) (void)pop3_quit(conn); /* ignore errors on the LOGOUT */ - Curl_pp_disconnect(&pop3c->pp); return CURLE_OK; @@ -939,6 +941,7 @@ static CURLcode pop3_doing(struct connectdata *conn, DEBUGF(infof(conn->data, "DO phase is complete\n")); } + return result; } @@ -952,9 +955,8 @@ static CURLcode pop3_doing(struct connectdata *conn, * remote host. * */ -static -CURLcode pop3_regular_transfer(struct connectdata *conn, - bool *dophase_done) +static CURLcode pop3_regular_transfer(struct connectdata *conn, + bool *dophase_done) { CURLcode result=CURLE_OK; bool connected=FALSE; -- cgit v1.2.1 From 01690ed2bce50be86a045fe6edfe9ee72a9e9b9f Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sun, 25 Mar 2012 11:21:59 +0100 Subject: pop3: Removed the need for the single message LIST command handler Simplified the code to remove the need for a separate "LIST " command handler and state machine and instead use the LIST command handler for both operations. --- lib/pop3.c | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index e3f31c893..2bba61547 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -447,26 +447,6 @@ static CURLcode pop3_state_list_resp(struct connectdata *conn, return result; } -/* for LIST response with a given message */ -static CURLcode pop3_state_list_single_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 != 'O') { - failf(data, "Invalid message. %c", pop3code); - result = CURLE_REMOTE_FILE_NOT_FOUND; - } - - state(conn, POP3_STOP); - - return result; -} - /* for the retr response */ static CURLcode pop3_state_retr_resp(struct connectdata *conn, int pop3code, @@ -518,17 +498,20 @@ static CURLcode pop3_list(struct connectdata *conn) CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; - if(pop3c->mailbox[0] != '\0') + if(pop3c->mailbox[0] != '\0') { + /* Message specific LIST means no transfer */ + struct FTP *pop3 = conn->data->state.proto.pop3; + pop3->transfer = FTPTRANSFER_INFO; + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST %s", pop3c->mailbox); + } else result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST"); + if(result) return result; - if(pop3c->mailbox[0] != '\0') - state(conn, POP3_LIST_SINGLE); - else - state(conn, POP3_LIST); + state(conn, POP3_LIST); return result; } @@ -588,10 +571,6 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_list_resp(conn, pop3code, pop3c->state); break; - case POP3_LIST_SINGLE: - result = pop3_state_list_single_resp(conn, pop3code, pop3c->state); - break; - case POP3_RETR: result = pop3_state_retr_resp(conn, pop3code, pop3c->state); break; -- cgit v1.2.1 From 9f96e6da2817ffcfd813da6af2c238d5796b527e Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sun, 25 Mar 2012 11:28:59 +0100 Subject: pop.c: Small code tidy up --- lib/pop3.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 2bba61547..435e80b5f 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -258,7 +258,7 @@ static CURLcode pop3_state_user(struct connectdata *conn) /* send USER */ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s", - pop3->user?pop3->user:""); + pop3->user ? pop3->user : ""); if(result) return result; @@ -364,7 +364,7 @@ static CURLcode pop3_state_user_resp(struct connectdata *conn, else /* send PASS */ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s", - pop3->passwd?pop3->passwd:""); + pop3->passwd ? pop3->passwd : ""); if(result) return result; @@ -621,6 +621,7 @@ static CURLcode pop3_init(struct connectdata *conn) { struct SessionHandle *data = conn->data; struct FTP *pop3 = data->state.proto.pop3; + if(!pop3) { pop3 = data->state.proto.pop3 = calloc(sizeof(struct FTP), 1); if(!pop3) @@ -653,7 +654,7 @@ static CURLcode pop3_connect(struct connectdata *conn, { CURLcode result; struct pop3_conn *pop3c = &conn->proto.pop3c; - struct SessionHandle *data=conn->data; + struct SessionHandle *data = conn->data; struct pingpong *pp = &pop3c->pp; *done = FALSE; /* default to not done yet */ @@ -727,7 +728,7 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, if(status) { conn->bits.close = TRUE; /* marked for closure */ - result = status; /* use the already set error code */ + result = status; /* use the already set error code */ } Curl_safefree(pop3c->mailbox); @@ -752,7 +753,7 @@ CURLcode pop3_perform(struct connectdata *conn, bool *dophase_done) { /* this is POP3 and no proxy */ - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; DEBUGF(infof(conn->data, "DO phase starts\n")); @@ -937,8 +938,8 @@ static CURLcode pop3_doing(struct connectdata *conn, static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *dophase_done) { - CURLcode result=CURLE_OK; - bool connected=FALSE; + CURLcode result = CURLE_OK; + bool connected = FALSE; struct SessionHandle *data = conn->data; data->req.size = -1; /* make sure this is unknown at this point */ @@ -948,7 +949,7 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn, Curl_pgrsSetDownloadSize(data, 0); result = pop3_perform(conn, - &connected, /* have we connected after PASV/PORT */ + &connected, /* have we connected after PASV/PORT */ dophase_done); /* all commands in the DO-phase done? */ if(CURLE_OK == result) { -- cgit v1.2.1 From 982315573c14c7d8ce27c205294fd37d786cfbbe Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sun, 25 Mar 2012 12:47:39 +0100 Subject: pop3.c: Corrected problem with state() introduced in 01690ed2bce5 --- lib/pop3.c | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 435e80b5f..25d22bd35 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -236,7 +236,6 @@ static void state(struct connectdata *conn, "PASS", "STARTTLS", "LIST", - "LIST_SINGLE", "RETR", "QUIT", /* LAST */ -- cgit v1.2.1 From 761c3c544623cdcfe26aabaa9b685b75983ce3aa Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sat, 31 Mar 2012 18:46:22 +0100 Subject: pop3: Added support for additional pop3 commands This feature allows the user to specify and use additional POP3 commands such as UIDL and DELE via libcurl's CURLOPT_CUSTOMREQUEST or curl's -X command line option. --- lib/pop3.c | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 25d22bd35..44db3a474 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -89,6 +89,7 @@ /* Local API functions */ static CURLcode pop3_parse_url_path(struct connectdata *conn); +static CURLcode pop3_parse_custom_request(struct connectdata *conn); static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done); static CURLcode pop3_do(struct connectdata *conn, bool *done); static CURLcode pop3_done(struct connectdata *conn, @@ -502,10 +503,14 @@ static CURLcode pop3_list(struct connectdata *conn) struct FTP *pop3 = conn->data->state.proto.pop3; pop3->transfer = FTPTRANSFER_INFO; - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST %s", pop3c->mailbox); + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s", + (pop3c->custom && pop3c->custom[0] != '\0' ? + pop3c->custom : "LIST"), pop3c->mailbox); } else - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST"); + result = Curl_pp_sendf(&conn->proto.pop3c.pp, + (pop3c->custom && pop3c->custom[0] != '\0' ? + pop3c->custom : "LIST")); if(result) return result; @@ -521,7 +526,9 @@ static CURLcode pop3_retr(struct connectdata *conn) CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "RETR %s", pop3c->mailbox); + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s", + (pop3c->custom && pop3c->custom[0] != '\0' ? + pop3c->custom : "RETR"), pop3c->mailbox); if(result) return result; @@ -730,7 +737,9 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, result = status; /* use the already set error code */ } + /* Clear our variables for the next connection */ Curl_safefree(pop3c->mailbox); + Curl_safefree(pop3c->custom); /* Clear the transfer mode for the next connection */ pop3->transfer = FTPTRANSFER_BODY; @@ -817,10 +826,16 @@ static CURLcode pop3_do(struct connectdata *conn, bool *done) if(retcode) return retcode; + /* Parse the URL path */ retcode = pop3_parse_url_path(conn); if(retcode) return retcode; + /* Parse the custom request */ + retcode = pop3_parse_custom_request(conn); + if(retcode) + return retcode; + retcode = pop3_regular_transfer(conn, done); return retcode; @@ -890,15 +905,30 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn) struct SessionHandle *data = conn->data; const char *path = data->state.path; - /* url decode the path and use this mailbox */ + /* URL decode the path and use this mailbox */ return Curl_urldecode(data, path, 0, &pop3c->mailbox, NULL, TRUE); } +static CURLcode pop3_parse_custom_request(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + struct SessionHandle *data = conn->data; + const char *custom = conn->data->set.str[STRING_CUSTOMREQUEST]; + + /* URL decode the custom request */ + if(custom) + result = Curl_urldecode(data, custom, 0, &pop3c->custom, NULL, TRUE); + + return result; +} + /* call this when the DO phase has completed */ static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected) { struct FTP *pop3 = conn->data->state.proto.pop3; + (void)connected; if(pop3->transfer != FTPTRANSFER_BODY) @@ -983,6 +1013,7 @@ static CURLcode pop3_setup_connection(struct connectdata * conn) return CURLE_UNSUPPORTED_PROTOCOL; #endif } + /* * We explicitly mark this connection as persistent here as we're doing * POP3 over HTTP and thus we accidentally avoid setting this value -- cgit v1.2.1 From 15e1227ed4cbf3364c70f4aa8fb4141879777a6d Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Mon, 2 Apr 2012 23:24:00 +0100 Subject: pop3: Reworked the command sending and handling Reworked the command sending from two specific LIST and RETR command functions into a single command based function as well as the two associated response handlers into a generic command handler. --- lib/pop3.c | 119 +++++++++++++++---------------------------------------------- 1 file changed, 28 insertions(+), 91 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 44db3a474..91b544a0a 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -236,8 +236,7 @@ static void state(struct connectdata *conn, "USER", "PASS", "STARTTLS", - "LIST", - "RETR", + "COMMAND", "QUIT", /* LAST */ }; @@ -393,10 +392,10 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, return result; } -/* for the list response */ -static CURLcode pop3_state_list_resp(struct connectdata *conn, - int pop3code, - pop3state instate) +/* for the command response */ +static CURLcode pop3_state_command_resp(struct connectdata *conn, + int pop3code, + pop3state instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; @@ -421,50 +420,6 @@ static CURLcode pop3_state_list_resp(struct connectdata *conn, the strip counter here so that these bytes won't be delivered. */ pop3c->strip = 2; - /* POP3 download */ - Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, pop3->bytecountp, - -1, NULL); /* no upload here */ - - if(pp->cache) { - /* The header "cache" contains a bunch of data that is actually list data - so send it as such */ - - if(!data->set.opt_no_body) { - result = Curl_pop3_write(conn, pp->cache, pp->cache_size); - if(result) - return result; - } - - /* Free the cache */ - Curl_safefree(pp->cache); - - /* Reset the cache size */ - pp->cache_size = 0; - } - - state(conn, POP3_STOP); - - return result; -} - -/* for the retr response */ -static CURLcode pop3_state_retr_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct FTP *pop3 = data->state.proto.pop3; - struct pop3_conn *pop3c = &conn->proto.pop3c; - struct pingpong *pp = &pop3c->pp; - - (void)instate; /* no use for this yet */ - - if('O' != pop3code) { - state(conn, POP3_STOP); - return CURLE_RECV_ERROR; - } - /* POP3 download */ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, pop3->bytecountp, -1, NULL); /* no upload here */ @@ -492,47 +447,40 @@ static CURLcode pop3_state_retr_resp(struct connectdata *conn, return result; } -/* start the DO phase for LIST */ -static CURLcode pop3_list(struct connectdata *conn) +/* start the DO phase for the command */ +static CURLcode pop3_command(struct connectdata *conn) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; + const char *command = NULL; - if(pop3c->mailbox[0] != '\0') { - /* Message specific LIST means no transfer */ - struct FTP *pop3 = conn->data->state.proto.pop3; - pop3->transfer = FTPTRANSFER_INFO; + /* Calculate the default command */ + if(pop3c->mailbox[0] == '\0' || conn->data->set.ftp_list_only) { + command = "LIST"; + + if(pop3c->mailbox[0] != '\0') { + /* Message specific LIST so skip the BODY transfer */ + struct FTP *pop3 = conn->data->state.proto.pop3; + pop3->transfer = FTPTRANSFER_INFO; + } + } + else + command = "RETR"; + /* Send the command */ + if(pop3c->mailbox[0] != '\0') result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s", (pop3c->custom && pop3c->custom[0] != '\0' ? - pop3c->custom : "LIST"), pop3c->mailbox); - } + pop3c->custom : command), pop3c->mailbox); else result = Curl_pp_sendf(&conn->proto.pop3c.pp, (pop3c->custom && pop3c->custom[0] != '\0' ? - pop3c->custom : "LIST")); - - if(result) - return result; - - state(conn, POP3_LIST); - - return result; -} + pop3c->custom : command)); -/* start the DO phase for RETR */ -static CURLcode pop3_retr(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; - - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s", - (pop3c->custom && pop3c->custom[0] != '\0' ? - pop3c->custom : "RETR"), pop3c->mailbox); if(result) return result; - state(conn, POP3_RETR); + state(conn, POP3_COMMAND); return result; } @@ -573,12 +521,8 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_starttls_resp(conn, pop3code, pop3c->state); break; - case POP3_LIST: - result = pop3_state_list_resp(conn, pop3code, pop3c->state); - break; - - case POP3_RETR: - result = pop3_state_retr_resp(conn, pop3code, pop3c->state); + case POP3_COMMAND: + result = pop3_state_command_resp(conn, pop3code, pop3c->state); break; case POP3_QUIT: @@ -762,7 +706,6 @@ CURLcode pop3_perform(struct connectdata *conn, { /* this is POP3 and no proxy */ CURLcode result = CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; DEBUGF(infof(conn->data, "DO phase starts\n")); @@ -775,13 +718,7 @@ CURLcode pop3_perform(struct connectdata *conn, *dophase_done = FALSE; /* not done yet */ /* start the first command in the DO phase */ - /* If mailbox is empty, then assume user wants listing for mail IDs, - * otherwise, attempt to retrieve the mail-id stored in mailbox - */ - if(strlen(pop3c->mailbox) && !conn->data->set.ftp_list_only) - result = pop3_retr(conn); - else - result = pop3_list(conn); + result = pop3_command(conn); if(result) return result; -- cgit v1.2.1 From c6495bccbf7485d9088e994bf27cb2efd3b29d47 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sun, 27 May 2012 10:54:13 +0100 Subject: pop3: Code tidy up before the introduction of authentication code Moved EOB definition into header file. Switched the logic around in pop3_endofresp() to allow for the introduction of auth-mechanism detection. Repositioned second and third function variables where they will fit within the 78 character line limit. Tidied up some comments. --- lib/pop3.c | 84 +++++++++++++++++++++++++------------------------------------- 1 file changed, 34 insertions(+), 50 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 91b544a0a..99dc6c537 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -207,26 +207,24 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { #endif #endif -/* function that checks for a pop3 status code at the start of the given - string */ -static int pop3_endofresp(struct pingpong *pp, - int *resp) +/* Function that checks for an ending pop3 status code at the start of the + given string */ +static int pop3_endofresp(struct pingpong *pp, int *resp) { char *line = pp->linestart_resp; size_t len = pp->nread_resp; - if(((len >= 3) && !memcmp("+OK", line, 3)) || - ((len >= 4) && !memcmp("-ERR", line, 4))) { - *resp = line[1]; /* O or E */ - return TRUE; - } + if((len < 3 || memcmp("+OK", line, 3)) && + (len < 4 || memcmp("-ERR", line, 4))) + return FALSE; /* Nothing for us */ + + *resp = line[1]; /* O or E */ - return FALSE; /* nothing for us */ + return TRUE; } /* This is the ONLY way to change POP3 state! */ -static void state(struct connectdata *conn, - pop3state newstate) +static void state(struct connectdata *conn, pop3state newstate) { #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ @@ -267,8 +265,7 @@ static CURLcode pop3_state_user(struct connectdata *conn) } /* For the POP3 "protocol connect" and "doing" phases only */ -static int pop3_getsock(struct connectdata *conn, - curl_socket_t *socks, +static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks) { return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks); @@ -283,7 +280,7 @@ static void pop3_to_pop3s(struct connectdata *conn) #define pop3_to_pop3s(x) Curl_nop_stmt #endif -/* for the initial server greeting */ +/* For the initial server greeting */ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, int pop3code, pop3state instate) @@ -311,7 +308,7 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, return result; } -/* for STARTTLS responses */ +/* For STARTTLS responses */ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, int pop3code, pop3state instate) @@ -345,7 +342,7 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, return result; } -/* for USER responses */ +/* For USER responses */ static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code, pop3state instate) @@ -372,7 +369,7 @@ static CURLcode pop3_state_user_resp(struct connectdata *conn, return result; } -/* for PASS responses */ +/* For PASS responses */ static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code, pop3state instate) @@ -392,7 +389,7 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, return result; } -/* for the command response */ +/* For the command response */ static CURLcode pop3_state_command_resp(struct connectdata *conn, int pop3code, pop3state instate) @@ -447,7 +444,7 @@ static CURLcode pop3_state_command_resp(struct connectdata *conn, return result; } -/* start the DO phase for the command */ +/* Start the DO phase for the command */ static CURLcode pop3_command(struct connectdata *conn) { CURLcode result = CURLE_OK; @@ -537,7 +534,7 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) return result; } -/* called repeatedly until done from multi.c */ +/* Called repeatedly until done from multi.c */ static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done) { struct pop3_conn *pop3c = &conn->proto.pop3c; @@ -563,10 +560,8 @@ static CURLcode pop3_easy_statemach(struct connectdata *conn) return result; } -/* - * Allocate and initialize the struct POP3 for the current SessionHandle. If - * need be. - */ +/* Allocate and initialize the POP3 struct for the current SessionHandle if + required */ static CURLcode pop3_init(struct connectdata *conn) { struct SessionHandle *data = conn->data; @@ -591,16 +586,18 @@ static CURLcode pop3_init(struct connectdata *conn) return CURLE_OK; } -/* - * pop3_connect() should do everything that is to be considered a part of - * the connection phase. +/*********************************************************************** + * + * pop3_connect() + * + * This function should do everything that is to be considered a part of the + * connection phase. * * The variable 'done' points to will be TRUE if the protocol-layer connect * phase is done when this function returns, or FALSE is not. When called as * a part of the easy interface, it will always be TRUE. */ -static CURLcode pop3_connect(struct connectdata *conn, - bool *done) /* see description above */ +static CURLcode pop3_connect(struct connectdata *conn, bool *done) { CURLcode result; struct pop3_conn *pop3c = &conn->proto.pop3c; @@ -698,11 +695,8 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, * This is the actual DO function for POP3. Get a file/directory according to * the options previously setup. */ - -static -CURLcode pop3_perform(struct connectdata *conn, - bool *connected, /* connect status after PASV / PORT */ - bool *dophase_done) +static CURLcode pop3_perform(struct connectdata *conn, bool *connected, + bool *dophase_done) { /* this is POP3 and no proxy */ CURLcode result = CURLE_OK; @@ -785,7 +779,6 @@ static CURLcode pop3_do(struct connectdata *conn, bool *done) * This should be called before calling sclose(). We should then wait for the * response from the server before returning. The calling code should then try * to close the connection. - * */ static CURLcode pop3_quit(struct connectdata *conn) { @@ -861,8 +854,7 @@ static CURLcode pop3_parse_custom_request(struct connectdata *conn) } /* call this when the DO phase has completed */ -static CURLcode pop3_dophase_done(struct connectdata *conn, - bool connected) +static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected) { struct FTP *pop3 = conn->data->state.proto.pop3; @@ -876,8 +868,7 @@ static CURLcode pop3_dophase_done(struct connectdata *conn, } /* called from multi.c while DOing */ -static CURLcode pop3_doing(struct connectdata *conn, - bool *dophase_done) +static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done) { CURLcode result; result = pop3_multi_statemach(conn, dophase_done); @@ -899,7 +890,6 @@ static CURLcode pop3_doing(struct connectdata *conn, * * Performs all commands done before a regular transfer between a local and a * remote host. - * */ static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *dophase_done) @@ -951,11 +941,9 @@ static CURLcode pop3_setup_connection(struct connectdata * conn) #endif } - /* - * We explicitly mark this connection as persistent here as we're doing - * POP3 over HTTP and thus we accidentally avoid setting this value - * otherwise. - */ + /* We explicitly mark this connection as persistent here as we're doing + POP3 over HTTP and thus we accidentally avoid setting this value + otherwise. */ conn->bits.close = FALSE; #else failf(data, "POP3 over http proxy requires HTTP support built-in!"); @@ -968,10 +956,6 @@ static CURLcode pop3_setup_connection(struct connectdata * conn) return CURLE_OK; } -/* this is the 5-bytes End-Of-Body marker for POP3 */ -#define POP3_EOB "\x0d\x0a\x2e\x0d\x0a" -#define POP3_EOB_LEN 5 - /* * This function scans the body after the end-of-body and writes everything * until the end is found. -- cgit v1.2.1 From dc454bd16b546871b9910ec4d4b0ade899c43e56 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 27 May 2012 14:08:46 +0200 Subject: pop3: remove trailing whitespace --- lib/pop3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 99dc6c537..ae540378f 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -214,7 +214,7 @@ static int pop3_endofresp(struct pingpong *pp, int *resp) char *line = pp->linestart_resp; size_t len = pp->nread_resp; - if((len < 3 || memcmp("+OK", line, 3)) && + if((len < 3 || memcmp("+OK", line, 3)) && (len < 4 || memcmp("-ERR", line, 4))) return FALSE; /* Nothing for us */ -- cgit v1.2.1 From c267c53017bc37d34be23f885f34776659a13c43 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sun, 27 May 2012 19:09:38 +0100 Subject: pop3: Added support for SASL based authentication mechanism detection Added support for detecting the supported SASL authentication mechanisms via the AUTH command. There are two ways of detecting them, either by using the AUTH command, that will return -ERR if not supported or by using the CAPA command which will return SASL and the list of mechanisms if supported, not include SASL if SASL authentication is not supported or -ERR if the CAPA command is not supported. As such it seems simpler to use the AUTH command and fallback to normal clear text authentication if the the command is not supported. Additionally updated the test cases to return -ERR when the AUTH command is encountered. Additional test cases will be added when support for the individual authentication mechanisms is added. --- lib/pop3.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 4 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index ae540378f..2f47fd1a9 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -79,6 +79,7 @@ #include "url.h" #include "rawstr.h" #include "strtoofft.h" +#include "curl_sasl.h" #define _MPRINTF_REPLACE /* use our functions only */ #include @@ -208,11 +209,15 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { #endif /* Function that checks for an ending pop3 status code at the start of the - given string */ + given string, but also detects the allowed authentication mechanisms + according to the AUTH response. */ static int pop3_endofresp(struct pingpong *pp, int *resp) { char *line = pp->linestart_resp; size_t len = pp->nread_resp; + struct connectdata *conn = pp->conn; + struct pop3_conn *pop3c = &conn->proto.pop3c; + size_t wordlen; if((len < 3 || memcmp("+OK", line, 3)) && (len < 4 || memcmp("-ERR", line, 4))) @@ -220,6 +225,46 @@ static int pop3_endofresp(struct pingpong *pp, int *resp) *resp = line[1]; /* O or E */ + if(pop3c->state == POP3_AUTH && len >= 3 && !memcmp(line, "+OK", 3)) { + line += 3; + len -= 3; + + for(;;) { + while(len && + (*line == ' ' || *line == '\t' || + *line == '\r' || *line == '\n')) { + line++; + len--; + } + + if(!len || *line == '.') + break; + + for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && + line[wordlen] != '\t' && line[wordlen] != '\r' && + line[wordlen] != '\n';) + wordlen++; + + if(wordlen == 5 && !memcmp(line, "LOGIN", 5)) + pop3c->authmechs |= SASL_AUTH_LOGIN; + else if(wordlen == 5 && !memcmp(line, "PLAIN", 5)) + pop3c->authmechs |= SASL_AUTH_PLAIN; + else if(wordlen == 8 && !memcmp(line, "CRAM-MD5", 8)) + pop3c->authmechs |= SASL_AUTH_CRAM_MD5; + else if(wordlen == 10 && !memcmp(line, "DIGEST-MD5", 10)) + pop3c->authmechs |= SASL_AUTH_DIGEST_MD5; + else if(wordlen == 6 && !memcmp(line, "GSSAPI", 6)) + pop3c->authmechs |= SASL_AUTH_GSSAPI; + else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8)) + pop3c->authmechs |= SASL_AUTH_EXTERNAL; + else if(wordlen == 4 && !memcmp(line, "NTLM", 4)) + pop3c->authmechs |= SASL_AUTH_NTLM; + + line += wordlen; + len -= wordlen; + } + } + return TRUE; } @@ -231,6 +276,7 @@ static void state(struct connectdata *conn, pop3state newstate) static const char * const names[]={ "STOP", "SERVERGREET", + "AUTH", "USER", "PASS", "STARTTLS", @@ -248,6 +294,24 @@ static void state(struct connectdata *conn, pop3state newstate) pop3c->state = newstate; } +static CURLcode pop3_state_auth(struct connectdata *conn) +{ + CURLcode result; + struct pop3_conn *pop3c = &conn->proto.pop3c; + + pop3c->authmechs = 0; /* No known authentication mechanisms yet */ + + /* send AUTH */ + result = Curl_pp_sendf(&pop3c->pp, "AUTH"); + + if(result) + return result; + + state(conn, POP3_AUTH); + + return CURLE_OK; +} + static CURLcode pop3_state_user(struct connectdata *conn) { CURLcode result; @@ -303,7 +367,7 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, state(conn, POP3_STARTTLS); } else - result = pop3_state_user(conn); + result = pop3_state_auth(conn); return result; } @@ -325,14 +389,14 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, state(conn, POP3_STOP); } else - result = pop3_state_user(conn); + result = pop3_state_auth(conn); } else { /* Curl_ssl_connect is BLOCKING */ result = Curl_ssl_connect(conn, FIRSTSOCKET); if(CURLE_OK == result) { pop3_to_pop3s(conn); - result = pop3_state_user(conn); + result = pop3_state_auth(conn); } else { state(conn, POP3_STOP); @@ -342,6 +406,23 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, return result; } +/* For AUTH responses */ +static CURLcode pop3_state_auth_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct FTP *pop3 = data->state.proto.pop3; + + (void)instate; /* no use for this yet */ + + /* Proceed with clear text authentication as we used to for now */ + result = pop3_state_user(conn); + + return result; +} + /* For USER responses */ static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code, @@ -506,6 +587,10 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state); break; + case POP3_AUTH: + result = pop3_state_auth_resp(conn, pop3code, pop3c->state); + break; + case POP3_USER: result = pop3_state_user_resp(conn, pop3code, pop3c->state); break; -- cgit v1.2.1 From a7731673d02a80d3ab4b6d3be296daa2807025a8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 27 May 2012 23:29:15 +0200 Subject: pop3: remove variable-not-used warnings --- lib/pop3.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 2f47fd1a9..12d604043 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -407,15 +407,9 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, } /* For AUTH responses */ -static CURLcode pop3_state_auth_resp(struct connectdata *conn, - int pop3code, - pop3state instate) +static CURLcode pop3_state_auth_resp(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct FTP *pop3 = data->state.proto.pop3; - - (void)instate; /* no use for this yet */ /* Proceed with clear text authentication as we used to for now */ result = pop3_state_user(conn); @@ -588,7 +582,7 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) break; case POP3_AUTH: - result = pop3_state_auth_resp(conn, pop3code, pop3c->state); + result = pop3_state_auth_resp(conn); break; case POP3_USER: -- cgit v1.2.1 From a9d798c4d54e45d1480e4974eeda244fc0c3300e Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Mon, 28 May 2012 20:21:52 +0100 Subject: pop3: Small code tidy up following authentication work so far Changed the order of the state machine to match the order of actual events. Reworked some comments and function parameter positioning that I missed the other day. --- lib/pop3.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 12d604043..a9898e218 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -276,10 +276,10 @@ static void state(struct connectdata *conn, pop3state newstate) static const char * const names[]={ "STOP", "SERVERGREET", + "STARTTLS", "AUTH", "USER", "PASS", - "STARTTLS", "COMMAND", "QUIT", /* LAST */ @@ -581,6 +581,10 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state); break; + case POP3_STARTTLS: + result = pop3_state_starttls_resp(conn, pop3code, pop3c->state); + break; + case POP3_AUTH: result = pop3_state_auth_resp(conn); break; @@ -593,10 +597,6 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_pass_resp(conn, pop3code, pop3c->state); break; - case POP3_STARTTLS: - result = pop3_state_starttls_resp(conn, pop3code, pop3c->state); - break; - case POP3_COMMAND: result = pop3_state_command_resp(conn, pop3code, pop3c->state); break; @@ -905,7 +905,6 @@ static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection) * pop3_parse_url_path() * * Parse the URL path into separate path components. - * */ static CURLcode pop3_parse_url_path(struct connectdata *conn) { @@ -983,9 +982,7 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn, Curl_pgrsSetUploadSize(data, 0); Curl_pgrsSetDownloadSize(data, 0); - result = pop3_perform(conn, - &connected, /* have we connected after PASV/PORT */ - dophase_done); /* all commands in the DO-phase done? */ + result = pop3_perform(conn, &connected, dophase_done); if(CURLE_OK == result) { @@ -1035,13 +1032,9 @@ static CURLcode pop3_setup_connection(struct connectdata * conn) return CURLE_OK; } -/* - * This function scans the body after the end-of-body and writes everything - * until the end is found. - */ -CURLcode Curl_pop3_write(struct connectdata *conn, - char *str, - size_t nread) +/* This function scans the body after the end-of-body and writes everything + until the end is found */ +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; @@ -1142,7 +1135,7 @@ CURLcode Curl_pop3_write(struct connectdata *conn, /* We have a full match so the transfer is done, however we must transfer the CRLF at the start of the EOB as this is considered to be part of the message as per RFC-1939, sect. 3 */ - result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB, 2); + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2); k->keepon &= ~KEEP_RECV; pop3c->eob = 0; -- cgit v1.2.1 From 3fa0fbb816bb03b5d68d80a26323ee8c8609c369 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Mon, 28 May 2012 20:59:10 +0100 Subject: pop3: Changed response code from O and E to + and - The POP3 protocol doesn't really have the concept of error codes and uses +, +OK and -ERR in response to commands to indicate continue, success and error. The AUTH command is one of those commands that requires multiple pieces of data to be sent to the server where the server will respond with + as part of the handshaking. This meant changing the values before continuing with the next stage of adding authentication support. --- lib/pop3.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index a9898e218..782da9216 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -223,7 +223,7 @@ static int pop3_endofresp(struct pingpong *pp, int *resp) (len < 4 || memcmp("-ERR", line, 4))) return FALSE; /* Nothing for us */ - *resp = line[1]; /* O or E */ + *resp = line[0]; /* + or - */ if(pop3c->state == POP3_AUTH && len >= 3 && !memcmp(line, "+OK", 3)) { line += 3; @@ -355,7 +355,7 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, (void)instate; /* no use for this yet */ - if(pop3code != 'O') { + if(pop3code != '+') { failf(data, "Got unexpected pop3-server response"); return CURLE_FTP_WEIRD_SERVER_REPLY; } @@ -382,7 +382,7 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, (void)instate; /* no use for this yet */ - if(pop3code != 'O') { + if(pop3code != '+') { if(data->set.use_ssl != CURLUSESSL_TRY) { failf(data, "STARTTLS denied. %c", pop3code); result = CURLE_USE_SSL_FAILED; @@ -428,7 +428,7 @@ static CURLcode pop3_state_user_resp(struct connectdata *conn, (void)instate; /* no use for this yet */ - if(pop3code != 'O') { + if(pop3code != '+') { failf(data, "Access denied. %c", pop3code); result = CURLE_LOGIN_DENIED; } @@ -454,7 +454,7 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, (void)instate; /* no use for this yet */ - if(pop3code != 'O') { + if(pop3code != '+') { failf(data, "Access denied. %c", pop3code); result = CURLE_LOGIN_DENIED; } @@ -477,7 +477,7 @@ static CURLcode pop3_state_command_resp(struct connectdata *conn, (void)instate; /* no use for this yet */ - if('O' != pop3code) { + if(pop3code != '+') { state(conn, POP3_STOP); return CURLE_RECV_ERROR; } -- cgit v1.2.1 From 7291c1f5654b1c433177207bfa7e21bb30fe5a50 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Mon, 28 May 2012 21:29:01 +0100 Subject: pop3: Introduced the continue response in pop3_endofresp() --- lib/pop3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 782da9216..d3b84f342 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -219,7 +219,8 @@ static int pop3_endofresp(struct pingpong *pp, int *resp) struct pop3_conn *pop3c = &conn->proto.pop3c; size_t wordlen; - if((len < 3 || memcmp("+OK", line, 3)) && + if((len < 1 || memcmp("+", line, 1)) && + (len < 3 || memcmp("+OK", line, 3)) && (len < 4 || memcmp("-ERR", line, 4))) return FALSE; /* Nothing for us */ -- cgit v1.2.1 From 2c6d32b864d5bdf7979c22b7b37818e54e6207d8 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Thu, 31 May 2012 20:45:53 +0100 Subject: pop3: Added support for sasl plain text authentication --- lib/pop3.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 5 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index d3b84f342..38cde50d0 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -18,9 +18,11 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * RFC1734 POP3 Authentication * RFC1939 POP3 protocol * RFC2384 POP URL Scheme * RFC2595 Using TLS with IMAP, POP3 and ACAP + * RFC4616 PLAIN authentication * ***************************************************************************/ @@ -279,6 +281,8 @@ static void state(struct connectdata *conn, pop3state newstate) "SERVERGREET", "STARTTLS", "AUTH", + "AUTH_PLAIN", + "AUTH_FINAL", "USER", "PASS", "COMMAND", @@ -301,6 +305,7 @@ static CURLcode pop3_state_auth(struct connectdata *conn) struct pop3_conn *pop3c = &conn->proto.pop3c; pop3c->authmechs = 0; /* No known authentication mechanisms yet */ + pop3c->authused = 0; /* Clear the authentication mechanism used */ /* send AUTH */ result = Curl_pp_sendf(&pop3c->pp, "AUTH"); @@ -329,6 +334,35 @@ static CURLcode pop3_state_user(struct connectdata *conn) return CURLE_OK; } +static CURLcode pop3_authenticate(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + const char *mech = NULL; + pop3state authstate = POP3_STOP; + + /* Check supported authentication mechanisms by decreasing order of + security */ + if(pop3c->authmechs & SASL_AUTH_PLAIN) { + mech = "PLAIN"; + authstate = POP3_AUTH_PLAIN; + pop3c->authused = SASL_AUTH_PLAIN; + } + else { + infof(conn->data, "No known SASL auth mechanisms supported!\n"); + result = CURLE_LOGIN_DENIED; /* Other mechanisms not supported */ + } + + if(!result) { + result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech); + + if(!result) + state(conn, authstate); + } + + return result; +} + /* For the POP3 "protocol connect" and "doing" phases only */ static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks) @@ -408,12 +442,72 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, } /* For AUTH responses */ -static CURLcode pop3_state_auth_resp(struct connectdata *conn) +static CURLcode pop3_state_auth_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') + result = pop3_state_user(conn); + else + result = pop3_authenticate(conn); + + return result; +} + +/* For AUTH PLAIN 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; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + failf(data, "Access denied. %c", pop3code); + result = CURLE_LOGIN_DENIED; + } + else { + result = Curl_sasl_create_plain_message(conn->data, conn->user, + conn->passwd, &plainauth, &len); + + 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 final responses in the AUTH sequence */ +static CURLcode pop3_state_auth_final_resp(struct connectdata *conn, + int pop3code, + pop3state instate) { CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + failf(data, "Authentication failed: %d", pop3code); + result = CURLE_LOGIN_DENIED; + } - /* Proceed with clear text authentication as we used to for now */ - result = pop3_state_user(conn); + state(conn, POP3_STOP); /* End of connect phase */ return result; } @@ -460,7 +554,7 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } - state(conn, POP3_STOP); + state(conn, POP3_STOP); /* End of connect phase */ return result; } @@ -587,7 +681,15 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) break; case POP3_AUTH: - result = pop3_state_auth_resp(conn); + result = pop3_state_auth_resp(conn, pop3code, pop3c->state); + break; + + case POP3_AUTH_PLAIN: + result = pop3_state_auth_plain_resp(conn, pop3code, pop3c->state); + break; + + case POP3_AUTH_FINAL: + result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state); break; case POP3_USER: -- cgit v1.2.1 From 2df6e6d9f8cb84c6010ac1c0471cfaa5d66f8d7d Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Fri, 1 Jun 2012 15:59:29 +0100 Subject: pop3: Added support for sasl login authentication --- lib/pop3.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 2 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 38cde50d0..9660bb57a 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -282,6 +282,8 @@ static void state(struct connectdata *conn, pop3state newstate) "STARTTLS", "AUTH", "AUTH_PLAIN", + "AUTH_LOGIN", + "AUTH_LOGIN_PASSWD", "AUTH_FINAL", "USER", "PASS", @@ -343,7 +345,12 @@ static CURLcode pop3_authenticate(struct connectdata *conn) /* Check supported authentication mechanisms by decreasing order of security */ - if(pop3c->authmechs & SASL_AUTH_PLAIN) { + if(pop3c->authmechs & SASL_AUTH_LOGIN) { + mech = "LOGIN"; + authstate = POP3_AUTH_LOGIN; + pop3c->authused = SASL_AUTH_LOGIN; + } + else if(pop3c->authmechs & SASL_AUTH_PLAIN) { mech = "PLAIN"; authstate = POP3_AUTH_PLAIN; pop3c->authused = SASL_AUTH_PLAIN; @@ -492,7 +499,75 @@ static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn, return result; } -/* For final responses in the AUTH sequence */ +/* For AUTH LOGIN responses */ +static CURLcode pop3_state_auth_login_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + size_t len = 0; + char *authuser = NULL; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + failf(data, "Access denied: %d", pop3code); + result = CURLE_LOGIN_DENIED; + } + else { + result = Curl_sasl_create_login_message(conn->data, conn->user, + &authuser, &len); + + if(!result) { + if(authuser) { + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authuser); + + if(!result) + state(conn, POP3_AUTH_LOGIN_PASSWD); + } + Curl_safefree(authuser); + } + } + + return result; +} + +/* For AUTH LOGIN user entry responses */ +static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + size_t len = 0; + char *authpasswd = NULL; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + failf(data, "Access denied: %d", pop3code); + result = CURLE_LOGIN_DENIED; + } + else { + result = Curl_sasl_create_login_message(conn->data, conn->passwd, + &authpasswd, &len); + + if(!result) { + if(authpasswd) { + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authpasswd); + + if(!result) + state(conn, POP3_AUTH_FINAL); + } + Curl_safefree(authpasswd); + } + } + + return result; +} + +/* For final responses to the AUTH sequence */ static CURLcode pop3_state_auth_final_resp(struct connectdata *conn, int pop3code, pop3state instate) @@ -688,6 +763,14 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) 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; + case POP3_AUTH_FINAL: result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state); break; -- cgit v1.2.1 From 69f7156ad96877b18b1867f9adc29454774d7cf7 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sat, 2 Jun 2012 11:55:58 +0100 Subject: pop3: Added support for sasl ntlm authentication --- lib/pop3.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 9660bb57a..b212e9536 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -284,6 +284,8 @@ static void state(struct connectdata *conn, pop3state newstate) "AUTH_PLAIN", "AUTH_LOGIN", "AUTH_LOGIN_PASSWD", + "AUTH_NTLM", + "AUTH_NTLM_TYPE2MSG", "AUTH_FINAL", "USER", "PASS", @@ -345,6 +347,14 @@ static CURLcode pop3_authenticate(struct connectdata *conn) /* Check supported authentication mechanisms by decreasing order of security */ +#ifdef USE_NTLM + if(pop3c->authmechs & SASL_AUTH_NTLM) { + mech = "NTLM"; + authstate = POP3_AUTH_NTLM; + pop3c->authused = SASL_AUTH_NTLM; + } + else +#endif if(pop3c->authmechs & SASL_AUTH_LOGIN) { mech = "LOGIN"; authstate = POP3_AUTH_LOGIN; @@ -567,6 +577,80 @@ static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn, return result; } +#ifdef USE_NTLM +/* For AUTH NTLM responses */ +static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + char *type1msg = NULL; + size_t len = 0; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + failf(data, "Access denied: %d", pop3code); + result = CURLE_LOGIN_DENIED; + } + else { + result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, + &conn->ntlm, &type1msg, &len); + + 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); + } + } + + return result; +} + +/* For the NTLM type-2 response (sent in reponse to our type-1 message) */ +static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + char *type3msg = NULL; + size_t len = 0; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + failf(data, "Access denied: %d", pop3code); + result = CURLE_LOGIN_DENIED; + } + else { + result = Curl_sasl_decode_ntlm_type2_message(data, + data->state.buffer + 2, + conn->user, conn->passwd, + &conn->ntlm, + &type3msg, &len); + 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; +} +#endif + /* For final responses to the AUTH sequence */ static CURLcode pop3_state_auth_final_resp(struct connectdata *conn, int pop3code, @@ -771,6 +855,14 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_auth_login_password_resp(conn, pop3code, pop3c->state); break; + 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; + case POP3_AUTH_FINAL: result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state); break; @@ -1069,7 +1161,7 @@ static CURLcode pop3_quit(struct connectdata *conn) */ static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection) { - struct pop3_conn *pop3c= &conn->proto.pop3c; + struct pop3_conn *pop3c = &conn->proto.pop3c; /* We cannot send quit unconditionally. If this connection is stale or bad in any way, sending quit and waiting around here will make the @@ -1083,6 +1175,9 @@ static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection) Curl_pp_disconnect(&pop3c->pp); + /* Cleanup the sasl module */ + Curl_sasl_cleanup(conn, pop3c->authused); + return CURLE_OK; } -- cgit v1.2.1 From 1fa2af5136e1167bfc18a128d16a89865ca5065a Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sat, 2 Jun 2012 21:38:55 +0100 Subject: pop3.c: Small code tidy up Corrected lines exceeding 78 characters. Repositioned some comments and added extra clarity. --- lib/pop3.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index b212e9536..579e77bb5 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -367,7 +367,7 @@ static CURLcode pop3_authenticate(struct connectdata *conn) } else { infof(conn->data, "No known SASL auth mechanisms supported!\n"); - result = CURLE_LOGIN_DENIED; /* Other mechanisms not supported */ + result = CURLE_LOGIN_DENIED; /* Other mechanisms not supported */ } if(!result) { @@ -666,7 +666,8 @@ static CURLcode pop3_state_auth_final_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } - state(conn, POP3_STOP); /* End of connect phase */ + /* End of connect phase */ + state(conn, POP3_STOP); return result; } @@ -713,7 +714,8 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } - state(conn, POP3_STOP); /* End of connect phase */ + /* End of connect phase */ + state(conn, POP3_STOP); return result; } @@ -768,6 +770,7 @@ static CURLcode pop3_state_command_resp(struct connectdata *conn, pp->cache_size = 0; } + /* End of do phase */ state(conn, POP3_STOP); return result; @@ -852,7 +855,8 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) break; case POP3_AUTH_LOGIN_PASSWD: - result = pop3_state_auth_login_password_resp(conn, pop3code, pop3c->state); + result = pop3_state_auth_login_password_resp(conn, pop3code, + pop3c->state); break; case POP3_AUTH_NTLM: @@ -860,7 +864,8 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) break; case POP3_AUTH_NTLM_TYPE2MSG: - result = pop3_state_auth_ntlm_type2msg_resp(conn, pop3code, pop3c->state); + result = pop3_state_auth_ntlm_type2msg_resp(conn, pop3code, + pop3c->state); break; case POP3_AUTH_FINAL: -- cgit v1.2.1 From 69ba0da8272d7bddeef518670d4c1298b0627ad7 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sat, 2 Jun 2012 22:11:37 +0100 Subject: pop3: Fixed the issue of having to supply the user name for all requests Previously it wasn't possible to connect to POP3 and not specify the user name as a CURLE_ACCESS_DENIED error would be returned. This error occurred because USER would be sent to the server with a blank user name if no mailbox user was specified as the server would reply with -ERR. This wasn't a problem prior to the 7.26.0 release but with the introduction of custom commands the user and/or application developer might want to issue a CAPA command without having to log in as a specific mailbox user. Additionally this fix won't send the newly introduced AUTH command if no user name is specified. --- lib/pop3.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 579e77bb5..64efb255f 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -305,12 +305,20 @@ static void state(struct connectdata *conn, pop3state newstate) static CURLcode pop3_state_auth(struct connectdata *conn) { - CURLcode result; + 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 */ + /* Check we have a username and password to authenticate with and end the + connect phase if we don't */ + if(!conn->bits.user_passwd) { + state(conn, SMTP_STOP); + + return result; + } + /* send AUTH */ result = Curl_pp_sendf(&pop3c->pp, "AUTH"); -- cgit v1.2.1 From 9c7016f5607ede09a9454fa62aaf5102b7ec0086 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sat, 2 Jun 2012 23:12:07 +0100 Subject: pop3.c:Corrected typo in commit 69ba0da8272d --- lib/pop3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 64efb255f..f0ee23967 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -314,7 +314,7 @@ static CURLcode pop3_state_auth(struct connectdata *conn) /* Check we have a username and password to authenticate with and end the connect phase if we don't */ if(!conn->bits.user_passwd) { - state(conn, SMTP_STOP); + state(conn, POP3_STOP); return result; } -- cgit v1.2.1 From b5bb61ee697b9a12e37c15b3bcbad33d808961d5 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sun, 3 Jun 2012 17:06:48 +0100 Subject: pop3: Fixed an issue with changes introduced in commit c267c53017bc Because pop3_endofresp() is called for each line of data yet is not passed the line and line length, so we have to use the data pointed to by pp->linestart_resp which contains the whole packet, the mechanisms were being detected in one call yet the function would be called for each line of data. Using curl with verbose mode enabled would show that one line of data would be received in response to the AUTH command, before the AUTH command was sent to the server and then the next few lines of the original AUTH command would be displayed before the response from the AUTH command. This would then cause problems when parsing the CRAM-MD5 challenge data as extra data was contained in the buffer. Changed the parsing so that each line is checked for the mechanisms and the function returns FALSE until the whole of the AUTH response has been processed. --- lib/pop3.c | 51 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 13 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index f0ee23967..81a51cf4a 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -216,38 +216,56 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { static int pop3_endofresp(struct pingpong *pp, int *resp) { char *line = pp->linestart_resp; - size_t len = pp->nread_resp; + size_t len = strlen(pp->linestart_resp); struct connectdata *conn = pp->conn; struct pop3_conn *pop3c = &conn->proto.pop3c; size_t wordlen; - if((len < 1 || memcmp("+", line, 1)) && - (len < 3 || memcmp("+OK", line, 3)) && - (len < 4 || memcmp("-ERR", line, 4))) - return FALSE; /* Nothing for us */ + /* Do we have an error response? */ + if(len >= 4 && !memcmp("-ERR", line, 4)) { + *resp = '-'; - *resp = line[0]; /* + or - */ + return FALSE; + } - if(pop3c->state == POP3_AUTH && len >= 3 && !memcmp(line, "+OK", 3)) { - line += 3; - len -= 3; + /* Are we processing reponses to our AUTH command */ + if(pop3c->state == POP3_AUTH) { + /* Advance past our positive response if necessary */ + if(len >= 3 && !memcmp(line, "+OK", 3)) { + line += 3; + len -= 3; + } + + /* Loop through the data line */ for(;;) { while(len && (*line == ' ' || *line == '\t' || *line == '\r' || *line == '\n')) { + if(*line == '\n') + return FALSE; + line++; len--; } - if(!len || *line == '.') + if(!len) break; + /* Until we receive the terminating character */ + if(*line == '.') { + *resp = '+'; + + return TRUE; + } + + /* Extract the word */ for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && line[wordlen] != '\t' && line[wordlen] != '\r' && line[wordlen] != '\n';) wordlen++; + /* Test the word for a matching authentication mechanism */ if(wordlen == 5 && !memcmp(line, "LOGIN", 5)) pop3c->authmechs |= SASL_AUTH_LOGIN; else if(wordlen == 5 && !memcmp(line, "PLAIN", 5)) @@ -268,6 +286,13 @@ static int pop3_endofresp(struct pingpong *pp, int *resp) } } + if((len < 1 || memcmp("+", line, 1)) && + (len < 3 || memcmp("+OK", line, 3))) + return FALSE; /* Nothing for us */ + + /* Otherwise it's a positive response */ + *resp = '+'; + return TRUE; } @@ -500,7 +525,7 @@ static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else { - result = Curl_sasl_create_plain_message(conn->data, conn->user, + result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, &plainauth, &len); if(!result) { @@ -534,7 +559,7 @@ static CURLcode pop3_state_auth_login_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else { - result = Curl_sasl_create_login_message(conn->data, conn->user, + result = Curl_sasl_create_login_message(data, conn->user, &authuser, &len); if(!result) { @@ -568,7 +593,7 @@ static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else { - result = Curl_sasl_create_login_message(conn->data, conn->passwd, + result = Curl_sasl_create_login_message(data, conn->passwd, &authpasswd, &len); if(!result) { -- cgit v1.2.1 From 3b8cf5bd142b289effcbc1bb12a01e0ae2fe2af2 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sun, 3 Jun 2012 17:40:05 +0100 Subject: pop3.c: Added conditional compilation for NTLM function calls Added USE_NTLM condition compilation around the NTLM functions called from pop3_statemach_act() introduced in commit 69f7156ad96877. --- lib/pop3.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 81a51cf4a..6d7b9ab45 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -892,6 +892,7 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) pop3c->state); break; +#ifdef USE_NTLM case POP3_AUTH_NTLM: result = pop3_state_auth_ntlm_resp(conn, pop3code, pop3c->state); break; @@ -900,6 +901,7 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_auth_ntlm_type2msg_resp(conn, pop3code, pop3c->state); break; +#endif case POP3_AUTH_FINAL: result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state); -- cgit v1.2.1 From 8c0bfd3e0c2b36a081169612cba0ac5431d6c122 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sun, 3 Jun 2012 19:13:16 +0100 Subject: pop3: Added support for sasl cram-md5 authentication --- lib/pop3.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 2 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 6d7b9ab45..7d22e8251 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -20,6 +20,7 @@ * * RFC1734 POP3 Authentication * RFC1939 POP3 protocol + * RFC2195 CRAM-MD5 authentication * RFC2384 POP URL Scheme * RFC2595 Using TLS with IMAP, POP3 and ACAP * RFC4616 PLAIN authentication @@ -309,6 +310,7 @@ static void state(struct connectdata *conn, pop3state newstate) "AUTH_PLAIN", "AUTH_LOGIN", "AUTH_LOGIN_PASSWD", + "AUTH_CRAMMD5", "AUTH_NTLM", "AUTH_NTLM_TYPE2MSG", "AUTH_FINAL", @@ -380,6 +382,14 @@ static CURLcode pop3_authenticate(struct connectdata *conn) /* Check supported authentication mechanisms by decreasing order of security */ +#ifndef CURL_DISABLE_CRYPTO_AUTH + if(pop3c->authmechs & SASL_AUTH_CRAM_MD5) { + mech = "CRAM-MD5"; + authstate = POP3_AUTH_CRAMMD5; + pop3c->authused = SASL_AUTH_CRAM_MD5; + } + else +#endif #ifdef USE_NTLM if(pop3c->authmechs & SASL_AUTH_NTLM) { mech = "NTLM"; @@ -610,6 +620,58 @@ static CURLcode pop3_state_auth_login_password_resp(struct connectdata *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) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + char *chlg64 = data->state.buffer; + size_t len = 0; + char *rplyb64 = NULL; + + (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'; + } + } + + result = Curl_sasl_create_cram_md5_message(data, chlg64, conn->user, + conn->passwd, &rplyb64, &len); + + if(!result) { + if(rplyb64) { + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64); + + if(!result) + state(conn, POP3_AUTH_FINAL); + } + Curl_safefree(rplyb64); + } + + return result; +} +#endif + #ifdef USE_NTLM /* For AUTH NTLM responses */ static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn, @@ -618,8 +680,8 @@ static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn, { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - char *type1msg = NULL; size_t len = 0; + char *type1msg = NULL; (void)instate; /* no use for this yet */ @@ -653,8 +715,8 @@ static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn, { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - char *type3msg = NULL; size_t len = 0; + char *type3msg = NULL; (void)instate; /* no use for this yet */ @@ -892,6 +954,12 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) pop3c->state); break; +#ifndef CURL_DISABLE_CRYPTO_AUTH + case POP3_AUTH_CRAMMD5: + result = pop3_state_auth_cram_resp(conn, pop3code, pop3c->state); + break; +#endif + #ifdef USE_NTLM case POP3_AUTH_NTLM: result = pop3_state_auth_ntlm_resp(conn, pop3code, pop3c->state); -- cgit v1.2.1 From e336bc7c42c73409671ce69ff43830cf077eb234 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Mon, 4 Jun 2012 19:09:45 +0100 Subject: pop3: Changed the sasl mechanism detection from auth to capa Not all SASL enabled POP3 servers support the AUTH command on its own when trying to detect the supported mechanisms. As such changed the mechanism detection to use the CAPA command instead. --- lib/pop3.c | 56 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 26 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 7d22e8251..9ed240fed 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -213,7 +213,7 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { /* Function that checks for an ending pop3 status code at the start of the given string, but also detects the allowed authentication mechanisms - according to the AUTH response. */ + according to the CAPA response. */ static int pop3_endofresp(struct pingpong *pp, int *resp) { char *line = pp->linestart_resp; @@ -229,20 +229,31 @@ static int pop3_endofresp(struct pingpong *pp, int *resp) return FALSE; } - /* Are we processing reponses to our AUTH command */ - if(pop3c->state == POP3_AUTH) { + /* Are we processing reponses to our CAPA command? */ + if(pop3c->state == POP3_CAPA) { - /* Advance past our positive response if necessary */ - if(len >= 3 && !memcmp(line, "+OK", 3)) { - line += 3; - len -= 3; + /* Do we have the terminating character? */ + if(len >= 1 && !memcmp(line, ".", 1)) { + *resp = '+'; + + return TRUE; + } + + /* We are only interested in the SASL line */ + if(len < 4 || memcmp(line, "SASL", 3)) { + return FALSE; } + /* Advance past the SASL keyword */ + line += 4; + len -= 4; + /* Loop through the data line */ for(;;) { while(len && (*line == ' ' || *line == '\t' || *line == '\r' || *line == '\n')) { + if(*line == '\n') return FALSE; @@ -253,13 +264,6 @@ static int pop3_endofresp(struct pingpong *pp, int *resp) if(!len) break; - /* Until we receive the terminating character */ - if(*line == '.') { - *resp = '+'; - - return TRUE; - } - /* Extract the word */ for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && line[wordlen] != '\t' && line[wordlen] != '\r' && @@ -306,7 +310,7 @@ static void state(struct connectdata *conn, pop3state newstate) "STOP", "SERVERGREET", "STARTTLS", - "AUTH", + "CAPA", "AUTH_PLAIN", "AUTH_LOGIN", "AUTH_LOGIN_PASSWD", @@ -330,7 +334,7 @@ static void state(struct connectdata *conn, pop3state newstate) pop3c->state = newstate; } -static CURLcode pop3_state_auth(struct connectdata *conn) +static CURLcode pop3_state_capa(struct connectdata *conn) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; @@ -346,13 +350,13 @@ static CURLcode pop3_state_auth(struct connectdata *conn) return result; } - /* send AUTH */ - result = Curl_pp_sendf(&pop3c->pp, "AUTH"); + /* send CAPA */ + result = Curl_pp_sendf(&pop3c->pp, "CAPA"); if(result) return result; - state(conn, POP3_AUTH); + state(conn, POP3_CAPA); return CURLE_OK; } @@ -462,7 +466,7 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, state(conn, POP3_STARTTLS); } else - result = pop3_state_auth(conn); + result = pop3_state_capa(conn); return result; } @@ -484,14 +488,14 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, state(conn, POP3_STOP); } else - result = pop3_state_auth(conn); + result = pop3_state_capa(conn); } else { /* Curl_ssl_connect is BLOCKING */ result = Curl_ssl_connect(conn, FIRSTSOCKET); if(CURLE_OK == result) { pop3_to_pop3s(conn); - result = pop3_state_auth(conn); + result = pop3_state_capa(conn); } else { state(conn, POP3_STOP); @@ -501,8 +505,8 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, return result; } -/* For AUTH responses */ -static CURLcode pop3_state_auth_resp(struct connectdata *conn, +/* For CAPA responses */ +static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code, pop3state instate) { @@ -937,8 +941,8 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_starttls_resp(conn, pop3code, pop3c->state); break; - case POP3_AUTH: - result = pop3_state_auth_resp(conn, pop3code, pop3c->state); + case POP3_CAPA: + result = pop3_state_capa_resp(conn, pop3code, pop3c->state); break; case POP3_AUTH_PLAIN: -- cgit v1.2.1 From 7759d10f3653d03f2816b6628164917f3c4914cf Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Mon, 4 Jun 2012 21:50:16 +0100 Subject: pop3: Added support for sasl digest-md5 authentication --- lib/pop3.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 9ed240fed..922c5908d 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -23,6 +23,7 @@ * RFC2195 CRAM-MD5 authentication * RFC2384 POP URL Scheme * RFC2595 Using TLS with IMAP, POP3 and ACAP + * RFC2831 DIGEST-MD5 authentication * RFC4616 PLAIN authentication * ***************************************************************************/ @@ -315,6 +316,8 @@ static void state(struct connectdata *conn, pop3state newstate) "AUTH_LOGIN", "AUTH_LOGIN_PASSWD", "AUTH_CRAMMD5", + "AUTH_DIGESTMD5", + "AUTH_DIGESTMD5_RESP", "AUTH_NTLM", "AUTH_NTLM_TYPE2MSG", "AUTH_FINAL", @@ -387,7 +390,12 @@ static CURLcode pop3_authenticate(struct connectdata *conn) /* Check supported authentication mechanisms by decreasing order of security */ #ifndef CURL_DISABLE_CRYPTO_AUTH - if(pop3c->authmechs & SASL_AUTH_CRAM_MD5) { + if(pop3c->authmechs & SASL_AUTH_DIGEST_MD5) { + mech = "DIGEST-MD5"; + authstate = POP3_AUTH_DIGESTMD5; + pop3c->authused = SASL_AUTH_DIGEST_MD5; + } + else if(pop3c->authmechs & SASL_AUTH_CRAM_MD5) { mech = "CRAM-MD5"; authstate = POP3_AUTH_CRAMMD5; pop3c->authused = SASL_AUTH_CRAM_MD5; @@ -674,6 +682,70 @@ static CURLcode pop3_state_auth_cram_resp(struct connectdata *conn, return result; } + +/* For AUTH DIGEST-MD5 challenge responses */ +static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + char *chlg64 = data->state.buffer; + size_t len = 0; + char *rplyb64 = NULL; + + (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++) + ; + + result = Curl_sasl_create_digest_md5_message(data, chlg64, conn->user, + conn->passwd, "pop", + &rplyb64, &len); + + if(!result) { + if(rplyb64) { + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64); + + if(!result) + state(conn, POP3_AUTH_DIGESTMD5_RESP); + } + + Curl_safefree(rplyb64); + } + + return result; +} + +/* For AUTH DIGEST-MD5 challenge-response responses */ +static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + failf(data, "Authentication failed: %d", pop3code); + result = CURLE_LOGIN_DENIED; + } + else { + result = Curl_pp_sendf(&conn->proto.pop3c.pp, ""); + + if(!result) + state(conn, POP3_AUTH_FINAL); + } + + return result; +} #endif #ifdef USE_NTLM @@ -962,6 +1034,14 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) 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 -- cgit v1.2.1 From 38dfe525596f3dcb81c31fae0b7605751c6c3769 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Mon, 4 Jun 2012 22:15:51 +0100 Subject: pop3: Post authentication code tidy up Corrected lines longer than 78 characters. Changed POP3_AUTH_FINAL to POP3_AUTH to match SMTP code now that the AUTH command is no longer sent on its own. Introduced some comments in data sending functions. Another attempt at trying to rational code and comment style. --- lib/pop3.c | 79 ++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 31 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 922c5908d..2f772ba60 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -307,7 +307,7 @@ static void state(struct connectdata *conn, pop3state newstate) { #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ - static const char * const names[]={ + static const char * const names[] = { "STOP", "SERVERGREET", "STARTTLS", @@ -320,7 +320,7 @@ static void state(struct connectdata *conn, pop3state newstate) "AUTH_DIGESTMD5_RESP", "AUTH_NTLM", "AUTH_NTLM_TYPE2MSG", - "AUTH_FINAL", + "AUTH", "USER", "PASS", "COMMAND", @@ -353,7 +353,7 @@ static CURLcode pop3_state_capa(struct connectdata *conn) return result; } - /* send CAPA */ + /* Send the CAPA command */ result = Curl_pp_sendf(&pop3c->pp, "CAPA"); if(result) @@ -369,7 +369,7 @@ static CURLcode pop3_state_user(struct connectdata *conn) CURLcode result; struct FTP *pop3 = conn->data->state.proto.pop3; - /* send USER */ + /* Send the USER command */ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s", pop3->user ? pop3->user : ""); if(result) @@ -547,15 +547,17 @@ static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else { - result = Curl_sasl_create_plain_message(data, conn->user, - conn->passwd, &plainauth, &len); + /* 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); + state(conn, POP3_AUTH); } Curl_safefree(plainauth); } @@ -581,9 +583,11 @@ static CURLcode pop3_state_auth_login_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else { + /* Create the login message */ result = Curl_sasl_create_login_message(data, conn->user, &authuser, &len); + /* Send the login */ if(!result) { if(authuser) { result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authuser); @@ -615,15 +619,17 @@ static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn, 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); + state(conn, POP3_AUTH); } Curl_safefree(authpasswd); } @@ -667,15 +673,17 @@ static CURLcode pop3_state_auth_cram_resp(struct connectdata *conn, } } + /* 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); if(!result) - state(conn, POP3_AUTH_FINAL); + state(conn, POP3_AUTH); } Curl_safefree(rplyb64); } @@ -705,10 +713,12 @@ static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn, for(chlg64 += 2; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++) ; + /* Create the response message */ result = Curl_sasl_create_digest_md5_message(data, chlg64, conn->user, conn->passwd, "pop", &rplyb64, &len); + /* Send the response */ if(!result) { if(rplyb64) { result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64); @@ -738,10 +748,11 @@ static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else { + /* Send an empty response */ result = Curl_pp_sendf(&conn->proto.pop3c.pp, ""); if(!result) - state(conn, POP3_AUTH_FINAL); + state(conn, POP3_AUTH); } return result; @@ -767,7 +778,8 @@ static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn, } else { result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, &type1msg, &len); + &conn->ntlm, + &type1msg, &len); if(!result) { if(type1msg) { @@ -801,17 +813,19 @@ static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else { + /* Create the type-3 message */ result = Curl_sasl_decode_ntlm_type2_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); + state(conn, POP3_AUTH); } Curl_safefree(type3msg); @@ -859,7 +873,7 @@ static CURLcode pop3_state_user_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else - /* send PASS */ + /* Send the PASS command */ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s", pop3->passwd ? pop3->passwd : ""); if(result) @@ -994,16 +1008,17 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) struct pingpong *pp = &pop3c->pp; size_t nread = 0; + /* Flush any data that needs to be sent */ if(pp->sendleft) return Curl_pp_flushsend(pp); - /* we read a piece of response */ + /* Read the response from the server */ result = Curl_pp_readresp(sock, pp, &pop3code, &nread); if(result) return result; if(pop3code) { - /* we have now received a full POP3 server response */ + /* We have now received a full POP3 server response */ switch(pop3c->state) { case POP3_SERVERGREET: result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state); @@ -1055,7 +1070,7 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) break; #endif - case POP3_AUTH_FINAL: + case POP3_AUTH: result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state); break; @@ -1122,7 +1137,7 @@ static CURLcode pop3_init(struct connectdata *conn) return CURLE_OUT_OF_MEMORY; } - /* get some initial data into the pop3 struct */ + /* Get some initial data into the pop3 struct */ pop3->bytecountp = &data->req.bytecount; /* No need to duplicate user+password, the connectdata struct won't change @@ -1247,25 +1262,25 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, static CURLcode pop3_perform(struct connectdata *conn, bool *connected, bool *dophase_done) { - /* this is POP3 and no proxy */ + /* This is POP3 and no proxy */ CURLcode result = CURLE_OK; DEBUGF(infof(conn->data, "DO phase starts\n")); if(conn->data->set.opt_no_body) { - /* requested no body means no transfer... */ + /* Requested no body means no transfer */ struct FTP *pop3 = conn->data->state.proto.pop3; pop3->transfer = FTPTRANSFER_INFO; } *dophase_done = FALSE; /* not done yet */ - /* start the first command in the DO phase */ + /* Start the first command in the DO phase */ result = pop3_command(conn); if(result) return result; - /* run the state-machine */ + /* Run the state-machine */ if(conn->data->state.used_interface == Curl_if_multi) result = pop3_multi_statemach(conn, dophase_done); else { @@ -1351,14 +1366,14 @@ static CURLcode pop3_quit(struct connectdata *conn) * 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; /* We cannot send quit unconditionally. If this connection is stale or bad in any way, sending quit and waiting around here will make the - disconnect wait in vain and cause more problems than we need to. - */ + disconnect wait in vain and cause more problems than we need to */ /* The POP3 session may or may not have been allocated/setup at this point! */ @@ -1367,7 +1382,7 @@ static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection) Curl_pp_disconnect(&pop3c->pp); - /* Cleanup the sasl module */ + /* Cleanup the SASL module */ Curl_sasl_cleanup(conn, pop3c->authused); return CURLE_OK; @@ -1381,7 +1396,7 @@ static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection) */ static CURLcode pop3_parse_url_path(struct connectdata *conn) { - /* the pop3 struct is already inited in pop3_connect() */ + /* The POP3 struct is already initialised in pop3_connect() */ struct pop3_conn *pop3c = &conn->proto.pop3c; struct SessionHandle *data = conn->data; const char *path = data->state.path; @@ -1404,7 +1419,7 @@ static CURLcode pop3_parse_custom_request(struct connectdata *conn) return result; } -/* call this when the DO phase has completed */ +/* Call this when the DO phase has completed */ static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected) { struct FTP *pop3 = conn->data->state.proto.pop3; @@ -1418,7 +1433,7 @@ static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected) return CURLE_OK; } -/* called from multi.c while DOing */ +/* Called from multi.c while DOing */ static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done) { CURLcode result; @@ -1448,7 +1463,9 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn, CURLcode result = CURLE_OK; bool connected = FALSE; struct SessionHandle *data = conn->data; - data->req.size = -1; /* make sure this is unknown at this point */ + + /* Make sure size is unknown at this point */ + data->req.size = -1; Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); @@ -1460,7 +1477,7 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn, if(CURLE_OK == result) { if(!*dophase_done) - /* the DO phase has not completed yet */ + /* The DO phase has not completed yet */ return CURLE_OK; result = pop3_dophase_done(conn, connected); @@ -1492,7 +1509,7 @@ static CURLcode pop3_setup_connection(struct connectdata * conn) /* We explicitly mark this connection as persistent here as we're doing POP3 over HTTP and thus we accidentally avoid setting this value - otherwise. */ + otherwise */ conn->bits.close = FALSE; #else failf(data, "POP3 over http proxy requires HTTP support built-in!"); -- cgit v1.2.1 From 64510fe917be0508bb4fa381af966ece7dfd4775 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Mon, 4 Jun 2012 22:25:45 +0100 Subject: sasl: Renamed Curl_sasl_decode_ntlm_type2_message() For consistency with other SASL based functions renamed this function to Curl_sasl_create_ntlm_type3_message() which better describes its usage. --- lib/pop3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 2f772ba60..4e6fbd365 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -814,7 +814,7 @@ static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn, } else { /* Create the type-3 message */ - result = Curl_sasl_decode_ntlm_type2_message(data, + result = Curl_sasl_create_ntlm_type3_message(data, data->state.buffer + 2, conn->user, conn->passwd, &conn->ntlm, -- cgit v1.2.1 From 57e63367942cf34c20a7ccec61d6e5c4416b2349 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Tue, 5 Jun 2012 11:18:07 +0100 Subject: email: Removed duplicated header file --- lib/pop3.c | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 4e6fbd365..2f67f8f9e 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -82,7 +82,6 @@ #include "multiif.h" #include "url.h" #include "rawstr.h" -#include "strtoofft.h" #include "curl_sasl.h" #define _MPRINTF_REPLACE /* use our functions only */ -- cgit v1.2.1 From 0f3c330ad8c78b1cdcbe9562c2091841aa569d41 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Tue, 5 Jun 2012 13:49:50 +0100 Subject: pop3: Another small code tidy up Missed some comments that we identified during the SMTP tidy up earlier. --- lib/pop3.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 2f67f8f9e..a9463241e 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -505,6 +505,7 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, result = pop3_state_capa(conn); } else { + /* End of connect phase */ state(conn, POP3_STOP); } } @@ -582,11 +583,11 @@ static CURLcode pop3_state_auth_login_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else { - /* Create the login message */ + /* Create the user message */ result = Curl_sasl_create_login_message(data, conn->user, &authuser, &len); - /* Send the login */ + /* Send the user */ if(!result) { if(authuser) { result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authuser); @@ -776,10 +777,12 @@ static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn, 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); @@ -795,7 +798,7 @@ static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn, return result; } -/* For the NTLM type-2 response (sent in reponse to our type-1 message) */ +/* 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) @@ -818,6 +821,7 @@ static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn, conn->user, conn->passwd, &conn->ntlm, &type3msg, &len); + /* Send the message */ if(!result) { if(type3msg) { @@ -904,7 +908,7 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, return result; } -/* For the command response */ +/* For command responses */ static CURLcode pop3_state_command_resp(struct connectdata *conn, int pop3code, pop3state instate) -- cgit v1.2.1 From 0cd8c287a46420768a5b11406638316f859a4873 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Fri, 8 Jun 2012 19:52:28 +0100 Subject: sasl: Re-factored mechanism constants in preparation for APOP work --- lib/pop3.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index a9463241e..02d6e7aeb 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -272,19 +272,19 @@ static int pop3_endofresp(struct pingpong *pp, int *resp) /* Test the word for a matching authentication mechanism */ if(wordlen == 5 && !memcmp(line, "LOGIN", 5)) - pop3c->authmechs |= SASL_AUTH_LOGIN; + pop3c->authmechs |= SASL_MECH_LOGIN; else if(wordlen == 5 && !memcmp(line, "PLAIN", 5)) - pop3c->authmechs |= SASL_AUTH_PLAIN; + pop3c->authmechs |= SASL_MECH_PLAIN; else if(wordlen == 8 && !memcmp(line, "CRAM-MD5", 8)) - pop3c->authmechs |= SASL_AUTH_CRAM_MD5; + pop3c->authmechs |= SASL_MECH_CRAM_MD5; else if(wordlen == 10 && !memcmp(line, "DIGEST-MD5", 10)) - pop3c->authmechs |= SASL_AUTH_DIGEST_MD5; + pop3c->authmechs |= SASL_MECH_DIGEST_MD5; else if(wordlen == 6 && !memcmp(line, "GSSAPI", 6)) - pop3c->authmechs |= SASL_AUTH_GSSAPI; + pop3c->authmechs |= SASL_MECH_GSSAPI; else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8)) - pop3c->authmechs |= SASL_AUTH_EXTERNAL; + pop3c->authmechs |= SASL_MECH_EXTERNAL; else if(wordlen == 4 && !memcmp(line, "NTLM", 4)) - pop3c->authmechs |= SASL_AUTH_NTLM; + pop3c->authmechs |= SASL_MECH_NTLM; line += wordlen; len -= wordlen; @@ -389,38 +389,38 @@ static CURLcode pop3_authenticate(struct connectdata *conn) /* Check supported authentication mechanisms by decreasing order of security */ #ifndef CURL_DISABLE_CRYPTO_AUTH - if(pop3c->authmechs & SASL_AUTH_DIGEST_MD5) { + if(pop3c->authmechs & SASL_MECH_DIGEST_MD5) { mech = "DIGEST-MD5"; authstate = POP3_AUTH_DIGESTMD5; - pop3c->authused = SASL_AUTH_DIGEST_MD5; + pop3c->authused = SASL_MECH_DIGEST_MD5; } - else if(pop3c->authmechs & SASL_AUTH_CRAM_MD5) { + else if(pop3c->authmechs & SASL_MECH_CRAM_MD5) { mech = "CRAM-MD5"; authstate = POP3_AUTH_CRAMMD5; - pop3c->authused = SASL_AUTH_CRAM_MD5; + pop3c->authused = SASL_MECH_CRAM_MD5; } else #endif #ifdef USE_NTLM - if(pop3c->authmechs & SASL_AUTH_NTLM) { + if(pop3c->authmechs & SASL_MECH_NTLM) { mech = "NTLM"; authstate = POP3_AUTH_NTLM; - pop3c->authused = SASL_AUTH_NTLM; + pop3c->authused = SASL_MECH_NTLM; } else #endif - if(pop3c->authmechs & SASL_AUTH_LOGIN) { + if(pop3c->authmechs & SASL_MECH_LOGIN) { mech = "LOGIN"; authstate = POP3_AUTH_LOGIN; - pop3c->authused = SASL_AUTH_LOGIN; + pop3c->authused = SASL_MECH_LOGIN; } - else if(pop3c->authmechs & SASL_AUTH_PLAIN) { + else if(pop3c->authmechs & SASL_MECH_PLAIN) { mech = "PLAIN"; authstate = POP3_AUTH_PLAIN; - pop3c->authused = SASL_AUTH_PLAIN; + pop3c->authused = SASL_MECH_PLAIN; } else { - infof(conn->data, "No known SASL auth mechanisms supported!\n"); + infof(conn->data, "No known SASL authentication mechanisms supported!\n"); result = CURLE_LOGIN_DENIED; /* Other mechanisms not supported */ } -- cgit v1.2.1 From 6478e1d7e5cf9a03a24f1d34eb92d4a4aad01f24 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sat, 9 Jun 2012 11:08:08 +0100 Subject: pop3.c: Fixed length of SASL check --- lib/pop3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 02d6e7aeb..a166208db 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -240,7 +240,7 @@ static int pop3_endofresp(struct pingpong *pp, int *resp) } /* We are only interested in the SASL line */ - if(len < 4 || memcmp(line, "SASL", 3)) { + if(len < 4 || memcmp(line, "SASL", 4)) { return FALSE; } -- cgit v1.2.1 From 4e430a8a16460f340c776dbd6f305cdf1e9dacc8 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sat, 9 Jun 2012 11:48:44 +0100 Subject: pop3: Enhanced the extended authentication mechanism detection Enhanced the authentication type / mechanism detection in preparation for the introduction of APOP support. --- lib/pop3.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index a166208db..1e399a03b 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -22,6 +22,7 @@ * RFC1939 POP3 protocol * RFC2195 CRAM-MD5 authentication * RFC2384 POP URL Scheme + * RFC2449 POP3 Extension Mechanism * RFC2595 Using TLS with IMAP, POP3 and ACAP * RFC2831 DIGEST-MD5 authentication * RFC4616 PLAIN authentication @@ -212,8 +213,8 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { #endif /* Function that checks for an ending pop3 status code at the start of the - given string, but also detects the allowed authentication mechanisms - according to the CAPA response. */ + given string, but also detects the supported authentication types as well + as the allowed SASL authentication mechanisms within the CAPA response. */ static int pop3_endofresp(struct pingpong *pp, int *resp) { char *line = pp->linestart_resp; @@ -239,11 +240,24 @@ static int pop3_endofresp(struct pingpong *pp, int *resp) return TRUE; } - /* We are only interested in the SASL line */ - if(len < 4 || memcmp(line, "SASL", 4)) { + /* Does the server support clear text? */ + if(len >= 4 && !memcmp(line, "USER", 4)) { + pop3c->authtypes |= POP3_TYPE_CLEARTEXT; return FALSE; } + /* Does the server support APOP? */ + if(len >= 4 && !memcmp(line, "APOP", 4)) { + pop3c->authtypes |= POP3_TYPE_APOP; + return FALSE; + } + + /* Does the server support SASL? */ + if(len < 4 || memcmp(line, "SASL", 4)) + return FALSE; + + pop3c->authtypes |= POP3_TYPE_SASL; + /* Advance past the SASL keyword */ line += 4; len -= 4; @@ -524,8 +538,17 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, if(pop3code != '+') result = pop3_state_user(conn); - else - result = pop3_authenticate(conn); + else { + /* Check supported authentication types by decreasing order of security */ + if(conn->proto.pop3c.authtypes & POP3_TYPE_SASL) + result = pop3_authenticate(conn); + else if(conn->proto.pop3c.authtypes & POP3_TYPE_CLEARTEXT) + result = pop3_state_user(conn); + else { + infof(conn->data, "No known authentication types supported!\n"); + result = CURLE_LOGIN_DENIED; /* Other types not supported */ + } + } return result; } -- cgit v1.2.1 From c09c621af7ad0bb81a5ab96ed0e0ce4e99ae3119 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sat, 9 Jun 2012 13:49:37 +0100 Subject: pop3: Added support for apop authentication --- lib/pop3.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 4 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 1e399a03b..8ce7f259b 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -84,6 +84,8 @@ #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 @@ -213,8 +215,9 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { #endif /* Function that checks for an ending pop3 status code at the start of the - given string, but also detects the supported authentication types as well - as the allowed SASL authentication mechanisms within the CAPA response. */ + given string, but also detects the APOP timestamp from the server greeting + as well as the supported authentication types and allowed SASL mechanisms + from the CAPA response. */ static int pop3_endofresp(struct pingpong *pp, int *resp) { char *line = pp->linestart_resp; @@ -222,6 +225,7 @@ static int pop3_endofresp(struct pingpong *pp, int *resp) struct connectdata *conn = pp->conn; 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)) { @@ -230,8 +234,31 @@ static int pop3_endofresp(struct pingpong *pp, int *resp) return FALSE; } - /* Are we processing reponses to our CAPA command? */ - if(pop3c->state == POP3_CAPA) { + /* 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) { /* Do we have the terminating character? */ if(len >= 1 && !memcmp(line, ".", 1)) { @@ -334,6 +361,7 @@ static void state(struct connectdata *conn, pop3state newstate) "AUTH_NTLM", "AUTH_NTLM_TYPE2MSG", "AUTH", + "APOP", "USER", "PASS", "COMMAND", @@ -393,6 +421,40 @@ static CURLcode pop3_state_user(struct connectdata *conn) return CURLE_OK; } +static CURLcode pop3_state_apop(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + size_t i; + MD5_context *ctxt; + unsigned char digest[MD5_DIGEST_LEN]; + char secret[2 * MD5_DIGEST_LEN + 1]; + + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp, + curlx_uztoui(strlen(pop3c->apoptimestamp))); + + Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd, + curlx_uztoui(strlen(conn->passwd))); + + /* Finalise the digest */ + Curl_MD5_final(ctxt, digest); + + /* Convert the calculated 16 octet digest into a 32 byte hex string */ + for(i = 0; i < MD5_DIGEST_LEN; i++) + snprintf(&secret[2 * i], 3, "%02x", digest[i]); + + result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret); + + if(!result) + state(conn, POP3_APOP); + + return result; +} + static CURLcode pop3_authenticate(struct connectdata *conn) { CURLcode result = CURLE_OK; @@ -542,6 +604,8 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, /* Check supported authentication types by decreasing order of security */ if(conn->proto.pop3c.authtypes & POP3_TYPE_SASL) result = pop3_authenticate(conn); + else if(conn->proto.pop3c.authtypes & POP3_TYPE_APOP) + result = pop3_state_apop(conn); else if(conn->proto.pop3c.authtypes & POP3_TYPE_CLEARTEXT) result = pop3_state_user(conn); else { @@ -883,6 +947,26 @@ static CURLcode pop3_state_auth_final_resp(struct connectdata *conn, return result; } +static CURLcode pop3_state_apop_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; + } + + /* End of connect phase */ + state(conn, POP3_STOP); + + return result; +} + /* For USER responses */ static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code, @@ -1100,6 +1184,10 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state); break; + case POP3_APOP: + result = pop3_state_apop_resp(conn, pop3code, pop3c->state); + break; + case POP3_USER: result = pop3_state_user_resp(conn, pop3code, pop3c->state); break; @@ -1408,6 +1496,9 @@ static CURLcode pop3_disconnect(struct connectdata *conn, Curl_pp_disconnect(&pop3c->pp); + /* Clear our variables */ + Curl_safefree(pop3c->apoptimestamp); + /* Cleanup the SASL module */ Curl_sasl_cleanup(conn, pop3c->authused); -- cgit v1.2.1 From a3660127a4497b2e30988c5f6aad3d17343ed6e0 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sat, 9 Jun 2012 19:21:44 +0100 Subject: pop3: Post apop feature code tidy up --- lib/pop3.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 8ce7f259b..844c463f1 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -1356,7 +1356,7 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, result = status; /* use the already set error code */ } - /* Clear our variables for the next connection */ + /* Cleanup our do based variables */ Curl_safefree(pop3c->mailbox); Curl_safefree(pop3c->custom); @@ -1494,14 +1494,15 @@ static CURLcode pop3_disconnect(struct connectdata *conn, if(!dead_connection && pop3c->pp.conn) (void)pop3_quit(conn); /* ignore errors on the LOGOUT */ + /* Disconnect from the server */ Curl_pp_disconnect(&pop3c->pp); - /* Clear our variables */ - Curl_safefree(pop3c->apoptimestamp); - /* Cleanup the SASL module */ Curl_sasl_cleanup(conn, pop3c->authused); + /* Cleanup our connection based variables */ + Curl_safefree(pop3c->apoptimestamp); + return CURLE_OK; } -- cgit v1.2.1 From 8b15c84ea91e0d4212657585c2ea397820dc8955 Mon Sep 17 00:00:00 2001 From: Stanislav Ivochkin Date: Wed, 5 Dec 2012 22:31:40 +0400 Subject: build: fix compilation with CURL_DISABLE_CRYPTO_AUTH flag --- lib/pop3.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/pop3.c') diff --git a/lib/pop3.c b/lib/pop3.c index 844c463f1..c00fb6261 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -421,6 +421,7 @@ static CURLcode pop3_state_user(struct connectdata *conn) return CURLE_OK; } +#ifndef CURL_DISABLE_CRYPTO_AUTH static CURLcode pop3_state_apop(struct connectdata *conn) { CURLcode result = CURLE_OK; @@ -454,6 +455,7 @@ static CURLcode pop3_state_apop(struct connectdata *conn) return result; } +#endif static CURLcode pop3_authenticate(struct connectdata *conn) { @@ -604,8 +606,10 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, /* Check supported authentication types by decreasing order of security */ if(conn->proto.pop3c.authtypes & POP3_TYPE_SASL) result = pop3_authenticate(conn); +#ifndef CURL_DISABLE_CRYPTO_AUTH else if(conn->proto.pop3c.authtypes & POP3_TYPE_APOP) result = pop3_state_apop(conn); +#endif else if(conn->proto.pop3c.authtypes & POP3_TYPE_CLEARTEXT) result = pop3_state_user(conn); else { -- cgit v1.2.1