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