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