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