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 * 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_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 /* Clear text is supported when CAPA isn't recognised */
785 pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
787 result = pop3_perform_authentication(conn);
793 /* For STARTTLS responses */
794 static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
798 CURLcode result = CURLE_OK;
799 struct SessionHandle *data = conn->data;
801 (void)instate; /* no use for this yet */
803 if(pop3code != '+') {
804 if(data->set.use_ssl != CURLUSESSL_TRY) {
805 failf(data, "STARTTLS denied. %c", pop3code);
806 result = CURLE_USE_SSL_FAILED;
809 result = pop3_perform_authentication(conn);
812 result = pop3_perform_upgrade_tls(conn);
817 /* For AUTH PLAIN (without initial response) responses */
818 static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn,
822 CURLcode result = CURLE_OK;
823 struct SessionHandle *data = conn->data;
825 char *plainauth = NULL;
827 (void)instate; /* no use for this yet */
829 if(pop3code != '+') {
830 failf(data, "Access denied. %c", pop3code);
831 result = CURLE_LOGIN_DENIED;
834 /* Create the authorisation message */
835 result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd,
837 if(!result && plainauth) {
838 /* Send the message */
839 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", plainauth);
842 state(conn, POP3_AUTH_FINAL);
846 Curl_safefree(plainauth);
851 /* For AUTH LOGIN (without initial response) responses */
852 static CURLcode pop3_state_auth_login_resp(struct connectdata *conn,
856 CURLcode result = CURLE_OK;
857 struct SessionHandle *data = conn->data;
859 char *authuser = NULL;
861 (void)instate; /* no use for this yet */
863 if(pop3code != '+') {
864 failf(data, "Access denied: %d", pop3code);
865 result = CURLE_LOGIN_DENIED;
868 /* Create the user message */
869 result = Curl_sasl_create_login_message(data, conn->user,
871 if(!result && authuser) {
873 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authuser);
876 state(conn, POP3_AUTH_LOGIN_PASSWD);
880 Curl_safefree(authuser);
885 /* For AUTH LOGIN user entry responses */
886 static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn,
890 CURLcode result = CURLE_OK;
891 struct SessionHandle *data = conn->data;
893 char *authpasswd = NULL;
895 (void)instate; /* no use for this yet */
897 if(pop3code != '+') {
898 failf(data, "Access denied: %d", pop3code);
899 result = CURLE_LOGIN_DENIED;
902 /* Create the password message */
903 result = Curl_sasl_create_login_message(data, conn->passwd,
905 if(!result && authpasswd) {
906 /* Send the password */
907 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authpasswd);
910 state(conn, POP3_AUTH_FINAL);
914 Curl_safefree(authpasswd);
919 #ifndef CURL_DISABLE_CRYPTO_AUTH
920 /* For AUTH CRAM-MD5 responses */
921 static CURLcode pop3_state_auth_cram_resp(struct connectdata *conn,
925 CURLcode result = CURLE_OK;
926 struct SessionHandle *data = conn->data;
929 char *rplyb64 = NULL;
932 (void)instate; /* no use for this yet */
934 if(pop3code != '+') {
935 failf(data, "Access denied: %d", pop3code);
936 return CURLE_LOGIN_DENIED;
939 /* Get the challenge message */
940 pop3_get_message(data->state.buffer, &chlg64);
942 /* Decode the challenge message */
943 result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len);
945 /* Send the cancellation */
946 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
949 state(conn, POP3_AUTH_CANCEL);
952 /* Create the response message */
953 result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user,
954 conn->passwd, &rplyb64, &len);
955 if(!result && rplyb64) {
956 /* Send the response */
957 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
960 state(conn, POP3_AUTH_FINAL);
965 Curl_safefree(rplyb64);
970 /* For AUTH DIGEST-MD5 challenge responses */
971 static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn,
975 CURLcode result = CURLE_OK;
976 struct SessionHandle *data = conn->data;
978 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 /* Create the response message */
992 result = Curl_sasl_create_digest_md5_message(data, chlg64,
993 conn->user, conn->passwd,
994 "pop", &rplyb64, &len);
996 if(result == CURLE_BAD_CONTENT_ENCODING) {
997 /* Send the cancellation */
998 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
1001 state(conn, POP3_AUTH_CANCEL);
1005 /* Send the response */
1006 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
1009 state(conn, POP3_AUTH_DIGESTMD5_RESP);
1012 Curl_safefree(rplyb64);
1017 /* For AUTH DIGEST-MD5 challenge-response responses */
1018 static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn,
1022 CURLcode result = CURLE_OK;
1023 struct SessionHandle *data = conn->data;
1025 (void)instate; /* no use for this yet */
1027 if(pop3code != '+') {
1028 failf(data, "Authentication failed: %d", pop3code);
1029 result = CURLE_LOGIN_DENIED;
1032 /* Send an empty response */
1033 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "");
1036 state(conn, POP3_AUTH_FINAL);
1044 /* For AUTH NTLM (without initial response) responses */
1045 static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn,
1049 CURLcode result = CURLE_OK;
1050 struct SessionHandle *data = conn->data;
1052 char *type1msg = NULL;
1054 (void)instate; /* no use for this yet */
1056 if(pop3code != '+') {
1057 failf(data, "Access denied: %d", pop3code);
1058 result = CURLE_LOGIN_DENIED;
1061 /* Create the type-1 message */
1062 result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
1065 if(!result && type1msg) {
1066 /* Send the message */
1067 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type1msg);
1070 state(conn, POP3_AUTH_NTLM_TYPE2MSG);
1074 Curl_safefree(type1msg);
1079 /* For NTLM type-2 responses (sent in reponse to our type-1 message) */
1080 static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn,
1084 CURLcode result = CURLE_OK;
1085 struct SessionHandle *data = conn->data;
1086 char *type2msg = NULL;
1087 char *type3msg = NULL;
1090 (void)instate; /* no use for this yet */
1092 if(pop3code != '+') {
1093 failf(data, "Access denied: %d", pop3code);
1094 result = CURLE_LOGIN_DENIED;
1097 /* Get the type-2 message */
1098 pop3_get_message(data->state.buffer, &type2msg);
1100 /* Decode the type-2 message */
1101 result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm);
1103 /* Send the cancellation */
1104 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
1107 state(conn, POP3_AUTH_CANCEL);
1110 /* Create the type-3 message */
1111 result = Curl_sasl_create_ntlm_type3_message(data, conn->user,
1112 conn->passwd, &conn->ntlm,
1114 if(!result && type3msg) {
1115 /* Send the message */
1116 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type3msg);
1119 state(conn, POP3_AUTH_FINAL);
1124 Curl_safefree(type3msg);
1130 /* For AUTH XOAUTH2 (without initial response) responses */
1131 static CURLcode pop3_state_auth_xoauth2_resp(struct connectdata *conn,
1132 int pop3code, pop3state instate)
1134 CURLcode result = CURLE_OK;
1135 struct SessionHandle *data = conn->data;
1137 char *xoauth = NULL;
1139 (void)instate; /* no use for this yet */
1141 if(pop3code != '+') {
1142 failf(data, "Access denied: %d", pop3code);
1143 result = CURLE_LOGIN_DENIED;
1146 /* Create the authorisation message */
1147 result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
1148 conn->xoauth2_bearer,
1150 if(!result && xoauth) {
1151 /* Send the message */
1152 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", xoauth);
1155 state(conn, POP3_AUTH_FINAL);
1159 Curl_safefree(xoauth);
1164 /* For AUTH cancellation responses */
1165 static CURLcode pop3_state_auth_cancel_resp(struct connectdata *conn,
1169 CURLcode result = CURLE_OK;
1170 struct SessionHandle *data = conn->data;
1171 struct pop3_conn *pop3c = &conn->proto.pop3c;
1172 const char *mech = NULL;
1173 char *initresp = NULL;
1175 pop3state state1 = POP3_STOP;
1176 pop3state state2 = POP3_STOP;
1179 (void)instate; /* no use for this yet */
1181 /* Remove the offending mechanism from the supported list */
1182 pop3c->authmechs ^= pop3c->authused;
1184 /* Calculate alternative SASL login details */
1185 result = pop3_calc_sasl_details(conn, &mech, &initresp, &len, &state1,
1189 /* Do we have any mechanisms left or can we fallback to another
1190 authentication type? */
1192 /* Retry SASL based authentication */
1193 result = pop3_perform_auth(conn, mech, initresp, len, state1, state2);
1195 Curl_safefree(initresp);
1197 #ifndef CURL_DISABLE_CRYPTO_AUTH
1198 else if((pop3c->authtypes & POP3_TYPE_APOP) &&
1199 (pop3c->preftype & POP3_TYPE_APOP))
1200 /* Perform APOP authentication */
1201 result = pop3_perform_apop(conn);
1203 else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) &&
1204 (pop3c->preftype & POP3_TYPE_CLEARTEXT))
1205 /* Perform clear text authentication */
1206 result = pop3_perform_user(conn);
1208 failf(data, "Authentication cancelled");
1210 result = CURLE_LOGIN_DENIED;
1217 /* For final responses in the AUTH sequence */
1218 static CURLcode pop3_state_auth_final_resp(struct connectdata *conn,
1222 CURLcode result = CURLE_OK;
1223 struct SessionHandle *data = conn->data;
1225 (void)instate; /* no use for this yet */
1227 if(pop3code != '+') {
1228 failf(data, "Authentication failed: %d", pop3code);
1229 result = CURLE_LOGIN_DENIED;
1232 /* End of connect phase */
1233 state(conn, POP3_STOP);
1238 #ifndef CURL_DISABLE_CRYPTO_AUTH
1239 /* For APOP responses */
1240 static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code,
1243 CURLcode result = CURLE_OK;
1244 struct SessionHandle *data = conn->data;
1246 (void)instate; /* no use for this yet */
1248 if(pop3code != '+') {
1249 failf(data, "Authentication failed: %d", pop3code);
1250 result = CURLE_LOGIN_DENIED;
1253 /* End of connect phase */
1254 state(conn, POP3_STOP);
1260 /* For USER responses */
1261 static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code,
1264 CURLcode result = CURLE_OK;
1265 struct SessionHandle *data = conn->data;
1267 (void)instate; /* no use for this yet */
1269 if(pop3code != '+') {
1270 failf(data, "Access denied. %c", pop3code);
1271 result = CURLE_LOGIN_DENIED;
1274 /* Send the PASS command */
1275 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s",
1276 conn->passwd ? conn->passwd : "");
1278 state(conn, POP3_PASS);
1283 /* For PASS responses */
1284 static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code,
1287 CURLcode result = CURLE_OK;
1288 struct SessionHandle *data = conn->data;
1290 (void)instate; /* no use for this yet */
1292 if(pop3code != '+') {
1293 failf(data, "Access denied. %c", pop3code);
1294 result = CURLE_LOGIN_DENIED;
1297 /* End of connect phase */
1298 state(conn, POP3_STOP);
1303 /* For command responses */
1304 static CURLcode pop3_state_command_resp(struct connectdata *conn,
1308 CURLcode result = CURLE_OK;
1309 struct SessionHandle *data = conn->data;
1310 struct POP3 *pop3 = data->req.protop;
1311 struct pop3_conn *pop3c = &conn->proto.pop3c;
1312 struct pingpong *pp = &pop3c->pp;
1314 (void)instate; /* no use for this yet */
1316 if(pop3code != '+') {
1317 state(conn, POP3_STOP);
1318 return CURLE_RECV_ERROR;
1321 /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
1322 EOB string so count this is two matching bytes. This is necessary to make
1323 the code detect the EOB if the only data than comes now is %2e CR LF like
1324 when there is no body to return. */
1327 /* But since this initial CR LF pair is not part of the actual body, we set
1328 the strip counter here so that these bytes won't be delivered. */
1331 if(pop3->transfer == FTPTRANSFER_BODY) {
1333 Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
1336 /* The header "cache" contains a bunch of data that is actually body
1337 content so send it as such. Note that there may even be additional
1338 "headers" after the body */
1340 if(!data->set.opt_no_body) {
1341 result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
1346 /* Free the cache */
1347 Curl_safefree(pp->cache);
1349 /* Reset the cache size */
1354 /* End of DO phase */
1355 state(conn, POP3_STOP);
1360 static CURLcode pop3_statemach_act(struct connectdata *conn)
1362 CURLcode result = CURLE_OK;
1363 curl_socket_t sock = conn->sock[FIRSTSOCKET];
1365 struct pop3_conn *pop3c = &conn->proto.pop3c;
1366 struct pingpong *pp = &pop3c->pp;
1369 /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */
1370 if(pop3c->state == POP3_UPGRADETLS)
1371 return pop3_perform_upgrade_tls(conn);
1373 /* Flush any data that needs to be sent */
1375 return Curl_pp_flushsend(pp);
1378 /* Read the response from the server */
1379 result = Curl_pp_readresp(sock, pp, &pop3code, &nread);
1386 /* We have now received a full POP3 server response */
1387 switch(pop3c->state) {
1388 case POP3_SERVERGREET:
1389 result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state);
1393 result = pop3_state_capa_resp(conn, pop3code, pop3c->state);
1397 result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);
1400 case POP3_AUTH_PLAIN:
1401 result = pop3_state_auth_plain_resp(conn, pop3code, pop3c->state);
1404 case POP3_AUTH_LOGIN:
1405 result = pop3_state_auth_login_resp(conn, pop3code, pop3c->state);
1408 case POP3_AUTH_LOGIN_PASSWD:
1409 result = pop3_state_auth_login_password_resp(conn, pop3code,
1413 #ifndef CURL_DISABLE_CRYPTO_AUTH
1414 case POP3_AUTH_CRAMMD5:
1415 result = pop3_state_auth_cram_resp(conn, pop3code, pop3c->state);
1418 case POP3_AUTH_DIGESTMD5:
1419 result = pop3_state_auth_digest_resp(conn, pop3code, pop3c->state);
1422 case POP3_AUTH_DIGESTMD5_RESP:
1423 result = pop3_state_auth_digest_resp_resp(conn, pop3code, pop3c->state);
1428 case POP3_AUTH_NTLM:
1429 result = pop3_state_auth_ntlm_resp(conn, pop3code, pop3c->state);
1432 case POP3_AUTH_NTLM_TYPE2MSG:
1433 result = pop3_state_auth_ntlm_type2msg_resp(conn, pop3code,
1438 case POP3_AUTH_XOAUTH2:
1439 result = pop3_state_auth_xoauth2_resp(conn, pop3code, pop3c->state);
1442 case POP3_AUTH_CANCEL:
1443 result = pop3_state_auth_cancel_resp(conn, pop3code, pop3c->state);
1446 case POP3_AUTH_FINAL:
1447 result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state);
1450 #ifndef CURL_DISABLE_CRYPTO_AUTH
1452 result = pop3_state_apop_resp(conn, pop3code, pop3c->state);
1457 result = pop3_state_user_resp(conn, pop3code, pop3c->state);
1461 result = pop3_state_pass_resp(conn, pop3code, pop3c->state);
1465 result = pop3_state_command_resp(conn, pop3code, pop3c->state);
1469 /* fallthrough, just stop! */
1471 /* internal error */
1472 state(conn, POP3_STOP);
1475 } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp));
1480 /* Called repeatedly until done from multi.c */
1481 static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
1483 CURLcode result = CURLE_OK;
1484 struct pop3_conn *pop3c = &conn->proto.pop3c;
1486 if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
1487 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
1488 if(result || !pop3c->ssldone)
1492 result = Curl_pp_statemach(&pop3c->pp, FALSE);
1493 *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
1498 static CURLcode pop3_block_statemach(struct connectdata *conn)
1500 CURLcode result = CURLE_OK;
1501 struct pop3_conn *pop3c = &conn->proto.pop3c;
1503 while(pop3c->state != POP3_STOP && !result)
1504 result = Curl_pp_statemach(&pop3c->pp, TRUE);
1509 /* Allocate and initialize the POP3 struct for the current SessionHandle if
1511 static CURLcode pop3_init(struct connectdata *conn)
1513 CURLcode result = CURLE_OK;
1514 struct SessionHandle *data = conn->data;
1517 pop3 = data->req.protop = calloc(sizeof(struct POP3), 1);
1519 result = CURLE_OUT_OF_MEMORY;
1524 /* For the POP3 "protocol connect" and "doing" phases only */
1525 static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
1528 return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks);
1531 /***********************************************************************
1535 * This function should do everything that is to be considered a part of the
1538 * The variable 'done' points to will be TRUE if the protocol-layer connect
1539 * phase is done when this function returns, or FALSE if not.
1541 static CURLcode pop3_connect(struct connectdata *conn, bool *done)
1543 CURLcode result = CURLE_OK;
1544 struct pop3_conn *pop3c = &conn->proto.pop3c;
1545 struct pingpong *pp = &pop3c->pp;
1547 *done = FALSE; /* default to not done yet */
1549 /* We always support persistent connections in POP3 */
1550 connkeep(conn, "POP3 default");
1552 /* Set the default response time-out */
1553 pp->response_time = RESP_TIMEOUT;
1554 pp->statemach_act = pop3_statemach_act;
1555 pp->endofresp = pop3_endofresp;
1558 /* Set the default preferred authentication type and mechanism */
1559 pop3c->preftype = POP3_TYPE_ANY;
1560 pop3c->prefmech = SASL_AUTH_ANY;
1562 /* Initialise the pingpong layer */
1565 /* Parse the URL options */
1566 result = pop3_parse_url_options(conn);
1570 /* Start off waiting for the server greeting response */
1571 state(conn, POP3_SERVERGREET);
1573 result = pop3_multi_statemach(conn, done);
1578 /***********************************************************************
1582 * The DONE function. This does what needs to be done after a single DO has
1585 * Input argument is already checked for validity.
1587 static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
1590 CURLcode result = CURLE_OK;
1591 struct SessionHandle *data = conn->data;
1592 struct POP3 *pop3 = data->req.protop;
1597 /* When the easy handle is removed from the multi interface while libcurl
1598 is still trying to resolve the host name, the POP3 struct is not yet
1599 initialized. However, the removal action calls Curl_done() which in
1600 turn calls this function, so we simply return success. */
1604 connclose(conn, "POP3 done with bad status");
1605 result = status; /* use the already set error code */
1608 /* Cleanup our per-request based variables */
1609 Curl_safefree(pop3->id);
1610 Curl_safefree(pop3->custom);
1612 /* Clear the transfer mode for the next request */
1613 pop3->transfer = FTPTRANSFER_BODY;
1618 /***********************************************************************
1622 * This is the actual DO function for POP3. Get a message/listing according to
1623 * the options previously setup.
1625 static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
1628 /* This is POP3 and no proxy */
1629 CURLcode result = CURLE_OK;
1630 struct POP3 *pop3 = conn->data->req.protop;
1632 DEBUGF(infof(conn->data, "DO phase starts\n"));
1634 if(conn->data->set.opt_no_body) {
1635 /* Requested no body means no transfer */
1636 pop3->transfer = FTPTRANSFER_INFO;
1639 *dophase_done = FALSE; /* not done yet */
1641 /* Start the first command in the DO phase */
1642 result = pop3_perform_command(conn);
1646 /* Run the state-machine */
1647 result = pop3_multi_statemach(conn, dophase_done);
1649 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
1652 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1657 /***********************************************************************
1661 * This function is registered as 'curl_do' function. It decodes the path
1662 * parts etc as a wrapper to the actual DO function (pop3_perform).
1664 * The input argument is already checked for validity.
1666 static CURLcode pop3_do(struct connectdata *conn, bool *done)
1668 CURLcode result = CURLE_OK;
1670 *done = FALSE; /* default to false */
1672 /* Parse the URL path */
1673 result = pop3_parse_url_path(conn);
1677 /* Parse the custom request */
1678 result = pop3_parse_custom_request(conn);
1682 result = pop3_regular_transfer(conn, done);
1687 /***********************************************************************
1691 * Disconnect from an POP3 server. Cleanup protocol-specific per-connection
1692 * resources. BLOCKING.
1694 static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection)
1696 struct pop3_conn *pop3c = &conn->proto.pop3c;
1698 /* We cannot send quit unconditionally. If this connection is stale or
1699 bad in any way, sending quit and waiting around here will make the
1700 disconnect wait in vain and cause more problems than we need to. */
1702 /* The POP3 session may or may not have been allocated/setup at this
1704 if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart)
1705 if(!pop3_perform_quit(conn))
1706 (void)pop3_block_statemach(conn); /* ignore errors on QUIT */
1708 /* Disconnect from the server */
1709 Curl_pp_disconnect(&pop3c->pp);
1711 /* Cleanup the SASL module */
1712 Curl_sasl_cleanup(conn, pop3c->authused);
1714 /* Cleanup our connection based variables */
1715 Curl_safefree(pop3c->apoptimestamp);
1720 /* Call this when the DO phase has completed */
1721 static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected)
1729 /* Called from multi.c while DOing */
1730 static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done)
1732 CURLcode result = pop3_multi_statemach(conn, dophase_done);
1735 DEBUGF(infof(conn->data, "DO phase failed\n"));
1736 else if(*dophase_done) {
1737 result = pop3_dophase_done(conn, FALSE /* not connected */);
1739 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1745 /***********************************************************************
1747 * pop3_regular_transfer()
1749 * The input argument is already checked for validity.
1751 * Performs all commands done before a regular transfer between a local and a
1754 static CURLcode pop3_regular_transfer(struct connectdata *conn,
1757 CURLcode result = CURLE_OK;
1758 bool connected = FALSE;
1759 struct SessionHandle *data = conn->data;
1761 /* Make sure size is unknown at this point */
1762 data->req.size = -1;
1764 /* Set the progress data */
1765 Curl_pgrsSetUploadCounter(data, 0);
1766 Curl_pgrsSetDownloadCounter(data, 0);
1767 Curl_pgrsSetUploadSize(data, 0);
1768 Curl_pgrsSetDownloadSize(data, 0);
1770 /* Carry out the perform */
1771 result = pop3_perform(conn, &connected, dophase_done);
1773 /* Perform post DO phase operations if necessary */
1774 if(!result && *dophase_done)
1775 result = pop3_dophase_done(conn, connected);
1780 static CURLcode pop3_setup_connection(struct connectdata *conn)
1782 struct SessionHandle *data = conn->data;
1784 /* Initialise the POP3 layer */
1785 CURLcode result = pop3_init(conn);
1789 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
1790 /* Unless we have asked to tunnel POP3 operations through the proxy, we
1791 switch and use HTTP operations only */
1792 #ifndef CURL_DISABLE_HTTP
1793 if(conn->handler == &Curl_handler_pop3)
1794 conn->handler = &Curl_handler_pop3_proxy;
1797 conn->handler = &Curl_handler_pop3s_proxy;
1799 failf(data, "POP3S not supported!");
1800 return CURLE_UNSUPPORTED_PROTOCOL;
1804 /* set it up as an HTTP connection instead */
1805 return conn->handler->setup_connection(conn);
1807 failf(data, "POP3 over http proxy requires HTTP support built-in!");
1808 return CURLE_UNSUPPORTED_PROTOCOL;
1812 data->state.path++; /* don't include the initial slash */
1817 /***********************************************************************
1819 * pop3_parse_url_options()
1821 * Parse the URL login options.
1823 static CURLcode pop3_parse_url_options(struct connectdata *conn)
1825 CURLcode result = CURLE_OK;
1826 struct pop3_conn *pop3c = &conn->proto.pop3c;
1827 const char *options = conn->options;
1828 const char *ptr = options;
1831 while(ptr && *ptr) {
1832 const char *key = ptr;
1834 while(*ptr && *ptr != '=')
1837 if(strnequal(key, "AUTH", 4)) {
1839 const char *value = ++ptr;
1843 pop3c->preftype = POP3_TYPE_NONE;
1844 pop3c->prefmech = SASL_AUTH_NONE;
1847 while(*ptr && *ptr != ';') {
1852 if(strnequal(value, "*", len)) {
1853 pop3c->preftype = POP3_TYPE_ANY;
1854 pop3c->prefmech = SASL_AUTH_ANY;
1856 else if(strnequal(value, "+APOP", len)) {
1857 pop3c->preftype = POP3_TYPE_APOP;
1858 pop3c->prefmech = SASL_AUTH_NONE;
1860 else if(strnequal(value, SASL_MECH_STRING_LOGIN, len)) {
1861 pop3c->preftype = POP3_TYPE_SASL;
1862 pop3c->prefmech |= SASL_MECH_LOGIN;
1864 else if(strnequal(value, SASL_MECH_STRING_PLAIN, len)) {
1865 pop3c->preftype = POP3_TYPE_SASL;
1866 pop3c->prefmech |= SASL_MECH_PLAIN;
1868 else if(strnequal(value, SASL_MECH_STRING_CRAM_MD5, len)) {
1869 pop3c->preftype = POP3_TYPE_SASL;
1870 pop3c->prefmech |= SASL_MECH_CRAM_MD5;
1872 else if(strnequal(value, SASL_MECH_STRING_DIGEST_MD5, len)) {
1873 pop3c->preftype = POP3_TYPE_SASL;
1874 pop3c->prefmech |= SASL_MECH_DIGEST_MD5;
1876 else if(strnequal(value, SASL_MECH_STRING_GSSAPI, len)) {
1877 pop3c->preftype = POP3_TYPE_SASL;
1878 pop3c->prefmech |= SASL_MECH_GSSAPI;
1880 else if(strnequal(value, SASL_MECH_STRING_NTLM, len)) {
1881 pop3c->preftype = POP3_TYPE_SASL;
1882 pop3c->prefmech |= SASL_MECH_NTLM;
1884 else if(strnequal(value, SASL_MECH_STRING_XOAUTH2, len)) {
1885 pop3c->preftype = POP3_TYPE_SASL;
1886 pop3c->prefmech |= SASL_MECH_XOAUTH2;
1893 result = CURLE_URL_MALFORMAT;
1899 /***********************************************************************
1901 * pop3_parse_url_path()
1903 * Parse the URL path into separate path components.
1905 static CURLcode pop3_parse_url_path(struct connectdata *conn)
1907 /* The POP3 struct is already initialised in pop3_connect() */
1908 struct SessionHandle *data = conn->data;
1909 struct POP3 *pop3 = data->req.protop;
1910 const char *path = data->state.path;
1912 /* URL decode the path for the message ID */
1913 return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);
1916 /***********************************************************************
1918 * pop3_parse_custom_request()
1920 * Parse the custom request.
1922 static CURLcode pop3_parse_custom_request(struct connectdata *conn)
1924 CURLcode result = CURLE_OK;
1925 struct SessionHandle *data = conn->data;
1926 struct POP3 *pop3 = data->req.protop;
1927 const char *custom = data->set.str[STRING_CUSTOMREQUEST];
1929 /* URL decode the custom request */
1931 result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE);
1936 /***********************************************************************
1938 * pop3_calc_sasl_details()
1940 * Calculate the required login details for SASL authentication.
1942 static CURLcode pop3_calc_sasl_details(struct connectdata *conn,
1944 char **initresp, size_t *len,
1945 pop3state *state1, pop3state *state2)
1947 CURLcode result = CURLE_OK;
1948 struct SessionHandle *data = conn->data;
1949 struct pop3_conn *pop3c = &conn->proto.pop3c;
1951 /* Calculate the supported authentication mechanism, by decreasing order of
1952 security, as well as the initial response where appropriate */
1953 #ifndef CURL_DISABLE_CRYPTO_AUTH
1954 if((pop3c->authmechs & SASL_MECH_DIGEST_MD5) &&
1955 (pop3c->prefmech & SASL_MECH_DIGEST_MD5)) {
1956 *mech = SASL_MECH_STRING_DIGEST_MD5;
1957 *state1 = POP3_AUTH_DIGESTMD5;
1958 pop3c->authused = SASL_MECH_DIGEST_MD5;
1960 else if((pop3c->authmechs & SASL_MECH_CRAM_MD5) &&
1961 (pop3c->prefmech & SASL_MECH_CRAM_MD5)) {
1962 *mech = SASL_MECH_STRING_CRAM_MD5;
1963 *state1 = POP3_AUTH_CRAMMD5;
1964 pop3c->authused = SASL_MECH_CRAM_MD5;
1969 if((pop3c->authmechs & SASL_MECH_NTLM) &&
1970 (pop3c->prefmech & SASL_MECH_NTLM)) {
1971 *mech = SASL_MECH_STRING_NTLM;
1972 *state1 = POP3_AUTH_NTLM;
1973 *state2 = POP3_AUTH_NTLM_TYPE2MSG;
1974 pop3c->authused = SASL_MECH_NTLM;
1976 if(data->set.sasl_ir)
1977 result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
1983 if(((pop3c->authmechs & SASL_MECH_XOAUTH2) &&
1984 (pop3c->prefmech & SASL_MECH_XOAUTH2) &&
1985 (pop3c->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
1986 *mech = SASL_MECH_STRING_XOAUTH2;
1987 *state1 = POP3_AUTH_XOAUTH2;
1988 *state2 = POP3_AUTH_FINAL;
1989 pop3c->authused = SASL_MECH_XOAUTH2;
1991 if(data->set.sasl_ir)
1992 result = Curl_sasl_create_xoauth2_message(data, conn->user,
1993 conn->xoauth2_bearer,
1996 else if((pop3c->authmechs & SASL_MECH_LOGIN) &&
1997 (pop3c->prefmech & SASL_MECH_LOGIN)) {
1998 *mech = SASL_MECH_STRING_LOGIN;
1999 *state1 = POP3_AUTH_LOGIN;
2000 *state2 = POP3_AUTH_LOGIN_PASSWD;
2001 pop3c->authused = SASL_MECH_LOGIN;
2003 if(data->set.sasl_ir)
2004 result = Curl_sasl_create_login_message(data, conn->user, initresp, len);
2006 else if((pop3c->authmechs & SASL_MECH_PLAIN) &&
2007 (pop3c->prefmech & SASL_MECH_PLAIN)) {
2008 *mech = SASL_MECH_STRING_PLAIN;
2009 *state1 = POP3_AUTH_PLAIN;
2010 *state2 = POP3_AUTH_FINAL;
2011 pop3c->authused = SASL_MECH_PLAIN;
2013 if(data->set.sasl_ir)
2014 result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd,
2021 /***********************************************************************
2025 * This function scans the body after the end-of-body and writes everything
2026 * until the end is found.
2028 CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
2030 /* This code could be made into a special function in the handler struct */
2031 CURLcode result = CURLE_OK;
2032 struct SessionHandle *data = conn->data;
2033 struct SingleRequest *k = &data->req;
2035 struct pop3_conn *pop3c = &conn->proto.pop3c;
2036 bool strip_dot = FALSE;
2040 /* Search through the buffer looking for the end-of-body marker which is
2041 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
2042 the eob so the server will have prefixed it with an extra dot which we
2043 need to strip out. Additionally the marker could of course be spread out
2044 over 5 different data chunks. */
2045 for(i = 0; i < nread; i++) {
2046 size_t prev = pop3c->eob;
2050 if(pop3c->eob == 0) {
2054 /* Write out the body part that didn't match */
2055 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
2064 else if(pop3c->eob == 3)
2067 /* If the character match wasn't at position 0 or 3 then restart the
2073 if(pop3c->eob == 1 || pop3c->eob == 4)
2076 /* If the character match wasn't at position 1 or 4 then start the
2084 else if(pop3c->eob == 3) {
2085 /* We have an extra dot after the CRLF which we need to strip off */
2090 /* If the character match wasn't at position 2 then start the search
2100 /* Did we have a partial match which has subsequently failed? */
2101 if(prev && prev >= pop3c->eob) {
2102 /* Strip can only be non-zero for the very first mismatch after CRLF
2103 and then both prev and strip are equal and nothing will be output
2105 while(prev && pop3c->strip) {
2111 /* If the partial match was the CRLF and dot then only write the CRLF
2112 as the server would have inserted the dot */
2113 result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB,
2114 strip_dot ? prev - 1 : prev);
2125 if(pop3c->eob == POP3_EOB_LEN) {
2126 /* We have a full match so the transfer is done, however we must transfer
2127 the CRLF at the start of the EOB as this is considered to be part of the
2128 message as per RFC-1939, sect. 3 */
2129 result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
2131 k->keepon &= ~KEEP_RECV;
2138 /* While EOB is matching nothing should be output */
2142 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
2149 #endif /* CURL_DISABLE_POP3 */