1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2014, 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 * RFC4422 Simple Authentication and Security Layer (SASL)
29 * RFC4616 PLAIN authentication
30 * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
31 * RFC5034 POP3 SASL Authentication Mechanism
32 * RFC6749 OAuth 2.0 Authorization Framework
33 * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
35 ***************************************************************************/
37 #include "curl_setup.h"
39 #ifndef CURL_DISABLE_POP3
41 #ifdef HAVE_NETINET_IN_H
42 #include <netinet/in.h>
44 #ifdef HAVE_ARPA_INET_H
45 #include <arpa/inet.h>
48 #include <sys/utsname.h>
58 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
60 #define in_addr_t unsigned long
63 #include <curl/curl.h>
70 #include "http.h" /* for HTTP proxy tunnel stuff */
74 #include "strtoofft.h"
76 #include "vtls/vtls.h"
83 #include "curl_sasl.h"
87 #define _MPRINTF_REPLACE /* use our functions only */
88 #include <curl/mprintf.h>
90 #include "curl_memory.h"
91 /* The last #include file should be: */
94 /* Local API functions */
95 static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done);
96 static CURLcode pop3_do(struct connectdata *conn, bool *done);
97 static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
99 static CURLcode pop3_connect(struct connectdata *conn, bool *done);
100 static CURLcode pop3_disconnect(struct connectdata *conn, bool dead);
101 static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done);
102 static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
104 static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done);
105 static CURLcode pop3_setup_connection(struct connectdata *conn);
106 static CURLcode pop3_parse_url_options(struct connectdata *conn);
107 static CURLcode pop3_parse_url_path(struct connectdata *conn);
108 static CURLcode pop3_parse_custom_request(struct connectdata *conn);
109 static CURLcode pop3_calc_sasl_details(struct connectdata *conn,
111 char **initresp, size_t *len,
112 pop3state *state1, pop3state *state2);
115 * POP3 protocol handler.
118 const struct Curl_handler Curl_handler_pop3 = {
120 pop3_setup_connection, /* setup_connection */
122 pop3_done, /* done */
123 ZERO_NULL, /* do_more */
124 pop3_connect, /* connect_it */
125 pop3_multi_statemach, /* connecting */
126 pop3_doing, /* doing */
127 pop3_getsock, /* proto_getsock */
128 pop3_getsock, /* doing_getsock */
129 ZERO_NULL, /* domore_getsock */
130 ZERO_NULL, /* perform_getsock */
131 pop3_disconnect, /* disconnect */
132 ZERO_NULL, /* readwrite */
133 PORT_POP3, /* defport */
134 CURLPROTO_POP3, /* protocol */
135 PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
140 * POP3S protocol handler.
143 const struct Curl_handler Curl_handler_pop3s = {
144 "POP3S", /* scheme */
145 pop3_setup_connection, /* setup_connection */
147 pop3_done, /* done */
148 ZERO_NULL, /* do_more */
149 pop3_connect, /* connect_it */
150 pop3_multi_statemach, /* connecting */
151 pop3_doing, /* doing */
152 pop3_getsock, /* proto_getsock */
153 pop3_getsock, /* doing_getsock */
154 ZERO_NULL, /* domore_getsock */
155 ZERO_NULL, /* perform_getsock */
156 pop3_disconnect, /* disconnect */
157 ZERO_NULL, /* readwrite */
158 PORT_POP3S, /* defport */
159 CURLPROTO_POP3S, /* protocol */
160 PROTOPT_CLOSEACTION | PROTOPT_SSL
161 | PROTOPT_NOURLQUERY /* flags */
165 #ifndef CURL_DISABLE_HTTP
167 * HTTP-proxyed POP3 protocol handler.
170 static const struct Curl_handler Curl_handler_pop3_proxy = {
172 Curl_http_setup_conn, /* setup_connection */
173 Curl_http, /* do_it */
174 Curl_http_done, /* done */
175 ZERO_NULL, /* do_more */
176 ZERO_NULL, /* connect_it */
177 ZERO_NULL, /* connecting */
178 ZERO_NULL, /* doing */
179 ZERO_NULL, /* proto_getsock */
180 ZERO_NULL, /* doing_getsock */
181 ZERO_NULL, /* domore_getsock */
182 ZERO_NULL, /* perform_getsock */
183 ZERO_NULL, /* disconnect */
184 ZERO_NULL, /* readwrite */
185 PORT_POP3, /* defport */
186 CURLPROTO_HTTP, /* protocol */
187 PROTOPT_NONE /* flags */
192 * HTTP-proxyed POP3S protocol handler.
195 static const struct Curl_handler Curl_handler_pop3s_proxy = {
196 "POP3S", /* scheme */
197 Curl_http_setup_conn, /* setup_connection */
198 Curl_http, /* do_it */
199 Curl_http_done, /* done */
200 ZERO_NULL, /* do_more */
201 ZERO_NULL, /* connect_it */
202 ZERO_NULL, /* connecting */
203 ZERO_NULL, /* doing */
204 ZERO_NULL, /* proto_getsock */
205 ZERO_NULL, /* doing_getsock */
206 ZERO_NULL, /* domore_getsock */
207 ZERO_NULL, /* perform_getsock */
208 ZERO_NULL, /* disconnect */
209 ZERO_NULL, /* readwrite */
210 PORT_POP3S, /* defport */
211 CURLPROTO_HTTP, /* protocol */
212 PROTOPT_NONE /* flags */
218 static void pop3_to_pop3s(struct connectdata *conn)
220 conn->handler = &Curl_handler_pop3s;
223 #define pop3_to_pop3s(x) Curl_nop_stmt
226 /***********************************************************************
230 * Checks for an ending POP3 status code at the start of the given string, but
231 * also detects the APOP timestamp from the server greeting and various
232 * capabilities from the CAPA response including the supported authentication
233 * types and allowed SASL mechanisms.
235 static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
238 struct pop3_conn *pop3c = &conn->proto.pop3c;
240 /* Do we have an error response? */
241 if(len >= 4 && !memcmp("-ERR", line, 4)) {
247 /* Are we processing CAPA command responses? */
248 if(pop3c->state == POP3_CAPA) {
249 /* Do we have the terminating line? */
250 if(len >= 1 && !memcmp(line, ".", 1))
258 /* Do we have a command or continuation response? */
259 if((len >= 3 && !memcmp("+OK", line, 3)) ||
260 (len >= 1 && !memcmp("+", line, 1))) {
266 return FALSE; /* Nothing for us */
269 /***********************************************************************
273 * Gets the authentication message from the response buffer.
275 static void pop3_get_message(char *buffer, char** outptr)
278 char* message = NULL;
280 /* Find the start of the message */
281 for(message = buffer + 2; *message == ' ' || *message == '\t'; message++)
284 /* Find the end of the message */
285 for(len = strlen(message); len--;)
286 if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
287 message[len] != '\t')
290 /* Terminate the message */
298 /***********************************************************************
302 * This is the ONLY way to change POP3 state!
304 static void state(struct connectdata *conn, pop3state newstate)
306 struct pop3_conn *pop3c = &conn->proto.pop3c;
307 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
308 /* for debug purposes */
309 static const char * const names[] = {
320 "AUTH_DIGESTMD5_RESP",
322 "AUTH_NTLM_TYPE2MSG",
325 "AUTH_GSSAPI_NO_DATA",
337 if(pop3c->state != newstate)
338 infof(conn->data, "POP3 %p state change from %s to %s\n",
339 (void *)pop3c, names[pop3c->state], names[newstate]);
342 pop3c->state = newstate;
345 /***********************************************************************
347 * pop3_perform_capa()
349 * Sends the CAPA command in order to obtain a list of server side supported
352 static CURLcode pop3_perform_capa(struct connectdata *conn)
354 CURLcode result = CURLE_OK;
355 struct pop3_conn *pop3c = &conn->proto.pop3c;
357 pop3c->authmechs = 0; /* No known authentication mechanisms yet */
358 pop3c->authused = 0; /* Clear the authentication mechanism used */
359 pop3c->tls_supported = FALSE; /* Clear the TLS capability */
361 /* Send the CAPA command */
362 result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA");
365 state(conn, POP3_CAPA);
370 /***********************************************************************
372 * pop3_perform_starttls()
374 * Sends the STLS command to start the upgrade to TLS.
376 static CURLcode pop3_perform_starttls(struct connectdata *conn)
378 CURLcode result = CURLE_OK;
380 /* Send the STLS command */
381 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "STLS");
384 state(conn, POP3_STARTTLS);
389 /***********************************************************************
391 * pop3_perform_upgrade_tls()
393 * Performs the upgrade to TLS.
395 static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn)
397 CURLcode result = CURLE_OK;
398 struct pop3_conn *pop3c = &conn->proto.pop3c;
400 /* Start the SSL connection */
401 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
404 if(pop3c->state != POP3_UPGRADETLS)
405 state(conn, POP3_UPGRADETLS);
409 result = pop3_perform_capa(conn);
416 /***********************************************************************
418 * pop3_perform_user()
420 * Sends a clear text USER command to authenticate with.
422 static CURLcode pop3_perform_user(struct connectdata *conn)
424 CURLcode result = CURLE_OK;
426 /* Check we have a username and password to authenticate with and end the
427 connect phase if we don't */
428 if(!conn->bits.user_passwd) {
429 state(conn, POP3_STOP);
434 /* Send the USER command */
435 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s",
436 conn->user ? conn->user : "");
438 state(conn, POP3_USER);
443 #ifndef CURL_DISABLE_CRYPTO_AUTH
444 /***********************************************************************
446 * pop3_perform_apop()
448 * Sends an APOP command to authenticate with.
450 static CURLcode pop3_perform_apop(struct connectdata *conn)
452 CURLcode result = CURLE_OK;
453 struct pop3_conn *pop3c = &conn->proto.pop3c;
456 unsigned char digest[MD5_DIGEST_LEN];
457 char secret[2 * MD5_DIGEST_LEN + 1];
459 /* Check we have a username and password to authenticate with and end the
460 connect phase if we don't */
461 if(!conn->bits.user_passwd) {
462 state(conn, POP3_STOP);
467 /* Create the digest */
468 ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
470 return CURLE_OUT_OF_MEMORY;
472 Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp,
473 curlx_uztoui(strlen(pop3c->apoptimestamp)));
475 Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd,
476 curlx_uztoui(strlen(conn->passwd)));
478 /* Finalise the digest */
479 Curl_MD5_final(ctxt, digest);
481 /* Convert the calculated 16 octet digest into a 32 byte hex string */
482 for(i = 0; i < MD5_DIGEST_LEN; i++)
483 snprintf(&secret[2 * i], 3, "%02x", digest[i]);
485 result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret);
488 state(conn, POP3_APOP);
494 /***********************************************************************
496 * pop3_perform_auth()
498 * Sends an AUTH command allowing the client to login with the given SASL
499 * authentication mechanism.
501 static CURLcode pop3_perform_auth(struct connectdata *conn,
503 const char *initresp, size_t len,
504 pop3state state1, pop3state state2)
506 CURLcode result = CURLE_OK;
507 struct pop3_conn *pop3c = &conn->proto.pop3c;
509 if(initresp && 8 + strlen(mech) + len <= 255) { /* AUTH <mech> ...<crlf> */
510 /* Send the AUTH command with the initial response */
511 result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp);
517 /* Send the AUTH command */
518 result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
527 /***********************************************************************
529 * pop3_perform_authentication()
531 * Initiates the authentication sequence, with the appropriate SASL
532 * authentication mechanism, falling back to APOP and clear text should a
533 * common mechanism not be available between the client and server.
535 static CURLcode pop3_perform_authentication(struct connectdata *conn)
537 CURLcode result = CURLE_OK;
538 struct pop3_conn *pop3c = &conn->proto.pop3c;
539 const char *mech = NULL;
540 char *initresp = NULL;
542 pop3state state1 = POP3_STOP;
543 pop3state state2 = POP3_STOP;
545 /* Check we have a username and password to authenticate with and end the
546 connect phase if we don't */
547 if(!conn->bits.user_passwd) {
548 state(conn, POP3_STOP);
553 /* Calculate the SASL login details */
554 if(pop3c->authtypes & POP3_TYPE_SASL)
555 result = pop3_calc_sasl_details(conn, &mech, &initresp, &len, &state1,
559 if(mech && (pop3c->preftype & POP3_TYPE_SASL)) {
560 /* Perform SASL based authentication */
561 result = pop3_perform_auth(conn, mech, initresp, len, state1, state2);
563 #ifndef CURL_DISABLE_CRYPTO_AUTH
564 else if((pop3c->authtypes & POP3_TYPE_APOP) &&
565 (pop3c->preftype & POP3_TYPE_APOP))
566 /* Perform APOP authentication */
567 result = pop3_perform_apop(conn);
569 else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) &&
570 (pop3c->preftype & POP3_TYPE_CLEARTEXT))
571 /* Perform clear text authentication */
572 result = pop3_perform_user(conn);
574 /* Other mechanisms not supported */
575 infof(conn->data, "No known authentication mechanisms supported!\n");
576 result = CURLE_LOGIN_DENIED;
580 Curl_safefree(initresp);
585 /***********************************************************************
587 * pop3_perform_command()
589 * Sends a POP3 based command.
591 static CURLcode pop3_perform_command(struct connectdata *conn)
593 CURLcode result = CURLE_OK;
594 struct SessionHandle *data = conn->data;
595 struct POP3 *pop3 = data->req.protop;
596 const char *command = NULL;
598 /* Calculate the default command */
599 if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) {
602 if(pop3->id[0] != '\0')
603 /* Message specific LIST so skip the BODY transfer */
604 pop3->transfer = FTPTRANSFER_INFO;
609 /* Send the command */
610 if(pop3->id[0] != '\0')
611 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s",
612 (pop3->custom && pop3->custom[0] != '\0' ?
613 pop3->custom : command), pop3->id);
615 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s",
616 (pop3->custom && pop3->custom[0] != '\0' ?
617 pop3->custom : command));
620 state(conn, POP3_COMMAND);
625 /***********************************************************************
627 * pop3_perform_quit()
629 * Performs the quit action prior to sclose() be called.
631 static CURLcode pop3_perform_quit(struct connectdata *conn)
633 CURLcode result = CURLE_OK;
635 /* Send the QUIT command */
636 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "QUIT");
639 state(conn, POP3_QUIT);
644 /* For the initial server greeting */
645 static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
649 CURLcode result = CURLE_OK;
650 struct SessionHandle *data = conn->data;
651 struct pop3_conn *pop3c = &conn->proto.pop3c;
652 const char *line = data->state.buffer;
653 size_t len = strlen(line);
656 (void)instate; /* no use for this yet */
658 if(pop3code != '+') {
659 failf(data, "Got unexpected pop3-server response");
660 result = CURLE_FTP_WEIRD_SERVER_REPLY;
663 /* Does the server support APOP authentication? */
664 if(len >= 4 && line[len - 2] == '>') {
665 /* Look for the APOP timestamp */
666 for(i = 3; i < len - 2; ++i) {
668 /* Calculate the length of the timestamp */
669 size_t timestamplen = len - 1 - i;
673 /* Allocate some memory for the timestamp */
674 pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1);
676 if(!pop3c->apoptimestamp)
679 /* Copy the timestamp */
680 memcpy(pop3c->apoptimestamp, line + i, timestamplen);
681 pop3c->apoptimestamp[timestamplen] = '\0';
683 /* Store the APOP capability */
684 pop3c->authtypes |= POP3_TYPE_APOP;
690 result = pop3_perform_capa(conn);
696 /* For CAPA responses */
697 static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
700 CURLcode result = CURLE_OK;
701 struct SessionHandle *data = conn->data;
702 struct pop3_conn *pop3c = &conn->proto.pop3c;
703 const char *line = data->state.buffer;
704 size_t len = strlen(line);
707 (void)instate; /* no use for this yet */
709 /* Do we have a untagged response? */
710 if(pop3code == '*') {
711 /* Does the server support the STLS capability? */
712 if(len >= 4 && !memcmp(line, "STLS", 4))
713 pop3c->tls_supported = TRUE;
715 /* Does the server support clear text authentication? */
716 else if(len >= 4 && !memcmp(line, "USER", 4))
717 pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
719 /* Does the server support SASL based authentication? */
720 else if(len >= 5 && !memcmp(line, "SASL ", 5)) {
721 pop3c->authtypes |= POP3_TYPE_SASL;
723 /* Advance past the SASL keyword */
727 /* Loop through the data line */
730 (*line == ' ' || *line == '\t' ||
731 *line == '\r' || *line == '\n')) {
740 /* Extract the word */
741 for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
742 line[wordlen] != '\t' && line[wordlen] != '\r' &&
743 line[wordlen] != '\n';)
746 /* Test the word for a matching authentication mechanism */
747 if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
748 pop3c->authmechs |= SASL_MECH_LOGIN;
749 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
750 pop3c->authmechs |= SASL_MECH_PLAIN;
751 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
752 pop3c->authmechs |= SASL_MECH_CRAM_MD5;
753 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
754 pop3c->authmechs |= SASL_MECH_DIGEST_MD5;
755 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
756 pop3c->authmechs |= SASL_MECH_GSSAPI;
757 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
758 pop3c->authmechs |= SASL_MECH_EXTERNAL;
759 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
760 pop3c->authmechs |= SASL_MECH_NTLM;
761 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
762 pop3c->authmechs |= SASL_MECH_XOAUTH2;
769 else if(pop3code == '+') {
770 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
771 /* We don't have a SSL/TLS connection yet, but SSL is requested */
772 if(pop3c->tls_supported)
773 /* Switch to TLS connection now */
774 result = pop3_perform_starttls(conn);
775 else if(data->set.use_ssl == CURLUSESSL_TRY)
776 /* Fallback and carry on with authentication */
777 result = pop3_perform_authentication(conn);
779 failf(data, "STLS not supported.");
780 result = CURLE_USE_SSL_FAILED;
784 result = pop3_perform_authentication(conn);
787 /* Clear text is supported when CAPA isn't recognised */
788 pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
790 result = pop3_perform_authentication(conn);
796 /* For STARTTLS responses */
797 static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
801 CURLcode result = CURLE_OK;
802 struct SessionHandle *data = conn->data;
804 (void)instate; /* no use for this yet */
806 if(pop3code != '+') {
807 if(data->set.use_ssl != CURLUSESSL_TRY) {
808 failf(data, "STARTTLS denied. %c", pop3code);
809 result = CURLE_USE_SSL_FAILED;
812 result = pop3_perform_authentication(conn);
815 result = pop3_perform_upgrade_tls(conn);
820 /* For AUTH PLAIN (without initial response) responses */
821 static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn,
825 CURLcode result = CURLE_OK;
826 struct SessionHandle *data = conn->data;
828 char *plainauth = NULL;
830 (void)instate; /* no use for this yet */
832 if(pop3code != '+') {
833 failf(data, "Access denied. %c", pop3code);
834 result = CURLE_LOGIN_DENIED;
837 /* Create the authorisation message */
838 result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd,
840 if(!result && plainauth) {
841 /* Send the message */
842 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", plainauth);
845 state(conn, POP3_AUTH_FINAL);
849 Curl_safefree(plainauth);
854 /* For AUTH LOGIN (without initial response) responses */
855 static CURLcode pop3_state_auth_login_resp(struct connectdata *conn,
859 CURLcode result = CURLE_OK;
860 struct SessionHandle *data = conn->data;
862 char *authuser = NULL;
864 (void)instate; /* no use for this yet */
866 if(pop3code != '+') {
867 failf(data, "Access denied: %d", pop3code);
868 result = CURLE_LOGIN_DENIED;
871 /* Create the user message */
872 result = Curl_sasl_create_login_message(data, conn->user,
874 if(!result && authuser) {
876 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authuser);
879 state(conn, POP3_AUTH_LOGIN_PASSWD);
883 Curl_safefree(authuser);
888 /* For AUTH LOGIN user entry responses */
889 static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn,
893 CURLcode result = CURLE_OK;
894 struct SessionHandle *data = conn->data;
896 char *authpasswd = NULL;
898 (void)instate; /* no use for this yet */
900 if(pop3code != '+') {
901 failf(data, "Access denied: %d", pop3code);
902 result = CURLE_LOGIN_DENIED;
905 /* Create the password message */
906 result = Curl_sasl_create_login_message(data, conn->passwd,
908 if(!result && authpasswd) {
909 /* Send the password */
910 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authpasswd);
913 state(conn, POP3_AUTH_FINAL);
917 Curl_safefree(authpasswd);
922 #ifndef CURL_DISABLE_CRYPTO_AUTH
923 /* For AUTH CRAM-MD5 responses */
924 static CURLcode pop3_state_auth_cram_resp(struct connectdata *conn,
928 CURLcode result = CURLE_OK;
929 struct SessionHandle *data = conn->data;
932 char *rplyb64 = NULL;
935 (void)instate; /* no use for this yet */
937 if(pop3code != '+') {
938 failf(data, "Access denied: %d", pop3code);
939 return CURLE_LOGIN_DENIED;
942 /* Get the challenge message */
943 pop3_get_message(data->state.buffer, &chlg64);
945 /* Decode the challenge message */
946 result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len);
948 /* Send the cancellation */
949 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
952 state(conn, POP3_AUTH_CANCEL);
955 /* Create the response message */
956 result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user,
957 conn->passwd, &rplyb64, &len);
958 if(!result && rplyb64) {
959 /* Send the response */
960 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
963 state(conn, POP3_AUTH_FINAL);
968 Curl_safefree(rplyb64);
973 /* For AUTH DIGEST-MD5 challenge responses */
974 static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn,
978 CURLcode result = CURLE_OK;
979 struct SessionHandle *data = conn->data;
981 char *rplyb64 = NULL;
984 (void)instate; /* no use for this yet */
986 if(pop3code != '+') {
987 failf(data, "Access denied: %d", pop3code);
988 return CURLE_LOGIN_DENIED;
991 /* Get the challenge message */
992 pop3_get_message(data->state.buffer, &chlg64);
994 /* Create the response message */
995 result = Curl_sasl_create_digest_md5_message(data, chlg64,
996 conn->user, conn->passwd,
997 "pop", &rplyb64, &len);
999 if(result == CURLE_BAD_CONTENT_ENCODING) {
1000 /* Send the cancellation */
1001 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
1004 state(conn, POP3_AUTH_CANCEL);
1008 /* Send the response */
1009 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
1012 state(conn, POP3_AUTH_DIGESTMD5_RESP);
1015 Curl_safefree(rplyb64);
1020 /* For AUTH DIGEST-MD5 challenge-response responses */
1021 static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn,
1025 CURLcode result = CURLE_OK;
1026 struct SessionHandle *data = conn->data;
1028 (void)instate; /* no use for this yet */
1030 if(pop3code != '+') {
1031 failf(data, "Authentication failed: %d", pop3code);
1032 result = CURLE_LOGIN_DENIED;
1035 /* Send an empty response */
1036 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "");
1039 state(conn, POP3_AUTH_FINAL);
1047 /* For AUTH NTLM (without initial response) responses */
1048 static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn,
1052 CURLcode result = CURLE_OK;
1053 struct SessionHandle *data = conn->data;
1055 char *type1msg = NULL;
1057 (void)instate; /* no use for this yet */
1059 if(pop3code != '+') {
1060 failf(data, "Access denied: %d", pop3code);
1061 result = CURLE_LOGIN_DENIED;
1064 /* Create the type-1 message */
1065 result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
1068 if(!result && type1msg) {
1069 /* Send the message */
1070 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type1msg);
1073 state(conn, POP3_AUTH_NTLM_TYPE2MSG);
1077 Curl_safefree(type1msg);
1082 /* For NTLM type-2 responses (sent in reponse to our type-1 message) */
1083 static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn,
1087 CURLcode result = CURLE_OK;
1088 struct SessionHandle *data = conn->data;
1089 char *type2msg = NULL;
1090 char *type3msg = NULL;
1093 (void)instate; /* no use for this yet */
1095 if(pop3code != '+') {
1096 failf(data, "Access denied: %d", pop3code);
1097 result = CURLE_LOGIN_DENIED;
1100 /* Get the type-2 message */
1101 pop3_get_message(data->state.buffer, &type2msg);
1103 /* Decode the type-2 message */
1104 result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm);
1106 /* Send the cancellation */
1107 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
1110 state(conn, POP3_AUTH_CANCEL);
1113 /* Create the type-3 message */
1114 result = Curl_sasl_create_ntlm_type3_message(data, conn->user,
1115 conn->passwd, &conn->ntlm,
1117 if(!result && type3msg) {
1118 /* Send the message */
1119 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type3msg);
1122 state(conn, POP3_AUTH_FINAL);
1127 Curl_safefree(type3msg);
1133 #if defined(USE_KERBEROS5)
1134 /* For AUTH GSSAPI (without initial response) responses */
1135 static CURLcode pop3_state_auth_gssapi_resp(struct connectdata *conn,
1139 CURLcode result = CURLE_OK;
1140 struct SessionHandle *data = conn->data;
1141 struct pop3_conn *pop3c = &conn->proto.pop3c;
1143 char *respmsg = NULL;
1145 (void)instate; /* no use for this yet */
1147 if(pop3code != '+') {
1148 failf(data, "Access denied: %d", pop3code);
1149 result = CURLE_LOGIN_DENIED;
1152 /* Create the initial response message */
1153 result = Curl_sasl_create_gssapi_user_message(data, conn->user,
1154 conn->passwd, "pop",
1158 if(!result && respmsg) {
1159 /* Send the message */
1160 result = Curl_pp_sendf(&pop3c->pp, "%s", respmsg);
1163 state(conn, POP3_AUTH_GSSAPI_TOKEN);
1167 Curl_safefree(respmsg);
1172 /* For AUTH GSSAPI user token responses */
1173 static CURLcode pop3_state_auth_gssapi_token_resp(struct connectdata *conn,
1177 CURLcode result = CURLE_OK;
1178 struct SessionHandle *data = conn->data;
1179 struct pop3_conn *pop3c = &conn->proto.pop3c;
1180 char *chlgmsg = NULL;
1181 char *respmsg = NULL;
1184 (void)instate; /* no use for this yet */
1186 if(pop3code != '+') {
1187 failf(data, "Access denied: %d", pop3code);
1188 result = CURLE_LOGIN_DENIED;
1191 /* Get the challenge message */
1192 pop3_get_message(data->state.buffer, &chlgmsg);
1194 if(pop3c->mutual_auth)
1195 /* Decode the user token challenge and create the optional response
1197 result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL,
1199 chlgmsg, &conn->krb5,
1202 /* Decode the security challenge and create the response message */
1203 result = Curl_sasl_create_gssapi_security_message(data, chlgmsg,
1208 if(result == CURLE_BAD_CONTENT_ENCODING) {
1209 /* Send the cancellation */
1210 result = Curl_pp_sendf(&pop3c->pp, "%s", "*");
1213 state(conn, POP3_AUTH_CANCEL);
1217 /* Send the response */
1219 result = Curl_pp_sendf(&pop3c->pp, "%s", respmsg);
1221 result = Curl_pp_sendf(&pop3c->pp, "%s", "");
1224 state(conn, (pop3c->mutual_auth ? POP3_AUTH_GSSAPI_NO_DATA :
1229 Curl_safefree(respmsg);
1234 /* For AUTH GSSAPI no data responses */
1235 static CURLcode pop3_state_auth_gssapi_no_data_resp(struct connectdata *conn,
1239 CURLcode result = CURLE_OK;
1240 struct SessionHandle *data = conn->data;
1241 char *chlgmsg = NULL;
1242 char *respmsg = NULL;
1245 (void)instate; /* no use for this yet */
1247 if(pop3code != '+') {
1248 failf(data, "Access denied: %d", pop3code);
1249 result = CURLE_LOGIN_DENIED;
1252 /* Get the challenge message */
1253 pop3_get_message(data->state.buffer, &chlgmsg);
1255 /* Decode the security challenge and create the security message */
1256 result = Curl_sasl_create_gssapi_security_message(data, chlgmsg,
1260 if(result == CURLE_BAD_CONTENT_ENCODING) {
1261 /* Send the cancellation */
1262 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
1265 state(conn, POP3_AUTH_CANCEL);
1269 /* Send the response */
1271 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", respmsg);
1274 state(conn, POP3_AUTH_FINAL);
1279 Curl_safefree(respmsg);
1285 /* For AUTH XOAUTH2 (without initial response) responses */
1286 static CURLcode pop3_state_auth_xoauth2_resp(struct connectdata *conn,
1287 int pop3code, pop3state instate)
1289 CURLcode result = CURLE_OK;
1290 struct SessionHandle *data = conn->data;
1292 char *xoauth = NULL;
1294 (void)instate; /* no use for this yet */
1296 if(pop3code != '+') {
1297 failf(data, "Access denied: %d", pop3code);
1298 result = CURLE_LOGIN_DENIED;
1301 /* Create the authorisation message */
1302 result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
1303 conn->xoauth2_bearer,
1305 if(!result && xoauth) {
1306 /* Send the message */
1307 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", xoauth);
1310 state(conn, POP3_AUTH_FINAL);
1314 Curl_safefree(xoauth);
1319 /* For AUTH cancellation responses */
1320 static CURLcode pop3_state_auth_cancel_resp(struct connectdata *conn,
1324 CURLcode result = CURLE_OK;
1325 struct SessionHandle *data = conn->data;
1326 struct pop3_conn *pop3c = &conn->proto.pop3c;
1327 const char *mech = NULL;
1328 char *initresp = NULL;
1330 pop3state state1 = POP3_STOP;
1331 pop3state state2 = POP3_STOP;
1334 (void)instate; /* no use for this yet */
1336 /* Remove the offending mechanism from the supported list */
1337 pop3c->authmechs ^= pop3c->authused;
1339 /* Calculate alternative SASL login details */
1340 result = pop3_calc_sasl_details(conn, &mech, &initresp, &len, &state1,
1344 /* Do we have any mechanisms left or can we fallback to another
1345 authentication type? */
1347 /* Retry SASL based authentication */
1348 result = pop3_perform_auth(conn, mech, initresp, len, state1, state2);
1350 Curl_safefree(initresp);
1352 #ifndef CURL_DISABLE_CRYPTO_AUTH
1353 else if((pop3c->authtypes & POP3_TYPE_APOP) &&
1354 (pop3c->preftype & POP3_TYPE_APOP))
1355 /* Perform APOP authentication */
1356 result = pop3_perform_apop(conn);
1358 else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) &&
1359 (pop3c->preftype & POP3_TYPE_CLEARTEXT))
1360 /* Perform clear text authentication */
1361 result = pop3_perform_user(conn);
1363 failf(data, "Authentication cancelled");
1365 result = CURLE_LOGIN_DENIED;
1372 /* For final responses in the AUTH sequence */
1373 static CURLcode pop3_state_auth_final_resp(struct connectdata *conn,
1377 CURLcode result = CURLE_OK;
1378 struct SessionHandle *data = conn->data;
1380 (void)instate; /* no use for this yet */
1382 if(pop3code != '+') {
1383 failf(data, "Authentication failed: %d", pop3code);
1384 result = CURLE_LOGIN_DENIED;
1387 /* End of connect phase */
1388 state(conn, POP3_STOP);
1393 #ifndef CURL_DISABLE_CRYPTO_AUTH
1394 /* For APOP responses */
1395 static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code,
1398 CURLcode result = CURLE_OK;
1399 struct SessionHandle *data = conn->data;
1401 (void)instate; /* no use for this yet */
1403 if(pop3code != '+') {
1404 failf(data, "Authentication failed: %d", pop3code);
1405 result = CURLE_LOGIN_DENIED;
1408 /* End of connect phase */
1409 state(conn, POP3_STOP);
1415 /* For USER responses */
1416 static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code,
1419 CURLcode result = CURLE_OK;
1420 struct SessionHandle *data = conn->data;
1422 (void)instate; /* no use for this yet */
1424 if(pop3code != '+') {
1425 failf(data, "Access denied. %c", pop3code);
1426 result = CURLE_LOGIN_DENIED;
1429 /* Send the PASS command */
1430 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s",
1431 conn->passwd ? conn->passwd : "");
1433 state(conn, POP3_PASS);
1438 /* For PASS responses */
1439 static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code,
1442 CURLcode result = CURLE_OK;
1443 struct SessionHandle *data = conn->data;
1445 (void)instate; /* no use for this yet */
1447 if(pop3code != '+') {
1448 failf(data, "Access denied. %c", pop3code);
1449 result = CURLE_LOGIN_DENIED;
1452 /* End of connect phase */
1453 state(conn, POP3_STOP);
1458 /* For command responses */
1459 static CURLcode pop3_state_command_resp(struct connectdata *conn,
1463 CURLcode result = CURLE_OK;
1464 struct SessionHandle *data = conn->data;
1465 struct POP3 *pop3 = data->req.protop;
1466 struct pop3_conn *pop3c = &conn->proto.pop3c;
1467 struct pingpong *pp = &pop3c->pp;
1469 (void)instate; /* no use for this yet */
1471 if(pop3code != '+') {
1472 state(conn, POP3_STOP);
1473 return CURLE_RECV_ERROR;
1476 /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
1477 EOB string so count this is two matching bytes. This is necessary to make
1478 the code detect the EOB if the only data than comes now is %2e CR LF like
1479 when there is no body to return. */
1482 /* But since this initial CR LF pair is not part of the actual body, we set
1483 the strip counter here so that these bytes won't be delivered. */
1486 if(pop3->transfer == FTPTRANSFER_BODY) {
1488 Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
1491 /* The header "cache" contains a bunch of data that is actually body
1492 content so send it as such. Note that there may even be additional
1493 "headers" after the body */
1495 if(!data->set.opt_no_body) {
1496 result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
1501 /* Free the cache */
1502 Curl_safefree(pp->cache);
1504 /* Reset the cache size */
1509 /* End of DO phase */
1510 state(conn, POP3_STOP);
1515 static CURLcode pop3_statemach_act(struct connectdata *conn)
1517 CURLcode result = CURLE_OK;
1518 curl_socket_t sock = conn->sock[FIRSTSOCKET];
1520 struct pop3_conn *pop3c = &conn->proto.pop3c;
1521 struct pingpong *pp = &pop3c->pp;
1524 /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */
1525 if(pop3c->state == POP3_UPGRADETLS)
1526 return pop3_perform_upgrade_tls(conn);
1528 /* Flush any data that needs to be sent */
1530 return Curl_pp_flushsend(pp);
1533 /* Read the response from the server */
1534 result = Curl_pp_readresp(sock, pp, &pop3code, &nread);
1541 /* We have now received a full POP3 server response */
1542 switch(pop3c->state) {
1543 case POP3_SERVERGREET:
1544 result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state);
1548 result = pop3_state_capa_resp(conn, pop3code, pop3c->state);
1552 result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);
1555 case POP3_AUTH_PLAIN:
1556 result = pop3_state_auth_plain_resp(conn, pop3code, pop3c->state);
1559 case POP3_AUTH_LOGIN:
1560 result = pop3_state_auth_login_resp(conn, pop3code, pop3c->state);
1563 case POP3_AUTH_LOGIN_PASSWD:
1564 result = pop3_state_auth_login_password_resp(conn, pop3code,
1568 #ifndef CURL_DISABLE_CRYPTO_AUTH
1569 case POP3_AUTH_CRAMMD5:
1570 result = pop3_state_auth_cram_resp(conn, pop3code, pop3c->state);
1573 case POP3_AUTH_DIGESTMD5:
1574 result = pop3_state_auth_digest_resp(conn, pop3code, pop3c->state);
1577 case POP3_AUTH_DIGESTMD5_RESP:
1578 result = pop3_state_auth_digest_resp_resp(conn, pop3code, pop3c->state);
1583 case POP3_AUTH_NTLM:
1584 result = pop3_state_auth_ntlm_resp(conn, pop3code, pop3c->state);
1587 case POP3_AUTH_NTLM_TYPE2MSG:
1588 result = pop3_state_auth_ntlm_type2msg_resp(conn, pop3code,
1593 #if defined(USE_KERBEROS5)
1594 case POP3_AUTH_GSSAPI:
1595 result = pop3_state_auth_gssapi_resp(conn, pop3code, pop3c->state);
1598 case POP3_AUTH_GSSAPI_TOKEN:
1599 result = pop3_state_auth_gssapi_token_resp(conn, pop3code, pop3c->state);
1602 case POP3_AUTH_GSSAPI_NO_DATA:
1603 result = pop3_state_auth_gssapi_no_data_resp(conn, pop3code,
1608 case POP3_AUTH_XOAUTH2:
1609 result = pop3_state_auth_xoauth2_resp(conn, pop3code, pop3c->state);
1612 case POP3_AUTH_CANCEL:
1613 result = pop3_state_auth_cancel_resp(conn, pop3code, pop3c->state);
1616 case POP3_AUTH_FINAL:
1617 result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state);
1620 #ifndef CURL_DISABLE_CRYPTO_AUTH
1622 result = pop3_state_apop_resp(conn, pop3code, pop3c->state);
1627 result = pop3_state_user_resp(conn, pop3code, pop3c->state);
1631 result = pop3_state_pass_resp(conn, pop3code, pop3c->state);
1635 result = pop3_state_command_resp(conn, pop3code, pop3c->state);
1639 /* fallthrough, just stop! */
1641 /* internal error */
1642 state(conn, POP3_STOP);
1645 } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp));
1650 /* Called repeatedly until done from multi.c */
1651 static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
1653 CURLcode result = CURLE_OK;
1654 struct pop3_conn *pop3c = &conn->proto.pop3c;
1656 if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
1657 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
1658 if(result || !pop3c->ssldone)
1662 result = Curl_pp_statemach(&pop3c->pp, FALSE);
1663 *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
1668 static CURLcode pop3_block_statemach(struct connectdata *conn)
1670 CURLcode result = CURLE_OK;
1671 struct pop3_conn *pop3c = &conn->proto.pop3c;
1673 while(pop3c->state != POP3_STOP && !result)
1674 result = Curl_pp_statemach(&pop3c->pp, TRUE);
1679 /* Allocate and initialize the POP3 struct for the current SessionHandle if
1681 static CURLcode pop3_init(struct connectdata *conn)
1683 CURLcode result = CURLE_OK;
1684 struct SessionHandle *data = conn->data;
1687 pop3 = data->req.protop = calloc(sizeof(struct POP3), 1);
1689 result = CURLE_OUT_OF_MEMORY;
1694 /* For the POP3 "protocol connect" and "doing" phases only */
1695 static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
1698 return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks);
1701 /***********************************************************************
1705 * This function should do everything that is to be considered a part of the
1708 * The variable 'done' points to will be TRUE if the protocol-layer connect
1709 * phase is done when this function returns, or FALSE if not.
1711 static CURLcode pop3_connect(struct connectdata *conn, bool *done)
1713 CURLcode result = CURLE_OK;
1714 struct pop3_conn *pop3c = &conn->proto.pop3c;
1715 struct pingpong *pp = &pop3c->pp;
1717 *done = FALSE; /* default to not done yet */
1719 /* We always support persistent connections in POP3 */
1720 connkeep(conn, "POP3 default");
1722 /* Set the default response time-out */
1723 pp->response_time = RESP_TIMEOUT;
1724 pp->statemach_act = pop3_statemach_act;
1725 pp->endofresp = pop3_endofresp;
1728 /* Set the default preferred authentication type and mechanism */
1729 pop3c->preftype = POP3_TYPE_ANY;
1730 pop3c->prefmech = SASL_AUTH_ANY;
1732 /* Initialise the pingpong layer */
1735 /* Parse the URL options */
1736 result = pop3_parse_url_options(conn);
1740 /* Start off waiting for the server greeting response */
1741 state(conn, POP3_SERVERGREET);
1743 result = pop3_multi_statemach(conn, done);
1748 /***********************************************************************
1752 * The DONE function. This does what needs to be done after a single DO has
1755 * Input argument is already checked for validity.
1757 static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
1760 CURLcode result = CURLE_OK;
1761 struct SessionHandle *data = conn->data;
1762 struct POP3 *pop3 = data->req.protop;
1767 /* When the easy handle is removed from the multi interface while libcurl
1768 is still trying to resolve the host name, the POP3 struct is not yet
1769 initialized. However, the removal action calls Curl_done() which in
1770 turn calls this function, so we simply return success. */
1774 connclose(conn, "POP3 done with bad status");
1775 result = status; /* use the already set error code */
1778 /* Cleanup our per-request based variables */
1779 Curl_safefree(pop3->id);
1780 Curl_safefree(pop3->custom);
1782 /* Clear the transfer mode for the next request */
1783 pop3->transfer = FTPTRANSFER_BODY;
1788 /***********************************************************************
1792 * This is the actual DO function for POP3. Get a message/listing according to
1793 * the options previously setup.
1795 static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
1798 /* This is POP3 and no proxy */
1799 CURLcode result = CURLE_OK;
1800 struct POP3 *pop3 = conn->data->req.protop;
1802 DEBUGF(infof(conn->data, "DO phase starts\n"));
1804 if(conn->data->set.opt_no_body) {
1805 /* Requested no body means no transfer */
1806 pop3->transfer = FTPTRANSFER_INFO;
1809 *dophase_done = FALSE; /* not done yet */
1811 /* Start the first command in the DO phase */
1812 result = pop3_perform_command(conn);
1816 /* Run the state-machine */
1817 result = pop3_multi_statemach(conn, dophase_done);
1819 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
1822 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1827 /***********************************************************************
1831 * This function is registered as 'curl_do' function. It decodes the path
1832 * parts etc as a wrapper to the actual DO function (pop3_perform).
1834 * The input argument is already checked for validity.
1836 static CURLcode pop3_do(struct connectdata *conn, bool *done)
1838 CURLcode result = CURLE_OK;
1840 *done = FALSE; /* default to false */
1842 /* Parse the URL path */
1843 result = pop3_parse_url_path(conn);
1847 /* Parse the custom request */
1848 result = pop3_parse_custom_request(conn);
1852 result = pop3_regular_transfer(conn, done);
1857 /***********************************************************************
1861 * Disconnect from an POP3 server. Cleanup protocol-specific per-connection
1862 * resources. BLOCKING.
1864 static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection)
1866 struct pop3_conn *pop3c = &conn->proto.pop3c;
1868 /* We cannot send quit unconditionally. If this connection is stale or
1869 bad in any way, sending quit and waiting around here will make the
1870 disconnect wait in vain and cause more problems than we need to. */
1872 /* The POP3 session may or may not have been allocated/setup at this
1874 if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart)
1875 if(!pop3_perform_quit(conn))
1876 (void)pop3_block_statemach(conn); /* ignore errors on QUIT */
1878 /* Disconnect from the server */
1879 Curl_pp_disconnect(&pop3c->pp);
1881 /* Cleanup the SASL module */
1882 Curl_sasl_cleanup(conn, pop3c->authused);
1884 /* Cleanup our connection based variables */
1885 Curl_safefree(pop3c->apoptimestamp);
1890 /* Call this when the DO phase has completed */
1891 static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected)
1899 /* Called from multi.c while DOing */
1900 static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done)
1902 CURLcode result = pop3_multi_statemach(conn, dophase_done);
1905 DEBUGF(infof(conn->data, "DO phase failed\n"));
1906 else if(*dophase_done) {
1907 result = pop3_dophase_done(conn, FALSE /* not connected */);
1909 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1915 /***********************************************************************
1917 * pop3_regular_transfer()
1919 * The input argument is already checked for validity.
1921 * Performs all commands done before a regular transfer between a local and a
1924 static CURLcode pop3_regular_transfer(struct connectdata *conn,
1927 CURLcode result = CURLE_OK;
1928 bool connected = FALSE;
1929 struct SessionHandle *data = conn->data;
1931 /* Make sure size is unknown at this point */
1932 data->req.size = -1;
1934 /* Set the progress data */
1935 Curl_pgrsSetUploadCounter(data, 0);
1936 Curl_pgrsSetDownloadCounter(data, 0);
1937 Curl_pgrsSetUploadSize(data, -1);
1938 Curl_pgrsSetDownloadSize(data, -1);
1940 /* Carry out the perform */
1941 result = pop3_perform(conn, &connected, dophase_done);
1943 /* Perform post DO phase operations if necessary */
1944 if(!result && *dophase_done)
1945 result = pop3_dophase_done(conn, connected);
1950 static CURLcode pop3_setup_connection(struct connectdata *conn)
1952 struct SessionHandle *data = conn->data;
1954 /* Initialise the POP3 layer */
1955 CURLcode result = pop3_init(conn);
1959 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
1960 /* Unless we have asked to tunnel POP3 operations through the proxy, we
1961 switch and use HTTP operations only */
1962 #ifndef CURL_DISABLE_HTTP
1963 if(conn->handler == &Curl_handler_pop3)
1964 conn->handler = &Curl_handler_pop3_proxy;
1967 conn->handler = &Curl_handler_pop3s_proxy;
1969 failf(data, "POP3S not supported!");
1970 return CURLE_UNSUPPORTED_PROTOCOL;
1974 /* set it up as an HTTP connection instead */
1975 return conn->handler->setup_connection(conn);
1977 failf(data, "POP3 over http proxy requires HTTP support built-in!");
1978 return CURLE_UNSUPPORTED_PROTOCOL;
1982 data->state.path++; /* don't include the initial slash */
1987 /***********************************************************************
1989 * pop3_parse_url_options()
1991 * Parse the URL login options.
1993 static CURLcode pop3_parse_url_options(struct connectdata *conn)
1995 CURLcode result = CURLE_OK;
1996 struct pop3_conn *pop3c = &conn->proto.pop3c;
1997 const char *options = conn->options;
1998 const char *ptr = options;
2001 while(ptr && *ptr) {
2002 const char *key = ptr;
2004 while(*ptr && *ptr != '=')
2007 if(strnequal(key, "AUTH", 4)) {
2009 const char *value = ++ptr;
2013 pop3c->preftype = POP3_TYPE_NONE;
2014 pop3c->prefmech = SASL_AUTH_NONE;
2017 while(*ptr && *ptr != ';') {
2022 if(strnequal(value, "*", len)) {
2023 pop3c->preftype = POP3_TYPE_ANY;
2024 pop3c->prefmech = SASL_AUTH_ANY;
2026 else if(strnequal(value, "+APOP", len)) {
2027 pop3c->preftype = POP3_TYPE_APOP;
2028 pop3c->prefmech = SASL_AUTH_NONE;
2030 else if(strnequal(value, SASL_MECH_STRING_LOGIN, len)) {
2031 pop3c->preftype = POP3_TYPE_SASL;
2032 pop3c->prefmech |= SASL_MECH_LOGIN;
2034 else if(strnequal(value, SASL_MECH_STRING_PLAIN, len)) {
2035 pop3c->preftype = POP3_TYPE_SASL;
2036 pop3c->prefmech |= SASL_MECH_PLAIN;
2038 else if(strnequal(value, SASL_MECH_STRING_CRAM_MD5, len)) {
2039 pop3c->preftype = POP3_TYPE_SASL;
2040 pop3c->prefmech |= SASL_MECH_CRAM_MD5;
2042 else if(strnequal(value, SASL_MECH_STRING_DIGEST_MD5, len)) {
2043 pop3c->preftype = POP3_TYPE_SASL;
2044 pop3c->prefmech |= SASL_MECH_DIGEST_MD5;
2046 else if(strnequal(value, SASL_MECH_STRING_GSSAPI, len)) {
2047 pop3c->preftype = POP3_TYPE_SASL;
2048 pop3c->prefmech |= SASL_MECH_GSSAPI;
2050 else if(strnequal(value, SASL_MECH_STRING_NTLM, len)) {
2051 pop3c->preftype = POP3_TYPE_SASL;
2052 pop3c->prefmech |= SASL_MECH_NTLM;
2054 else if(strnequal(value, SASL_MECH_STRING_XOAUTH2, len)) {
2055 pop3c->preftype = POP3_TYPE_SASL;
2056 pop3c->prefmech |= SASL_MECH_XOAUTH2;
2063 result = CURLE_URL_MALFORMAT;
2069 /***********************************************************************
2071 * pop3_parse_url_path()
2073 * Parse the URL path into separate path components.
2075 static CURLcode pop3_parse_url_path(struct connectdata *conn)
2077 /* The POP3 struct is already initialised in pop3_connect() */
2078 struct SessionHandle *data = conn->data;
2079 struct POP3 *pop3 = data->req.protop;
2080 const char *path = data->state.path;
2082 /* URL decode the path for the message ID */
2083 return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);
2086 /***********************************************************************
2088 * pop3_parse_custom_request()
2090 * Parse the custom request.
2092 static CURLcode pop3_parse_custom_request(struct connectdata *conn)
2094 CURLcode result = CURLE_OK;
2095 struct SessionHandle *data = conn->data;
2096 struct POP3 *pop3 = data->req.protop;
2097 const char *custom = data->set.str[STRING_CUSTOMREQUEST];
2099 /* URL decode the custom request */
2101 result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE);
2106 /***********************************************************************
2108 * pop3_calc_sasl_details()
2110 * Calculate the required login details for SASL authentication.
2112 static CURLcode pop3_calc_sasl_details(struct connectdata *conn,
2114 char **initresp, size_t *len,
2115 pop3state *state1, pop3state *state2)
2117 CURLcode result = CURLE_OK;
2118 struct SessionHandle *data = conn->data;
2119 struct pop3_conn *pop3c = &conn->proto.pop3c;
2121 /* Calculate the supported authentication mechanism, by decreasing order of
2122 security, as well as the initial response where appropriate */
2123 #if defined(USE_KERBEROS5)
2124 if((pop3c->authmechs & SASL_MECH_GSSAPI) &&
2125 (pop3c->prefmech & SASL_MECH_GSSAPI)) {
2126 pop3c->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */
2128 *mech = SASL_MECH_STRING_GSSAPI;
2129 *state1 = POP3_AUTH_GSSAPI;
2130 *state2 = POP3_AUTH_GSSAPI_TOKEN;
2131 pop3c->authused = SASL_MECH_GSSAPI;
2133 if(data->set.sasl_ir)
2134 result = Curl_sasl_create_gssapi_user_message(data, conn->user,
2135 conn->passwd, "pop",
2142 #ifndef CURL_DISABLE_CRYPTO_AUTH
2143 if((pop3c->authmechs & SASL_MECH_DIGEST_MD5) &&
2144 (pop3c->prefmech & SASL_MECH_DIGEST_MD5)) {
2145 *mech = SASL_MECH_STRING_DIGEST_MD5;
2146 *state1 = POP3_AUTH_DIGESTMD5;
2147 pop3c->authused = SASL_MECH_DIGEST_MD5;
2149 else if((pop3c->authmechs & SASL_MECH_CRAM_MD5) &&
2150 (pop3c->prefmech & SASL_MECH_CRAM_MD5)) {
2151 *mech = SASL_MECH_STRING_CRAM_MD5;
2152 *state1 = POP3_AUTH_CRAMMD5;
2153 pop3c->authused = SASL_MECH_CRAM_MD5;
2158 if((pop3c->authmechs & SASL_MECH_NTLM) &&
2159 (pop3c->prefmech & SASL_MECH_NTLM)) {
2160 *mech = SASL_MECH_STRING_NTLM;
2161 *state1 = POP3_AUTH_NTLM;
2162 *state2 = POP3_AUTH_NTLM_TYPE2MSG;
2163 pop3c->authused = SASL_MECH_NTLM;
2165 if(data->set.sasl_ir)
2166 result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
2172 if(((pop3c->authmechs & SASL_MECH_XOAUTH2) &&
2173 (pop3c->prefmech & SASL_MECH_XOAUTH2) &&
2174 (pop3c->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
2175 *mech = SASL_MECH_STRING_XOAUTH2;
2176 *state1 = POP3_AUTH_XOAUTH2;
2177 *state2 = POP3_AUTH_FINAL;
2178 pop3c->authused = SASL_MECH_XOAUTH2;
2180 if(data->set.sasl_ir)
2181 result = Curl_sasl_create_xoauth2_message(data, conn->user,
2182 conn->xoauth2_bearer,
2185 else if((pop3c->authmechs & SASL_MECH_LOGIN) &&
2186 (pop3c->prefmech & SASL_MECH_LOGIN)) {
2187 *mech = SASL_MECH_STRING_LOGIN;
2188 *state1 = POP3_AUTH_LOGIN;
2189 *state2 = POP3_AUTH_LOGIN_PASSWD;
2190 pop3c->authused = SASL_MECH_LOGIN;
2192 if(data->set.sasl_ir)
2193 result = Curl_sasl_create_login_message(data, conn->user, initresp, len);
2195 else if((pop3c->authmechs & SASL_MECH_PLAIN) &&
2196 (pop3c->prefmech & SASL_MECH_PLAIN)) {
2197 *mech = SASL_MECH_STRING_PLAIN;
2198 *state1 = POP3_AUTH_PLAIN;
2199 *state2 = POP3_AUTH_FINAL;
2200 pop3c->authused = SASL_MECH_PLAIN;
2202 if(data->set.sasl_ir)
2203 result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd,
2210 /***********************************************************************
2214 * This function scans the body after the end-of-body and writes everything
2215 * until the end is found.
2217 CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
2219 /* This code could be made into a special function in the handler struct */
2220 CURLcode result = CURLE_OK;
2221 struct SessionHandle *data = conn->data;
2222 struct SingleRequest *k = &data->req;
2224 struct pop3_conn *pop3c = &conn->proto.pop3c;
2225 bool strip_dot = FALSE;
2229 /* Search through the buffer looking for the end-of-body marker which is
2230 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
2231 the eob so the server will have prefixed it with an extra dot which we
2232 need to strip out. Additionally the marker could of course be spread out
2233 over 5 different data chunks. */
2234 for(i = 0; i < nread; i++) {
2235 size_t prev = pop3c->eob;
2239 if(pop3c->eob == 0) {
2243 /* Write out the body part that didn't match */
2244 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
2253 else if(pop3c->eob == 3)
2256 /* If the character match wasn't at position 0 or 3 then restart the
2262 if(pop3c->eob == 1 || pop3c->eob == 4)
2265 /* If the character match wasn't at position 1 or 4 then start the
2273 else if(pop3c->eob == 3) {
2274 /* We have an extra dot after the CRLF which we need to strip off */
2279 /* If the character match wasn't at position 2 then start the search
2289 /* Did we have a partial match which has subsequently failed? */
2290 if(prev && prev >= pop3c->eob) {
2291 /* Strip can only be non-zero for the very first mismatch after CRLF
2292 and then both prev and strip are equal and nothing will be output
2294 while(prev && pop3c->strip) {
2300 /* If the partial match was the CRLF and dot then only write the CRLF
2301 as the server would have inserted the dot */
2302 result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB,
2303 strip_dot ? prev - 1 : prev);
2314 if(pop3c->eob == POP3_EOB_LEN) {
2315 /* We have a full match so the transfer is done, however we must transfer
2316 the CRLF at the start of the EOB as this is considered to be part of the
2317 message as per RFC-1939, sect. 3 */
2318 result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
2320 k->keepon &= ~KEEP_RECV;
2327 /* While EOB is matching nothing should be output */
2331 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
2338 #endif /* CURL_DISABLE_POP3 */