email: Renamed *_perform_authenticate() functions
[platform/upstream/curl.git] / lib / pop3.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
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.
13  *
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.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
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>
33  *
34  ***************************************************************************/
35
36 #include "curl_setup.h"
37
38 #ifndef CURL_DISABLE_POP3
39
40 #ifdef HAVE_NETINET_IN_H
41 #include <netinet/in.h>
42 #endif
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
45 #endif
46 #ifdef HAVE_UTSNAME_H
47 #include <sys/utsname.h>
48 #endif
49 #ifdef HAVE_NETDB_H
50 #include <netdb.h>
51 #endif
52 #ifdef __VMS
53 #include <in.h>
54 #include <inet.h>
55 #endif
56
57 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
58 #undef in_addr_t
59 #define in_addr_t unsigned long
60 #endif
61
62 #include <curl/curl.h>
63 #include "urldata.h"
64 #include "sendf.h"
65 #include "if2ip.h"
66 #include "hostip.h"
67 #include "progress.h"
68 #include "transfer.h"
69 #include "escape.h"
70 #include "http.h" /* for HTTP proxy tunnel stuff */
71 #include "socks.h"
72 #include "pop3.h"
73
74 #include "strtoofft.h"
75 #include "strequal.h"
76 #include "sslgen.h"
77 #include "connect.h"
78 #include "strerror.h"
79 #include "select.h"
80 #include "multiif.h"
81 #include "url.h"
82 #include "rawstr.h"
83 #include "curl_sasl.h"
84 #include "curl_md5.h"
85 #include "warnless.h"
86
87 #define _MPRINTF_REPLACE /* use our functions only */
88 #include <curl/mprintf.h>
89
90 #include "curl_memory.h"
91 /* The last #include file should be: */
92 #include "memdebug.h"
93
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,
98                           bool premature);
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,
103                         int numsocks);
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
110 /*
111  * POP3 protocol handler.
112  */
113
114 const struct Curl_handler Curl_handler_pop3 = {
115   "POP3",                           /* scheme */
116   pop3_setup_connection,            /* setup_connection */
117   pop3_do,                          /* do_it */
118   pop3_done,                        /* done */
119   ZERO_NULL,                        /* do_more */
120   pop3_connect,                     /* connect_it */
121   pop3_multi_statemach,             /* connecting */
122   pop3_doing,                       /* doing */
123   pop3_getsock,                     /* proto_getsock */
124   pop3_getsock,                     /* doing_getsock */
125   ZERO_NULL,                        /* domore_getsock */
126   ZERO_NULL,                        /* perform_getsock */
127   pop3_disconnect,                  /* disconnect */
128   ZERO_NULL,                        /* readwrite */
129   PORT_POP3,                        /* defport */
130   CURLPROTO_POP3,                   /* protocol */
131   PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
132 };
133
134 #ifdef USE_SSL
135 /*
136  * POP3S protocol handler.
137  */
138
139 const struct Curl_handler Curl_handler_pop3s = {
140   "POP3S",                          /* scheme */
141   pop3_setup_connection,            /* setup_connection */
142   pop3_do,                          /* do_it */
143   pop3_done,                        /* done */
144   ZERO_NULL,                        /* do_more */
145   pop3_connect,                     /* connect_it */
146   pop3_multi_statemach,             /* connecting */
147   pop3_doing,                       /* doing */
148   pop3_getsock,                     /* proto_getsock */
149   pop3_getsock,                     /* doing_getsock */
150   ZERO_NULL,                        /* domore_getsock */
151   ZERO_NULL,                        /* perform_getsock */
152   pop3_disconnect,                  /* disconnect */
153   ZERO_NULL,                        /* readwrite */
154   PORT_POP3S,                       /* defport */
155   CURLPROTO_POP3 | CURLPROTO_POP3S, /* protocol */
156   PROTOPT_CLOSEACTION | PROTOPT_SSL
157   | PROTOPT_NOURLQUERY              /* flags */
158 };
159 #endif
160
161 #ifndef CURL_DISABLE_HTTP
162 /*
163  * HTTP-proxyed POP3 protocol handler.
164  */
165
166 static const struct Curl_handler Curl_handler_pop3_proxy = {
167   "POP3",                               /* scheme */
168   Curl_http_setup_conn,                 /* setup_connection */
169   Curl_http,                            /* do_it */
170   Curl_http_done,                       /* done */
171   ZERO_NULL,                            /* do_more */
172   ZERO_NULL,                            /* connect_it */
173   ZERO_NULL,                            /* connecting */
174   ZERO_NULL,                            /* doing */
175   ZERO_NULL,                            /* proto_getsock */
176   ZERO_NULL,                            /* doing_getsock */
177   ZERO_NULL,                            /* domore_getsock */
178   ZERO_NULL,                            /* perform_getsock */
179   ZERO_NULL,                            /* disconnect */
180   ZERO_NULL,                            /* readwrite */
181   PORT_POP3,                            /* defport */
182   CURLPROTO_HTTP,                       /* protocol */
183   PROTOPT_NONE                          /* flags */
184 };
185
186 #ifdef USE_SSL
187 /*
188  * HTTP-proxyed POP3S protocol handler.
189  */
190
191 static const struct Curl_handler Curl_handler_pop3s_proxy = {
192   "POP3S",                              /* scheme */
193   Curl_http_setup_conn,                 /* setup_connection */
194   Curl_http,                            /* do_it */
195   Curl_http_done,                       /* done */
196   ZERO_NULL,                            /* do_more */
197   ZERO_NULL,                            /* connect_it */
198   ZERO_NULL,                            /* connecting */
199   ZERO_NULL,                            /* doing */
200   ZERO_NULL,                            /* proto_getsock */
201   ZERO_NULL,                            /* doing_getsock */
202   ZERO_NULL,                            /* domore_getsock */
203   ZERO_NULL,                            /* perform_getsock */
204   ZERO_NULL,                            /* disconnect */
205   ZERO_NULL,                            /* readwrite */
206   PORT_POP3S,                           /* defport */
207   CURLPROTO_HTTP,                       /* protocol */
208   PROTOPT_NONE                          /* flags */
209 };
210 #endif
211 #endif
212
213 #ifdef USE_SSL
214 static void pop3_to_pop3s(struct connectdata *conn)
215 {
216   conn->handler = &Curl_handler_pop3s;
217 }
218 #else
219 #define pop3_to_pop3s(x) Curl_nop_stmt
220 #endif
221
222 /***********************************************************************
223  *
224  * pop3_endofresp()
225  *
226  * Checks for an ending POP3 status code at the start of the given string, but
227  * also detects the APOP timestamp from the server greeting and various
228  * capabilities from the CAPA response including the supported authentication
229  * types and allowed SASL mechanisms.
230  */
231 static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
232                            int *resp)
233 {
234   struct pop3_conn *pop3c = &conn->proto.pop3c;
235   size_t wordlen;
236   size_t i;
237
238   /* Do we have an error response? */
239   if(len >= 4 && !memcmp("-ERR", line, 4)) {
240     *resp = '-';
241
242     return TRUE;
243   }
244
245   /* Are we processing servergreet responses? */
246   if(pop3c->state == POP3_SERVERGREET) {
247     /* Look for the APOP timestamp */
248     if(len >= 3 && line[len - 3] == '>') {
249       for(i = 0; i < len - 3; ++i) {
250         if(line[i] == '<') {
251           /* Calculate the length of the timestamp */
252           size_t timestamplen = len - 2 - i;
253
254           /* Allocate some memory for the timestamp */
255           pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1);
256
257           if(!pop3c->apoptimestamp)
258             break;
259
260           /* Copy the timestamp */
261           memcpy(pop3c->apoptimestamp, line + i, timestamplen);
262           pop3c->apoptimestamp[timestamplen] = '\0';
263           break;
264         }
265       }
266     }
267   }
268   /* Are we processing CAPA command responses? */
269   else if(pop3c->state == POP3_CAPA) {
270     /* Do we have the terminating line? */
271     if(len >= 1 && !memcmp(line, ".", 1)) {
272       *resp = '+';
273
274       return TRUE;
275     }
276
277     /* Does the server support the STLS capability? */
278     if(len >= 4 && !memcmp(line, "STLS", 4))
279       pop3c->tls_supported = TRUE;
280
281     /* Does the server support clear text authentication? */
282     else if(len >= 4 && !memcmp(line, "USER", 4))
283       pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
284
285     /* Does the server support APOP authentication? */
286     else if(len >= 4 && !memcmp(line, "APOP", 4))
287       pop3c->authtypes |= POP3_TYPE_APOP;
288
289     /* Does the server support SASL based authentication? */
290     else if(len >= 5 && !memcmp(line, "SASL ", 5)) {
291       pop3c->authtypes |= POP3_TYPE_SASL;
292
293       /* Advance past the SASL keyword */
294       line += 5;
295       len -= 5;
296
297       /* Loop through the data line */
298       for(;;) {
299         while(len &&
300               (*line == ' ' || *line == '\t' ||
301                *line == '\r' || *line == '\n')) {
302
303           line++;
304           len--;
305         }
306
307         if(!len)
308           break;
309
310         /* Extract the word */
311         for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
312               line[wordlen] != '\t' && line[wordlen] != '\r' &&
313               line[wordlen] != '\n';)
314           wordlen++;
315
316         /* Test the word for a matching authentication mechanism */
317         if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
318           pop3c->authmechs |= SASL_MECH_LOGIN;
319         else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
320           pop3c->authmechs |= SASL_MECH_PLAIN;
321         else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
322           pop3c->authmechs |= SASL_MECH_CRAM_MD5;
323         else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
324           pop3c->authmechs |= SASL_MECH_DIGEST_MD5;
325         else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
326           pop3c->authmechs |= SASL_MECH_GSSAPI;
327         else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
328           pop3c->authmechs |= SASL_MECH_EXTERNAL;
329         else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
330           pop3c->authmechs |= SASL_MECH_NTLM;
331         else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
332           pop3c->authmechs |= SASL_MECH_XOAUTH2;
333
334         line += wordlen;
335         len -= wordlen;
336       }
337     }
338
339     return FALSE;
340   }
341
342   /* Do we have a command or continuation response? */
343   if((len >= 3 && !memcmp("+OK", line, 3)) ||
344      (len >= 1 && !memcmp("+", line, 1))) {
345     *resp = '+';
346
347     return TRUE;
348   }
349
350   return FALSE; /* Nothing for us */
351 }
352
353 /***********************************************************************
354  *
355  * pop3_get_message()
356  *
357  * Gets the authentication message from the response buffer.
358  */
359 static void pop3_get_message(char *buffer, char** outptr)
360 {
361   size_t len = 0;
362   char* message = NULL;
363
364   /* Find the start of the message */
365   for(message = buffer + 2; *message == ' ' || *message == '\t'; message++)
366     ;
367
368   /* Find the end of the message */
369   for(len = strlen(message); len--;)
370     if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
371         message[len] != '\t')
372       break;
373
374   /* Terminate the message */
375   if(++len) {
376     message[len] = '\0';
377   }
378
379   *outptr = message;
380 }
381
382 /***********************************************************************
383  *
384  * state()
385  *
386  * This is the ONLY way to change POP3 state!
387  */
388 static void state(struct connectdata *conn, pop3state newstate)
389 {
390   struct pop3_conn *pop3c = &conn->proto.pop3c;
391 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
392   /* for debug purposes */
393   static const char * const names[] = {
394     "STOP",
395     "SERVERGREET",
396     "CAPA",
397     "STARTTLS",
398     "UPGRADETLS",
399     "AUTH_PLAIN",
400     "AUTH_LOGIN",
401     "AUTH_LOGIN_PASSWD",
402     "AUTH_CRAMMD5",
403     "AUTH_DIGESTMD5",
404     "AUTH_DIGESTMD5_RESP",
405     "AUTH_NTLM",
406     "AUTH_NTLM_TYPE2MSG",
407     "AUTH_XOAUTH2",
408     "AUTH_CANCEL",
409     "AUTH_FINAL",
410     "APOP",
411     "USER",
412     "PASS",
413     "COMMAND",
414     "QUIT",
415     /* LAST */
416   };
417
418   if(pop3c->state != newstate)
419     infof(conn->data, "POP3 %p state change from %s to %s\n",
420           (void *)pop3c, names[pop3c->state], names[newstate]);
421 #endif
422
423   pop3c->state = newstate;
424 }
425
426 /***********************************************************************
427  *
428  * pop3_perform_capa()
429  *
430  * Sends the CAPA command in order to obtain a list of server side supported
431  * capabilities.
432  */
433 static CURLcode pop3_perform_capa(struct connectdata *conn)
434 {
435   CURLcode result = CURLE_OK;
436   struct pop3_conn *pop3c = &conn->proto.pop3c;
437
438   pop3c->authmechs = 0;         /* No known authentication mechanisms yet */
439   pop3c->authused = 0;          /* Clear the authentication mechanism used */
440   pop3c->tls_supported = FALSE; /* Clear the TLS capability */
441
442   /* Send the CAPA command */
443   result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA");
444
445   if(!result)
446     state(conn, POP3_CAPA);
447
448   return result;
449 }
450
451 /***********************************************************************
452  *
453  * pop3_perform_starttls()
454  *
455  * Sends the STLS command to start the upgrade to TLS.
456  */
457 static CURLcode pop3_perform_starttls(struct connectdata *conn)
458 {
459   CURLcode result = CURLE_OK;
460
461   /* Send the STLS command */
462   result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "STLS");
463
464   if(!result)
465     state(conn, POP3_STARTTLS);
466
467   return result;
468 }
469
470 /***********************************************************************
471  *
472  * pop3_perform_upgrade_tls()
473  *
474  * Performs the upgrade to TLS.
475  */
476 static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn)
477 {
478   CURLcode result = CURLE_OK;
479   struct pop3_conn *pop3c = &conn->proto.pop3c;
480
481   /* Start the SSL connection */
482   result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
483
484   if(!result) {
485     if(pop3c->state != POP3_UPGRADETLS)
486       state(conn, POP3_UPGRADETLS);
487
488     if(pop3c->ssldone) {
489       pop3_to_pop3s(conn);
490       result = pop3_perform_capa(conn);
491     }
492   }
493
494   return result;
495 }
496
497 /***********************************************************************
498  *
499  * pop3_perform_user()
500  *
501  * Sends a clear text USER command to authenticate with.
502  */
503 static CURLcode pop3_perform_user(struct connectdata *conn)
504 {
505   CURLcode result = CURLE_OK;
506
507   /* Check we have a username and password to authenticate with and end the
508      connect phase if we don't */
509   if(!conn->bits.user_passwd) {
510     state(conn, POP3_STOP);
511
512     return result;
513   }
514
515   /* Send the USER command */
516   result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s",
517                          conn->user ? conn->user : "");
518   if(!result)
519     state(conn, POP3_USER);
520
521   return result;
522 }
523
524 #ifndef CURL_DISABLE_CRYPTO_AUTH
525 /***********************************************************************
526  *
527  * pop3_perform_apop()
528  *
529  * Sends an APOP command to authenticate with.
530  */
531 static CURLcode pop3_perform_apop(struct connectdata *conn)
532 {
533   CURLcode result = CURLE_OK;
534   struct pop3_conn *pop3c = &conn->proto.pop3c;
535   size_t i;
536   MD5_context *ctxt;
537   unsigned char digest[MD5_DIGEST_LEN];
538   char secret[2 * MD5_DIGEST_LEN + 1];
539
540   /* Check we have a username and password to authenticate with and end the
541      connect phase if we don't */
542   if(!conn->bits.user_passwd) {
543     state(conn, POP3_STOP);
544
545     return result;
546   }
547
548   /* Create the digest */
549   ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
550   if(!ctxt)
551     return CURLE_OUT_OF_MEMORY;
552
553   Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp,
554                   curlx_uztoui(strlen(pop3c->apoptimestamp)));
555
556   Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd,
557                   curlx_uztoui(strlen(conn->passwd)));
558
559   /* Finalise the digest */
560   Curl_MD5_final(ctxt, digest);
561
562   /* Convert the calculated 16 octet digest into a 32 byte hex string */
563   for(i = 0; i < MD5_DIGEST_LEN; i++)
564     snprintf(&secret[2 * i], 3, "%02x", digest[i]);
565
566   result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret);
567
568   if(!result)
569     state(conn, POP3_APOP);
570
571   return result;
572 }
573 #endif
574
575 /***********************************************************************
576  *
577  * pop3_perform_authentication()
578  *
579  * Initiates the authentication sequence, with the appropriate SASL
580  * authentication mechanism, falling back to APOP and clear text should a
581  * common mechanism not be available between the client and server.
582  */
583 static CURLcode pop3_perform_authentication(struct connectdata *conn)
584 {
585   CURLcode result = CURLE_OK;
586   struct SessionHandle *data = conn->data;
587   struct pop3_conn *pop3c = &conn->proto.pop3c;
588   const char *mech = NULL;
589   char *initresp = NULL;
590   size_t len = 0;
591   pop3state state1 = POP3_STOP;
592   pop3state state2 = POP3_STOP;
593
594   /* Check we have a username and password to authenticate with and end the
595      connect phase if we don't */
596   if(!conn->bits.user_passwd) {
597     state(conn, POP3_STOP);
598
599     return result;
600   }
601
602   /* Calculate the supported authentication mechanism, by decreasing order of
603      security, as well as the initial response where appropriate */
604   if(pop3c->authtypes & POP3_TYPE_SASL) {
605 #ifndef CURL_DISABLE_CRYPTO_AUTH
606     if((pop3c->authmechs & SASL_MECH_DIGEST_MD5) &&
607        (pop3c->prefmech & SASL_MECH_DIGEST_MD5)) {
608       mech = SASL_MECH_STRING_DIGEST_MD5;
609       state1 = POP3_AUTH_DIGESTMD5;
610       pop3c->authused = SASL_MECH_DIGEST_MD5;
611     }
612     else if((pop3c->authmechs & SASL_MECH_CRAM_MD5) &&
613             (pop3c->prefmech & SASL_MECH_CRAM_MD5)) {
614       mech = SASL_MECH_STRING_CRAM_MD5;
615       state1 = POP3_AUTH_CRAMMD5;
616       pop3c->authused = SASL_MECH_CRAM_MD5;
617     }
618     else
619 #endif
620 #ifdef USE_NTLM
621     if((pop3c->authmechs & SASL_MECH_NTLM) &&
622        (pop3c->prefmech & SASL_MECH_NTLM)) {
623       mech = SASL_MECH_STRING_NTLM;
624       state1 = POP3_AUTH_NTLM;
625       state2 = POP3_AUTH_NTLM_TYPE2MSG;
626       pop3c->authused = SASL_MECH_NTLM;
627
628       if(data->set.sasl_ir)
629         result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
630                                                      &conn->ntlm,
631                                                      &initresp, &len);
632     }
633     else
634 #endif
635     if(((pop3c->authmechs & SASL_MECH_XOAUTH2) &&
636         (pop3c->prefmech & SASL_MECH_XOAUTH2) &&
637         (pop3c->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
638       mech = SASL_MECH_STRING_XOAUTH2;
639       state1 = POP3_AUTH_XOAUTH2;
640       state2 = POP3_AUTH_FINAL;
641       pop3c->authused = SASL_MECH_XOAUTH2;
642
643       if(data->set.sasl_ir)
644         result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
645                                                   conn->xoauth2_bearer,
646                                                   &initresp, &len);
647     }
648     else if((pop3c->authmechs & SASL_MECH_LOGIN) &&
649        (pop3c->prefmech & SASL_MECH_LOGIN)) {
650       mech = SASL_MECH_STRING_LOGIN;
651       state1 = POP3_AUTH_LOGIN;
652       state2 = POP3_AUTH_LOGIN_PASSWD;
653       pop3c->authused = SASL_MECH_LOGIN;
654
655       if(data->set.sasl_ir)
656         result = Curl_sasl_create_login_message(conn->data, conn->user,
657                                                 &initresp, &len);
658     }
659     else if((pop3c->authmechs & SASL_MECH_PLAIN) &&
660             (pop3c->prefmech & SASL_MECH_PLAIN)) {
661       mech = SASL_MECH_STRING_PLAIN;
662       state1 = POP3_AUTH_PLAIN;
663       state2 = POP3_AUTH_FINAL;
664       pop3c->authused = SASL_MECH_PLAIN;
665
666       if(data->set.sasl_ir)
667         result = Curl_sasl_create_plain_message(conn->data, conn->user,
668                                                 conn->passwd, &initresp,
669                                                 &len);
670     }
671   }
672
673   if(!result) {
674     if(mech && (pop3c->preftype & POP3_TYPE_SASL)) {
675       /* Perform SASL based authentication */
676       if(initresp &&
677          8 + strlen(mech) + len <= 255) { /* AUTH <mech> ...<crlf> */
678         result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp);
679
680         if(!result)
681           state(conn, state2);
682       }
683       else {
684         result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
685
686         if(!result)
687           state(conn, state1);
688       }
689
690       Curl_safefree(initresp);
691     }
692 #ifndef CURL_DISABLE_CRYPTO_AUTH
693     else if((pop3c->authtypes & POP3_TYPE_APOP) &&
694             (pop3c->preftype & POP3_TYPE_APOP))
695       /* Perform APOP authentication */
696       result = pop3_perform_apop(conn);
697 #endif
698     else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) &&
699             (pop3c->preftype & POP3_TYPE_CLEARTEXT))
700       /* Perform clear text authentication */
701       result = pop3_perform_user(conn);
702     else {
703       /* Other mechanisms not supported */
704       infof(conn->data, "No known authentication mechanisms supported!\n");
705       result = CURLE_LOGIN_DENIED;
706     }
707   }
708
709   return result;
710 }
711
712 /***********************************************************************
713  *
714  * pop3_perform_command()
715  *
716  * Sends a POP3 based command.
717  */
718 static CURLcode pop3_perform_command(struct connectdata *conn)
719 {
720   CURLcode result = CURLE_OK;
721   struct SessionHandle *data = conn->data;
722   struct POP3 *pop3 = data->req.protop;
723   const char *command = NULL;
724
725   /* Calculate the default command */
726   if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) {
727     command = "LIST";
728
729     if(pop3->id[0] != '\0')
730       /* Message specific LIST so skip the BODY transfer */
731       pop3->transfer = FTPTRANSFER_INFO;
732   }
733   else
734     command = "RETR";
735
736   /* Send the command */
737   if(pop3->id[0] != '\0')
738     result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s",
739                            (pop3->custom && pop3->custom[0] != '\0' ?
740                             pop3->custom : command), pop3->id);
741   else
742     result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s",
743                            (pop3->custom && pop3->custom[0] != '\0' ?
744                             pop3->custom : command));
745
746   if(!result)
747     state(conn, POP3_COMMAND);
748
749   return result;
750 }
751
752 /***********************************************************************
753  *
754  * pop3_perform_quit()
755  *
756  * Performs the quit action prior to sclose() be called.
757  */
758 static CURLcode pop3_perform_quit(struct connectdata *conn)
759 {
760   CURLcode result = CURLE_OK;
761
762   /* Send the QUIT command */
763   result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "QUIT");
764
765   if(!result)
766     state(conn, POP3_QUIT);
767
768   return result;
769 }
770
771 /* For the initial server greeting */
772 static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
773                                             int pop3code,
774                                             pop3state instate)
775 {
776   CURLcode result = CURLE_OK;
777   struct SessionHandle *data = conn->data;
778
779   (void)instate; /* no use for this yet */
780
781   if(pop3code != '+') {
782     failf(data, "Got unexpected pop3-server response");
783     result = CURLE_FTP_WEIRD_SERVER_REPLY;
784   }
785   else
786     result = pop3_perform_capa(conn);
787
788   return result;
789 }
790
791 /* For CAPA responses */
792 static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
793                                      pop3state instate)
794 {
795   CURLcode result = CURLE_OK;
796   struct SessionHandle *data = conn->data;
797   struct pop3_conn *pop3c = &conn->proto.pop3c;
798
799   (void)instate; /* no use for this yet */
800
801   if(pop3code != '+')
802     result = pop3_perform_user(conn);
803   else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
804     /* We don't have a SSL/TLS connection yet, but SSL is requested */
805     if(pop3c->tls_supported)
806       /* Switch to TLS connection now */
807       result = pop3_perform_starttls(conn);
808     else if(data->set.use_ssl == CURLUSESSL_TRY)
809       /* Fallback and carry on with authentication */
810       result = pop3_perform_authentication(conn);
811     else {
812       failf(data, "STLS not supported.");
813       result = CURLE_USE_SSL_FAILED;
814     }
815   }
816   else
817     result = pop3_perform_authentication(conn);
818
819   return result;
820 }
821
822 /* For STARTTLS responses */
823 static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
824                                          int pop3code,
825                                          pop3state instate)
826 {
827   CURLcode result = CURLE_OK;
828   struct SessionHandle *data = conn->data;
829
830   (void)instate; /* no use for this yet */
831
832   if(pop3code != '+') {
833     if(data->set.use_ssl != CURLUSESSL_TRY) {
834       failf(data, "STARTTLS denied. %c", pop3code);
835       result = CURLE_USE_SSL_FAILED;
836     }
837     else
838       result = pop3_perform_authentication(conn);
839   }
840   else
841     result = pop3_perform_upgrade_tls(conn);
842
843   return result;
844 }
845
846 /* For AUTH PLAIN (without initial response) responses */
847 static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn,
848                                            int pop3code,
849                                            pop3state instate)
850 {
851   CURLcode result = CURLE_OK;
852   struct SessionHandle *data = conn->data;
853   size_t len = 0;
854   char *plainauth = NULL;
855
856   (void)instate; /* no use for this yet */
857
858   if(pop3code != '+') {
859     failf(data, "Access denied. %c", pop3code);
860     result = CURLE_LOGIN_DENIED;
861   }
862   else {
863     /* Create the authorisation message */
864     result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd,
865                                             &plainauth, &len);
866     if(!result && plainauth) {
867       /* Send the message */
868       result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", plainauth);
869
870       if(!result)
871         state(conn, POP3_AUTH_FINAL);
872     }
873   }
874
875   Curl_safefree(plainauth);
876
877   return result;
878 }
879
880 /* For AUTH LOGIN (without initial response) responses */
881 static CURLcode pop3_state_auth_login_resp(struct connectdata *conn,
882                                            int pop3code,
883                                            pop3state instate)
884 {
885   CURLcode result = CURLE_OK;
886   struct SessionHandle *data = conn->data;
887   size_t len = 0;
888   char *authuser = NULL;
889
890   (void)instate; /* no use for this yet */
891
892   if(pop3code != '+') {
893     failf(data, "Access denied: %d", pop3code);
894     result = CURLE_LOGIN_DENIED;
895   }
896   else {
897     /* Create the user message */
898     result = Curl_sasl_create_login_message(data, conn->user,
899                                             &authuser, &len);
900     if(!result && authuser) {
901       /* Send the user */
902       result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authuser);
903
904       if(!result)
905         state(conn, POP3_AUTH_LOGIN_PASSWD);
906     }
907   }
908
909   Curl_safefree(authuser);
910
911   return result;
912 }
913
914 /* For AUTH LOGIN user entry responses */
915 static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn,
916                                                     int pop3code,
917                                                     pop3state instate)
918 {
919   CURLcode result = CURLE_OK;
920   struct SessionHandle *data = conn->data;
921   size_t len = 0;
922   char *authpasswd = NULL;
923
924   (void)instate; /* no use for this yet */
925
926   if(pop3code != '+') {
927     failf(data, "Access denied: %d", pop3code);
928     result = CURLE_LOGIN_DENIED;
929   }
930   else {
931     /* Create the password message */
932     result = Curl_sasl_create_login_message(data, conn->passwd,
933                                             &authpasswd, &len);
934     if(!result && authpasswd) {
935       /* Send the password */
936       result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authpasswd);
937
938       if(!result)
939         state(conn, POP3_AUTH_FINAL);
940     }
941   }
942
943   Curl_safefree(authpasswd);
944
945   return result;
946 }
947
948 #ifndef CURL_DISABLE_CRYPTO_AUTH
949 /* For AUTH CRAM-MD5 responses */
950 static CURLcode pop3_state_auth_cram_resp(struct connectdata *conn,
951                                           int pop3code,
952                                           pop3state instate)
953 {
954   CURLcode result = CURLE_OK;
955   struct SessionHandle *data = conn->data;
956   char *chlg = NULL;
957   char *chlg64 = NULL;
958   char *rplyb64 = NULL;
959   size_t len = 0;
960
961   (void)instate; /* no use for this yet */
962
963   if(pop3code != '+') {
964     failf(data, "Access denied: %d", pop3code);
965     return CURLE_LOGIN_DENIED;
966   }
967
968   /* Get the challenge message */
969   pop3_get_message(data->state.buffer, &chlg64);
970
971   /* Decode the challenge message */
972   result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len);
973   if(result) {
974     /* Send the cancellation */
975     result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
976
977     if(!result)
978       state(conn, POP3_AUTH_CANCEL);
979   }
980   else {
981     /* Create the response message */
982     result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user,
983                                                conn->passwd, &rplyb64, &len);
984     if(!result && rplyb64) {
985       /* Send the response */
986       result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
987
988       if(!result)
989         state(conn, POP3_AUTH_FINAL);
990     }
991   }
992
993   Curl_safefree(chlg);
994   Curl_safefree(rplyb64);
995
996   return result;
997 }
998
999 /* For AUTH DIGEST-MD5 challenge responses */
1000 static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn,
1001                                             int pop3code,
1002                                             pop3state instate)
1003 {
1004   CURLcode result = CURLE_OK;
1005   struct SessionHandle *data = conn->data;
1006   char *chlg64 = NULL;
1007   char *rplyb64 = NULL;
1008   size_t len = 0;
1009
1010   char nonce[64];
1011   char realm[128];
1012   char algorithm[64];
1013
1014   (void)instate; /* no use for this yet */
1015
1016   if(pop3code != '+') {
1017     failf(data, "Access denied: %d", pop3code);
1018     return CURLE_LOGIN_DENIED;
1019   }
1020
1021   /* Get the challenge message */
1022   pop3_get_message(data->state.buffer, &chlg64);
1023
1024   /* Decode the challange message */
1025   result = Curl_sasl_decode_digest_md5_message(chlg64, nonce, sizeof(nonce),
1026                                                realm, sizeof(realm),
1027                                                algorithm, sizeof(algorithm));
1028   if(result || strcmp(algorithm, "md5-sess") != 0) {
1029     /* Send the cancellation */
1030     result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
1031
1032     if(!result)
1033       state(conn, POP3_AUTH_CANCEL);
1034   }
1035   else {
1036     /* Create the response message */
1037     result = Curl_sasl_create_digest_md5_message(data, nonce, realm,
1038                                                  conn->user, conn->passwd,
1039                                                  "pop", &rplyb64, &len);
1040     if(!result && rplyb64) {
1041       /* Send the response */
1042       result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
1043
1044       if(!result)
1045         state(conn, POP3_AUTH_DIGESTMD5_RESP);
1046     }
1047   }
1048
1049   Curl_safefree(rplyb64);
1050
1051   return result;
1052 }
1053
1054 /* For AUTH DIGEST-MD5 challenge-response responses */
1055 static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn,
1056                                                  int pop3code,
1057                                                  pop3state instate)
1058 {
1059   CURLcode result = CURLE_OK;
1060   struct SessionHandle *data = conn->data;
1061
1062   (void)instate; /* no use for this yet */
1063
1064   if(pop3code != '+') {
1065     failf(data, "Authentication failed: %d", pop3code);
1066     result = CURLE_LOGIN_DENIED;
1067   }
1068   else {
1069     /* Send an empty response */
1070     result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "");
1071
1072     if(!result)
1073       state(conn, POP3_AUTH_FINAL);
1074   }
1075
1076   return result;
1077 }
1078 #endif
1079
1080 #ifdef USE_NTLM
1081 /* For AUTH NTLM (without initial response) responses */
1082 static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn,
1083                                           int pop3code,
1084                                           pop3state instate)
1085 {
1086   CURLcode result = CURLE_OK;
1087   struct SessionHandle *data = conn->data;
1088   size_t len = 0;
1089   char *type1msg = NULL;
1090
1091   (void)instate; /* no use for this yet */
1092
1093   if(pop3code != '+') {
1094     failf(data, "Access denied: %d", pop3code);
1095     result = CURLE_LOGIN_DENIED;
1096   }
1097   else {
1098     /* Create the type-1 message */
1099     result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
1100                                                  &conn->ntlm,
1101                                                  &type1msg, &len);
1102     if(!result && type1msg) {
1103       /* Send the message */
1104       result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type1msg);
1105
1106       if(!result)
1107         state(conn, POP3_AUTH_NTLM_TYPE2MSG);
1108     }
1109   }
1110
1111   Curl_safefree(type1msg);
1112
1113   return result;
1114 }
1115
1116 /* For NTLM type-2 responses (sent in reponse to our type-1 message) */
1117 static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn,
1118                                                    int pop3code,
1119                                                    pop3state instate)
1120 {
1121   CURLcode result = CURLE_OK;
1122   struct SessionHandle *data = conn->data;
1123   char *type2msg = NULL;
1124   char *type3msg = NULL;
1125   size_t len = 0;
1126
1127   (void)instate; /* no use for this yet */
1128
1129   if(pop3code != '+') {
1130     failf(data, "Access denied: %d", pop3code);
1131     result = CURLE_LOGIN_DENIED;
1132   }
1133   else {
1134     /* Get the type-2 message */
1135     pop3_get_message(data->state.buffer, &type2msg);
1136
1137     /* Decode the type-2 message */
1138     result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm);
1139     if(result) {
1140       /* Send the cancellation */
1141       result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
1142
1143       if(!result)
1144         state(conn, POP3_AUTH_CANCEL);
1145     }
1146     else {
1147       /* Create the type-3 message */
1148       result = Curl_sasl_create_ntlm_type3_message(data, conn->user,
1149                                                    conn->passwd, &conn->ntlm,
1150                                                    &type3msg, &len);
1151       if(!result && type3msg) {
1152         /* Send the message */
1153         result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type3msg);
1154
1155         if(!result)
1156           state(conn, POP3_AUTH_FINAL);
1157       }
1158     }
1159   }
1160
1161   Curl_safefree(type3msg);
1162
1163   return result;
1164 }
1165 #endif
1166
1167 /* For AUTH XOAUTH2 (without initial response) responses */
1168 static CURLcode pop3_state_auth_xoauth2_resp(struct connectdata *conn,
1169                                              int pop3code, pop3state instate)
1170 {
1171   CURLcode result = CURLE_OK;
1172   struct SessionHandle *data = conn->data;
1173   size_t len = 0;
1174   char *xoauth = NULL;
1175
1176   (void)instate; /* no use for this yet */
1177
1178   if(pop3code != '+') {
1179     failf(data, "Access denied: %d", pop3code);
1180     result = CURLE_LOGIN_DENIED;
1181   }
1182   else {
1183     /* Create the authorisation message */
1184     result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
1185                                               conn->xoauth2_bearer,
1186                                               &xoauth, &len);
1187     if(!result && xoauth) {
1188       /* Send the message */
1189       result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", xoauth);
1190
1191       if(!result)
1192         state(conn, POP3_AUTH_FINAL);
1193     }
1194   }
1195
1196   Curl_safefree(xoauth);
1197
1198   return result;
1199 }
1200
1201 /* For AUTH cancellation responses */
1202 static CURLcode pop3_state_auth_cancel_resp(struct connectdata *conn,
1203                                             int pop3code,
1204                                             pop3state instate)
1205 {
1206   struct SessionHandle *data = conn->data;
1207
1208   (void)pop3code;
1209   (void)instate; /* no use for this yet */
1210
1211   failf(data, "Authentication cancelled");
1212
1213   return CURLE_LOGIN_DENIED;
1214 }
1215
1216 /* For final responses in the AUTH sequence */
1217 static CURLcode pop3_state_auth_final_resp(struct connectdata *conn,
1218                                            int pop3code,
1219                                            pop3state instate)
1220 {
1221   CURLcode result = CURLE_OK;
1222   struct SessionHandle *data = conn->data;
1223
1224   (void)instate; /* no use for this yet */
1225
1226   if(pop3code != '+') {
1227     failf(data, "Authentication failed: %d", pop3code);
1228     result = CURLE_LOGIN_DENIED;
1229   }
1230   else
1231     /* End of connect phase */
1232     state(conn, POP3_STOP);
1233
1234   return result;
1235 }
1236
1237 #ifndef CURL_DISABLE_CRYPTO_AUTH
1238 /* For APOP responses */
1239 static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code,
1240                                      pop3state instate)
1241 {
1242   CURLcode result = CURLE_OK;
1243   struct SessionHandle *data = conn->data;
1244
1245   (void)instate; /* no use for this yet */
1246
1247   if(pop3code != '+') {
1248     failf(data, "Authentication failed: %d", pop3code);
1249     result = CURLE_LOGIN_DENIED;
1250   }
1251   else
1252     /* End of connect phase */
1253     state(conn, POP3_STOP);
1254
1255   return result;
1256 }
1257 #endif
1258
1259 /* For USER responses */
1260 static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code,
1261                                      pop3state instate)
1262 {
1263   CURLcode result = CURLE_OK;
1264   struct SessionHandle *data = conn->data;
1265
1266   (void)instate; /* no use for this yet */
1267
1268   if(pop3code != '+') {
1269     failf(data, "Access denied. %c", pop3code);
1270     result = CURLE_LOGIN_DENIED;
1271   }
1272   else
1273     /* Send the PASS command */
1274     result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s",
1275                            conn->passwd ? conn->passwd : "");
1276   if(!result)
1277     state(conn, POP3_PASS);
1278
1279   return result;
1280 }
1281
1282 /* For PASS responses */
1283 static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code,
1284                                      pop3state instate)
1285 {
1286   CURLcode result = CURLE_OK;
1287   struct SessionHandle *data = conn->data;
1288
1289   (void)instate; /* no use for this yet */
1290
1291   if(pop3code != '+') {
1292     failf(data, "Access denied. %c", pop3code);
1293     result = CURLE_LOGIN_DENIED;
1294   }
1295   else
1296     /* End of connect phase */
1297     state(conn, POP3_STOP);
1298
1299   return result;
1300 }
1301
1302 /* For command responses */
1303 static CURLcode pop3_state_command_resp(struct connectdata *conn,
1304                                         int pop3code,
1305                                         pop3state instate)
1306 {
1307   CURLcode result = CURLE_OK;
1308   struct SessionHandle *data = conn->data;
1309   struct POP3 *pop3 = data->req.protop;
1310   struct pop3_conn *pop3c = &conn->proto.pop3c;
1311   struct pingpong *pp = &pop3c->pp;
1312
1313   (void)instate; /* no use for this yet */
1314
1315   if(pop3code != '+') {
1316     state(conn, POP3_STOP);
1317     return CURLE_RECV_ERROR;
1318   }
1319
1320   /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
1321      EOB string so count this is two matching bytes. This is necessary to make
1322      the code detect the EOB if the only data than comes now is %2e CR LF like
1323      when there is no body to return. */
1324   pop3c->eob = 2;
1325
1326   /* But since this initial CR LF pair is not part of the actual body, we set
1327      the strip counter here so that these bytes won't be delivered. */
1328   pop3c->strip = 2;
1329
1330   if(pop3->transfer == FTPTRANSFER_BODY) {
1331     /* POP3 download */
1332     Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
1333
1334     if(pp->cache) {
1335       /* The header "cache" contains a bunch of data that is actually body
1336          content so send it as such. Note that there may even be additional
1337          "headers" after the body */
1338
1339       if(!data->set.opt_no_body) {
1340         result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
1341         if(result)
1342           return result;
1343       }
1344
1345       /* Free the cache */
1346       Curl_safefree(pp->cache);
1347
1348       /* Reset the cache size */
1349       pp->cache_size = 0;
1350     }
1351   }
1352
1353   /* End of DO phase */
1354   state(conn, POP3_STOP);
1355
1356   return result;
1357 }
1358
1359 static CURLcode pop3_statemach_act(struct connectdata *conn)
1360 {
1361   CURLcode result = CURLE_OK;
1362   curl_socket_t sock = conn->sock[FIRSTSOCKET];
1363   int pop3code;
1364   struct pop3_conn *pop3c = &conn->proto.pop3c;
1365   struct pingpong *pp = &pop3c->pp;
1366   size_t nread = 0;
1367
1368   /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */
1369   if(pop3c->state == POP3_UPGRADETLS)
1370     return pop3_perform_upgrade_tls(conn);
1371
1372   /* Flush any data that needs to be sent */
1373   if(pp->sendleft)
1374     return Curl_pp_flushsend(pp);
1375
1376   /* Read the response from the server */
1377   result = Curl_pp_readresp(sock, pp, &pop3code, &nread);
1378   if(result)
1379     return result;
1380
1381   if(pop3code) {
1382     /* We have now received a full POP3 server response */
1383     switch(pop3c->state) {
1384     case POP3_SERVERGREET:
1385       result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state);
1386       break;
1387
1388     case POP3_CAPA:
1389       result = pop3_state_capa_resp(conn, pop3code, pop3c->state);
1390       break;
1391
1392     case POP3_STARTTLS:
1393       result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);
1394       break;
1395
1396     case POP3_AUTH_PLAIN:
1397       result = pop3_state_auth_plain_resp(conn, pop3code, pop3c->state);
1398       break;
1399
1400     case POP3_AUTH_LOGIN:
1401       result = pop3_state_auth_login_resp(conn, pop3code, pop3c->state);
1402       break;
1403
1404     case POP3_AUTH_LOGIN_PASSWD:
1405       result = pop3_state_auth_login_password_resp(conn, pop3code,
1406                                                    pop3c->state);
1407       break;
1408
1409 #ifndef CURL_DISABLE_CRYPTO_AUTH
1410     case POP3_AUTH_CRAMMD5:
1411       result = pop3_state_auth_cram_resp(conn, pop3code, pop3c->state);
1412       break;
1413
1414     case POP3_AUTH_DIGESTMD5:
1415       result = pop3_state_auth_digest_resp(conn, pop3code, pop3c->state);
1416       break;
1417
1418     case POP3_AUTH_DIGESTMD5_RESP:
1419       result = pop3_state_auth_digest_resp_resp(conn, pop3code, pop3c->state);
1420       break;
1421 #endif
1422
1423 #ifdef USE_NTLM
1424     case POP3_AUTH_NTLM:
1425       result = pop3_state_auth_ntlm_resp(conn, pop3code, pop3c->state);
1426       break;
1427
1428     case POP3_AUTH_NTLM_TYPE2MSG:
1429       result = pop3_state_auth_ntlm_type2msg_resp(conn, pop3code,
1430                                                   pop3c->state);
1431       break;
1432 #endif
1433
1434     case POP3_AUTH_XOAUTH2:
1435       result = pop3_state_auth_xoauth2_resp(conn, pop3code, pop3c->state);
1436       break;
1437
1438     case POP3_AUTH_CANCEL:
1439       result = pop3_state_auth_cancel_resp(conn, pop3code, pop3c->state);
1440       break;
1441
1442     case POP3_AUTH_FINAL:
1443       result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state);
1444       break;
1445
1446 #ifndef CURL_DISABLE_CRYPTO_AUTH
1447     case POP3_APOP:
1448       result = pop3_state_apop_resp(conn, pop3code, pop3c->state);
1449       break;
1450 #endif
1451
1452     case POP3_USER:
1453       result = pop3_state_user_resp(conn, pop3code, pop3c->state);
1454       break;
1455
1456     case POP3_PASS:
1457       result = pop3_state_pass_resp(conn, pop3code, pop3c->state);
1458       break;
1459
1460     case POP3_COMMAND:
1461       result = pop3_state_command_resp(conn, pop3code, pop3c->state);
1462       break;
1463
1464     case POP3_QUIT:
1465       /* fallthrough, just stop! */
1466     default:
1467       /* internal error */
1468       state(conn, POP3_STOP);
1469       break;
1470     }
1471   }
1472
1473   return result;
1474 }
1475
1476 /* Called repeatedly until done from multi.c */
1477 static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
1478 {
1479   CURLcode result = CURLE_OK;
1480   struct pop3_conn *pop3c = &conn->proto.pop3c;
1481
1482   if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
1483     result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
1484     if(result || !pop3c->ssldone)
1485       return result;
1486   }
1487
1488   result = Curl_pp_statemach(&pop3c->pp, FALSE);
1489   *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
1490
1491   return result;
1492 }
1493
1494 static CURLcode pop3_block_statemach(struct connectdata *conn)
1495 {
1496   CURLcode result = CURLE_OK;
1497   struct pop3_conn *pop3c = &conn->proto.pop3c;
1498
1499   while(pop3c->state != POP3_STOP && !result)
1500     result = Curl_pp_statemach(&pop3c->pp, TRUE);
1501
1502   return result;
1503 }
1504
1505 /* Allocate and initialize the POP3 struct for the current SessionHandle if
1506    required */
1507 static CURLcode pop3_init(struct connectdata *conn)
1508 {
1509   CURLcode result = CURLE_OK;
1510   struct SessionHandle *data = conn->data;
1511   struct POP3 *pop3;
1512
1513   pop3 = data->req.protop = calloc(sizeof(struct POP3), 1);
1514   if(!pop3)
1515     result = CURLE_OUT_OF_MEMORY;
1516
1517   return result;
1518 }
1519
1520 /* For the POP3 "protocol connect" and "doing" phases only */
1521 static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
1522                         int numsocks)
1523 {
1524   return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks);
1525 }
1526
1527 /***********************************************************************
1528  *
1529  * pop3_connect()
1530  *
1531  * This function should do everything that is to be considered a part of the
1532  * connection phase.
1533  *
1534  * The variable 'done' points to will be TRUE if the protocol-layer connect
1535  * phase is done when this function returns, or FALSE if not.
1536  */
1537 static CURLcode pop3_connect(struct connectdata *conn, bool *done)
1538 {
1539   CURLcode result = CURLE_OK;
1540   struct pop3_conn *pop3c = &conn->proto.pop3c;
1541   struct pingpong *pp = &pop3c->pp;
1542
1543   *done = FALSE; /* default to not done yet */
1544
1545   /* We always support persistent connections in POP3 */
1546   conn->bits.close = FALSE;
1547
1548   /* Set the default response time-out */
1549   pp->response_time = RESP_TIMEOUT;
1550   pp->statemach_act = pop3_statemach_act;
1551   pp->endofresp = pop3_endofresp;
1552   pp->conn = conn;
1553
1554   /* Set the default preferred authentication type and mechanism */
1555   pop3c->preftype = POP3_TYPE_ANY;
1556   pop3c->prefmech = SASL_AUTH_ANY;
1557
1558   /* Initialise the pingpong layer */
1559   Curl_pp_init(pp);
1560
1561   /* Parse the URL options */
1562   result = pop3_parse_url_options(conn);
1563   if(result)
1564     return result;
1565
1566   /* Start off waiting for the server greeting response */
1567   state(conn, POP3_SERVERGREET);
1568
1569   result = pop3_multi_statemach(conn, done);
1570
1571   return result;
1572 }
1573
1574 /***********************************************************************
1575  *
1576  * pop3_done()
1577  *
1578  * The DONE function. This does what needs to be done after a single DO has
1579  * performed.
1580  *
1581  * Input argument is already checked for validity.
1582  */
1583 static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
1584                           bool premature)
1585 {
1586   CURLcode result = CURLE_OK;
1587   struct SessionHandle *data = conn->data;
1588   struct POP3 *pop3 = data->req.protop;
1589
1590   (void)premature;
1591
1592   if(!pop3)
1593     /* When the easy handle is removed from the multi interface while libcurl
1594        is still trying to resolve the host name, the POP3 struct is not yet
1595        initialized. However, the removal action calls Curl_done() which in
1596        turn calls this function, so we simply return success. */
1597     return CURLE_OK;
1598
1599   if(status) {
1600     conn->bits.close = TRUE; /* marked for closure */
1601     result = status;         /* use the already set error code */
1602   }
1603
1604   /* Cleanup our per-request based variables */
1605   Curl_safefree(pop3->id);
1606   Curl_safefree(pop3->custom);
1607
1608   /* Clear the transfer mode for the next request */
1609   pop3->transfer = FTPTRANSFER_BODY;
1610
1611   return result;
1612 }
1613
1614 /***********************************************************************
1615  *
1616  * pop3_perform()
1617  *
1618  * This is the actual DO function for POP3. Get a message/listing according to
1619  * the options previously setup.
1620  */
1621 static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
1622                              bool *dophase_done)
1623 {
1624   /* This is POP3 and no proxy */
1625   CURLcode result = CURLE_OK;
1626   struct POP3 *pop3 = conn->data->req.protop;
1627
1628   DEBUGF(infof(conn->data, "DO phase starts\n"));
1629
1630   if(conn->data->set.opt_no_body) {
1631     /* Requested no body means no transfer */
1632     pop3->transfer = FTPTRANSFER_INFO;
1633   }
1634
1635   *dophase_done = FALSE; /* not done yet */
1636
1637   /* Start the first command in the DO phase */
1638   result = pop3_perform_command(conn);
1639   if(result)
1640     return result;
1641
1642   /* Run the state-machine */
1643   result = pop3_multi_statemach(conn, dophase_done);
1644
1645   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
1646
1647   if(*dophase_done)
1648     DEBUGF(infof(conn->data, "DO phase is complete\n"));
1649
1650   return result;
1651 }
1652
1653 /***********************************************************************
1654  *
1655  * pop3_do()
1656  *
1657  * This function is registered as 'curl_do' function. It decodes the path
1658  * parts etc as a wrapper to the actual DO function (pop3_perform).
1659  *
1660  * The input argument is already checked for validity.
1661  */
1662 static CURLcode pop3_do(struct connectdata *conn, bool *done)
1663 {
1664   CURLcode result = CURLE_OK;
1665
1666   *done = FALSE; /* default to false */
1667
1668   /* Parse the URL path */
1669   result = pop3_parse_url_path(conn);
1670   if(result)
1671     return result;
1672
1673   /* Parse the custom request */
1674   result = pop3_parse_custom_request(conn);
1675   if(result)
1676     return result;
1677
1678   result = pop3_regular_transfer(conn, done);
1679
1680   return result;
1681 }
1682
1683 /***********************************************************************
1684  *
1685  * pop3_disconnect()
1686  *
1687  * Disconnect from an POP3 server. Cleanup protocol-specific per-connection
1688  * resources. BLOCKING.
1689  */
1690 static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection)
1691 {
1692   struct pop3_conn *pop3c = &conn->proto.pop3c;
1693
1694   /* We cannot send quit unconditionally. If this connection is stale or
1695      bad in any way, sending quit and waiting around here will make the
1696      disconnect wait in vain and cause more problems than we need to. */
1697
1698   /* The POP3 session may or may not have been allocated/setup at this
1699      point! */
1700   if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart)
1701     if(!pop3_perform_quit(conn))
1702       (void)pop3_block_statemach(conn); /* ignore errors on QUIT */
1703
1704   /* Disconnect from the server */
1705   Curl_pp_disconnect(&pop3c->pp);
1706
1707   /* Cleanup the SASL module */
1708   Curl_sasl_cleanup(conn, pop3c->authused);
1709
1710   /* Cleanup our connection based variables */
1711   Curl_safefree(pop3c->apoptimestamp);
1712
1713   return CURLE_OK;
1714 }
1715
1716 /* Call this when the DO phase has completed */
1717 static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected)
1718 {
1719   (void)conn;
1720   (void)connected;
1721
1722   return CURLE_OK;
1723 }
1724
1725 /* Called from multi.c while DOing */
1726 static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done)
1727 {
1728   CURLcode result = pop3_multi_statemach(conn, dophase_done);
1729
1730   if(result)
1731     DEBUGF(infof(conn->data, "DO phase failed\n"));
1732   else if(*dophase_done) {
1733     result = pop3_dophase_done(conn, FALSE /* not connected */);
1734
1735     DEBUGF(infof(conn->data, "DO phase is complete\n"));
1736   }
1737
1738   return result;
1739 }
1740
1741 /***********************************************************************
1742  *
1743  * pop3_regular_transfer()
1744  *
1745  * The input argument is already checked for validity.
1746  *
1747  * Performs all commands done before a regular transfer between a local and a
1748  * remote host.
1749  */
1750 static CURLcode pop3_regular_transfer(struct connectdata *conn,
1751                                       bool *dophase_done)
1752 {
1753   CURLcode result = CURLE_OK;
1754   bool connected = FALSE;
1755   struct SessionHandle *data = conn->data;
1756
1757   /* Make sure size is unknown at this point */
1758   data->req.size = -1;
1759
1760   /* Set the progress data */
1761   Curl_pgrsSetUploadCounter(data, 0);
1762   Curl_pgrsSetDownloadCounter(data, 0);
1763   Curl_pgrsSetUploadSize(data, 0);
1764   Curl_pgrsSetDownloadSize(data, 0);
1765
1766   /* Carry out the perform */
1767   result = pop3_perform(conn, &connected, dophase_done);
1768
1769   /* Perform post DO phase operations if necessary */
1770   if(!result && *dophase_done)
1771     result = pop3_dophase_done(conn, connected);
1772
1773   return result;
1774 }
1775
1776 static CURLcode pop3_setup_connection(struct connectdata *conn)
1777 {
1778   struct SessionHandle *data = conn->data;
1779
1780   /* Initialise the POP3 layer */
1781   CURLcode result = pop3_init(conn);
1782   if(result)
1783     return result;
1784
1785   if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
1786     /* Unless we have asked to tunnel POP3 operations through the proxy, we
1787        switch and use HTTP operations only */
1788 #ifndef CURL_DISABLE_HTTP
1789     if(conn->handler == &Curl_handler_pop3)
1790       conn->handler = &Curl_handler_pop3_proxy;
1791     else {
1792 #ifdef USE_SSL
1793       conn->handler = &Curl_handler_pop3s_proxy;
1794 #else
1795       failf(data, "POP3S not supported!");
1796       return CURLE_UNSUPPORTED_PROTOCOL;
1797 #endif
1798     }
1799
1800     /* set it up as an HTTP connection instead */
1801     return conn->handler->setup_connection(conn);
1802 #else
1803     failf(data, "POP3 over http proxy requires HTTP support built-in!");
1804     return CURLE_UNSUPPORTED_PROTOCOL;
1805 #endif
1806   }
1807
1808   data->state.path++;   /* don't include the initial slash */
1809
1810   return CURLE_OK;
1811 }
1812
1813 /***********************************************************************
1814  *
1815  * pop3_parse_url_options()
1816  *
1817  * Parse the URL login options.
1818  */
1819 static CURLcode pop3_parse_url_options(struct connectdata *conn)
1820 {
1821   CURLcode result = CURLE_OK;
1822   struct pop3_conn *pop3c = &conn->proto.pop3c;
1823   const char *options = conn->options;
1824   const char *ptr = options;
1825
1826   if(options) {
1827     const char *key = ptr;
1828
1829     while(*ptr && *ptr != '=')
1830         ptr++;
1831
1832     if(strnequal(key, "AUTH", 4)) {
1833       const char *value = ptr + 1;
1834
1835       if(strequal(value, "*")) {
1836         pop3c->preftype = POP3_TYPE_ANY;
1837         pop3c->prefmech = SASL_AUTH_ANY;
1838       }
1839       else if(strequal(value, "+APOP")) {
1840         pop3c->preftype = POP3_TYPE_APOP;
1841         pop3c->prefmech = SASL_AUTH_NONE;
1842       }
1843       else if(strequal(value, SASL_MECH_STRING_LOGIN)) {
1844         pop3c->preftype = POP3_TYPE_SASL;
1845         pop3c->prefmech = SASL_MECH_LOGIN;
1846       }
1847       else if(strequal(value, SASL_MECH_STRING_PLAIN)) {
1848         pop3c->preftype = POP3_TYPE_SASL;
1849         pop3c->prefmech = SASL_MECH_PLAIN;
1850       }
1851       else if(strequal(value, SASL_MECH_STRING_CRAM_MD5)) {
1852         pop3c->preftype = POP3_TYPE_SASL;
1853         pop3c->prefmech = SASL_MECH_CRAM_MD5;
1854       }
1855       else if(strequal(value, SASL_MECH_STRING_DIGEST_MD5)) {
1856         pop3c->preftype = POP3_TYPE_SASL;
1857         pop3c->prefmech = SASL_MECH_DIGEST_MD5;
1858       }
1859       else if(strequal(value, SASL_MECH_STRING_GSSAPI)) {
1860         pop3c->preftype = POP3_TYPE_SASL;
1861         pop3c->prefmech = SASL_MECH_GSSAPI;
1862       }
1863       else if(strequal(value, SASL_MECH_STRING_NTLM)) {
1864         pop3c->preftype = POP3_TYPE_SASL;
1865         pop3c->prefmech = SASL_MECH_NTLM;
1866       }
1867       else if(strequal(value, SASL_MECH_STRING_XOAUTH2)) {
1868         pop3c->preftype = POP3_TYPE_SASL;
1869         pop3c->prefmech = SASL_MECH_XOAUTH2;
1870       }
1871       else {
1872         pop3c->preftype = POP3_TYPE_NONE;
1873         pop3c->prefmech = SASL_AUTH_NONE;
1874       }
1875     }
1876     else
1877       result = CURLE_URL_MALFORMAT;
1878   }
1879
1880   return result;
1881 }
1882
1883 /***********************************************************************
1884  *
1885  * pop3_parse_url_path()
1886  *
1887  * Parse the URL path into separate path components.
1888  */
1889 static CURLcode pop3_parse_url_path(struct connectdata *conn)
1890 {
1891   /* The POP3 struct is already initialised in pop3_connect() */
1892   struct SessionHandle *data = conn->data;
1893   struct POP3 *pop3 = data->req.protop;
1894   const char *path = data->state.path;
1895
1896   /* URL decode the path for the message ID */
1897   return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);
1898 }
1899
1900 /***********************************************************************
1901  *
1902  * pop3_parse_custom_request()
1903  *
1904  * Parse the custom request.
1905  */
1906 static CURLcode pop3_parse_custom_request(struct connectdata *conn)
1907 {
1908   CURLcode result = CURLE_OK;
1909   struct SessionHandle *data = conn->data;
1910   struct POP3 *pop3 = data->req.protop;
1911   const char *custom = data->set.str[STRING_CUSTOMREQUEST];
1912
1913   /* URL decode the custom request */
1914   if(custom)
1915     result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE);
1916
1917   return result;
1918 }
1919
1920 /***********************************************************************
1921  *
1922  * Curl_pop3_write()
1923  *
1924  * This function scans the body after the end-of-body and writes everything
1925  * until the end is found.
1926  */
1927 CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
1928 {
1929   /* This code could be made into a special function in the handler struct */
1930   CURLcode result = CURLE_OK;
1931   struct SessionHandle *data = conn->data;
1932   struct SingleRequest *k = &data->req;
1933
1934   struct pop3_conn *pop3c = &conn->proto.pop3c;
1935   bool strip_dot = FALSE;
1936   size_t last = 0;
1937   size_t i;
1938
1939   /* Search through the buffer looking for the end-of-body marker which is
1940      5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
1941      the eob so the server will have prefixed it with an extra dot which we
1942      need to strip out. Additionally the marker could of course be spread out
1943      over 5 different data chunks. */
1944   for(i = 0; i < nread; i++) {
1945     size_t prev = pop3c->eob;
1946
1947     switch(str[i]) {
1948     case 0x0d:
1949       if(pop3c->eob == 0) {
1950         pop3c->eob++;
1951
1952         if(i) {
1953           /* Write out the body part that didn't match */
1954           result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
1955                                      i - last);
1956
1957           if(result)
1958             return result;
1959
1960           last = i;
1961         }
1962       }
1963       else if(pop3c->eob == 3)
1964         pop3c->eob++;
1965       else
1966         /* If the character match wasn't at position 0 or 3 then restart the
1967            pattern matching */
1968         pop3c->eob = 1;
1969       break;
1970
1971     case 0x0a:
1972       if(pop3c->eob == 1 || pop3c->eob == 4)
1973         pop3c->eob++;
1974       else
1975         /* If the character match wasn't at position 1 or 4 then start the
1976            search again */
1977         pop3c->eob = 0;
1978       break;
1979
1980     case 0x2e:
1981       if(pop3c->eob == 2)
1982         pop3c->eob++;
1983       else if(pop3c->eob == 3) {
1984         /* We have an extra dot after the CRLF which we need to strip off */
1985         strip_dot = TRUE;
1986         pop3c->eob = 0;
1987       }
1988       else
1989         /* If the character match wasn't at position 2 then start the search
1990            again */
1991         pop3c->eob = 0;
1992       break;
1993
1994     default:
1995       pop3c->eob = 0;
1996       break;
1997     }
1998
1999     /* Did we have a partial match which has subsequently failed? */
2000     if(prev && prev >= pop3c->eob) {
2001       /* Strip can only be non-zero for the very first mismatch after CRLF
2002          and then both prev and strip are equal and nothing will be output
2003          below */
2004       while(prev && pop3c->strip) {
2005         prev--;
2006         pop3c->strip--;
2007       }
2008
2009       if(prev) {
2010         /* If the partial match was the CRLF and dot then only write the CRLF
2011            as the server would have inserted the dot */
2012         result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB,
2013                                    strip_dot ? prev - 1 : prev);
2014
2015         if(result)
2016           return result;
2017
2018         last = i;
2019         strip_dot = FALSE;
2020       }
2021     }
2022   }
2023
2024   if(pop3c->eob == POP3_EOB_LEN) {
2025     /* We have a full match so the transfer is done, however we must transfer
2026     the CRLF at the start of the EOB as this is considered to be part of the
2027     message as per RFC-1939, sect. 3 */
2028     result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
2029
2030     k->keepon &= ~KEEP_RECV;
2031     pop3c->eob = 0;
2032
2033     return result;
2034   }
2035
2036   if(pop3c->eob)
2037     /* While EOB is matching nothing should be output */
2038     return CURLE_OK;
2039
2040   if(nread - last) {
2041     result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
2042                                nread - last);
2043   }
2044
2045   return result;
2046 }
2047
2048 #endif /* CURL_DISABLE_POP3 */