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 * RFC4422 Simple Authentication and Security Layer (SASL)
29 * RFC4616 PLAIN authentication
30 * RFC5034 POP3 SASL Authentication Mechanism
31 * RFC6749 OAuth 2.0 Authorization Framework
32 * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
34 ***************************************************************************/
36 #include "curl_setup.h"
38 #ifndef CURL_DISABLE_POP3
40 #ifdef HAVE_NETINET_IN_H
41 #include <netinet/in.h>
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
47 #include <sys/utsname.h>
57 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
59 #define in_addr_t unsigned long
62 #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_POP3 | 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",
334 if(pop3c->state != newstate)
335 infof(conn->data, "POP3 %p state change from %s to %s\n",
336 (void *)pop3c, names[pop3c->state], names[newstate]);
339 pop3c->state = newstate;
342 /***********************************************************************
344 * pop3_perform_capa()
346 * Sends the CAPA command in order to obtain a list of server side supported
349 static CURLcode pop3_perform_capa(struct connectdata *conn)
351 CURLcode result = CURLE_OK;
352 struct pop3_conn *pop3c = &conn->proto.pop3c;
354 pop3c->authmechs = 0; /* No known authentication mechanisms yet */
355 pop3c->authused = 0; /* Clear the authentication mechanism used */
356 pop3c->tls_supported = FALSE; /* Clear the TLS capability */
358 /* Send the CAPA command */
359 result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA");
362 state(conn, POP3_CAPA);
367 /***********************************************************************
369 * pop3_perform_starttls()
371 * Sends the STLS command to start the upgrade to TLS.
373 static CURLcode pop3_perform_starttls(struct connectdata *conn)
375 CURLcode result = CURLE_OK;
377 /* Send the STLS command */
378 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "STLS");
381 state(conn, POP3_STARTTLS);
386 /***********************************************************************
388 * pop3_perform_upgrade_tls()
390 * Performs the upgrade to TLS.
392 static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn)
394 CURLcode result = CURLE_OK;
395 struct pop3_conn *pop3c = &conn->proto.pop3c;
397 /* Start the SSL connection */
398 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
401 if(pop3c->state != POP3_UPGRADETLS)
402 state(conn, POP3_UPGRADETLS);
406 result = pop3_perform_capa(conn);
413 /***********************************************************************
415 * pop3_perform_user()
417 * Sends a clear text USER command to authenticate with.
419 static CURLcode pop3_perform_user(struct connectdata *conn)
421 CURLcode result = CURLE_OK;
423 /* Check we have a username and password to authenticate with and end the
424 connect phase if we don't */
425 if(!conn->bits.user_passwd) {
426 state(conn, POP3_STOP);
431 /* Send the USER command */
432 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s",
433 conn->user ? conn->user : "");
435 state(conn, POP3_USER);
440 #ifndef CURL_DISABLE_CRYPTO_AUTH
441 /***********************************************************************
443 * pop3_perform_apop()
445 * Sends an APOP command to authenticate with.
447 static CURLcode pop3_perform_apop(struct connectdata *conn)
449 CURLcode result = CURLE_OK;
450 struct pop3_conn *pop3c = &conn->proto.pop3c;
453 unsigned char digest[MD5_DIGEST_LEN];
454 char secret[2 * MD5_DIGEST_LEN + 1];
456 /* Check we have a username and password to authenticate with and end the
457 connect phase if we don't */
458 if(!conn->bits.user_passwd) {
459 state(conn, POP3_STOP);
464 /* Create the digest */
465 ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
467 return CURLE_OUT_OF_MEMORY;
469 Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp,
470 curlx_uztoui(strlen(pop3c->apoptimestamp)));
472 Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd,
473 curlx_uztoui(strlen(conn->passwd)));
475 /* Finalise the digest */
476 Curl_MD5_final(ctxt, digest);
478 /* Convert the calculated 16 octet digest into a 32 byte hex string */
479 for(i = 0; i < MD5_DIGEST_LEN; i++)
480 snprintf(&secret[2 * i], 3, "%02x", digest[i]);
482 result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret);
485 state(conn, POP3_APOP);
491 /***********************************************************************
493 * pop3_perform_auth()
495 * Sends an AUTH command allowing the client to login with the given SASL
496 * authentication mechanism.
498 static CURLcode pop3_perform_auth(struct connectdata *conn,
500 const char *initresp, size_t len,
501 pop3state state1, pop3state state2)
503 CURLcode result = CURLE_OK;
504 struct pop3_conn *pop3c = &conn->proto.pop3c;
506 if(initresp && 8 + strlen(mech) + len <= 255) { /* AUTH <mech> ...<crlf> */
507 /* Send the AUTH command with the initial response */
508 result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp);
514 /* Send the AUTH command */
515 result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
524 /***********************************************************************
526 * pop3_perform_authentication()
528 * Initiates the authentication sequence, with the appropriate SASL
529 * authentication mechanism, falling back to APOP and clear text should a
530 * common mechanism not be available between the client and server.
532 static CURLcode pop3_perform_authentication(struct connectdata *conn)
534 CURLcode result = CURLE_OK;
535 struct pop3_conn *pop3c = &conn->proto.pop3c;
536 const char *mech = NULL;
537 char *initresp = NULL;
539 pop3state state1 = POP3_STOP;
540 pop3state state2 = POP3_STOP;
542 /* Check we have a username and password to authenticate with and end the
543 connect phase if we don't */
544 if(!conn->bits.user_passwd) {
545 state(conn, POP3_STOP);
550 /* Calculate the SASL login details */
551 if(pop3c->authtypes & POP3_TYPE_SASL)
552 result = pop3_calc_sasl_details(conn, &mech, &initresp, &len, &state1,
556 if(mech && (pop3c->preftype & POP3_TYPE_SASL)) {
557 /* Perform SASL based authentication */
558 result = pop3_perform_auth(conn, mech, initresp, len, state1, state2);
560 Curl_safefree(initresp);
562 #ifndef CURL_DISABLE_CRYPTO_AUTH
563 else if((pop3c->authtypes & POP3_TYPE_APOP) &&
564 (pop3c->preftype & POP3_TYPE_APOP))
565 /* Perform APOP authentication */
566 result = pop3_perform_apop(conn);
568 else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) &&
569 (pop3c->preftype & POP3_TYPE_CLEARTEXT))
570 /* Perform clear text authentication */
571 result = pop3_perform_user(conn);
573 /* Other mechanisms not supported */
574 infof(conn->data, "No known authentication mechanisms supported!\n");
575 result = CURLE_LOGIN_DENIED;
582 /***********************************************************************
584 * pop3_perform_command()
586 * Sends a POP3 based command.
588 static CURLcode pop3_perform_command(struct connectdata *conn)
590 CURLcode result = CURLE_OK;
591 struct SessionHandle *data = conn->data;
592 struct POP3 *pop3 = data->req.protop;
593 const char *command = NULL;
595 /* Calculate the default command */
596 if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) {
599 if(pop3->id[0] != '\0')
600 /* Message specific LIST so skip the BODY transfer */
601 pop3->transfer = FTPTRANSFER_INFO;
606 /* Send the command */
607 if(pop3->id[0] != '\0')
608 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s",
609 (pop3->custom && pop3->custom[0] != '\0' ?
610 pop3->custom : command), pop3->id);
612 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s",
613 (pop3->custom && pop3->custom[0] != '\0' ?
614 pop3->custom : command));
617 state(conn, POP3_COMMAND);
622 /***********************************************************************
624 * pop3_perform_quit()
626 * Performs the quit action prior to sclose() be called.
628 static CURLcode pop3_perform_quit(struct connectdata *conn)
630 CURLcode result = CURLE_OK;
632 /* Send the QUIT command */
633 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "QUIT");
636 state(conn, POP3_QUIT);
641 /* For the initial server greeting */
642 static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
646 CURLcode result = CURLE_OK;
647 struct SessionHandle *data = conn->data;
648 struct pop3_conn *pop3c = &conn->proto.pop3c;
649 const char *line = data->state.buffer;
650 size_t len = strlen(line);
653 (void)instate; /* no use for this yet */
655 if(pop3code != '+') {
656 failf(data, "Got unexpected pop3-server response");
657 result = CURLE_FTP_WEIRD_SERVER_REPLY;
660 /* Does the server support APOP authentication? */
661 if(len >= 4 && line[len - 2] == '>') {
662 /* Look for the APOP timestamp */
663 for(i = 3; i < len - 2; ++i) {
665 /* Calculate the length of the timestamp */
666 size_t timestamplen = len - 1 - i;
670 /* Allocate some memory for the timestamp */
671 pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1);
673 if(!pop3c->apoptimestamp)
676 /* Copy the timestamp */
677 memcpy(pop3c->apoptimestamp, line + i, timestamplen);
678 pop3c->apoptimestamp[timestamplen] = '\0';
680 /* Store the APOP capability */
681 pop3c->authtypes |= POP3_TYPE_APOP;
687 result = pop3_perform_capa(conn);
693 /* For CAPA responses */
694 static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
697 CURLcode result = CURLE_OK;
698 struct SessionHandle *data = conn->data;
699 struct pop3_conn *pop3c = &conn->proto.pop3c;
700 const char *line = data->state.buffer;
701 size_t len = strlen(line);
704 (void)instate; /* no use for this yet */
706 /* Do we have a untagged response? */
707 if(pop3code == '*') {
708 /* Does the server support the STLS capability? */
709 if(len >= 4 && !memcmp(line, "STLS", 4))
710 pop3c->tls_supported = TRUE;
712 /* Does the server support clear text authentication? */
713 else if(len >= 4 && !memcmp(line, "USER", 4))
714 pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
716 /* Does the server support SASL based authentication? */
717 else if(len >= 5 && !memcmp(line, "SASL ", 5)) {
718 pop3c->authtypes |= POP3_TYPE_SASL;
720 /* Advance past the SASL keyword */
724 /* Loop through the data line */
727 (*line == ' ' || *line == '\t' ||
728 *line == '\r' || *line == '\n')) {
737 /* Extract the word */
738 for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
739 line[wordlen] != '\t' && line[wordlen] != '\r' &&
740 line[wordlen] != '\n';)
743 /* Test the word for a matching authentication mechanism */
744 if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
745 pop3c->authmechs |= SASL_MECH_LOGIN;
746 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
747 pop3c->authmechs |= SASL_MECH_PLAIN;
748 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
749 pop3c->authmechs |= SASL_MECH_CRAM_MD5;
750 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
751 pop3c->authmechs |= SASL_MECH_DIGEST_MD5;
752 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
753 pop3c->authmechs |= SASL_MECH_GSSAPI;
754 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
755 pop3c->authmechs |= SASL_MECH_EXTERNAL;
756 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
757 pop3c->authmechs |= SASL_MECH_NTLM;
758 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
759 pop3c->authmechs |= SASL_MECH_XOAUTH2;
766 else if(pop3code == '+') {
767 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
768 /* We don't have a SSL/TLS connection yet, but SSL is requested */
769 if(pop3c->tls_supported)
770 /* Switch to TLS connection now */
771 result = pop3_perform_starttls(conn);
772 else if(data->set.use_ssl == CURLUSESSL_TRY)
773 /* Fallback and carry on with authentication */
774 result = pop3_perform_authentication(conn);
776 failf(data, "STLS not supported.");
777 result = CURLE_USE_SSL_FAILED;
781 result = pop3_perform_authentication(conn);
784 result = pop3_perform_user(conn);
789 /* For STARTTLS responses */
790 static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
794 CURLcode result = CURLE_OK;
795 struct SessionHandle *data = conn->data;
797 (void)instate; /* no use for this yet */
799 if(pop3code != '+') {
800 if(data->set.use_ssl != CURLUSESSL_TRY) {
801 failf(data, "STARTTLS denied. %c", pop3code);
802 result = CURLE_USE_SSL_FAILED;
805 result = pop3_perform_authentication(conn);
808 result = pop3_perform_upgrade_tls(conn);
813 /* For AUTH PLAIN (without initial response) responses */
814 static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn,
818 CURLcode result = CURLE_OK;
819 struct SessionHandle *data = conn->data;
821 char *plainauth = NULL;
823 (void)instate; /* no use for this yet */
825 if(pop3code != '+') {
826 failf(data, "Access denied. %c", pop3code);
827 result = CURLE_LOGIN_DENIED;
830 /* Create the authorisation message */
831 result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd,
833 if(!result && plainauth) {
834 /* Send the message */
835 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", plainauth);
838 state(conn, POP3_AUTH_FINAL);
842 Curl_safefree(plainauth);
847 /* For AUTH LOGIN (without initial response) responses */
848 static CURLcode pop3_state_auth_login_resp(struct connectdata *conn,
852 CURLcode result = CURLE_OK;
853 struct SessionHandle *data = conn->data;
855 char *authuser = NULL;
857 (void)instate; /* no use for this yet */
859 if(pop3code != '+') {
860 failf(data, "Access denied: %d", pop3code);
861 result = CURLE_LOGIN_DENIED;
864 /* Create the user message */
865 result = Curl_sasl_create_login_message(data, conn->user,
867 if(!result && authuser) {
869 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authuser);
872 state(conn, POP3_AUTH_LOGIN_PASSWD);
876 Curl_safefree(authuser);
881 /* For AUTH LOGIN user entry responses */
882 static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn,
886 CURLcode result = CURLE_OK;
887 struct SessionHandle *data = conn->data;
889 char *authpasswd = NULL;
891 (void)instate; /* no use for this yet */
893 if(pop3code != '+') {
894 failf(data, "Access denied: %d", pop3code);
895 result = CURLE_LOGIN_DENIED;
898 /* Create the password message */
899 result = Curl_sasl_create_login_message(data, conn->passwd,
901 if(!result && authpasswd) {
902 /* Send the password */
903 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authpasswd);
906 state(conn, POP3_AUTH_FINAL);
910 Curl_safefree(authpasswd);
915 #ifndef CURL_DISABLE_CRYPTO_AUTH
916 /* For AUTH CRAM-MD5 responses */
917 static CURLcode pop3_state_auth_cram_resp(struct connectdata *conn,
921 CURLcode result = CURLE_OK;
922 struct SessionHandle *data = conn->data;
925 char *rplyb64 = NULL;
928 (void)instate; /* no use for this yet */
930 if(pop3code != '+') {
931 failf(data, "Access denied: %d", pop3code);
932 return CURLE_LOGIN_DENIED;
935 /* Get the challenge message */
936 pop3_get_message(data->state.buffer, &chlg64);
938 /* Decode the challenge message */
939 result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len);
941 /* Send the cancellation */
942 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
945 state(conn, POP3_AUTH_CANCEL);
948 /* Create the response message */
949 result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user,
950 conn->passwd, &rplyb64, &len);
951 if(!result && rplyb64) {
952 /* Send the response */
953 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
956 state(conn, POP3_AUTH_FINAL);
961 Curl_safefree(rplyb64);
966 /* For AUTH DIGEST-MD5 challenge responses */
967 static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn,
971 CURLcode result = CURLE_OK;
972 struct SessionHandle *data = conn->data;
974 char *rplyb64 = NULL;
981 (void)instate; /* no use for this yet */
983 if(pop3code != '+') {
984 failf(data, "Access denied: %d", pop3code);
985 return CURLE_LOGIN_DENIED;
988 /* Get the challenge message */
989 pop3_get_message(data->state.buffer, &chlg64);
991 /* Decode the challange message */
992 result = Curl_sasl_decode_digest_md5_message(chlg64, nonce, sizeof(nonce),
993 realm, sizeof(realm),
994 algorithm, sizeof(algorithm));
995 if(result || strcmp(algorithm, "md5-sess") != 0) {
996 /* Send the cancellation */
997 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
1000 state(conn, POP3_AUTH_CANCEL);
1003 /* Create the response message */
1004 result = Curl_sasl_create_digest_md5_message(data, nonce, realm,
1005 conn->user, conn->passwd,
1006 "pop", &rplyb64, &len);
1007 if(!result && rplyb64) {
1008 /* Send the response */
1009 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
1012 state(conn, POP3_AUTH_DIGESTMD5_RESP);
1016 Curl_safefree(rplyb64);
1021 /* For AUTH DIGEST-MD5 challenge-response responses */
1022 static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn,
1026 CURLcode result = CURLE_OK;
1027 struct SessionHandle *data = conn->data;
1029 (void)instate; /* no use for this yet */
1031 if(pop3code != '+') {
1032 failf(data, "Authentication failed: %d", pop3code);
1033 result = CURLE_LOGIN_DENIED;
1036 /* Send an empty response */
1037 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "");
1040 state(conn, POP3_AUTH_FINAL);
1048 /* For AUTH NTLM (without initial response) responses */
1049 static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn,
1053 CURLcode result = CURLE_OK;
1054 struct SessionHandle *data = conn->data;
1056 char *type1msg = NULL;
1058 (void)instate; /* no use for this yet */
1060 if(pop3code != '+') {
1061 failf(data, "Access denied: %d", pop3code);
1062 result = CURLE_LOGIN_DENIED;
1065 /* Create the type-1 message */
1066 result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
1069 if(!result && type1msg) {
1070 /* Send the message */
1071 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type1msg);
1074 state(conn, POP3_AUTH_NTLM_TYPE2MSG);
1078 Curl_safefree(type1msg);
1083 /* For NTLM type-2 responses (sent in reponse to our type-1 message) */
1084 static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn,
1088 CURLcode result = CURLE_OK;
1089 struct SessionHandle *data = conn->data;
1090 char *type2msg = NULL;
1091 char *type3msg = NULL;
1094 (void)instate; /* no use for this yet */
1096 if(pop3code != '+') {
1097 failf(data, "Access denied: %d", pop3code);
1098 result = CURLE_LOGIN_DENIED;
1101 /* Get the type-2 message */
1102 pop3_get_message(data->state.buffer, &type2msg);
1104 /* Decode the type-2 message */
1105 result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm);
1107 /* Send the cancellation */
1108 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
1111 state(conn, POP3_AUTH_CANCEL);
1114 /* Create the type-3 message */
1115 result = Curl_sasl_create_ntlm_type3_message(data, conn->user,
1116 conn->passwd, &conn->ntlm,
1118 if(!result && type3msg) {
1119 /* Send the message */
1120 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type3msg);
1123 state(conn, POP3_AUTH_FINAL);
1128 Curl_safefree(type3msg);
1134 /* For AUTH XOAUTH2 (without initial response) responses */
1135 static CURLcode pop3_state_auth_xoauth2_resp(struct connectdata *conn,
1136 int pop3code, pop3state instate)
1138 CURLcode result = CURLE_OK;
1139 struct SessionHandle *data = conn->data;
1141 char *xoauth = NULL;
1143 (void)instate; /* no use for this yet */
1145 if(pop3code != '+') {
1146 failf(data, "Access denied: %d", pop3code);
1147 result = CURLE_LOGIN_DENIED;
1150 /* Create the authorisation message */
1151 result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
1152 conn->xoauth2_bearer,
1154 if(!result && xoauth) {
1155 /* Send the message */
1156 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", xoauth);
1159 state(conn, POP3_AUTH_FINAL);
1163 Curl_safefree(xoauth);
1168 /* For AUTH cancellation responses */
1169 static CURLcode pop3_state_auth_cancel_resp(struct connectdata *conn,
1173 CURLcode result = CURLE_OK;
1174 struct SessionHandle *data = conn->data;
1175 struct pop3_conn *pop3c = &conn->proto.pop3c;
1176 const char *mech = NULL;
1177 char *initresp = NULL;
1179 pop3state state1 = POP3_STOP;
1180 pop3state state2 = POP3_STOP;
1183 (void)instate; /* no use for this yet */
1185 /* Remove the offending mechanism from the supported list */
1186 pop3c->authmechs ^= pop3c->authused;
1188 /* Calculate alternative SASL login details */
1189 result = pop3_calc_sasl_details(conn, &mech, &initresp, &len, &state1,
1193 /* Do we have any mechanisms left or can we fallback to another
1194 authentication type? */
1196 /* Retry SASL based authentication */
1197 result = pop3_perform_auth(conn, mech, initresp, len, state1, state2);
1199 Curl_safefree(initresp);
1201 #ifndef CURL_DISABLE_CRYPTO_AUTH
1202 else if((pop3c->authtypes & POP3_TYPE_APOP) &&
1203 (pop3c->preftype & POP3_TYPE_APOP))
1204 /* Perform APOP authentication */
1205 result = pop3_perform_apop(conn);
1207 else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) &&
1208 (pop3c->preftype & POP3_TYPE_CLEARTEXT))
1209 /* Perform clear text authentication */
1210 result = pop3_perform_user(conn);
1212 failf(data, "Authentication cancelled");
1214 result = CURLE_LOGIN_DENIED;
1221 /* For final responses in the AUTH sequence */
1222 static CURLcode pop3_state_auth_final_resp(struct connectdata *conn,
1226 CURLcode result = CURLE_OK;
1227 struct SessionHandle *data = conn->data;
1229 (void)instate; /* no use for this yet */
1231 if(pop3code != '+') {
1232 failf(data, "Authentication failed: %d", pop3code);
1233 result = CURLE_LOGIN_DENIED;
1236 /* End of connect phase */
1237 state(conn, POP3_STOP);
1242 #ifndef CURL_DISABLE_CRYPTO_AUTH
1243 /* For APOP responses */
1244 static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code,
1247 CURLcode result = CURLE_OK;
1248 struct SessionHandle *data = conn->data;
1250 (void)instate; /* no use for this yet */
1252 if(pop3code != '+') {
1253 failf(data, "Authentication failed: %d", pop3code);
1254 result = CURLE_LOGIN_DENIED;
1257 /* End of connect phase */
1258 state(conn, POP3_STOP);
1264 /* For USER responses */
1265 static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code,
1268 CURLcode result = CURLE_OK;
1269 struct SessionHandle *data = conn->data;
1271 (void)instate; /* no use for this yet */
1273 if(pop3code != '+') {
1274 failf(data, "Access denied. %c", pop3code);
1275 result = CURLE_LOGIN_DENIED;
1278 /* Send the PASS command */
1279 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s",
1280 conn->passwd ? conn->passwd : "");
1282 state(conn, POP3_PASS);
1287 /* For PASS responses */
1288 static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code,
1291 CURLcode result = CURLE_OK;
1292 struct SessionHandle *data = conn->data;
1294 (void)instate; /* no use for this yet */
1296 if(pop3code != '+') {
1297 failf(data, "Access denied. %c", pop3code);
1298 result = CURLE_LOGIN_DENIED;
1301 /* End of connect phase */
1302 state(conn, POP3_STOP);
1307 /* For command responses */
1308 static CURLcode pop3_state_command_resp(struct connectdata *conn,
1312 CURLcode result = CURLE_OK;
1313 struct SessionHandle *data = conn->data;
1314 struct POP3 *pop3 = data->req.protop;
1315 struct pop3_conn *pop3c = &conn->proto.pop3c;
1316 struct pingpong *pp = &pop3c->pp;
1318 (void)instate; /* no use for this yet */
1320 if(pop3code != '+') {
1321 state(conn, POP3_STOP);
1322 return CURLE_RECV_ERROR;
1325 /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
1326 EOB string so count this is two matching bytes. This is necessary to make
1327 the code detect the EOB if the only data than comes now is %2e CR LF like
1328 when there is no body to return. */
1331 /* But since this initial CR LF pair is not part of the actual body, we set
1332 the strip counter here so that these bytes won't be delivered. */
1335 if(pop3->transfer == FTPTRANSFER_BODY) {
1337 Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
1340 /* The header "cache" contains a bunch of data that is actually body
1341 content so send it as such. Note that there may even be additional
1342 "headers" after the body */
1344 if(!data->set.opt_no_body) {
1345 result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
1350 /* Free the cache */
1351 Curl_safefree(pp->cache);
1353 /* Reset the cache size */
1358 /* End of DO phase */
1359 state(conn, POP3_STOP);
1364 static CURLcode pop3_statemach_act(struct connectdata *conn)
1366 CURLcode result = CURLE_OK;
1367 curl_socket_t sock = conn->sock[FIRSTSOCKET];
1369 struct pop3_conn *pop3c = &conn->proto.pop3c;
1370 struct pingpong *pp = &pop3c->pp;
1373 /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */
1374 if(pop3c->state == POP3_UPGRADETLS)
1375 return pop3_perform_upgrade_tls(conn);
1377 /* Flush any data that needs to be sent */
1379 return Curl_pp_flushsend(pp);
1382 /* Read the response from the server */
1383 result = Curl_pp_readresp(sock, pp, &pop3code, &nread);
1390 /* We have now received a full POP3 server response */
1391 switch(pop3c->state) {
1392 case POP3_SERVERGREET:
1393 result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state);
1397 result = pop3_state_capa_resp(conn, pop3code, pop3c->state);
1401 result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);
1404 case POP3_AUTH_PLAIN:
1405 result = pop3_state_auth_plain_resp(conn, pop3code, pop3c->state);
1408 case POP3_AUTH_LOGIN:
1409 result = pop3_state_auth_login_resp(conn, pop3code, pop3c->state);
1412 case POP3_AUTH_LOGIN_PASSWD:
1413 result = pop3_state_auth_login_password_resp(conn, pop3code,
1417 #ifndef CURL_DISABLE_CRYPTO_AUTH
1418 case POP3_AUTH_CRAMMD5:
1419 result = pop3_state_auth_cram_resp(conn, pop3code, pop3c->state);
1422 case POP3_AUTH_DIGESTMD5:
1423 result = pop3_state_auth_digest_resp(conn, pop3code, pop3c->state);
1426 case POP3_AUTH_DIGESTMD5_RESP:
1427 result = pop3_state_auth_digest_resp_resp(conn, pop3code, pop3c->state);
1432 case POP3_AUTH_NTLM:
1433 result = pop3_state_auth_ntlm_resp(conn, pop3code, pop3c->state);
1436 case POP3_AUTH_NTLM_TYPE2MSG:
1437 result = pop3_state_auth_ntlm_type2msg_resp(conn, pop3code,
1442 case POP3_AUTH_XOAUTH2:
1443 result = pop3_state_auth_xoauth2_resp(conn, pop3code, pop3c->state);
1446 case POP3_AUTH_CANCEL:
1447 result = pop3_state_auth_cancel_resp(conn, pop3code, pop3c->state);
1450 case POP3_AUTH_FINAL:
1451 result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state);
1454 #ifndef CURL_DISABLE_CRYPTO_AUTH
1456 result = pop3_state_apop_resp(conn, pop3code, pop3c->state);
1461 result = pop3_state_user_resp(conn, pop3code, pop3c->state);
1465 result = pop3_state_pass_resp(conn, pop3code, pop3c->state);
1469 result = pop3_state_command_resp(conn, pop3code, pop3c->state);
1473 /* fallthrough, just stop! */
1475 /* internal error */
1476 state(conn, POP3_STOP);
1479 } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp));
1484 /* Called repeatedly until done from multi.c */
1485 static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
1487 CURLcode result = CURLE_OK;
1488 struct pop3_conn *pop3c = &conn->proto.pop3c;
1490 if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
1491 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
1492 if(result || !pop3c->ssldone)
1496 result = Curl_pp_statemach(&pop3c->pp, FALSE);
1497 *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
1502 static CURLcode pop3_block_statemach(struct connectdata *conn)
1504 CURLcode result = CURLE_OK;
1505 struct pop3_conn *pop3c = &conn->proto.pop3c;
1507 while(pop3c->state != POP3_STOP && !result)
1508 result = Curl_pp_statemach(&pop3c->pp, TRUE);
1513 /* Allocate and initialize the POP3 struct for the current SessionHandle if
1515 static CURLcode pop3_init(struct connectdata *conn)
1517 CURLcode result = CURLE_OK;
1518 struct SessionHandle *data = conn->data;
1521 pop3 = data->req.protop = calloc(sizeof(struct POP3), 1);
1523 result = CURLE_OUT_OF_MEMORY;
1528 /* For the POP3 "protocol connect" and "doing" phases only */
1529 static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
1532 return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks);
1535 /***********************************************************************
1539 * This function should do everything that is to be considered a part of the
1542 * The variable 'done' points to will be TRUE if the protocol-layer connect
1543 * phase is done when this function returns, or FALSE if not.
1545 static CURLcode pop3_connect(struct connectdata *conn, bool *done)
1547 CURLcode result = CURLE_OK;
1548 struct pop3_conn *pop3c = &conn->proto.pop3c;
1549 struct pingpong *pp = &pop3c->pp;
1551 *done = FALSE; /* default to not done yet */
1553 /* We always support persistent connections in POP3 */
1554 conn->bits.close = FALSE;
1556 /* Set the default response time-out */
1557 pp->response_time = RESP_TIMEOUT;
1558 pp->statemach_act = pop3_statemach_act;
1559 pp->endofresp = pop3_endofresp;
1562 /* Set the default preferred authentication type and mechanism */
1563 pop3c->preftype = POP3_TYPE_ANY;
1564 pop3c->prefmech = SASL_AUTH_ANY;
1566 /* Initialise the pingpong layer */
1569 /* Parse the URL options */
1570 result = pop3_parse_url_options(conn);
1574 /* Start off waiting for the server greeting response */
1575 state(conn, POP3_SERVERGREET);
1577 result = pop3_multi_statemach(conn, done);
1582 /***********************************************************************
1586 * The DONE function. This does what needs to be done after a single DO has
1589 * Input argument is already checked for validity.
1591 static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
1594 CURLcode result = CURLE_OK;
1595 struct SessionHandle *data = conn->data;
1596 struct POP3 *pop3 = data->req.protop;
1601 /* When the easy handle is removed from the multi interface while libcurl
1602 is still trying to resolve the host name, the POP3 struct is not yet
1603 initialized. However, the removal action calls Curl_done() which in
1604 turn calls this function, so we simply return success. */
1608 conn->bits.close = TRUE; /* marked for closure */
1609 result = status; /* use the already set error code */
1612 /* Cleanup our per-request based variables */
1613 Curl_safefree(pop3->id);
1614 Curl_safefree(pop3->custom);
1616 /* Clear the transfer mode for the next request */
1617 pop3->transfer = FTPTRANSFER_BODY;
1622 /***********************************************************************
1626 * This is the actual DO function for POP3. Get a message/listing according to
1627 * the options previously setup.
1629 static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
1632 /* This is POP3 and no proxy */
1633 CURLcode result = CURLE_OK;
1634 struct POP3 *pop3 = conn->data->req.protop;
1636 DEBUGF(infof(conn->data, "DO phase starts\n"));
1638 if(conn->data->set.opt_no_body) {
1639 /* Requested no body means no transfer */
1640 pop3->transfer = FTPTRANSFER_INFO;
1643 *dophase_done = FALSE; /* not done yet */
1645 /* Start the first command in the DO phase */
1646 result = pop3_perform_command(conn);
1650 /* Run the state-machine */
1651 result = pop3_multi_statemach(conn, dophase_done);
1653 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
1656 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1661 /***********************************************************************
1665 * This function is registered as 'curl_do' function. It decodes the path
1666 * parts etc as a wrapper to the actual DO function (pop3_perform).
1668 * The input argument is already checked for validity.
1670 static CURLcode pop3_do(struct connectdata *conn, bool *done)
1672 CURLcode result = CURLE_OK;
1674 *done = FALSE; /* default to false */
1676 /* Parse the URL path */
1677 result = pop3_parse_url_path(conn);
1681 /* Parse the custom request */
1682 result = pop3_parse_custom_request(conn);
1686 result = pop3_regular_transfer(conn, done);
1691 /***********************************************************************
1695 * Disconnect from an POP3 server. Cleanup protocol-specific per-connection
1696 * resources. BLOCKING.
1698 static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection)
1700 struct pop3_conn *pop3c = &conn->proto.pop3c;
1702 /* We cannot send quit unconditionally. If this connection is stale or
1703 bad in any way, sending quit and waiting around here will make the
1704 disconnect wait in vain and cause more problems than we need to. */
1706 /* The POP3 session may or may not have been allocated/setup at this
1708 if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart)
1709 if(!pop3_perform_quit(conn))
1710 (void)pop3_block_statemach(conn); /* ignore errors on QUIT */
1712 /* Disconnect from the server */
1713 Curl_pp_disconnect(&pop3c->pp);
1715 /* Cleanup the SASL module */
1716 Curl_sasl_cleanup(conn, pop3c->authused);
1718 /* Cleanup our connection based variables */
1719 Curl_safefree(pop3c->apoptimestamp);
1724 /* Call this when the DO phase has completed */
1725 static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected)
1733 /* Called from multi.c while DOing */
1734 static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done)
1736 CURLcode result = pop3_multi_statemach(conn, dophase_done);
1739 DEBUGF(infof(conn->data, "DO phase failed\n"));
1740 else if(*dophase_done) {
1741 result = pop3_dophase_done(conn, FALSE /* not connected */);
1743 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1749 /***********************************************************************
1751 * pop3_regular_transfer()
1753 * The input argument is already checked for validity.
1755 * Performs all commands done before a regular transfer between a local and a
1758 static CURLcode pop3_regular_transfer(struct connectdata *conn,
1761 CURLcode result = CURLE_OK;
1762 bool connected = FALSE;
1763 struct SessionHandle *data = conn->data;
1765 /* Make sure size is unknown at this point */
1766 data->req.size = -1;
1768 /* Set the progress data */
1769 Curl_pgrsSetUploadCounter(data, 0);
1770 Curl_pgrsSetDownloadCounter(data, 0);
1771 Curl_pgrsSetUploadSize(data, 0);
1772 Curl_pgrsSetDownloadSize(data, 0);
1774 /* Carry out the perform */
1775 result = pop3_perform(conn, &connected, dophase_done);
1777 /* Perform post DO phase operations if necessary */
1778 if(!result && *dophase_done)
1779 result = pop3_dophase_done(conn, connected);
1784 static CURLcode pop3_setup_connection(struct connectdata *conn)
1786 struct SessionHandle *data = conn->data;
1788 /* Initialise the POP3 layer */
1789 CURLcode result = pop3_init(conn);
1793 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
1794 /* Unless we have asked to tunnel POP3 operations through the proxy, we
1795 switch and use HTTP operations only */
1796 #ifndef CURL_DISABLE_HTTP
1797 if(conn->handler == &Curl_handler_pop3)
1798 conn->handler = &Curl_handler_pop3_proxy;
1801 conn->handler = &Curl_handler_pop3s_proxy;
1803 failf(data, "POP3S not supported!");
1804 return CURLE_UNSUPPORTED_PROTOCOL;
1808 /* set it up as an HTTP connection instead */
1809 return conn->handler->setup_connection(conn);
1811 failf(data, "POP3 over http proxy requires HTTP support built-in!");
1812 return CURLE_UNSUPPORTED_PROTOCOL;
1816 data->state.path++; /* don't include the initial slash */
1821 /***********************************************************************
1823 * pop3_parse_url_options()
1825 * Parse the URL login options.
1827 static CURLcode pop3_parse_url_options(struct connectdata *conn)
1829 CURLcode result = CURLE_OK;
1830 struct pop3_conn *pop3c = &conn->proto.pop3c;
1831 const char *options = conn->options;
1832 const char *ptr = options;
1835 while(ptr && *ptr) {
1836 const char *key = ptr;
1838 while(*ptr && *ptr != '=')
1841 if(strnequal(key, "AUTH", 4)) {
1843 const char *value = ++ptr;
1847 pop3c->preftype = POP3_TYPE_NONE;
1848 pop3c->prefmech = SASL_AUTH_NONE;
1851 while(*ptr && *ptr != ';') {
1856 if(strnequal(value, "*", len)) {
1857 pop3c->preftype = POP3_TYPE_ANY;
1858 pop3c->prefmech = SASL_AUTH_ANY;
1860 else if(strnequal(value, "+APOP", len)) {
1861 pop3c->preftype = POP3_TYPE_APOP;
1862 pop3c->prefmech = SASL_AUTH_NONE;
1864 else if(strnequal(value, SASL_MECH_STRING_LOGIN, len)) {
1865 pop3c->preftype = POP3_TYPE_SASL;
1866 pop3c->prefmech |= SASL_MECH_LOGIN;
1868 else if(strnequal(value, SASL_MECH_STRING_PLAIN, len)) {
1869 pop3c->preftype = POP3_TYPE_SASL;
1870 pop3c->prefmech |= SASL_MECH_PLAIN;
1872 else if(strnequal(value, SASL_MECH_STRING_CRAM_MD5, len)) {
1873 pop3c->preftype = POP3_TYPE_SASL;
1874 pop3c->prefmech |= SASL_MECH_CRAM_MD5;
1876 else if(strnequal(value, SASL_MECH_STRING_DIGEST_MD5, len)) {
1877 pop3c->preftype = POP3_TYPE_SASL;
1878 pop3c->prefmech |= SASL_MECH_DIGEST_MD5;
1880 else if(strnequal(value, SASL_MECH_STRING_GSSAPI, len)) {
1881 pop3c->preftype = POP3_TYPE_SASL;
1882 pop3c->prefmech |= SASL_MECH_GSSAPI;
1884 else if(strnequal(value, SASL_MECH_STRING_NTLM, len)) {
1885 pop3c->preftype = POP3_TYPE_SASL;
1886 pop3c->prefmech |= SASL_MECH_NTLM;
1888 else if(strnequal(value, SASL_MECH_STRING_XOAUTH2, len)) {
1889 pop3c->preftype = POP3_TYPE_SASL;
1890 pop3c->prefmech |= SASL_MECH_XOAUTH2;
1897 result = CURLE_URL_MALFORMAT;
1903 /***********************************************************************
1905 * pop3_parse_url_path()
1907 * Parse the URL path into separate path components.
1909 static CURLcode pop3_parse_url_path(struct connectdata *conn)
1911 /* The POP3 struct is already initialised in pop3_connect() */
1912 struct SessionHandle *data = conn->data;
1913 struct POP3 *pop3 = data->req.protop;
1914 const char *path = data->state.path;
1916 /* URL decode the path for the message ID */
1917 return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);
1920 /***********************************************************************
1922 * pop3_parse_custom_request()
1924 * Parse the custom request.
1926 static CURLcode pop3_parse_custom_request(struct connectdata *conn)
1928 CURLcode result = CURLE_OK;
1929 struct SessionHandle *data = conn->data;
1930 struct POP3 *pop3 = data->req.protop;
1931 const char *custom = data->set.str[STRING_CUSTOMREQUEST];
1933 /* URL decode the custom request */
1935 result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE);
1940 /***********************************************************************
1942 * pop3_calc_sasl_details()
1944 * Calculate the required login details for SASL authentication.
1946 static CURLcode pop3_calc_sasl_details(struct connectdata *conn,
1948 char **initresp, size_t *len,
1949 pop3state *state1, pop3state *state2)
1951 CURLcode result = CURLE_OK;
1952 struct SessionHandle *data = conn->data;
1953 struct pop3_conn *pop3c = &conn->proto.pop3c;
1955 /* Calculate the supported authentication mechanism, by decreasing order of
1956 security, as well as the initial response where appropriate */
1957 #ifndef CURL_DISABLE_CRYPTO_AUTH
1958 if((pop3c->authmechs & SASL_MECH_DIGEST_MD5) &&
1959 (pop3c->prefmech & SASL_MECH_DIGEST_MD5)) {
1960 *mech = SASL_MECH_STRING_DIGEST_MD5;
1961 *state1 = POP3_AUTH_DIGESTMD5;
1962 pop3c->authused = SASL_MECH_DIGEST_MD5;
1964 else if((pop3c->authmechs & SASL_MECH_CRAM_MD5) &&
1965 (pop3c->prefmech & SASL_MECH_CRAM_MD5)) {
1966 *mech = SASL_MECH_STRING_CRAM_MD5;
1967 *state1 = POP3_AUTH_CRAMMD5;
1968 pop3c->authused = SASL_MECH_CRAM_MD5;
1973 if((pop3c->authmechs & SASL_MECH_NTLM) &&
1974 (pop3c->prefmech & SASL_MECH_NTLM)) {
1975 *mech = SASL_MECH_STRING_NTLM;
1976 *state1 = POP3_AUTH_NTLM;
1977 *state2 = POP3_AUTH_NTLM_TYPE2MSG;
1978 pop3c->authused = SASL_MECH_NTLM;
1980 if(data->set.sasl_ir)
1981 result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
1987 if(((pop3c->authmechs & SASL_MECH_XOAUTH2) &&
1988 (pop3c->prefmech & SASL_MECH_XOAUTH2) &&
1989 (pop3c->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
1990 *mech = SASL_MECH_STRING_XOAUTH2;
1991 *state1 = POP3_AUTH_XOAUTH2;
1992 *state2 = POP3_AUTH_FINAL;
1993 pop3c->authused = SASL_MECH_XOAUTH2;
1995 if(data->set.sasl_ir)
1996 result = Curl_sasl_create_xoauth2_message(data, conn->user,
1997 conn->xoauth2_bearer,
2000 else if((pop3c->authmechs & SASL_MECH_LOGIN) &&
2001 (pop3c->prefmech & SASL_MECH_LOGIN)) {
2002 *mech = SASL_MECH_STRING_LOGIN;
2003 *state1 = POP3_AUTH_LOGIN;
2004 *state2 = POP3_AUTH_LOGIN_PASSWD;
2005 pop3c->authused = SASL_MECH_LOGIN;
2007 if(data->set.sasl_ir)
2008 result = Curl_sasl_create_login_message(data, conn->user, initresp, len);
2010 else if((pop3c->authmechs & SASL_MECH_PLAIN) &&
2011 (pop3c->prefmech & SASL_MECH_PLAIN)) {
2012 *mech = SASL_MECH_STRING_PLAIN;
2013 *state1 = POP3_AUTH_PLAIN;
2014 *state2 = POP3_AUTH_FINAL;
2015 pop3c->authused = SASL_MECH_PLAIN;
2017 if(data->set.sasl_ir)
2018 result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd,
2025 /***********************************************************************
2029 * This function scans the body after the end-of-body and writes everything
2030 * until the end is found.
2032 CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
2034 /* This code could be made into a special function in the handler struct */
2035 CURLcode result = CURLE_OK;
2036 struct SessionHandle *data = conn->data;
2037 struct SingleRequest *k = &data->req;
2039 struct pop3_conn *pop3c = &conn->proto.pop3c;
2040 bool strip_dot = FALSE;
2044 /* Search through the buffer looking for the end-of-body marker which is
2045 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
2046 the eob so the server will have prefixed it with an extra dot which we
2047 need to strip out. Additionally the marker could of course be spread out
2048 over 5 different data chunks. */
2049 for(i = 0; i < nread; i++) {
2050 size_t prev = pop3c->eob;
2054 if(pop3c->eob == 0) {
2058 /* Write out the body part that didn't match */
2059 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
2068 else if(pop3c->eob == 3)
2071 /* If the character match wasn't at position 0 or 3 then restart the
2077 if(pop3c->eob == 1 || pop3c->eob == 4)
2080 /* If the character match wasn't at position 1 or 4 then start the
2088 else if(pop3c->eob == 3) {
2089 /* We have an extra dot after the CRLF which we need to strip off */
2094 /* If the character match wasn't at position 2 then start the search
2104 /* Did we have a partial match which has subsequently failed? */
2105 if(prev && prev >= pop3c->eob) {
2106 /* Strip can only be non-zero for the very first mismatch after CRLF
2107 and then both prev and strip are equal and nothing will be output
2109 while(prev && pop3c->strip) {
2115 /* If the partial match was the CRLF and dot then only write the CRLF
2116 as the server would have inserted the dot */
2117 result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB,
2118 strip_dot ? prev - 1 : prev);
2129 if(pop3c->eob == POP3_EOB_LEN) {
2130 /* We have a full match so the transfer is done, however we must transfer
2131 the CRLF at the start of the EOB as this is considered to be part of the
2132 message as per RFC-1939, sect. 3 */
2133 result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
2135 k->keepon &= ~KEEP_RECV;
2142 /* While EOB is matching nothing should be output */
2146 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
2153 #endif /* CURL_DISABLE_POP3 */