1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * RFC1734 POP3 Authentication
22 * RFC1939 POP3 protocol
23 * RFC2195 CRAM-MD5 authentication
24 * RFC2384 POP URL Scheme
25 * RFC2449 POP3 Extension Mechanism
26 * RFC2595 Using TLS with IMAP, POP3 and ACAP
27 * RFC2831 DIGEST-MD5 authentication
28 * RFC4616 PLAIN authentication
30 ***************************************************************************/
32 #include "curl_setup.h"
34 #ifndef CURL_DISABLE_POP3
36 #ifdef HAVE_NETINET_IN_H
37 #include <netinet/in.h>
39 #ifdef HAVE_ARPA_INET_H
40 #include <arpa/inet.h>
43 #include <sys/utsname.h>
53 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
55 #define in_addr_t unsigned long
58 #include <curl/curl.h>
59 #include "curl_urldata.h"
60 #include "curl_sendf.h"
61 #include "curl_if2ip.h"
62 #include "curl_hostip.h"
63 #include "curl_progress.h"
64 #include "curl_transfer.h"
65 #include "curl_escape.h"
66 #include "curl_http.h" /* for HTTP proxy tunnel stuff */
67 #include "curl_socks.h"
68 #include "curl_pop3.h"
70 #include "curl_strtoofft.h"
71 #include "curl_strequal.h"
72 #include "curl_sslgen.h"
73 #include "curl_connect.h"
74 #include "curl_strerror.h"
75 #include "curl_select.h"
76 #include "curl_multiif.h"
78 #include "curl_rawstr.h"
79 #include "curl_sasl.h"
81 #include "curl_warnless.h"
83 #define _MPRINTF_REPLACE /* use our functions only */
84 #include <curl/mprintf.h>
86 #include "curl_memory.h"
87 /* The last #include file should be: */
88 #include "curl_memdebug.h"
90 /* Local API functions */
91 static CURLcode pop3_parse_url_path(struct connectdata *conn);
92 static CURLcode pop3_parse_custom_request(struct connectdata *conn);
93 static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done);
94 static CURLcode pop3_do(struct connectdata *conn, bool *done);
95 static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
97 static CURLcode pop3_connect(struct connectdata *conn, bool *done);
98 static CURLcode pop3_disconnect(struct connectdata *conn, bool dead);
99 static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done);
100 static int pop3_getsock(struct connectdata *conn,
101 curl_socket_t *socks,
103 static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done);
104 static CURLcode pop3_setup_connection(struct connectdata *conn);
107 * POP3 protocol handler.
110 const struct Curl_handler Curl_handler_pop3 = {
112 pop3_setup_connection, /* setup_connection */
114 pop3_done, /* done */
115 ZERO_NULL, /* do_more */
116 pop3_connect, /* connect_it */
117 pop3_multi_statemach, /* connecting */
118 pop3_doing, /* doing */
119 pop3_getsock, /* proto_getsock */
120 pop3_getsock, /* doing_getsock */
121 ZERO_NULL, /* domore_getsock */
122 ZERO_NULL, /* perform_getsock */
123 pop3_disconnect, /* disconnect */
124 ZERO_NULL, /* readwrite */
125 PORT_POP3, /* defport */
126 CURLPROTO_POP3, /* protocol */
127 PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
132 * POP3S protocol handler.
135 const struct Curl_handler Curl_handler_pop3s = {
136 "POP3S", /* scheme */
137 pop3_setup_connection, /* setup_connection */
139 pop3_done, /* done */
140 ZERO_NULL, /* do_more */
141 pop3_connect, /* connect_it */
142 pop3_multi_statemach, /* connecting */
143 pop3_doing, /* doing */
144 pop3_getsock, /* proto_getsock */
145 pop3_getsock, /* doing_getsock */
146 ZERO_NULL, /* domore_getsock */
147 ZERO_NULL, /* perform_getsock */
148 pop3_disconnect, /* disconnect */
149 ZERO_NULL, /* readwrite */
150 PORT_POP3S, /* defport */
151 CURLPROTO_POP3 | CURLPROTO_POP3S, /* protocol */
152 PROTOPT_CLOSEACTION | PROTOPT_SSL
153 | PROTOPT_NOURLQUERY /* flags */
157 #ifndef CURL_DISABLE_HTTP
159 * HTTP-proxyed POP3 protocol handler.
162 static const struct Curl_handler Curl_handler_pop3_proxy = {
164 ZERO_NULL, /* setup_connection */
165 Curl_http, /* do_it */
166 Curl_http_done, /* done */
167 ZERO_NULL, /* do_more */
168 ZERO_NULL, /* connect_it */
169 ZERO_NULL, /* connecting */
170 ZERO_NULL, /* doing */
171 ZERO_NULL, /* proto_getsock */
172 ZERO_NULL, /* doing_getsock */
173 ZERO_NULL, /* domore_getsock */
174 ZERO_NULL, /* perform_getsock */
175 ZERO_NULL, /* disconnect */
176 ZERO_NULL, /* readwrite */
177 PORT_POP3, /* defport */
178 CURLPROTO_HTTP, /* protocol */
179 PROTOPT_NONE /* flags */
184 * HTTP-proxyed POP3S protocol handler.
187 static const struct Curl_handler Curl_handler_pop3s_proxy = {
188 "POP3S", /* scheme */
189 ZERO_NULL, /* setup_connection */
190 Curl_http, /* do_it */
191 Curl_http_done, /* done */
192 ZERO_NULL, /* do_more */
193 ZERO_NULL, /* connect_it */
194 ZERO_NULL, /* connecting */
195 ZERO_NULL, /* doing */
196 ZERO_NULL, /* proto_getsock */
197 ZERO_NULL, /* doing_getsock */
198 ZERO_NULL, /* domore_getsock */
199 ZERO_NULL, /* perform_getsock */
200 ZERO_NULL, /* disconnect */
201 ZERO_NULL, /* readwrite */
202 PORT_POP3S, /* defport */
203 CURLPROTO_HTTP, /* protocol */
204 PROTOPT_NONE /* flags */
209 /* Function that checks for an ending pop3 status code at the start of the
210 given string, but also detects the APOP timestamp from the server greeting
211 as well as the supported authentication types and allowed SASL mechanisms
212 from the CAPA response. */
213 static int pop3_endofresp(struct pingpong *pp, int *resp)
215 char *line = pp->linestart_resp;
216 size_t len = strlen(pp->linestart_resp);
217 struct connectdata *conn = pp->conn;
218 struct pop3_conn *pop3c = &conn->proto.pop3c;
222 /* Do we have an error response? */
223 if(len >= 4 && !memcmp("-ERR", line, 4)) {
229 /* Are we processing servergreet responses */
230 if(pop3c->state == POP3_SERVERGREET) {
231 /* Look for the APOP timestamp */
232 if(len >= 3 && line[len - 3] == '>') {
233 for(i = 0; i < len - 3; ++i) {
235 /* Calculate the length of the timestamp */
236 size_t timestamplen = len - 2 - i;
238 /* Allocate some memory for the timestamp */
239 pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1);
241 if(!pop3c->apoptimestamp)
244 /* Copy the timestamp */
245 memcpy(pop3c->apoptimestamp, line + i, timestamplen);
246 pop3c->apoptimestamp[timestamplen] = '\0';
252 /* Are we processing CAPA command responses? */
253 else if(pop3c->state == POP3_CAPA) {
255 /* Do we have the terminating character? */
256 if(len >= 1 && !memcmp(line, ".", 1)) {
262 /* Does the server support clear text? */
263 if(len >= 4 && !memcmp(line, "USER", 4)) {
264 pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
268 /* Does the server support APOP? */
269 if(len >= 4 && !memcmp(line, "APOP", 4)) {
270 pop3c->authtypes |= POP3_TYPE_APOP;
274 /* Does the server support SASL? */
275 if(len < 4 || memcmp(line, "SASL", 4))
278 pop3c->authtypes |= POP3_TYPE_SASL;
280 /* Advance past the SASL keyword */
284 /* Loop through the data line */
287 (*line == ' ' || *line == '\t' ||
288 *line == '\r' || *line == '\n')) {
300 /* Extract the word */
301 for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
302 line[wordlen] != '\t' && line[wordlen] != '\r' &&
303 line[wordlen] != '\n';)
306 /* Test the word for a matching authentication mechanism */
307 if(wordlen == 5 && !memcmp(line, "LOGIN", 5))
308 pop3c->authmechs |= SASL_MECH_LOGIN;
309 else if(wordlen == 5 && !memcmp(line, "PLAIN", 5))
310 pop3c->authmechs |= SASL_MECH_PLAIN;
311 else if(wordlen == 8 && !memcmp(line, "CRAM-MD5", 8))
312 pop3c->authmechs |= SASL_MECH_CRAM_MD5;
313 else if(wordlen == 10 && !memcmp(line, "DIGEST-MD5", 10))
314 pop3c->authmechs |= SASL_MECH_DIGEST_MD5;
315 else if(wordlen == 6 && !memcmp(line, "GSSAPI", 6))
316 pop3c->authmechs |= SASL_MECH_GSSAPI;
317 else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8))
318 pop3c->authmechs |= SASL_MECH_EXTERNAL;
319 else if(wordlen == 4 && !memcmp(line, "NTLM", 4))
320 pop3c->authmechs |= SASL_MECH_NTLM;
327 if((len < 1 || memcmp("+", line, 1)) &&
328 (len < 3 || memcmp("+OK", line, 3)))
329 return FALSE; /* Nothing for us */
331 /* Otherwise it's a positive response */
337 /* This is the ONLY way to change POP3 state! */
338 static void state(struct connectdata *conn, pop3state newstate)
340 struct pop3_conn *pop3c = &conn->proto.pop3c;
341 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
342 /* for debug purposes */
343 static const char * const names[] = {
353 "AUTH_DIGESTMD5_RESP",
355 "AUTH_NTLM_TYPE2MSG",
365 if(pop3c->state != newstate)
366 infof(conn->data, "POP3 %p state change from %s to %s\n",
367 pop3c, names[pop3c->state], names[newstate]);
370 pop3c->state = newstate;
373 static CURLcode pop3_state_capa(struct connectdata *conn)
375 CURLcode result = CURLE_OK;
376 struct pop3_conn *pop3c = &conn->proto.pop3c;
378 pop3c->authmechs = 0; /* No known authentication mechanisms yet */
379 pop3c->authused = 0; /* Clear the authentication mechanism used */
381 /* Check we have a username and password to authenticate with and end the
382 connect phase if we don't */
383 if(!conn->bits.user_passwd) {
384 state(conn, POP3_STOP);
389 /* Send the CAPA command */
390 result = Curl_pp_sendf(&pop3c->pp, "CAPA");
395 state(conn, POP3_CAPA);
400 static CURLcode pop3_state_user(struct connectdata *conn)
403 struct FTP *pop3 = conn->data->state.proto.pop3;
405 /* Send the USER command */
406 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s",
407 pop3->user ? pop3->user : "");
411 state(conn, POP3_USER);
416 #ifndef CURL_DISABLE_CRYPTO_AUTH
417 static CURLcode pop3_state_apop(struct connectdata *conn)
419 CURLcode result = CURLE_OK;
420 struct pop3_conn *pop3c = &conn->proto.pop3c;
423 unsigned char digest[MD5_DIGEST_LEN];
424 char secret[2 * MD5_DIGEST_LEN + 1];
426 ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
428 return CURLE_OUT_OF_MEMORY;
430 Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp,
431 curlx_uztoui(strlen(pop3c->apoptimestamp)));
433 Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd,
434 curlx_uztoui(strlen(conn->passwd)));
436 /* Finalise the digest */
437 Curl_MD5_final(ctxt, digest);
439 /* Convert the calculated 16 octet digest into a 32 byte hex string */
440 for(i = 0; i < MD5_DIGEST_LEN; i++)
441 snprintf(&secret[2 * i], 3, "%02x", digest[i]);
443 result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret);
446 state(conn, POP3_APOP);
452 static CURLcode pop3_authenticate(struct connectdata *conn)
454 CURLcode result = CURLE_OK;
455 struct pop3_conn *pop3c = &conn->proto.pop3c;
456 const char *mech = NULL;
457 pop3state authstate = POP3_STOP;
459 /* Check supported authentication mechanisms by decreasing order of
461 #ifndef CURL_DISABLE_CRYPTO_AUTH
462 if(pop3c->authmechs & SASL_MECH_DIGEST_MD5) {
464 authstate = POP3_AUTH_DIGESTMD5;
465 pop3c->authused = SASL_MECH_DIGEST_MD5;
467 else if(pop3c->authmechs & SASL_MECH_CRAM_MD5) {
469 authstate = POP3_AUTH_CRAMMD5;
470 pop3c->authused = SASL_MECH_CRAM_MD5;
475 if(pop3c->authmechs & SASL_MECH_NTLM) {
477 authstate = POP3_AUTH_NTLM;
478 pop3c->authused = SASL_MECH_NTLM;
482 if(pop3c->authmechs & SASL_MECH_LOGIN) {
484 authstate = POP3_AUTH_LOGIN;
485 pop3c->authused = SASL_MECH_LOGIN;
487 else if(pop3c->authmechs & SASL_MECH_PLAIN) {
489 authstate = POP3_AUTH_PLAIN;
490 pop3c->authused = SASL_MECH_PLAIN;
493 infof(conn->data, "No known SASL authentication mechanisms supported!\n");
494 result = CURLE_LOGIN_DENIED; /* Other mechanisms not supported */
498 result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
501 state(conn, authstate);
507 /* For the POP3 "protocol connect" and "doing" phases only */
508 static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
511 return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks);
515 static void pop3_to_pop3s(struct connectdata *conn)
517 conn->handler = &Curl_handler_pop3s;
520 #define pop3_to_pop3s(x) Curl_nop_stmt
523 /* For the initial server greeting */
524 static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
528 CURLcode result = CURLE_OK;
529 struct SessionHandle *data = conn->data;
530 struct pop3_conn *pop3c = &conn->proto.pop3c;
532 (void)instate; /* no use for this yet */
534 if(pop3code != '+') {
535 failf(data, "Got unexpected pop3-server response");
536 return CURLE_FTP_WEIRD_SERVER_REPLY;
539 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
540 /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
541 to TLS connection now */
542 result = Curl_pp_sendf(&pop3c->pp, "STLS");
543 state(conn, POP3_STARTTLS);
546 result = pop3_state_capa(conn);
551 /* For STARTTLS responses */
552 static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
556 CURLcode result = CURLE_OK;
557 struct SessionHandle *data = conn->data;
559 (void)instate; /* no use for this yet */
561 if(pop3code != '+') {
562 if(data->set.use_ssl != CURLUSESSL_TRY) {
563 failf(data, "STARTTLS denied. %c", pop3code);
564 result = CURLE_USE_SSL_FAILED;
567 result = pop3_state_capa(conn);
570 /* Curl_ssl_connect is BLOCKING */
571 result = Curl_ssl_connect(conn, FIRSTSOCKET);
572 if(CURLE_OK == result) {
574 result = pop3_state_capa(conn);
581 /* For CAPA responses */
582 static CURLcode pop3_state_capa_resp(struct connectdata *conn,
586 CURLcode result = CURLE_OK;
588 (void)instate; /* no use for this yet */
591 result = pop3_state_user(conn);
593 /* Check supported authentication types by decreasing order of security */
594 if(conn->proto.pop3c.authtypes & POP3_TYPE_SASL)
595 result = pop3_authenticate(conn);
596 #ifndef CURL_DISABLE_CRYPTO_AUTH
597 else if(conn->proto.pop3c.authtypes & POP3_TYPE_APOP)
598 result = pop3_state_apop(conn);
600 else if(conn->proto.pop3c.authtypes & POP3_TYPE_CLEARTEXT)
601 result = pop3_state_user(conn);
603 infof(conn->data, "No known authentication types supported!\n");
604 result = CURLE_LOGIN_DENIED; /* Other types not supported */
611 /* For AUTH PLAIN responses */
612 static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn,
616 CURLcode result = CURLE_OK;
617 struct SessionHandle *data = conn->data;
619 char *plainauth = NULL;
621 (void)instate; /* no use for this yet */
623 if(pop3code != '+') {
624 failf(data, "Access denied. %c", pop3code);
625 result = CURLE_LOGIN_DENIED;
628 /* Create the authorisation message */
629 result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd,
632 /* Send the message */
635 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", plainauth);
638 state(conn, POP3_AUTH);
641 Curl_safefree(plainauth);
648 /* For AUTH LOGIN responses */
649 static CURLcode pop3_state_auth_login_resp(struct connectdata *conn,
653 CURLcode result = CURLE_OK;
654 struct SessionHandle *data = conn->data;
656 char *authuser = NULL;
658 (void)instate; /* no use for this yet */
660 if(pop3code != '+') {
661 failf(data, "Access denied: %d", pop3code);
662 result = CURLE_LOGIN_DENIED;
665 /* Create the user message */
666 result = Curl_sasl_create_login_message(data, conn->user,
672 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authuser);
675 state(conn, POP3_AUTH_LOGIN_PASSWD);
678 Curl_safefree(authuser);
685 /* For AUTH LOGIN user entry responses */
686 static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn,
690 CURLcode result = CURLE_OK;
691 struct SessionHandle *data = conn->data;
693 char *authpasswd = NULL;
695 (void)instate; /* no use for this yet */
697 if(pop3code != '+') {
698 failf(data, "Access denied: %d", pop3code);
699 result = CURLE_LOGIN_DENIED;
702 /* Create the password message */
703 result = Curl_sasl_create_login_message(data, conn->passwd,
706 /* Send the password */
709 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authpasswd);
712 state(conn, POP3_AUTH);
715 Curl_safefree(authpasswd);
722 #ifndef CURL_DISABLE_CRYPTO_AUTH
723 /* For AUTH CRAM-MD5 responses */
724 static CURLcode pop3_state_auth_cram_resp(struct connectdata *conn,
728 CURLcode result = CURLE_OK;
729 struct SessionHandle *data = conn->data;
730 char *chlg64 = data->state.buffer;
732 char *rplyb64 = NULL;
734 (void)instate; /* no use for this yet */
736 if(pop3code != '+') {
737 failf(data, "Access denied: %d", pop3code);
738 return CURLE_LOGIN_DENIED;
741 /* Get the challenge */
742 for(chlg64 += 2; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
745 /* Terminate the challenge */
747 for(len = strlen(chlg64); len--;)
748 if(chlg64[len] != '\r' && chlg64[len] != '\n' && chlg64[len] != ' ' &&
757 /* Create the response message */
758 result = Curl_sasl_create_cram_md5_message(data, chlg64, conn->user,
759 conn->passwd, &rplyb64, &len);
761 /* Send the response */
764 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
767 state(conn, POP3_AUTH);
770 Curl_safefree(rplyb64);
776 /* For AUTH DIGEST-MD5 challenge responses */
777 static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn,
781 CURLcode result = CURLE_OK;
782 struct SessionHandle *data = conn->data;
783 char *chlg64 = data->state.buffer;
785 char *rplyb64 = NULL;
787 (void)instate; /* no use for this yet */
789 if(pop3code != '+') {
790 failf(data, "Access denied: %d", pop3code);
791 return CURLE_LOGIN_DENIED;
794 /* Get the challenge */
795 for(chlg64 += 2; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
798 /* Create the response message */
799 result = Curl_sasl_create_digest_md5_message(data, chlg64, conn->user,
803 /* Send the response */
806 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
809 state(conn, POP3_AUTH_DIGESTMD5_RESP);
812 Curl_safefree(rplyb64);
818 /* For AUTH DIGEST-MD5 challenge-response responses */
819 static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn,
823 CURLcode result = CURLE_OK;
824 struct SessionHandle *data = conn->data;
826 (void)instate; /* no use for this yet */
828 if(pop3code != '+') {
829 failf(data, "Authentication failed: %d", pop3code);
830 result = CURLE_LOGIN_DENIED;
833 /* Send an empty response */
834 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "");
837 state(conn, POP3_AUTH);
845 /* For AUTH NTLM responses */
846 static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn,
850 CURLcode result = CURLE_OK;
851 struct SessionHandle *data = conn->data;
853 char *type1msg = NULL;
855 (void)instate; /* no use for this yet */
857 if(pop3code != '+') {
858 failf(data, "Access denied: %d", pop3code);
859 result = CURLE_LOGIN_DENIED;
862 /* Create the type-1 message */
863 result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
867 /* Send the message */
870 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type1msg);
873 state(conn, POP3_AUTH_NTLM_TYPE2MSG);
876 Curl_safefree(type1msg);
883 /* For NTLM type-2 responses (sent in reponse to our type-1 message) */
884 static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn,
888 CURLcode result = CURLE_OK;
889 struct SessionHandle *data = conn->data;
891 char *type3msg = NULL;
893 (void)instate; /* no use for this yet */
895 if(pop3code != '+') {
896 failf(data, "Access denied: %d", pop3code);
897 result = CURLE_LOGIN_DENIED;
900 /* Create the type-3 message */
901 result = Curl_sasl_create_ntlm_type3_message(data,
902 data->state.buffer + 2,
903 conn->user, conn->passwd,
907 /* Send the message */
910 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type3msg);
913 state(conn, POP3_AUTH);
916 Curl_safefree(type3msg);
924 /* For final responses to the AUTH sequence */
925 static CURLcode pop3_state_auth_final_resp(struct connectdata *conn,
929 CURLcode result = CURLE_OK;
930 struct SessionHandle *data = conn->data;
932 (void)instate; /* no use for this yet */
934 if(pop3code != '+') {
935 failf(data, "Authentication failed: %d", pop3code);
936 result = CURLE_LOGIN_DENIED;
939 /* End of connect phase */
940 state(conn, POP3_STOP);
945 static CURLcode pop3_state_apop_resp(struct connectdata *conn,
949 CURLcode result = CURLE_OK;
950 struct SessionHandle *data = conn->data;
952 (void)instate; /* no use for this yet */
954 if(pop3code != '+') {
955 failf(data, "Authentication failed: %d", pop3code);
956 result = CURLE_LOGIN_DENIED;
959 /* End of connect phase */
960 state(conn, POP3_STOP);
965 /* For USER responses */
966 static CURLcode pop3_state_user_resp(struct connectdata *conn,
970 CURLcode result = CURLE_OK;
971 struct SessionHandle *data = conn->data;
972 struct FTP *pop3 = data->state.proto.pop3;
974 (void)instate; /* no use for this yet */
976 if(pop3code != '+') {
977 failf(data, "Access denied. %c", pop3code);
978 result = CURLE_LOGIN_DENIED;
981 /* Send the PASS command */
982 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s",
983 pop3->passwd ? pop3->passwd : "");
987 state(conn, POP3_PASS);
992 /* For PASS responses */
993 static CURLcode pop3_state_pass_resp(struct connectdata *conn,
997 CURLcode result = CURLE_OK;
998 struct SessionHandle *data = conn->data;
1000 (void)instate; /* no use for this yet */
1002 if(pop3code != '+') {
1003 failf(data, "Access denied. %c", pop3code);
1004 result = CURLE_LOGIN_DENIED;
1007 /* End of connect phase */
1008 state(conn, POP3_STOP);
1013 /* Start the DO phase for the command */
1014 static CURLcode pop3_command(struct connectdata *conn)
1016 CURLcode result = CURLE_OK;
1017 struct pop3_conn *pop3c = &conn->proto.pop3c;
1018 const char *command = NULL;
1020 /* Calculate the default command */
1021 if(pop3c->mailbox[0] == '\0' || conn->data->set.ftp_list_only) {
1024 if(pop3c->mailbox[0] != '\0') {
1025 /* Message specific LIST so skip the BODY transfer */
1026 struct FTP *pop3 = conn->data->state.proto.pop3;
1027 pop3->transfer = FTPTRANSFER_INFO;
1033 /* Send the command */
1034 if(pop3c->mailbox[0] != '\0')
1035 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s",
1036 (pop3c->custom && pop3c->custom[0] != '\0' ?
1037 pop3c->custom : command), pop3c->mailbox);
1039 result = Curl_pp_sendf(&conn->proto.pop3c.pp,
1040 (pop3c->custom && pop3c->custom[0] != '\0' ?
1041 pop3c->custom : command));
1046 state(conn, POP3_COMMAND);
1051 /* For command responses */
1052 static CURLcode pop3_state_command_resp(struct connectdata *conn,
1056 CURLcode result = CURLE_OK;
1057 struct SessionHandle *data = conn->data;
1058 struct FTP *pop3 = data->state.proto.pop3;
1059 struct pop3_conn *pop3c = &conn->proto.pop3c;
1060 struct pingpong *pp = &pop3c->pp;
1062 (void)instate; /* no use for this yet */
1064 if(pop3code != '+') {
1065 state(conn, POP3_STOP);
1066 return CURLE_RECV_ERROR;
1069 /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
1070 EOB string so count this is two matching bytes. This is necessary to make
1071 the code detect the EOB if the only data than comes now is %2e CR LF like
1072 when there is no body to return. */
1075 /* But since this initial CR LF pair is not part of the actual body, we set
1076 the strip counter here so that these bytes won't be delivered. */
1080 Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, pop3->bytecountp,
1081 -1, NULL); /* no upload here */
1084 /* The header "cache" contains a bunch of data that is actually body
1085 content so send it as such. Note that there may even be additional
1086 "headers" after the body */
1088 if(!data->set.opt_no_body) {
1089 result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
1094 /* Free the cache */
1095 Curl_safefree(pp->cache);
1097 /* Reset the cache size */
1101 /* End of do phase */
1102 state(conn, POP3_STOP);
1107 static CURLcode pop3_statemach_act(struct connectdata *conn)
1110 curl_socket_t sock = conn->sock[FIRSTSOCKET];
1112 struct pop3_conn *pop3c = &conn->proto.pop3c;
1113 struct pingpong *pp = &pop3c->pp;
1116 /* Flush any data that needs to be sent */
1118 return Curl_pp_flushsend(pp);
1120 /* Read the response from the server */
1121 result = Curl_pp_readresp(sock, pp, &pop3code, &nread);
1126 /* We have now received a full POP3 server response */
1127 switch(pop3c->state) {
1128 case POP3_SERVERGREET:
1129 result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state);
1133 result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);
1137 result = pop3_state_capa_resp(conn, pop3code, pop3c->state);
1140 case POP3_AUTH_PLAIN:
1141 result = pop3_state_auth_plain_resp(conn, pop3code, pop3c->state);
1144 case POP3_AUTH_LOGIN:
1145 result = pop3_state_auth_login_resp(conn, pop3code, pop3c->state);
1148 case POP3_AUTH_LOGIN_PASSWD:
1149 result = pop3_state_auth_login_password_resp(conn, pop3code,
1153 #ifndef CURL_DISABLE_CRYPTO_AUTH
1154 case POP3_AUTH_CRAMMD5:
1155 result = pop3_state_auth_cram_resp(conn, pop3code, pop3c->state);
1158 case POP3_AUTH_DIGESTMD5:
1159 result = pop3_state_auth_digest_resp(conn, pop3code, pop3c->state);
1162 case POP3_AUTH_DIGESTMD5_RESP:
1163 result = pop3_state_auth_digest_resp_resp(conn, pop3code, pop3c->state);
1168 case POP3_AUTH_NTLM:
1169 result = pop3_state_auth_ntlm_resp(conn, pop3code, pop3c->state);
1172 case POP3_AUTH_NTLM_TYPE2MSG:
1173 result = pop3_state_auth_ntlm_type2msg_resp(conn, pop3code,
1179 result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state);
1183 result = pop3_state_apop_resp(conn, pop3code, pop3c->state);
1187 result = pop3_state_user_resp(conn, pop3code, pop3c->state);
1191 result = pop3_state_pass_resp(conn, pop3code, pop3c->state);
1195 result = pop3_state_command_resp(conn, pop3code, pop3c->state);
1199 /* fallthrough, just stop! */
1201 /* internal error */
1202 state(conn, POP3_STOP);
1210 /* Called repeatedly until done from curl_multi.c */
1211 static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
1213 struct pop3_conn *pop3c = &conn->proto.pop3c;
1214 CURLcode result = Curl_pp_multi_statemach(&pop3c->pp);
1216 *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
1221 static CURLcode pop3_easy_statemach(struct connectdata *conn)
1223 struct pop3_conn *pop3c = &conn->proto.pop3c;
1224 struct pingpong *pp = &pop3c->pp;
1225 CURLcode result = CURLE_OK;
1227 while(pop3c->state != POP3_STOP) {
1228 result = Curl_pp_easy_statemach(pp);
1236 /* Allocate and initialize the POP3 struct for the current SessionHandle if
1238 static CURLcode pop3_init(struct connectdata *conn)
1240 struct SessionHandle *data = conn->data;
1241 struct FTP *pop3 = data->state.proto.pop3;
1244 pop3 = data->state.proto.pop3 = calloc(sizeof(struct FTP), 1);
1246 return CURLE_OUT_OF_MEMORY;
1249 /* Get some initial data into the pop3 struct */
1250 pop3->bytecountp = &data->req.bytecount;
1252 /* No need to duplicate user+password, the connectdata struct won't change
1253 during a session, but we re-init them here since on subsequent inits
1254 since the conn struct may have changed or been replaced.
1256 pop3->user = conn->user;
1257 pop3->passwd = conn->passwd;
1262 /***********************************************************************
1266 * This function should do everything that is to be considered a part of the
1269 * The variable 'done' points to will be TRUE if the protocol-layer connect
1270 * phase is done when this function returns, or FALSE is not. When called as
1271 * a part of the easy interface, it will always be TRUE.
1273 static CURLcode pop3_connect(struct connectdata *conn, bool *done)
1276 struct pop3_conn *pop3c = &conn->proto.pop3c;
1277 struct SessionHandle *data = conn->data;
1278 struct pingpong *pp = &pop3c->pp;
1280 *done = FALSE; /* default to not done yet */
1282 /* If there already is a protocol-specific struct allocated for this
1283 sessionhandle, deal with it */
1284 Curl_reset_reqproto(conn);
1286 result = pop3_init(conn);
1287 if(CURLE_OK != result)
1290 /* We always support persistent connections on pop3 */
1291 conn->bits.close = FALSE;
1293 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
1294 pp->statemach_act = pop3_statemach_act;
1295 pp->endofresp = pop3_endofresp;
1298 if(conn->handler->flags & PROTOPT_SSL) {
1299 /* POP3S is simply pop3 with SSL for the control channel */
1300 /* so perform the SSL initialization for this socket */
1301 result = Curl_ssl_connect(conn, FIRSTSOCKET);
1306 /* Initialise the response reader stuff */
1309 /* Start off waiting for the server greeting response */
1310 state(conn, POP3_SERVERGREET);
1312 if(data->state.used_interface == Curl_if_multi)
1313 result = pop3_multi_statemach(conn, done);
1315 result = pop3_easy_statemach(conn);
1323 /***********************************************************************
1327 * The DONE function. This does what needs to be done after a single DO has
1330 * Input argument is already checked for validity.
1332 static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
1335 struct SessionHandle *data = conn->data;
1336 struct FTP *pop3 = data->state.proto.pop3;
1337 struct pop3_conn *pop3c = &conn->proto.pop3c;
1338 CURLcode result = CURLE_OK;
1343 /* When the easy handle is removed from the multi while libcurl is still
1344 * trying to resolve the host name, it seems that the pop3 struct is not
1345 * yet initialized, but the removal action calls Curl_done() which calls
1346 * this function. So we simply return success if no pop3 pointer is set.
1351 conn->bits.close = TRUE; /* marked for closure */
1352 result = status; /* use the already set error code */
1355 /* Cleanup our do based variables */
1356 Curl_safefree(pop3c->mailbox);
1357 Curl_safefree(pop3c->custom);
1359 /* Clear the transfer mode for the next connection */
1360 pop3->transfer = FTPTRANSFER_BODY;
1365 /***********************************************************************
1369 * This is the actual DO function for POP3. Get a file/directory according to
1370 * the options previously setup.
1372 static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
1375 /* This is POP3 and no proxy */
1376 CURLcode result = CURLE_OK;
1378 DEBUGF(infof(conn->data, "DO phase starts\n"));
1380 if(conn->data->set.opt_no_body) {
1381 /* Requested no body means no transfer */
1382 struct FTP *pop3 = conn->data->state.proto.pop3;
1383 pop3->transfer = FTPTRANSFER_INFO;
1386 *dophase_done = FALSE; /* not done yet */
1388 /* Start the first command in the DO phase */
1389 result = pop3_command(conn);
1393 /* Run the state-machine */
1394 if(conn->data->state.used_interface == Curl_if_multi)
1395 result = pop3_multi_statemach(conn, dophase_done);
1397 result = pop3_easy_statemach(conn);
1398 *dophase_done = TRUE; /* with the easy interface we are done here */
1400 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
1403 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1408 /***********************************************************************
1412 * This function is registered as 'curl_do' function. It decodes the path
1413 * parts etc as a wrapper to the actual DO function (pop3_perform).
1415 * The input argument is already checked for validity.
1417 static CURLcode pop3_do(struct connectdata *conn, bool *done)
1419 CURLcode retcode = CURLE_OK;
1421 *done = FALSE; /* default to false */
1424 Since connections can be re-used between SessionHandles, this might be a
1425 connection already existing but on a fresh SessionHandle struct so we must
1426 make sure we have a good 'struct POP3' to play with. For new connections,
1427 the struct POP3 is allocated and setup in the pop3_connect() function.
1429 Curl_reset_reqproto(conn);
1430 retcode = pop3_init(conn);
1434 /* Parse the URL path */
1435 retcode = pop3_parse_url_path(conn);
1439 /* Parse the custom request */
1440 retcode = pop3_parse_custom_request(conn);
1444 retcode = pop3_regular_transfer(conn, done);
1449 /***********************************************************************
1453 * This should be called before calling sclose(). We should then wait for the
1454 * response from the server before returning. The calling code should then try
1455 * to close the connection.
1457 static CURLcode pop3_quit(struct connectdata *conn)
1459 CURLcode result = CURLE_OK;
1461 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "QUIT", NULL);
1465 state(conn, POP3_QUIT);
1467 result = pop3_easy_statemach(conn);
1472 /***********************************************************************
1476 * Disconnect from an POP3 server. Cleanup protocol-specific per-connection
1477 * resources. BLOCKING.
1479 static CURLcode pop3_disconnect(struct connectdata *conn,
1480 bool dead_connection)
1482 struct pop3_conn *pop3c = &conn->proto.pop3c;
1484 /* We cannot send quit unconditionally. If this connection is stale or
1485 bad in any way, sending quit and waiting around here will make the
1486 disconnect wait in vain and cause more problems than we need to */
1488 /* The POP3 session may or may not have been allocated/setup at this
1490 if(!dead_connection && pop3c->pp.conn)
1491 (void)pop3_quit(conn); /* ignore errors on the LOGOUT */
1493 /* Disconnect from the server */
1494 Curl_pp_disconnect(&pop3c->pp);
1496 /* Cleanup the SASL module */
1497 Curl_sasl_cleanup(conn, pop3c->authused);
1499 /* Cleanup our connection based variables */
1500 Curl_safefree(pop3c->apoptimestamp);
1505 /***********************************************************************
1507 * pop3_parse_url_path()
1509 * Parse the URL path into separate path components.
1511 static CURLcode pop3_parse_url_path(struct connectdata *conn)
1513 /* The POP3 struct is already initialised in pop3_connect() */
1514 struct pop3_conn *pop3c = &conn->proto.pop3c;
1515 struct SessionHandle *data = conn->data;
1516 const char *path = data->state.path;
1518 /* URL decode the path and use this mailbox */
1519 return Curl_urldecode(data, path, 0, &pop3c->mailbox, NULL, TRUE);
1522 static CURLcode pop3_parse_custom_request(struct connectdata *conn)
1524 CURLcode result = CURLE_OK;
1525 struct pop3_conn *pop3c = &conn->proto.pop3c;
1526 struct SessionHandle *data = conn->data;
1527 const char *custom = conn->data->set.str[STRING_CUSTOMREQUEST];
1529 /* URL decode the custom request */
1531 result = Curl_urldecode(data, custom, 0, &pop3c->custom, NULL, TRUE);
1536 /* Call this when the DO phase has completed */
1537 static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected)
1539 struct FTP *pop3 = conn->data->state.proto.pop3;
1543 if(pop3->transfer != FTPTRANSFER_BODY)
1544 /* no data to transfer */
1545 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1550 /* Called from curl_multi.c while DOing */
1551 static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done)
1553 CURLcode result = pop3_multi_statemach(conn, dophase_done);
1556 DEBUGF(infof(conn->data, "DO phase failed\n"));
1559 result = pop3_dophase_done(conn, FALSE /* not connected */);
1561 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1568 /***********************************************************************
1570 * pop3_regular_transfer()
1572 * The input argument is already checked for validity.
1574 * Performs all commands done before a regular transfer between a local and a
1577 static CURLcode pop3_regular_transfer(struct connectdata *conn,
1580 CURLcode result = CURLE_OK;
1581 bool connected = FALSE;
1582 struct SessionHandle *data = conn->data;
1584 /* Make sure size is unknown at this point */
1585 data->req.size = -1;
1587 Curl_pgrsSetUploadCounter(data, 0);
1588 Curl_pgrsSetDownloadCounter(data, 0);
1589 Curl_pgrsSetUploadSize(data, 0);
1590 Curl_pgrsSetDownloadSize(data, 0);
1592 result = pop3_perform(conn, &connected, dophase_done);
1594 if(CURLE_OK == result) {
1596 /* The DO phase has not completed yet */
1599 result = pop3_dophase_done(conn, connected);
1607 static CURLcode pop3_setup_connection(struct connectdata * conn)
1609 struct SessionHandle *data = conn->data;
1611 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
1612 /* Unless we have asked to tunnel pop3 operations through the proxy, we
1613 switch and use HTTP operations only */
1614 #ifndef CURL_DISABLE_HTTP
1615 if(conn->handler == &Curl_handler_pop3)
1616 conn->handler = &Curl_handler_pop3_proxy;
1619 conn->handler = &Curl_handler_pop3s_proxy;
1621 failf(data, "POP3S not supported!");
1622 return CURLE_UNSUPPORTED_PROTOCOL;
1626 /* We explicitly mark this connection as persistent here as we're doing
1627 POP3 over HTTP and thus we accidentally avoid setting this value
1629 conn->bits.close = FALSE;
1631 failf(data, "POP3 over http proxy requires HTTP support built-in!");
1632 return CURLE_UNSUPPORTED_PROTOCOL;
1636 data->state.path++; /* don't include the initial slash */
1641 /* This function scans the body after the end-of-body and writes everything
1642 until the end is found */
1643 CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
1645 /* This code could be made into a special function in the handler struct */
1646 CURLcode result = CURLE_OK;
1647 struct SessionHandle *data = conn->data;
1648 struct SingleRequest *k = &data->req;
1650 struct pop3_conn *pop3c = &conn->proto.pop3c;
1651 bool strip_dot = FALSE;
1655 /* Search through the buffer looking for the end-of-body marker which is
1656 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
1657 the eob so the server will have prefixed it with an extra dot which we
1658 need to strip out. Additionally the marker could of course be spread out
1659 over 5 different data chunks */
1660 for(i = 0; i < nread; i++) {
1661 size_t prev = pop3c->eob;
1665 if(pop3c->eob == 0) {
1669 /* Write out the body part that didn't match */
1670 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
1679 else if(pop3c->eob == 3)
1682 /* If the character match wasn't at position 0 or 3 then restart the
1688 if(pop3c->eob == 1 || pop3c->eob == 4)
1691 /* If the character match wasn't at position 1 or 4 then start the
1699 else if(pop3c->eob == 3) {
1700 /* We have an extra dot after the CRLF which we need to strip off */
1705 /* If the character match wasn't at position 2 then start the search
1715 /* Did we have a partial match which has subsequently failed? */
1716 if(prev && prev >= pop3c->eob) {
1717 /* Strip can only be non-zero for the very first mismatch after CRLF
1718 and then both prev and strip are equal and nothing will be output
1720 while(prev && pop3c->strip) {
1726 /* If the partial match was the CRLF and dot then only write the CRLF
1727 as the server would have inserted the dot */
1728 result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB,
1729 strip_dot ? prev - 1 : prev);
1740 if(pop3c->eob == POP3_EOB_LEN) {
1741 /* We have a full match so the transfer is done, however we must transfer
1742 the CRLF at the start of the EOB as this is considered to be part of the
1743 message as per RFC-1939, sect. 3 */
1744 result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
1746 k->keepon &= ~KEEP_RECV;
1753 /* While EOB is matching nothing should be output */
1757 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
1764 #endif /* CURL_DISABLE_POP3 */