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