openssl: guard against OOM on context creation
[platform/upstream/curl.git] / lib / smtp.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2020, 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 https://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  * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
28  * RFC4954 SMTP Authentication
29  * RFC5321 SMTP protocol
30  * RFC5890 Internationalized Domain Names for Applications (IDNA)
31  * RFC6531 SMTP Extension for Internationalized Email
32  * RFC6532 Internationalized Email Headers
33  * RFC6749 OAuth 2.0 Authorization Framework
34  * RFC8314 Use of TLS for Email Submission and Access
35  * Draft   SMTP URL Interface   <draft-earhart-url-smtp-00.txt>
36  * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
37  *
38  ***************************************************************************/
39
40 #include "curl_setup.h"
41
42 #ifndef CURL_DISABLE_SMTP
43
44 #ifdef HAVE_NETINET_IN_H
45 #include <netinet/in.h>
46 #endif
47 #ifdef HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
49 #endif
50 #ifdef HAVE_UTSNAME_H
51 #include <sys/utsname.h>
52 #endif
53 #ifdef HAVE_NETDB_H
54 #include <netdb.h>
55 #endif
56 #ifdef __VMS
57 #include <in.h>
58 #include <inet.h>
59 #endif
60
61 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
62 #undef in_addr_t
63 #define in_addr_t unsigned long
64 #endif
65
66 #include <curl/curl.h>
67 #include "urldata.h"
68 #include "sendf.h"
69 #include "hostip.h"
70 #include "progress.h"
71 #include "transfer.h"
72 #include "escape.h"
73 #include "http.h" /* for HTTP proxy tunnel stuff */
74 #include "mime.h"
75 #include "socks.h"
76 #include "smtp.h"
77 #include "strtoofft.h"
78 #include "strcase.h"
79 #include "vtls/vtls.h"
80 #include "connect.h"
81 #include "strerror.h"
82 #include "select.h"
83 #include "multiif.h"
84 #include "url.h"
85 #include "curl_gethostname.h"
86 #include "curl_sasl.h"
87 #include "warnless.h"
88 /* The last 3 #include files should be in this order */
89 #include "curl_printf.h"
90 #include "curl_memory.h"
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 static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done);
103 static CURLcode smtp_setup_connection(struct connectdata *conn);
104 static CURLcode smtp_parse_url_options(struct connectdata *conn);
105 static CURLcode smtp_parse_url_path(struct connectdata *conn);
106 static CURLcode smtp_parse_custom_request(struct connectdata *conn);
107 static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma,
108                                    char **address, struct hostname *host);
109 static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech,
110                                   const char *initresp);
111 static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp);
112 static void smtp_get_message(char *buffer, char **outptr);
113
114 /*
115  * SMTP protocol handler.
116  */
117
118 const struct Curl_handler Curl_handler_smtp = {
119   "SMTP",                           /* scheme */
120   smtp_setup_connection,            /* setup_connection */
121   smtp_do,                          /* do_it */
122   smtp_done,                        /* done */
123   ZERO_NULL,                        /* do_more */
124   smtp_connect,                     /* connect_it */
125   smtp_multi_statemach,             /* connecting */
126   smtp_doing,                       /* doing */
127   smtp_getsock,                     /* proto_getsock */
128   smtp_getsock,                     /* doing_getsock */
129   ZERO_NULL,                        /* domore_getsock */
130   ZERO_NULL,                        /* perform_getsock */
131   smtp_disconnect,                  /* disconnect */
132   ZERO_NULL,                        /* readwrite */
133   ZERO_NULL,                        /* connection_check */
134   PORT_SMTP,                        /* defport */
135   CURLPROTO_SMTP,                   /* protocol */
136   CURLPROTO_SMTP,                   /* family */
137   PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
138   PROTOPT_URLOPTIONS
139 };
140
141 #ifdef USE_SSL
142 /*
143  * SMTPS protocol handler.
144  */
145
146 const struct Curl_handler Curl_handler_smtps = {
147   "SMTPS",                          /* scheme */
148   smtp_setup_connection,            /* setup_connection */
149   smtp_do,                          /* do_it */
150   smtp_done,                        /* done */
151   ZERO_NULL,                        /* do_more */
152   smtp_connect,                     /* connect_it */
153   smtp_multi_statemach,             /* connecting */
154   smtp_doing,                       /* doing */
155   smtp_getsock,                     /* proto_getsock */
156   smtp_getsock,                     /* doing_getsock */
157   ZERO_NULL,                        /* domore_getsock */
158   ZERO_NULL,                        /* perform_getsock */
159   smtp_disconnect,                  /* disconnect */
160   ZERO_NULL,                        /* readwrite */
161   ZERO_NULL,                        /* connection_check */
162   PORT_SMTPS,                       /* defport */
163   CURLPROTO_SMTPS,                  /* protocol */
164   CURLPROTO_SMTP,                   /* family */
165   PROTOPT_CLOSEACTION | PROTOPT_SSL
166   | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */
167 };
168 #endif
169
170 /* SASL parameters for the smtp protocol */
171 static const struct SASLproto saslsmtp = {
172   "smtp",                     /* The service name */
173   334,                        /* Code received when continuation is expected */
174   235,                        /* Code to receive upon authentication success */
175   512 - 8,                    /* Maximum initial response length (no max) */
176   smtp_perform_auth,          /* Send authentication command */
177   smtp_continue_auth,         /* Send authentication continuation */
178   smtp_get_message            /* Get SASL response message */
179 };
180
181 #ifdef USE_SSL
182 static void smtp_to_smtps(struct connectdata *conn)
183 {
184   /* Change the connection handler */
185   conn->handler = &Curl_handler_smtps;
186
187   /* Set the connection's upgraded to TLS flag */
188   conn->bits.tls_upgraded = TRUE;
189 }
190 #else
191 #define smtp_to_smtps(x) Curl_nop_stmt
192 #endif
193
194 /***********************************************************************
195  *
196  * smtp_endofresp()
197  *
198  * Checks for an ending SMTP status code at the start of the given string, but
199  * also detects various capabilities from the EHLO response including the
200  * supported authentication mechanisms.
201  */
202 static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
203                            int *resp)
204 {
205   struct smtp_conn *smtpc = &conn->proto.smtpc;
206   bool result = FALSE;
207
208   /* Nothing for us */
209   if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
210     return FALSE;
211
212   /* Do we have a command response? This should be the response code followed
213      by a space and optionally some text as per RFC-5321 and as outlined in
214      Section 4. Examples of RFC-4954 but some e-mail servers ignore this and
215      only send the response code instead as per Section 4.2. */
216   if(line[3] == ' ' || len == 5) {
217     char tmpline[6];
218
219     result = TRUE;
220     memset(tmpline, '\0', sizeof(tmpline));
221     memcpy(tmpline, line, (len == 5 ? 5 : 3));
222     *resp = curlx_sltosi(strtol(tmpline, NULL, 10));
223
224     /* Make sure real server never sends internal value */
225     if(*resp == 1)
226       *resp = 0;
227   }
228   /* Do we have a multiline (continuation) response? */
229   else if(line[3] == '-' &&
230           (smtpc->state == SMTP_EHLO || smtpc->state == SMTP_COMMAND)) {
231     result = TRUE;
232     *resp = 1;  /* Internal response code */
233   }
234
235   return result;
236 }
237
238 /***********************************************************************
239  *
240  * smtp_get_message()
241  *
242  * Gets the authentication message from the response buffer.
243  */
244 static void smtp_get_message(char *buffer, char **outptr)
245 {
246   size_t len = strlen(buffer);
247   char *message = NULL;
248
249   if(len > 4) {
250     /* Find the start of the message */
251     len -= 4;
252     for(message = buffer + 4; *message == ' ' || *message == '\t';
253         message++, len--)
254       ;
255
256     /* Find the end of the message */
257     for(; len--;)
258       if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
259          message[len] != '\t')
260         break;
261
262     /* Terminate the message */
263     if(++len) {
264       message[len] = '\0';
265     }
266   }
267   else
268     /* junk input => zero length output */
269     message = &buffer[len];
270
271   *outptr = message;
272 }
273
274 /***********************************************************************
275  *
276  * state()
277  *
278  * This is the ONLY way to change SMTP state!
279  */
280 static void state(struct connectdata *conn, smtpstate newstate)
281 {
282   struct smtp_conn *smtpc = &conn->proto.smtpc;
283 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
284   /* for debug purposes */
285   static const char * const names[] = {
286     "STOP",
287     "SERVERGREET",
288     "EHLO",
289     "HELO",
290     "STARTTLS",
291     "UPGRADETLS",
292     "AUTH",
293     "COMMAND",
294     "MAIL",
295     "RCPT",
296     "DATA",
297     "POSTDATA",
298     "QUIT",
299     /* LAST */
300   };
301
302   if(smtpc->state != newstate)
303     infof(conn->data, "SMTP %p state change from %s to %s\n",
304           (void *)smtpc, names[smtpc->state], names[newstate]);
305 #endif
306
307   smtpc->state = newstate;
308 }
309
310 /***********************************************************************
311  *
312  * smtp_perform_ehlo()
313  *
314  * Sends the EHLO command to not only initialise communication with the ESMTP
315  * server but to also obtain a list of server side supported capabilities.
316  */
317 static CURLcode smtp_perform_ehlo(struct connectdata *conn)
318 {
319   CURLcode result = CURLE_OK;
320   struct smtp_conn *smtpc = &conn->proto.smtpc;
321
322   smtpc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanism yet */
323   smtpc->sasl.authused = SASL_AUTH_NONE;  /* Clear the authentication mechanism
324                                              used for esmtp connections */
325   smtpc->tls_supported = FALSE;           /* Clear the TLS capability */
326   smtpc->auth_supported = FALSE;          /* Clear the AUTH capability */
327
328   /* Send the EHLO command */
329   result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain);
330
331   if(!result)
332     state(conn, SMTP_EHLO);
333
334   return result;
335 }
336
337 /***********************************************************************
338  *
339  * smtp_perform_helo()
340  *
341  * Sends the HELO command to initialise communication with the SMTP server.
342  */
343 static CURLcode smtp_perform_helo(struct connectdata *conn)
344 {
345   CURLcode result = CURLE_OK;
346   struct smtp_conn *smtpc = &conn->proto.smtpc;
347
348   smtpc->sasl.authused = SASL_AUTH_NONE; /* No authentication mechanism used
349                                             in smtp connections */
350
351   /* Send the HELO command */
352   result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain);
353
354   if(!result)
355     state(conn, SMTP_HELO);
356
357   return result;
358 }
359
360 /***********************************************************************
361  *
362  * smtp_perform_starttls()
363  *
364  * Sends the STLS command to start the upgrade to TLS.
365  */
366 static CURLcode smtp_perform_starttls(struct connectdata *conn)
367 {
368   /* Send the STARTTLS command */
369   CURLcode result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "STARTTLS");
370
371   if(!result)
372     state(conn, SMTP_STARTTLS);
373
374   return result;
375 }
376
377 /***********************************************************************
378  *
379  * smtp_perform_upgrade_tls()
380  *
381  * Performs the upgrade to TLS.
382  */
383 static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn)
384 {
385   /* Start the SSL connection */
386   struct smtp_conn *smtpc = &conn->proto.smtpc;
387   CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET,
388                                                  &smtpc->ssldone);
389
390   if(!result) {
391     if(smtpc->state != SMTP_UPGRADETLS)
392       state(conn, SMTP_UPGRADETLS);
393
394     if(smtpc->ssldone) {
395       smtp_to_smtps(conn);
396       result = smtp_perform_ehlo(conn);
397     }
398   }
399
400   return result;
401 }
402
403 /***********************************************************************
404  *
405  * smtp_perform_auth()
406  *
407  * Sends an AUTH command allowing the client to login with the given SASL
408  * authentication mechanism.
409  */
410 static CURLcode smtp_perform_auth(struct connectdata *conn,
411                                   const char *mech,
412                                   const char *initresp)
413 {
414   CURLcode result = CURLE_OK;
415   struct smtp_conn *smtpc = &conn->proto.smtpc;
416
417   if(initresp) {                                  /* AUTH <mech> ...<crlf> */
418     /* Send the AUTH command with the initial response */
419     result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
420   }
421   else {
422     /* Send the AUTH command */
423     result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
424   }
425
426   return result;
427 }
428
429 /***********************************************************************
430  *
431  * smtp_continue_auth()
432  *
433  * Sends SASL continuation data or cancellation.
434  */
435 static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp)
436 {
437   struct smtp_conn *smtpc = &conn->proto.smtpc;
438
439   return Curl_pp_sendf(&smtpc->pp, "%s", resp);
440 }
441
442 /***********************************************************************
443  *
444  * smtp_perform_authentication()
445  *
446  * Initiates the authentication sequence, with the appropriate SASL
447  * authentication mechanism.
448  */
449 static CURLcode smtp_perform_authentication(struct connectdata *conn)
450 {
451   CURLcode result = CURLE_OK;
452   struct smtp_conn *smtpc = &conn->proto.smtpc;
453   saslprogress progress;
454
455   /* Check we have enough data to authenticate with, and the
456      server supports authentiation, and end the connect phase if not */
457   if(!smtpc->auth_supported ||
458      !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
459     state(conn, SMTP_STOP);
460     return result;
461   }
462
463   /* Calculate the SASL login details */
464   result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress);
465
466   if(!result) {
467     if(progress == SASL_INPROGRESS)
468       state(conn, SMTP_AUTH);
469     else {
470       /* Other mechanisms not supported */
471       infof(conn->data, "No known authentication mechanisms supported!\n");
472       result = CURLE_LOGIN_DENIED;
473     }
474   }
475
476   return result;
477 }
478
479 /***********************************************************************
480  *
481  * smtp_perform_command()
482  *
483  * Sends a SMTP based command.
484  */
485 static CURLcode smtp_perform_command(struct connectdata *conn)
486 {
487   CURLcode result = CURLE_OK;
488   struct Curl_easy *data = conn->data;
489   struct SMTP *smtp = data->req.protop;
490
491   if(smtp->rcpt) {
492     /* We notify the server we are sending UTF-8 data if a) it supports the
493        SMTPUTF8 extension and b) The mailbox contains UTF-8 charaacters, in
494        either the local address or host name parts. This is regardless of
495        whether the host name is encoded using IDN ACE */
496     bool utf8 = FALSE;
497
498     if((!smtp->custom) || (!smtp->custom[0])) {
499       char *address = NULL;
500       struct hostname host = { NULL, NULL, NULL, NULL };
501
502       /* Parse the mailbox to verify into the local address and host name
503          parts, converting the host name to an IDN A-label if necessary */
504       result = smtp_parse_address(conn, smtp->rcpt->data,
505                                   &address, &host);
506       if(result)
507         return result;
508
509       /* Establish whether we should report SMTPUTF8 to the server for this
510          mailbox as per RFC-6531 sect. 3.1 point 6 */
511       utf8 = (conn->proto.smtpc.utf8_supported) &&
512              ((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
513               (!Curl_is_ASCII_name(host.name)));
514
515       /* Send the VRFY command (Note: The host name part may be absent when the
516          host is a local system) */
517       result = Curl_pp_sendf(&conn->proto.smtpc.pp, "VRFY %s%s%s%s",
518                              address,
519                              host.name ? "@" : "",
520                              host.name ? host.name : "",
521                              utf8 ? " SMTPUTF8" : "");
522
523       Curl_free_idnconverted_hostname(&host);
524       free(address);
525     }
526     else {
527       /* Establish whether we should report that we support SMTPUTF8 for EXPN
528          commands to the server as per RFC-6531 sect. 3.1 point 6 */
529       utf8 = (conn->proto.smtpc.utf8_supported) &&
530              (!strcmp(smtp->custom, "EXPN"));
531
532       /* Send the custom recipient based command such as the EXPN command */
533       result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s %s%s", smtp->custom,
534                              smtp->rcpt->data,
535                              utf8 ? " SMTPUTF8" : "");
536     }
537   }
538   else
539     /* Send the non-recipient based command such as HELP */
540     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s",
541                            smtp->custom && smtp->custom[0] != '\0' ?
542                            smtp->custom : "HELP");
543
544   if(!result)
545     state(conn, SMTP_COMMAND);
546
547   return result;
548 }
549
550 /***********************************************************************
551  *
552  * smtp_perform_mail()
553  *
554  * Sends an MAIL command to initiate the upload of a message.
555  */
556 static CURLcode smtp_perform_mail(struct connectdata *conn)
557 {
558   char *from = NULL;
559   char *auth = NULL;
560   char *size = NULL;
561   CURLcode result = CURLE_OK;
562   struct Curl_easy *data = conn->data;
563
564   /* We notify the server we are sending UTF-8 data if a) it supports the
565      SMTPUTF8 extension and b) The mailbox contains UTF-8 charaacters, in
566      either the local address or host name parts. This is regardless of
567      whether the host name is encoded using IDN ACE */
568   bool utf8 = FALSE;
569
570   /* Calculate the FROM parameter */
571   if(data->set.str[STRING_MAIL_FROM]) {
572     char *address = NULL;
573     struct hostname host = { NULL, NULL, NULL, NULL };
574
575     /* Parse the FROM mailbox into the local address and host name parts,
576        converting the host name to an IDN A-label if necessary */
577     result = smtp_parse_address(conn, data->set.str[STRING_MAIL_FROM],
578                                 &address, &host);
579     if(result)
580       return result;
581
582     /* Establish whether we should report SMTPUTF8 to the server for this
583        mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
584     utf8 = (conn->proto.smtpc.utf8_supported) &&
585            ((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
586             (!Curl_is_ASCII_name(host.name)));
587
588     if(host.name) {
589       from = aprintf("<%s@%s>", address, host.name);
590
591       Curl_free_idnconverted_hostname(&host);
592     }
593     else
594       /* An invalid mailbox was provided but we'll simply let the server worry
595          about that and reply with a 501 error */
596       from = aprintf("<%s>", address);
597
598     free(address);
599   }
600   else
601     /* Null reverse-path, RFC-5321, sect. 3.6.3 */
602     from = strdup("<>");
603
604   if(!from)
605     return CURLE_OUT_OF_MEMORY;
606
607   /* Calculate the optional AUTH parameter */
608   if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) {
609     if(data->set.str[STRING_MAIL_AUTH][0] != '\0') {
610       char *address = NULL;
611       struct hostname host = { NULL, NULL, NULL, NULL };
612
613       /* Parse the AUTH mailbox into the local address and host name parts,
614          converting the host name to an IDN A-label if necessary */
615       result = smtp_parse_address(conn, data->set.str[STRING_MAIL_AUTH],
616                                   &address, &host);
617       if(result) {
618         free(from);
619         return result;
620       }
621
622       /* Establish whether we should report SMTPUTF8 to the server for this
623          mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
624       if((!utf8) && (conn->proto.smtpc.utf8_supported) &&
625          ((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
626           (!Curl_is_ASCII_name(host.name))))
627         utf8 = TRUE;
628
629       if(host.name) {
630         auth = aprintf("<%s@%s>", address, host.name);
631
632         Curl_free_idnconverted_hostname(&host);
633       }
634       else
635         /* An invalid mailbox was provided but we'll simply let the server
636            worry about it */
637         auth = aprintf("<%s>", address);
638
639       free(address);
640     }
641     else
642       /* Empty AUTH, RFC-2554, sect. 5 */
643       auth = strdup("<>");
644
645     if(!auth) {
646       free(from);
647
648       return CURLE_OUT_OF_MEMORY;
649     }
650   }
651
652   /* Prepare the mime data if some. */
653   if(data->set.mimepost.kind != MIMEKIND_NONE) {
654     /* Use the whole structure as data. */
655     data->set.mimepost.flags &= ~MIME_BODY_ONLY;
656
657     /* Add external headers and mime version. */
658     curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
659     result = Curl_mime_prepare_headers(&data->set.mimepost, NULL,
660                                        NULL, MIMESTRATEGY_MAIL);
661
662     if(!result)
663       if(!Curl_checkheaders(conn, "Mime-Version"))
664         result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
665                                       "Mime-Version: 1.0");
666
667     /* Make sure we will read the entire mime structure. */
668     if(!result)
669       result = Curl_mime_rewind(&data->set.mimepost);
670
671     if(result) {
672       free(from);
673       free(auth);
674
675       return result;
676     }
677
678     data->state.infilesize = Curl_mime_size(&data->set.mimepost);
679
680     /* Read from mime structure. */
681     data->state.fread_func = (curl_read_callback) Curl_mime_read;
682     data->state.in = (void *) &data->set.mimepost;
683   }
684
685   /* Calculate the optional SIZE parameter */
686   if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) {
687     size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize);
688
689     if(!size) {
690       free(from);
691       free(auth);
692
693       return CURLE_OUT_OF_MEMORY;
694     }
695   }
696
697   /* If the mailboxes in the FROM and AUTH parameters don't include a UTF-8
698      based address then quickly scan through the recipient list and check if
699      any there do, as we need to correctly identify our support for SMTPUTF8
700      in the envelope, as per RFC-6531 sect. 3.4 */
701   if(conn->proto.smtpc.utf8_supported && !utf8) {
702     struct SMTP *smtp = data->req.protop;
703     struct curl_slist *rcpt = smtp->rcpt;
704
705     while(rcpt && !utf8) {
706       /* Does the host name contain non-ASCII characters? */
707       if(!Curl_is_ASCII_name(rcpt->data))
708         utf8 = TRUE;
709
710       rcpt = rcpt->next;
711     }
712   }
713
714   /* Send the MAIL command */
715   result = Curl_pp_sendf(&conn->proto.smtpc.pp,
716                          "MAIL FROM:%s%s%s%s%s%s",
717                          from,                 /* Mandatory                 */
718                          auth ? " AUTH=" : "", /* Optional on AUTH support  */
719                          auth ? auth : "",     /*                           */
720                          size ? " SIZE=" : "", /* Optional on SIZE support  */
721                          size ? size : "",     /*                           */
722                          utf8 ? " SMTPUTF8"    /* Internationalised mailbox */
723                                : "");          /* included in our envelope  */
724
725   free(from);
726   free(auth);
727   free(size);
728
729   if(!result)
730     state(conn, SMTP_MAIL);
731
732   return result;
733 }
734
735 /***********************************************************************
736  *
737  * smtp_perform_rcpt_to()
738  *
739  * Sends a RCPT TO command for a given recipient as part of the message upload
740  * process.
741  */
742 static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
743 {
744   CURLcode result = CURLE_OK;
745   struct Curl_easy *data = conn->data;
746   struct SMTP *smtp = data->req.protop;
747   char *address = NULL;
748   struct hostname host = { NULL, NULL, NULL, NULL };
749
750   /* Parse the recipient mailbox into the local address and host name parts,
751      converting the host name to an IDN A-label if necessary */
752   result = smtp_parse_address(conn, smtp->rcpt->data,
753                               &address, &host);
754   if(result)
755     return result;
756
757   /* Send the RCPT TO command */
758   if(host.name)
759     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s@%s>", address,
760                            host.name);
761   else
762     /* An invalid mailbox was provided but we'll simply let the server worry
763        about that and reply with a 501 error */
764     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>", address);
765
766   Curl_free_idnconverted_hostname(&host);
767   free(address);
768
769   if(!result)
770     state(conn, SMTP_RCPT);
771
772   return result;
773 }
774
775 /***********************************************************************
776  *
777  * smtp_perform_quit()
778  *
779  * Performs the quit action prior to sclose() being called.
780  */
781 static CURLcode smtp_perform_quit(struct connectdata *conn)
782 {
783   /* Send the QUIT command */
784   CURLcode result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "QUIT");
785
786   if(!result)
787     state(conn, SMTP_QUIT);
788
789   return result;
790 }
791
792 /* For the initial server greeting */
793 static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
794                                             int smtpcode,
795                                             smtpstate instate)
796 {
797   CURLcode result = CURLE_OK;
798   struct Curl_easy *data = conn->data;
799
800   (void)instate; /* no use for this yet */
801
802   if(smtpcode/100 != 2) {
803     failf(data, "Got unexpected smtp-server response: %d", smtpcode);
804     result = CURLE_WEIRD_SERVER_REPLY;
805   }
806   else
807     result = smtp_perform_ehlo(conn);
808
809   return result;
810 }
811
812 /* For STARTTLS responses */
813 static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
814                                          int smtpcode,
815                                          smtpstate instate)
816 {
817   CURLcode result = CURLE_OK;
818   struct Curl_easy *data = conn->data;
819
820   (void)instate; /* no use for this yet */
821
822   if(smtpcode != 220) {
823     if(data->set.use_ssl != CURLUSESSL_TRY) {
824       failf(data, "STARTTLS denied, code %d", smtpcode);
825       result = CURLE_USE_SSL_FAILED;
826     }
827     else
828       result = smtp_perform_authentication(conn);
829   }
830   else
831     result = smtp_perform_upgrade_tls(conn);
832
833   return result;
834 }
835
836 /* For EHLO responses */
837 static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
838                                      smtpstate instate)
839 {
840   CURLcode result = CURLE_OK;
841   struct Curl_easy *data = conn->data;
842   struct smtp_conn *smtpc = &conn->proto.smtpc;
843   const char *line = data->state.buffer;
844   size_t len = strlen(line);
845
846   (void)instate; /* no use for this yet */
847
848   if(smtpcode/100 != 2 && smtpcode != 1) {
849     if(data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use)
850       result = smtp_perform_helo(conn);
851     else {
852       failf(data, "Remote access denied: %d", smtpcode);
853       result = CURLE_REMOTE_ACCESS_DENIED;
854     }
855   }
856   else if(len >= 4) {
857     line += 4;
858     len -= 4;
859
860     /* Does the server support the STARTTLS capability? */
861     if(len >= 8 && !memcmp(line, "STARTTLS", 8))
862       smtpc->tls_supported = TRUE;
863
864     /* Does the server support the SIZE capability? */
865     else if(len >= 4 && !memcmp(line, "SIZE", 4))
866       smtpc->size_supported = TRUE;
867
868     /* Does the server support the UTF-8 capability? */
869     else if(len >= 8 && !memcmp(line, "SMTPUTF8", 8))
870       smtpc->utf8_supported = TRUE;
871
872     /* Does the server support authentication? */
873     else if(len >= 5 && !memcmp(line, "AUTH ", 5)) {
874       smtpc->auth_supported = TRUE;
875
876       /* Advance past the AUTH keyword */
877       line += 5;
878       len -= 5;
879
880       /* Loop through the data line */
881       for(;;) {
882         size_t llen;
883         size_t wordlen;
884         unsigned int mechbit;
885
886         while(len &&
887               (*line == ' ' || *line == '\t' ||
888                *line == '\r' || *line == '\n')) {
889
890           line++;
891           len--;
892         }
893
894         if(!len)
895           break;
896
897         /* Extract the word */
898         for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
899               line[wordlen] != '\t' && line[wordlen] != '\r' &&
900               line[wordlen] != '\n';)
901           wordlen++;
902
903         /* Test the word for a matching authentication mechanism */
904         mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
905         if(mechbit && llen == wordlen)
906           smtpc->sasl.authmechs |= mechbit;
907
908         line += wordlen;
909         len -= wordlen;
910       }
911     }
912
913     if(smtpcode != 1) {
914       if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
915         /* We don't have a SSL/TLS connection yet, but SSL is requested */
916         if(smtpc->tls_supported)
917           /* Switch to TLS connection now */
918           result = smtp_perform_starttls(conn);
919         else if(data->set.use_ssl == CURLUSESSL_TRY)
920           /* Fallback and carry on with authentication */
921           result = smtp_perform_authentication(conn);
922         else {
923           failf(data, "STARTTLS not supported.");
924           result = CURLE_USE_SSL_FAILED;
925         }
926       }
927       else
928         result = smtp_perform_authentication(conn);
929     }
930   }
931   else {
932     failf(data, "Unexpectedly short EHLO response");
933     result = CURLE_WEIRD_SERVER_REPLY;
934   }
935
936   return result;
937 }
938
939 /* For HELO responses */
940 static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode,
941                                      smtpstate instate)
942 {
943   CURLcode result = CURLE_OK;
944   struct Curl_easy *data = conn->data;
945
946   (void)instate; /* no use for this yet */
947
948   if(smtpcode/100 != 2) {
949     failf(data, "Remote access denied: %d", smtpcode);
950     result = CURLE_REMOTE_ACCESS_DENIED;
951   }
952   else
953     /* End of connect phase */
954     state(conn, SMTP_STOP);
955
956   return result;
957 }
958
959 /* For SASL authentication responses */
960 static CURLcode smtp_state_auth_resp(struct connectdata *conn,
961                                      int smtpcode,
962                                      smtpstate instate)
963 {
964   CURLcode result = CURLE_OK;
965   struct Curl_easy *data = conn->data;
966   struct smtp_conn *smtpc = &conn->proto.smtpc;
967   saslprogress progress;
968
969   (void)instate; /* no use for this yet */
970
971   result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress);
972   if(!result)
973     switch(progress) {
974     case SASL_DONE:
975       state(conn, SMTP_STOP);  /* Authenticated */
976       break;
977     case SASL_IDLE:            /* No mechanism left after cancellation */
978       failf(data, "Authentication cancelled");
979       result = CURLE_LOGIN_DENIED;
980       break;
981     default:
982       break;
983     }
984
985   return result;
986 }
987
988 /* For command responses */
989 static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
990                                         smtpstate instate)
991 {
992   CURLcode result = CURLE_OK;
993   struct Curl_easy *data = conn->data;
994   struct SMTP *smtp = data->req.protop;
995   char *line = data->state.buffer;
996   size_t len = strlen(line);
997
998   (void)instate; /* no use for this yet */
999
1000   if((smtp->rcpt && smtpcode/100 != 2 && smtpcode != 553 && smtpcode != 1) ||
1001      (!smtp->rcpt && smtpcode/100 != 2 && smtpcode != 1)) {
1002     failf(data, "Command failed: %d", smtpcode);
1003     result = CURLE_RECV_ERROR;
1004   }
1005   else {
1006     /* Temporarily add the LF character back and send as body to the client */
1007     if(!data->set.opt_no_body) {
1008       line[len] = '\n';
1009       result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
1010       line[len] = '\0';
1011     }
1012
1013     if(smtpcode != 1) {
1014       if(smtp->rcpt) {
1015         smtp->rcpt = smtp->rcpt->next;
1016
1017         if(smtp->rcpt) {
1018           /* Send the next command */
1019           result = smtp_perform_command(conn);
1020         }
1021         else
1022           /* End of DO phase */
1023           state(conn, SMTP_STOP);
1024       }
1025       else
1026         /* End of DO phase */
1027         state(conn, SMTP_STOP);
1028     }
1029   }
1030
1031   return result;
1032 }
1033
1034 /* For MAIL responses */
1035 static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
1036                                      smtpstate instate)
1037 {
1038   CURLcode result = CURLE_OK;
1039   struct Curl_easy *data = conn->data;
1040
1041   (void)instate; /* no use for this yet */
1042
1043   if(smtpcode/100 != 2) {
1044     failf(data, "MAIL failed: %d", smtpcode);
1045     result = CURLE_SEND_ERROR;
1046   }
1047   else
1048     /* Start the RCPT TO command */
1049     result = smtp_perform_rcpt_to(conn);
1050
1051   return result;
1052 }
1053
1054 /* For RCPT responses */
1055 static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
1056                                      smtpstate instate)
1057 {
1058   CURLcode result = CURLE_OK;
1059   struct Curl_easy *data = conn->data;
1060   struct SMTP *smtp = data->req.protop;
1061   bool is_smtp_err = FALSE;
1062   bool is_smtp_blocking_err = FALSE;
1063
1064   (void)instate; /* no use for this yet */
1065
1066   is_smtp_err = (smtpcode/100 != 2) ? TRUE : FALSE;
1067
1068   /* If there's multiple RCPT TO to be issued, it's possible to ignore errors
1069      and proceed with only the valid addresses. */
1070   is_smtp_blocking_err =
1071     (is_smtp_err && !data->set.mail_rcpt_allowfails) ? TRUE : FALSE;
1072
1073   if(is_smtp_err) {
1074     /* Remembering the last failure which we can report if all "RCPT TO" have
1075        failed and we cannot proceed. */
1076     smtp->rcpt_last_error = smtpcode;
1077
1078     if(is_smtp_blocking_err) {
1079       failf(data, "RCPT failed: %d", smtpcode);
1080       result = CURLE_SEND_ERROR;
1081     }
1082   }
1083   else {
1084     /* Some RCPT TO commands have succeeded. */
1085     smtp->rcpt_had_ok = TRUE;
1086   }
1087
1088   if(!is_smtp_blocking_err) {
1089     smtp->rcpt = smtp->rcpt->next;
1090
1091     if(smtp->rcpt)
1092       /* Send the next RCPT TO command */
1093       result = smtp_perform_rcpt_to(conn);
1094     else {
1095       /* We weren't able to issue a successful RCPT TO command while going
1096          over recipients (potentially multiple). Sending back last error. */
1097       if(!smtp->rcpt_had_ok) {
1098         failf(data, "RCPT failed: %d (last error)", smtp->rcpt_last_error);
1099         result = CURLE_SEND_ERROR;
1100       }
1101       else {
1102         /* Send the DATA command */
1103         result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA");
1104
1105         if(!result)
1106           state(conn, SMTP_DATA);
1107       }
1108     }
1109   }
1110
1111   return result;
1112 }
1113
1114 /* For DATA response */
1115 static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
1116                                      smtpstate instate)
1117 {
1118   CURLcode result = CURLE_OK;
1119   struct Curl_easy *data = conn->data;
1120
1121   (void)instate; /* no use for this yet */
1122
1123   if(smtpcode != 354) {
1124     failf(data, "DATA failed: %d", smtpcode);
1125     result = CURLE_SEND_ERROR;
1126   }
1127   else {
1128     /* Set the progress upload size */
1129     Curl_pgrsSetUploadSize(data, data->state.infilesize);
1130
1131     /* SMTP upload */
1132     Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
1133
1134     /* End of DO phase */
1135     state(conn, SMTP_STOP);
1136   }
1137
1138   return result;
1139 }
1140
1141 /* For POSTDATA responses, which are received after the entire DATA
1142    part has been sent to the server */
1143 static CURLcode smtp_state_postdata_resp(struct connectdata *conn,
1144                                          int smtpcode,
1145                                          smtpstate instate)
1146 {
1147   CURLcode result = CURLE_OK;
1148
1149   (void)instate; /* no use for this yet */
1150
1151   if(smtpcode != 250)
1152     result = CURLE_RECV_ERROR;
1153
1154   /* End of DONE phase */
1155   state(conn, SMTP_STOP);
1156
1157   return result;
1158 }
1159
1160 static CURLcode smtp_statemach_act(struct connectdata *conn)
1161 {
1162   CURLcode result = CURLE_OK;
1163   curl_socket_t sock = conn->sock[FIRSTSOCKET];
1164   struct Curl_easy *data = conn->data;
1165   int smtpcode;
1166   struct smtp_conn *smtpc = &conn->proto.smtpc;
1167   struct pingpong *pp = &smtpc->pp;
1168   size_t nread = 0;
1169
1170   /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */
1171   if(smtpc->state == SMTP_UPGRADETLS)
1172     return smtp_perform_upgrade_tls(conn);
1173
1174   /* Flush any data that needs to be sent */
1175   if(pp->sendleft)
1176     return Curl_pp_flushsend(pp);
1177
1178   do {
1179     /* Read the response from the server */
1180     result = Curl_pp_readresp(sock, pp, &smtpcode, &nread);
1181     if(result)
1182       return result;
1183
1184     /* Store the latest response for later retrieval if necessary */
1185     if(smtpc->state != SMTP_QUIT && smtpcode != 1)
1186       data->info.httpcode = smtpcode;
1187
1188     if(!smtpcode)
1189       break;
1190
1191     /* We have now received a full SMTP server response */
1192     switch(smtpc->state) {
1193     case SMTP_SERVERGREET:
1194       result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state);
1195       break;
1196
1197     case SMTP_EHLO:
1198       result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
1199       break;
1200
1201     case SMTP_HELO:
1202       result = smtp_state_helo_resp(conn, smtpcode, smtpc->state);
1203       break;
1204
1205     case SMTP_STARTTLS:
1206       result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state);
1207       break;
1208
1209     case SMTP_AUTH:
1210       result = smtp_state_auth_resp(conn, smtpcode, smtpc->state);
1211       break;
1212
1213     case SMTP_COMMAND:
1214       result = smtp_state_command_resp(conn, smtpcode, smtpc->state);
1215       break;
1216
1217     case SMTP_MAIL:
1218       result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
1219       break;
1220
1221     case SMTP_RCPT:
1222       result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state);
1223       break;
1224
1225     case SMTP_DATA:
1226       result = smtp_state_data_resp(conn, smtpcode, smtpc->state);
1227       break;
1228
1229     case SMTP_POSTDATA:
1230       result = smtp_state_postdata_resp(conn, smtpcode, smtpc->state);
1231       break;
1232
1233     case SMTP_QUIT:
1234       /* fallthrough, just stop! */
1235     default:
1236       /* internal error */
1237       state(conn, SMTP_STOP);
1238       break;
1239     }
1240   } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp));
1241
1242   return result;
1243 }
1244
1245 /* Called repeatedly until done from multi.c */
1246 static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done)
1247 {
1248   CURLcode result = CURLE_OK;
1249   struct smtp_conn *smtpc = &conn->proto.smtpc;
1250
1251   if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) {
1252     result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
1253     if(result || !smtpc->ssldone)
1254       return result;
1255   }
1256
1257   result = Curl_pp_statemach(&smtpc->pp, FALSE, FALSE);
1258   *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE;
1259
1260   return result;
1261 }
1262
1263 static CURLcode smtp_block_statemach(struct connectdata *conn,
1264                                      bool disconnecting)
1265 {
1266   CURLcode result = CURLE_OK;
1267   struct smtp_conn *smtpc = &conn->proto.smtpc;
1268
1269   while(smtpc->state != SMTP_STOP && !result)
1270     result = Curl_pp_statemach(&smtpc->pp, TRUE, disconnecting);
1271
1272   return result;
1273 }
1274
1275 /* Allocate and initialize the SMTP struct for the current Curl_easy if
1276    required */
1277 static CURLcode smtp_init(struct connectdata *conn)
1278 {
1279   CURLcode result = CURLE_OK;
1280   struct Curl_easy *data = conn->data;
1281   struct SMTP *smtp;
1282
1283   smtp = data->req.protop = calloc(sizeof(struct SMTP), 1);
1284   if(!smtp)
1285     result = CURLE_OUT_OF_MEMORY;
1286
1287   return result;
1288 }
1289
1290 /* For the SMTP "protocol connect" and "doing" phases only */
1291 static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks)
1292 {
1293   return Curl_pp_getsock(&conn->proto.smtpc.pp, socks);
1294 }
1295
1296 /***********************************************************************
1297  *
1298  * smtp_connect()
1299  *
1300  * This function should do everything that is to be considered a part of
1301  * the connection phase.
1302  *
1303  * The variable pointed to by 'done' will be TRUE if the protocol-layer
1304  * connect phase is done when this function returns, or FALSE if not.
1305  */
1306 static CURLcode smtp_connect(struct connectdata *conn, bool *done)
1307 {
1308   CURLcode result = CURLE_OK;
1309   struct smtp_conn *smtpc = &conn->proto.smtpc;
1310   struct pingpong *pp = &smtpc->pp;
1311
1312   *done = FALSE; /* default to not done yet */
1313
1314   /* We always support persistent connections in SMTP */
1315   connkeep(conn, "SMTP default");
1316
1317   /* Set the default response time-out */
1318   pp->response_time = RESP_TIMEOUT;
1319   pp->statemach_act = smtp_statemach_act;
1320   pp->endofresp = smtp_endofresp;
1321   pp->conn = conn;
1322
1323   /* Initialize the SASL storage */
1324   Curl_sasl_init(&smtpc->sasl, &saslsmtp);
1325
1326   /* Initialise the pingpong layer */
1327   Curl_pp_setup(pp);
1328   Curl_pp_init(pp);
1329
1330   /* Parse the URL options */
1331   result = smtp_parse_url_options(conn);
1332   if(result)
1333     return result;
1334
1335   /* Parse the URL path */
1336   result = smtp_parse_url_path(conn);
1337   if(result)
1338     return result;
1339
1340   /* Start off waiting for the server greeting response */
1341   state(conn, SMTP_SERVERGREET);
1342
1343   result = smtp_multi_statemach(conn, done);
1344
1345   return result;
1346 }
1347
1348 /***********************************************************************
1349  *
1350  * smtp_done()
1351  *
1352  * The DONE function. This does what needs to be done after a single DO has
1353  * performed.
1354  *
1355  * Input argument is already checked for validity.
1356  */
1357 static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
1358                           bool premature)
1359 {
1360   CURLcode result = CURLE_OK;
1361   struct Curl_easy *data = conn->data;
1362   struct SMTP *smtp = data->req.protop;
1363   struct pingpong *pp = &conn->proto.smtpc.pp;
1364   char *eob;
1365   ssize_t len;
1366   ssize_t bytes_written;
1367
1368   (void)premature;
1369
1370   if(!smtp || !pp->conn)
1371     return CURLE_OK;
1372
1373   /* Cleanup our per-request based variables */
1374   Curl_safefree(smtp->custom);
1375
1376   if(status) {
1377     connclose(conn, "SMTP done with bad status"); /* marked for closure */
1378     result = status;         /* use the already set error code */
1379   }
1380   else if(!data->set.connect_only && data->set.mail_rcpt &&
1381           (data->set.upload || data->set.mimepost.kind)) {
1382     /* Calculate the EOB taking into account any terminating CRLF from the
1383        previous line of the email or the CRLF of the DATA command when there
1384        is "no mail data". RFC-5321, sect. 4.1.1.4.
1385
1386        Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to
1387        fail when using a different pointer following a previous write, that
1388        returned CURLE_AGAIN, we duplicate the EOB now rather than when the
1389        bytes written doesn't equal len. */
1390     if(smtp->trailing_crlf || !conn->data->state.infilesize) {
1391       eob = strdup(&SMTP_EOB[2]);
1392       len = SMTP_EOB_LEN - 2;
1393     }
1394     else {
1395       eob = strdup(SMTP_EOB);
1396       len = SMTP_EOB_LEN;
1397     }
1398
1399     if(!eob)
1400       return CURLE_OUT_OF_MEMORY;
1401
1402     /* Send the end of block data */
1403     result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written);
1404     if(result) {
1405       free(eob);
1406       return result;
1407     }
1408
1409     if(bytes_written != len) {
1410       /* The whole chunk was not sent so keep it around and adjust the
1411          pingpong structure accordingly */
1412       pp->sendthis = eob;
1413       pp->sendsize = len;
1414       pp->sendleft = len - bytes_written;
1415     }
1416     else {
1417       /* Successfully sent so adjust the response timeout relative to now */
1418       pp->response = Curl_now();
1419
1420       free(eob);
1421     }
1422
1423     state(conn, SMTP_POSTDATA);
1424
1425     /* Run the state-machine */
1426     result = smtp_block_statemach(conn, FALSE);
1427   }
1428
1429   /* Clear the transfer mode for the next request */
1430   smtp->transfer = FTPTRANSFER_BODY;
1431
1432   return result;
1433 }
1434
1435 /***********************************************************************
1436  *
1437  * smtp_perform()
1438  *
1439  * This is the actual DO function for SMTP. Transfer a mail, send a command
1440  * or get some data according to the options previously setup.
1441  */
1442 static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
1443                              bool *dophase_done)
1444 {
1445   /* This is SMTP and no proxy */
1446   CURLcode result = CURLE_OK;
1447   struct Curl_easy *data = conn->data;
1448   struct SMTP *smtp = data->req.protop;
1449
1450   DEBUGF(infof(conn->data, "DO phase starts\n"));
1451
1452   if(data->set.opt_no_body) {
1453     /* Requested no body means no transfer */
1454     smtp->transfer = FTPTRANSFER_INFO;
1455   }
1456
1457   *dophase_done = FALSE; /* not done yet */
1458
1459   /* Store the first recipient (or NULL if not specified) */
1460   smtp->rcpt = data->set.mail_rcpt;
1461
1462   /* Track of whether we've successfully sent at least one RCPT TO command */
1463   smtp->rcpt_had_ok = FALSE;
1464
1465   /* Track of the last error we've received by sending RCPT TO command */
1466   smtp->rcpt_last_error = 0;
1467
1468   /* Initial data character is the first character in line: it is implicitly
1469      preceded by a virtual CRLF. */
1470   smtp->trailing_crlf = TRUE;
1471   smtp->eob = 2;
1472
1473   /* Start the first command in the DO phase */
1474   if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt)
1475     /* MAIL transfer */
1476     result = smtp_perform_mail(conn);
1477   else
1478     /* SMTP based command (VRFY, EXPN, NOOP, RSET or HELP) */
1479     result = smtp_perform_command(conn);
1480
1481   if(result)
1482     return result;
1483
1484   /* Run the state-machine */
1485   result = smtp_multi_statemach(conn, dophase_done);
1486
1487   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
1488
1489   if(*dophase_done)
1490     DEBUGF(infof(conn->data, "DO phase is complete\n"));
1491
1492   return result;
1493 }
1494
1495 /***********************************************************************
1496  *
1497  * smtp_do()
1498  *
1499  * This function is registered as 'curl_do' function. It decodes the path
1500  * parts etc as a wrapper to the actual DO function (smtp_perform).
1501  *
1502  * The input argument is already checked for validity.
1503  */
1504 static CURLcode smtp_do(struct connectdata *conn, bool *done)
1505 {
1506   CURLcode result = CURLE_OK;
1507
1508   *done = FALSE; /* default to false */
1509
1510   /* Parse the custom request */
1511   result = smtp_parse_custom_request(conn);
1512   if(result)
1513     return result;
1514
1515   result = smtp_regular_transfer(conn, done);
1516
1517   return result;
1518 }
1519
1520 /***********************************************************************
1521  *
1522  * smtp_disconnect()
1523  *
1524  * Disconnect from an SMTP server. Cleanup protocol-specific per-connection
1525  * resources. BLOCKING.
1526  */
1527 static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
1528 {
1529   struct smtp_conn *smtpc = &conn->proto.smtpc;
1530
1531   /* We cannot send quit unconditionally. If this connection is stale or
1532      bad in any way, sending quit and waiting around here will make the
1533      disconnect wait in vain and cause more problems than we need to. */
1534
1535   /* The SMTP session may or may not have been allocated/setup at this
1536      point! */
1537   if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart)
1538     if(!smtp_perform_quit(conn))
1539       (void)smtp_block_statemach(conn, TRUE); /* ignore errors on QUIT */
1540
1541   /* Disconnect from the server */
1542   Curl_pp_disconnect(&smtpc->pp);
1543
1544   /* Cleanup the SASL module */
1545   Curl_sasl_cleanup(conn, smtpc->sasl.authused);
1546
1547   /* Cleanup our connection based variables */
1548   Curl_safefree(smtpc->domain);
1549
1550   return CURLE_OK;
1551 }
1552
1553 /* Call this when the DO phase has completed */
1554 static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
1555 {
1556   struct SMTP *smtp = conn->data->req.protop;
1557
1558   (void)connected;
1559
1560   if(smtp->transfer != FTPTRANSFER_BODY)
1561     /* no data to transfer */
1562     Curl_setup_transfer(conn->data, -1, -1, FALSE, -1);
1563
1564   return CURLE_OK;
1565 }
1566
1567 /* Called from multi.c while DOing */
1568 static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done)
1569 {
1570   CURLcode result = smtp_multi_statemach(conn, dophase_done);
1571
1572   if(result)
1573     DEBUGF(infof(conn->data, "DO phase failed\n"));
1574   else if(*dophase_done) {
1575     result = smtp_dophase_done(conn, FALSE /* not connected */);
1576
1577     DEBUGF(infof(conn->data, "DO phase is complete\n"));
1578   }
1579
1580   return result;
1581 }
1582
1583 /***********************************************************************
1584  *
1585  * smtp_regular_transfer()
1586  *
1587  * The input argument is already checked for validity.
1588  *
1589  * Performs all commands done before a regular transfer between a local and a
1590  * remote host.
1591  */
1592 static CURLcode smtp_regular_transfer(struct connectdata *conn,
1593                                       bool *dophase_done)
1594 {
1595   CURLcode result = CURLE_OK;
1596   bool connected = FALSE;
1597   struct Curl_easy *data = conn->data;
1598
1599   /* Make sure size is unknown at this point */
1600   data->req.size = -1;
1601
1602   /* Set the progress data */
1603   Curl_pgrsSetUploadCounter(data, 0);
1604   Curl_pgrsSetDownloadCounter(data, 0);
1605   Curl_pgrsSetUploadSize(data, -1);
1606   Curl_pgrsSetDownloadSize(data, -1);
1607
1608   /* Carry out the perform */
1609   result = smtp_perform(conn, &connected, dophase_done);
1610
1611   /* Perform post DO phase operations if necessary */
1612   if(!result && *dophase_done)
1613     result = smtp_dophase_done(conn, connected);
1614
1615   return result;
1616 }
1617
1618 static CURLcode smtp_setup_connection(struct connectdata *conn)
1619 {
1620   CURLcode result;
1621
1622   /* Clear the TLS upgraded flag */
1623   conn->bits.tls_upgraded = FALSE;
1624
1625   /* Initialise the SMTP layer */
1626   result = smtp_init(conn);
1627   if(result)
1628     return result;
1629
1630   return CURLE_OK;
1631 }
1632
1633 /***********************************************************************
1634  *
1635  * smtp_parse_url_options()
1636  *
1637  * Parse the URL login options.
1638  */
1639 static CURLcode smtp_parse_url_options(struct connectdata *conn)
1640 {
1641   CURLcode result = CURLE_OK;
1642   struct smtp_conn *smtpc = &conn->proto.smtpc;
1643   const char *ptr = conn->options;
1644
1645   smtpc->sasl.resetprefs = TRUE;
1646
1647   while(!result && ptr && *ptr) {
1648     const char *key = ptr;
1649     const char *value;
1650
1651     while(*ptr && *ptr != '=')
1652       ptr++;
1653
1654     value = ptr + 1;
1655
1656     while(*ptr && *ptr != ';')
1657       ptr++;
1658
1659     if(strncasecompare(key, "AUTH=", 5))
1660       result = Curl_sasl_parse_url_auth_option(&smtpc->sasl,
1661                                                value, ptr - value);
1662     else
1663       result = CURLE_URL_MALFORMAT;
1664
1665     if(*ptr == ';')
1666       ptr++;
1667   }
1668
1669   return result;
1670 }
1671
1672 /***********************************************************************
1673  *
1674  * smtp_parse_url_path()
1675  *
1676  * Parse the URL path into separate path components.
1677  */
1678 static CURLcode smtp_parse_url_path(struct connectdata *conn)
1679 {
1680   /* The SMTP struct is already initialised in smtp_connect() */
1681   struct Curl_easy *data = conn->data;
1682   struct smtp_conn *smtpc = &conn->proto.smtpc;
1683   const char *path = &data->state.up.path[1]; /* skip leading path */
1684   char localhost[HOSTNAME_MAX + 1];
1685
1686   /* Calculate the path if necessary */
1687   if(!*path) {
1688     if(!Curl_gethostname(localhost, sizeof(localhost)))
1689       path = localhost;
1690     else
1691       path = "localhost";
1692   }
1693
1694   /* URL decode the path and use it as the domain in our EHLO */
1695   return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL,
1696                         REJECT_CTRL);
1697 }
1698
1699 /***********************************************************************
1700  *
1701  * smtp_parse_custom_request()
1702  *
1703  * Parse the custom request.
1704  */
1705 static CURLcode smtp_parse_custom_request(struct connectdata *conn)
1706 {
1707   CURLcode result = CURLE_OK;
1708   struct Curl_easy *data = conn->data;
1709   struct SMTP *smtp = data->req.protop;
1710   const char *custom = data->set.str[STRING_CUSTOMREQUEST];
1711
1712   /* URL decode the custom request */
1713   if(custom)
1714     result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, REJECT_CTRL);
1715
1716   return result;
1717 }
1718
1719 /***********************************************************************
1720  *
1721  * smtp_parse_address()
1722  *
1723  * Parse the fully qualified mailbox address into a local address part and the
1724  * host name, converting the host name to an IDN A-label, as per RFC-5890, if
1725  * necessary.
1726  *
1727  * Parameters:
1728  *
1729  * conn  [in]              - The connection handle.
1730  * fqma  [in]              - The fully qualified mailbox address (which may or
1731  *                           may not contain UTF-8 characters).
1732  * address        [in/out] - A new allocated buffer which holds the local
1733  *                           address part of the mailbox. This buffer must be
1734  *                           free'ed by the caller.
1735  * host           [in/out] - The host name structure that holds the original,
1736  *                           and optionally encoded, host name.
1737  *                           Curl_free_idnconverted_hostname() must be called
1738  *                           once the caller has finished with the structure.
1739  *
1740  * Returns CURLE_OK on success.
1741  *
1742  * Notes:
1743  *
1744  * Should a UTF-8 host name require conversion to IDN ACE and we cannot honor
1745  * that conversion then we shall return success. This allow the caller to send
1746  * the data to the server as a U-label (as per RFC-6531 sect. 3.2).
1747  *
1748  * If an mailbox '@' separator cannot be located then the mailbox is considered
1749  * to be either a local mailbox or an invalid mailbox (depending on what the
1750  * calling function deems it to be) then the input will simply be returned in
1751  * the address part with the host name being NULL.
1752  */
1753 static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma,
1754                                    char **address, struct hostname *host)
1755 {
1756   CURLcode result = CURLE_OK;
1757   size_t length;
1758
1759   /* Duplicate the fully qualified email address so we can manipulate it,
1760      ensuring it doesn't contain the delimiters if specified */
1761   char *dup = strdup(fqma[0] == '<' ? fqma + 1  : fqma);
1762   if(!dup)
1763     return CURLE_OUT_OF_MEMORY;
1764
1765   length = strlen(dup);
1766   if(length) {
1767     if(dup[length - 1] == '>')
1768       dup[length - 1] = '\0';
1769   }
1770
1771   /* Extract the host name from the address (if we can) */
1772   host->name = strpbrk(dup, "@");
1773   if(host->name) {
1774     *host->name = '\0';
1775     host->name = host->name + 1;
1776
1777     /* Attempt to convert the host name to IDN ACE */
1778     (void) Curl_idnconvert_hostname(conn, host);
1779
1780     /* If Curl_idnconvert_hostname() fails then we shall attempt to continue
1781        and send the host name using UTF-8 rather than as 7-bit ACE (which is
1782        our preference) */
1783   }
1784
1785   /* Extract the local address from the mailbox */
1786   *address = dup;
1787
1788   return result;
1789 }
1790
1791 CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
1792 {
1793   /* When sending a SMTP payload we must detect CRLF. sequences making sure
1794      they are sent as CRLF.. instead, as a . on the beginning of a line will
1795      be deleted by the server when not part of an EOB terminator and a
1796      genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of
1797      data by the server
1798   */
1799   ssize_t i;
1800   ssize_t si;
1801   struct Curl_easy *data = conn->data;
1802   struct SMTP *smtp = data->req.protop;
1803   char *scratch = data->state.scratch;
1804   char *newscratch = NULL;
1805   char *oldscratch = NULL;
1806   size_t eob_sent;
1807
1808   /* Do we need to allocate a scratch buffer? */
1809   if(!scratch || data->set.crlf) {
1810     oldscratch = scratch;
1811
1812     scratch = newscratch = malloc(2 * data->set.upload_buffer_size);
1813     if(!newscratch) {
1814       failf(data, "Failed to alloc scratch buffer!");
1815
1816       return CURLE_OUT_OF_MEMORY;
1817     }
1818   }
1819   DEBUGASSERT(data->set.upload_buffer_size >= (size_t)nread);
1820
1821   /* Have we already sent part of the EOB? */
1822   eob_sent = smtp->eob;
1823
1824   /* This loop can be improved by some kind of Boyer-Moore style of
1825      approach but that is saved for later... */
1826   for(i = 0, si = 0; i < nread; i++) {
1827     if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) {
1828       smtp->eob++;
1829
1830       /* Is the EOB potentially the terminating CRLF? */
1831       if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob)
1832         smtp->trailing_crlf = TRUE;
1833       else
1834         smtp->trailing_crlf = FALSE;
1835     }
1836     else if(smtp->eob) {
1837       /* A previous substring matched so output that first */
1838       memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
1839       si += smtp->eob - eob_sent;
1840
1841       /* Then compare the first byte */
1842       if(SMTP_EOB[0] == data->req.upload_fromhere[i])
1843         smtp->eob = 1;
1844       else
1845         smtp->eob = 0;
1846
1847       eob_sent = 0;
1848
1849       /* Reset the trailing CRLF flag as there was more data */
1850       smtp->trailing_crlf = FALSE;
1851     }
1852
1853     /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */
1854     if(SMTP_EOB_FIND_LEN == smtp->eob) {
1855       /* Copy the replacement data to the target buffer */
1856       memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent],
1857              SMTP_EOB_REPL_LEN - eob_sent);
1858       si += SMTP_EOB_REPL_LEN - eob_sent;
1859       smtp->eob = 0;
1860       eob_sent = 0;
1861     }
1862     else if(!smtp->eob)
1863       scratch[si++] = data->req.upload_fromhere[i];
1864   }
1865
1866   if(smtp->eob - eob_sent) {
1867     /* A substring matched before processing ended so output that now */
1868     memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
1869     si += smtp->eob - eob_sent;
1870   }
1871
1872   /* Only use the new buffer if we replaced something */
1873   if(si != nread) {
1874     /* Upload from the new (replaced) buffer instead */
1875     data->req.upload_fromhere = scratch;
1876
1877     /* Save the buffer so it can be freed later */
1878     data->state.scratch = scratch;
1879
1880     /* Free the old scratch buffer */
1881     free(oldscratch);
1882
1883     /* Set the new amount too */
1884     data->req.upload_present = si;
1885   }
1886   else
1887     free(newscratch);
1888
1889   return CURLE_OK;
1890 }
1891
1892 #endif /* CURL_DISABLE_SMTP */