1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * RFC1870 SMTP Service Extension for Message Size
22 * RFC2195 CRAM-MD5 authentication
23 * RFC2831 DIGEST-MD5 authentication
24 * RFC3207 SMTP over TLS
25 * RFC4422 Simple Authentication and Security Layer (SASL)
26 * RFC4616 PLAIN authentication
27 * RFC4954 SMTP Authentication
28 * RFC5321 SMTP protocol
29 * RFC6749 OAuth 2.0 Authorization Framework
30 * Draft SMTP URL Interface <draft-earhart-url-smtp-00.txt>
31 * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
33 ***************************************************************************/
35 #include "curl_setup.h"
37 #ifndef CURL_DISABLE_SMTP
39 #ifdef HAVE_NETINET_IN_H
40 #include <netinet/in.h>
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
46 #include <sys/utsname.h>
56 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
58 #define in_addr_t unsigned long
61 #include <curl/curl.h>
69 #include "http.h" /* for HTTP proxy tunnel stuff */
73 #include "strtoofft.h"
82 #include "curl_gethostname.h"
83 #include "curl_sasl.h"
86 #define _MPRINTF_REPLACE /* use our functions only */
87 #include <curl/mprintf.h>
89 #include "curl_memory.h"
90 /* The last #include file should be: */
93 /* Local API functions */
94 static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done);
95 static CURLcode smtp_do(struct connectdata *conn, bool *done);
96 static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
98 static CURLcode smtp_connect(struct connectdata *conn, bool *done);
99 static CURLcode smtp_disconnect(struct connectdata *conn, bool dead);
100 static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done);
101 static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
103 static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done);
104 static CURLcode smtp_setup_connection(struct connectdata *conn);
105 static CURLcode smtp_parse_url_options(struct connectdata *conn);
106 static CURLcode smtp_parse_url_path(struct connectdata *conn);
107 static CURLcode smtp_parse_custom_request(struct connectdata *conn);
110 * SMTP protocol handler.
113 const struct Curl_handler Curl_handler_smtp = {
115 smtp_setup_connection, /* setup_connection */
117 smtp_done, /* done */
118 ZERO_NULL, /* do_more */
119 smtp_connect, /* connect_it */
120 smtp_multi_statemach, /* connecting */
121 smtp_doing, /* doing */
122 smtp_getsock, /* proto_getsock */
123 smtp_getsock, /* doing_getsock */
124 ZERO_NULL, /* domore_getsock */
125 ZERO_NULL, /* perform_getsock */
126 smtp_disconnect, /* disconnect */
127 ZERO_NULL, /* readwrite */
128 PORT_SMTP, /* defport */
129 CURLPROTO_SMTP, /* protocol */
130 PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
135 * SMTPS protocol handler.
138 const struct Curl_handler Curl_handler_smtps = {
139 "SMTPS", /* scheme */
140 smtp_setup_connection, /* setup_connection */
142 smtp_done, /* done */
143 ZERO_NULL, /* do_more */
144 smtp_connect, /* connect_it */
145 smtp_multi_statemach, /* connecting */
146 smtp_doing, /* doing */
147 smtp_getsock, /* proto_getsock */
148 smtp_getsock, /* doing_getsock */
149 ZERO_NULL, /* domore_getsock */
150 ZERO_NULL, /* perform_getsock */
151 smtp_disconnect, /* disconnect */
152 ZERO_NULL, /* readwrite */
153 PORT_SMTPS, /* defport */
154 CURLPROTO_SMTP | CURLPROTO_SMTPS, /* protocol */
155 PROTOPT_CLOSEACTION | PROTOPT_SSL
156 | PROTOPT_NOURLQUERY /* flags */
160 #ifndef CURL_DISABLE_HTTP
162 * HTTP-proxyed SMTP protocol handler.
165 static const struct Curl_handler Curl_handler_smtp_proxy = {
167 Curl_http_setup_conn, /* setup_connection */
168 Curl_http, /* do_it */
169 Curl_http_done, /* done */
170 ZERO_NULL, /* do_more */
171 ZERO_NULL, /* connect_it */
172 ZERO_NULL, /* connecting */
173 ZERO_NULL, /* doing */
174 ZERO_NULL, /* proto_getsock */
175 ZERO_NULL, /* doing_getsock */
176 ZERO_NULL, /* domore_getsock */
177 ZERO_NULL, /* perform_getsock */
178 ZERO_NULL, /* disconnect */
179 ZERO_NULL, /* readwrite */
180 PORT_SMTP, /* defport */
181 CURLPROTO_HTTP, /* protocol */
182 PROTOPT_NONE /* flags */
187 * HTTP-proxyed SMTPS protocol handler.
190 static const struct Curl_handler Curl_handler_smtps_proxy = {
191 "SMTPS", /* scheme */
192 Curl_http_setup_conn, /* setup_connection */
193 Curl_http, /* do_it */
194 Curl_http_done, /* done */
195 ZERO_NULL, /* do_more */
196 ZERO_NULL, /* connect_it */
197 ZERO_NULL, /* connecting */
198 ZERO_NULL, /* doing */
199 ZERO_NULL, /* proto_getsock */
200 ZERO_NULL, /* doing_getsock */
201 ZERO_NULL, /* domore_getsock */
202 ZERO_NULL, /* perform_getsock */
203 ZERO_NULL, /* disconnect */
204 ZERO_NULL, /* readwrite */
205 PORT_SMTPS, /* defport */
206 CURLPROTO_HTTP, /* protocol */
207 PROTOPT_NONE /* flags */
213 static void smtp_to_smtps(struct connectdata *conn)
215 conn->handler = &Curl_handler_smtps;
218 #define smtp_to_smtps(x) Curl_nop_stmt
221 /***********************************************************************
225 * Checks for an ending SMTP status code at the start of the given string, but
226 * also detects various capabilities from the EHLO response including the
227 * supported authentication mechanisms.
229 static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
232 struct smtp_conn *smtpc = &conn->proto.smtpc;
236 if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
239 /* Do we have a command response? This should be the response code followed
240 by a space and optionally some text as per RFC-5321 and as outlined in
241 Section 4. Examples of RFC-4954 but some e-mail servers ignore this and
242 only send the response code instead as per Section 4.2. */
243 if(line[3] == ' ' || len == 5) {
245 *resp = curlx_sltosi(strtol(line, NULL, 10));
247 /* Make sure real server never sends internal value */
251 /* Do we have a multiline (continuation) response? */
252 else if(line[3] == '-' && smtpc->state == SMTP_EHLO) {
254 *resp = 1; /* Internal response code */
260 /***********************************************************************
264 * Gets the authentication message from the response buffer.
266 static void smtp_get_message(char *buffer, char** outptr)
269 char* message = NULL;
271 /* Find the start of the message */
272 for(message = buffer + 4; *message == ' ' || *message == '\t'; message++)
275 /* Find the end of the message */
276 for(len = strlen(message); len--;)
277 if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
278 message[len] != '\t')
281 /* Terminate the message */
289 /***********************************************************************
293 * This is the ONLY way to change SMTP state!
295 static void state(struct connectdata *conn, smtpstate newstate)
297 struct smtp_conn *smtpc = &conn->proto.smtpc;
298 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
299 /* for debug purposes */
300 static const char * const names[] = {
312 "AUTH_DIGESTMD5_RESP",
314 "AUTH_NTLM_TYPE2MSG",
327 if(smtpc->state != newstate)
328 infof(conn->data, "SMTP %p state change from %s to %s\n",
329 (void *)smtpc, names[smtpc->state], names[newstate]);
332 smtpc->state = newstate;
335 /***********************************************************************
337 * smtp_perform_ehlo()
339 * Sends the EHLO command to not only initialise communication with the ESMTP
340 * server but to also obtain a list of server side supported capabilities.
342 static CURLcode smtp_perform_ehlo(struct connectdata *conn)
344 CURLcode result = CURLE_OK;
345 struct smtp_conn *smtpc = &conn->proto.smtpc;
347 smtpc->authmechs = 0; /* No known authentication mechanisms yet */
348 smtpc->authused = 0; /* Clear the authentication mechanism used
349 for esmtp connections */
350 smtpc->tls_supported = FALSE; /* Clear the TLS capability */
352 /* Send the EHLO command */
353 result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain);
356 state(conn, SMTP_EHLO);
361 /***********************************************************************
363 * smtp_perform_helo()
365 * Sends the HELO command to initialise communication with the SMTP server.
367 static CURLcode smtp_perform_helo(struct connectdata *conn)
369 CURLcode result = CURLE_OK;
370 struct smtp_conn *smtpc = &conn->proto.smtpc;
372 smtpc->authused = 0; /* No authentication mechanism used in smtp
375 /* Send the HELO command */
376 result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain);
379 state(conn, SMTP_HELO);
384 /***********************************************************************
386 * smtp_perform_starttls()
388 * Sends the STLS command to start the upgrade to TLS.
390 static CURLcode smtp_perform_starttls(struct connectdata *conn)
392 CURLcode result = CURLE_OK;
394 /* Send the STARTTLS command */
395 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "STARTTLS");
398 state(conn, SMTP_STARTTLS);
403 /***********************************************************************
405 * smtp_perform_upgrade_tls()
407 * Performs the upgrade to TLS.
409 static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn)
411 CURLcode result = CURLE_OK;
412 struct smtp_conn *smtpc = &conn->proto.smtpc;
414 /* Start the SSL connection */
415 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
418 if(smtpc->state != SMTP_UPGRADETLS)
419 state(conn, SMTP_UPGRADETLS);
423 result = smtp_perform_ehlo(conn);
430 /***********************************************************************
432 * smtp_perform_authenticate()
434 * Sends an AUTH command allowing the client to login with the appropriate
435 * SASL authentication mechanism.
437 static CURLcode smtp_perform_authenticate(struct connectdata *conn)
439 CURLcode result = CURLE_OK;
440 struct SessionHandle *data = conn->data;
441 struct smtp_conn *smtpc = &conn->proto.smtpc;
442 const char *mech = NULL;
443 char *initresp = NULL;
445 smtpstate state1 = SMTP_STOP;
446 smtpstate state2 = SMTP_STOP;
448 /* Check we have a username and password to authenticate with and end the
449 connect phase if we don't */
450 if(!conn->bits.user_passwd) {
451 state(conn, SMTP_STOP);
456 /* Calculate the supported authentication mechanism, by decreasing order of
457 security, as well as the initial response where appropriate */
458 #ifndef CURL_DISABLE_CRYPTO_AUTH
459 if((smtpc->authmechs & SASL_MECH_DIGEST_MD5) &&
460 (smtpc->prefmech & SASL_MECH_DIGEST_MD5)) {
461 mech = SASL_MECH_STRING_DIGEST_MD5;
462 state1 = SMTP_AUTH_DIGESTMD5;
463 smtpc->authused = SASL_MECH_DIGEST_MD5;
465 else if((smtpc->authmechs & SASL_MECH_CRAM_MD5) &&
466 (smtpc->prefmech & SASL_MECH_CRAM_MD5)) {
467 mech = SASL_MECH_STRING_CRAM_MD5;
468 state1 = SMTP_AUTH_CRAMMD5;
469 smtpc->authused = SASL_MECH_CRAM_MD5;
474 if((smtpc->authmechs & SASL_MECH_NTLM) &&
475 (smtpc->prefmech & SASL_MECH_NTLM)) {
476 mech = SASL_MECH_STRING_NTLM;
477 state1 = SMTP_AUTH_NTLM;
478 state2 = SMTP_AUTH_NTLM_TYPE2MSG;
479 smtpc->authused = SASL_MECH_NTLM;
481 if(data->set.sasl_ir)
482 result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
488 if(((smtpc->authmechs & SASL_MECH_XOAUTH2) &&
489 (smtpc->prefmech & SASL_MECH_XOAUTH2) &&
490 (smtpc->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
491 mech = SASL_MECH_STRING_XOAUTH2;
492 state1 = SMTP_AUTH_XOAUTH2;
493 state2 = SMTP_AUTH_FINAL;
494 smtpc->authused = SASL_MECH_XOAUTH2;
496 if(data->set.sasl_ir)
497 result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
498 conn->xoauth2_bearer,
501 else if((smtpc->authmechs & SASL_MECH_LOGIN) &&
502 (smtpc->prefmech & SASL_MECH_LOGIN)) {
503 mech = SASL_MECH_STRING_LOGIN;
504 state1 = SMTP_AUTH_LOGIN;
505 state2 = SMTP_AUTH_LOGIN_PASSWD;
506 smtpc->authused = SASL_MECH_LOGIN;
508 if(data->set.sasl_ir)
509 result = Curl_sasl_create_login_message(conn->data, conn->user,
512 else if((smtpc->authmechs & SASL_MECH_PLAIN) &&
513 (smtpc->prefmech & SASL_MECH_PLAIN)) {
514 mech = SASL_MECH_STRING_PLAIN;
515 state1 = SMTP_AUTH_PLAIN;
516 state2 = SMTP_AUTH_FINAL;
517 smtpc->authused = SASL_MECH_PLAIN;
519 if(data->set.sasl_ir)
520 result = Curl_sasl_create_plain_message(conn->data, conn->user,
521 conn->passwd, &initresp, &len);
526 /* Perform SASL based authentication */
528 8 + strlen(mech) + len <= 512) { /* AUTH <mech> ...<crlf> */
529 result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
535 result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
541 Curl_safefree(initresp);
544 /* Other mechanisms not supported */
545 infof(conn->data, "No known authentication mechanisms supported!\n");
546 result = CURLE_LOGIN_DENIED;
553 /***********************************************************************
555 * smtp_perform_command()
557 * Sends a SMTP based command.
559 static CURLcode smtp_perform_command(struct connectdata *conn)
561 CURLcode result = CURLE_OK;
562 struct SessionHandle *data = conn->data;
563 struct SMTP *smtp = data->req.protop;
565 /* Send the command */
566 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s",
567 smtp->custom && smtp->custom[0] != '\0' ?
568 smtp->custom : "NOOP");
570 state(conn, SMTP_COMMAND);
575 /***********************************************************************
577 * smtp_perform_mail()
579 * Sends an MAIL command to initiate the upload of a message.
581 static CURLcode smtp_perform_mail(struct connectdata *conn)
586 CURLcode result = CURLE_OK;
587 struct SessionHandle *data = conn->data;
589 /* Calculate the FROM parameter */
590 if(!data->set.str[STRING_MAIL_FROM])
591 /* Null reverse-path, RFC-5321, sect. 3.6.3 */
593 else if(data->set.str[STRING_MAIL_FROM][0] == '<')
594 from = aprintf("%s", data->set.str[STRING_MAIL_FROM]);
596 from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]);
599 return CURLE_OUT_OF_MEMORY;
601 /* Calculate the optional AUTH parameter */
602 if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.authused) {
603 if(data->set.str[STRING_MAIL_AUTH][0] != '\0')
604 auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]);
606 /* Empty AUTH, RFC-2554, sect. 5 */
612 return CURLE_OUT_OF_MEMORY;
616 /* Calculate the optional SIZE parameter */
617 if(conn->proto.smtpc.size_supported && conn->data->set.infilesize > 0) {
618 size = aprintf("%" FORMAT_OFF_T, data->set.infilesize);
624 return CURLE_OUT_OF_MEMORY;
628 /* Send the MAIL command */
630 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
631 "MAIL FROM:%s", from);
632 else if(auth && !size)
633 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
634 "MAIL FROM:%s AUTH=%s", from, auth);
635 else if(auth && size)
636 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
637 "MAIL FROM:%s AUTH=%s SIZE=%s", from, auth, size);
639 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
640 "MAIL FROM:%s SIZE=%s", from, size);
647 state(conn, SMTP_MAIL);
652 /***********************************************************************
654 * smtp_perform_rcpt_to()
656 * Sends a RCPT TO command for a given recipient as part of the message upload
659 static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
661 CURLcode result = CURLE_OK;
662 struct SessionHandle *data = conn->data;
663 struct SMTP *smtp = data->req.protop;
665 /* Send the RCPT TO command */
667 if(smtp->rcpt->data[0] == '<')
668 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s",
671 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>",
674 state(conn, SMTP_RCPT);
680 /***********************************************************************
682 * smtp_perform_quit()
684 * Performs the quit action prior to sclose() being called.
686 static CURLcode smtp_perform_quit(struct connectdata *conn)
688 CURLcode result = CURLE_OK;
690 /* Send the QUIT command */
691 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "QUIT");
694 state(conn, SMTP_QUIT);
699 /* For the initial server greeting */
700 static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
704 CURLcode result = CURLE_OK;
705 struct SessionHandle *data = conn->data;
707 (void)instate; /* no use for this yet */
709 if(smtpcode/100 != 2) {
710 failf(data, "Got unexpected smtp-server response: %d", smtpcode);
711 result = CURLE_FTP_WEIRD_SERVER_REPLY;
714 result = smtp_perform_ehlo(conn);
719 /* For STARTTLS responses */
720 static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
724 CURLcode result = CURLE_OK;
725 struct SessionHandle *data = conn->data;
727 (void)instate; /* no use for this yet */
729 if(smtpcode != 220) {
730 if(data->set.use_ssl != CURLUSESSL_TRY) {
731 failf(data, "STARTTLS denied. %c", smtpcode);
732 result = CURLE_USE_SSL_FAILED;
735 result = smtp_perform_authenticate(conn);
738 result = smtp_perform_upgrade_tls(conn);
743 /* For EHLO responses */
744 static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
747 CURLcode result = CURLE_OK;
748 struct SessionHandle *data = conn->data;
749 struct smtp_conn *smtpc = &conn->proto.smtpc;
750 const char *line = data->state.buffer;
751 size_t len = strlen(line);
754 (void)instate; /* no use for this yet */
756 if(smtpcode/100 != 2 && smtpcode != 1) {
757 if((data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use) &&
758 !conn->bits.user_passwd)
759 result = smtp_perform_helo(conn);
761 failf(data, "Remote access denied: %d", smtpcode);
762 result = CURLE_REMOTE_ACCESS_DENIED;
769 /* Does the server support the STARTTLS capability? */
770 if(len >= 8 && !memcmp(line, "STARTTLS", 8))
771 smtpc->tls_supported = TRUE;
773 /* Does the server support the SIZE capability? */
774 else if(len >= 4 && !memcmp(line, "SIZE", 4))
775 smtpc->size_supported = TRUE;
777 /* Do we have the authentication mechanism list? */
778 else if(len >= 5 && !memcmp(line, "AUTH ", 5)) {
782 /* Loop through the data line */
785 (*line == ' ' || *line == '\t' ||
786 *line == '\r' || *line == '\n')) {
795 /* Extract the word */
796 for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
797 line[wordlen] != '\t' && line[wordlen] != '\r' &&
798 line[wordlen] != '\n';)
801 /* Test the word for a matching authentication mechanism */
802 if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
803 smtpc->authmechs |= SASL_MECH_LOGIN;
804 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
805 smtpc->authmechs |= SASL_MECH_PLAIN;
806 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
807 smtpc->authmechs |= SASL_MECH_CRAM_MD5;
808 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
809 smtpc->authmechs |= SASL_MECH_DIGEST_MD5;
810 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
811 smtpc->authmechs |= SASL_MECH_GSSAPI;
812 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
813 smtpc->authmechs |= SASL_MECH_EXTERNAL;
814 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
815 smtpc->authmechs |= SASL_MECH_NTLM;
816 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
817 smtpc->authmechs |= SASL_MECH_XOAUTH2;
825 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
826 /* We don't have a SSL/TLS connection yet, but SSL is requested */
827 if(smtpc->tls_supported)
828 /* Switch to TLS connection now */
829 result = smtp_perform_starttls(conn);
830 else if(data->set.use_ssl == CURLUSESSL_TRY)
831 /* Fallback and carry on with authentication */
832 result = smtp_perform_authenticate(conn);
834 failf(data, "STARTTLS not supported.");
835 result = CURLE_USE_SSL_FAILED;
839 result = smtp_perform_authenticate(conn);
846 /* For HELO responses */
847 static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode,
850 CURLcode result = CURLE_OK;
851 struct SessionHandle *data = conn->data;
853 (void)instate; /* no use for this yet */
855 if(smtpcode/100 != 2) {
856 failf(data, "Remote access denied: %d", smtpcode);
857 result = CURLE_REMOTE_ACCESS_DENIED;
860 /* End of connect phase */
861 state(conn, SMTP_STOP);
866 /* For AUTH PLAIN (without initial response) responses */
867 static CURLcode smtp_state_auth_plain_resp(struct connectdata *conn,
871 CURLcode result = CURLE_OK;
872 struct SessionHandle *data = conn->data;
874 char *plainauth = NULL;
876 (void)instate; /* no use for this yet */
878 if(smtpcode != 334) {
879 failf(data, "Access denied: %d", smtpcode);
880 result = CURLE_LOGIN_DENIED;
883 /* Create the authorisation message */
884 result = Curl_sasl_create_plain_message(conn->data, conn->user,
885 conn->passwd, &plainauth, &len);
886 if(!result && plainauth) {
887 /* Send the message */
888 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth);
891 state(conn, SMTP_AUTH_FINAL);
895 Curl_safefree(plainauth);
900 /* For AUTH LOGIN (without initial response) responses */
901 static CURLcode smtp_state_auth_login_resp(struct connectdata *conn,
905 CURLcode result = CURLE_OK;
906 struct SessionHandle *data = conn->data;
908 char *authuser = NULL;
910 (void)instate; /* no use for this yet */
912 if(smtpcode != 334) {
913 failf(data, "Access denied: %d", smtpcode);
914 result = CURLE_LOGIN_DENIED;
917 /* Create the user message */
918 result = Curl_sasl_create_login_message(conn->data, conn->user,
920 if(!result && authuser) {
922 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser);
925 state(conn, SMTP_AUTH_LOGIN_PASSWD);
929 Curl_safefree(authuser);
934 /* For AUTH LOGIN user entry responses */
935 static CURLcode smtp_state_auth_login_password_resp(struct connectdata *conn,
939 CURLcode result = CURLE_OK;
940 struct SessionHandle *data = conn->data;
942 char *authpasswd = NULL;
944 (void)instate; /* no use for this yet */
946 if(smtpcode != 334) {
947 failf(data, "Access denied: %d", smtpcode);
948 result = CURLE_LOGIN_DENIED;
951 /* Create the password message */
952 result = Curl_sasl_create_login_message(conn->data, conn->passwd,
954 if(!result && authpasswd) {
955 /* Send the password */
956 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd);
959 state(conn, SMTP_AUTH_FINAL);
963 Curl_safefree(authpasswd);
968 #ifndef CURL_DISABLE_CRYPTO_AUTH
969 /* For AUTH CRAM-MD5 responses */
970 static CURLcode smtp_state_auth_cram_resp(struct connectdata *conn,
974 CURLcode result = CURLE_OK;
975 struct SessionHandle *data = conn->data;
978 char *rplyb64 = NULL;
981 (void)instate; /* no use for this yet */
983 if(smtpcode != 334) {
984 failf(data, "Access denied: %d", smtpcode);
985 return CURLE_LOGIN_DENIED;
988 /* Get the challenge message */
989 smtp_get_message(data->state.buffer, &chlg64);
991 /* Decode the challenge message */
992 result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len);
994 /* Send the cancellation */
995 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*");
998 state(conn, SMTP_AUTH_CANCEL);
1001 /* Create the response message */
1002 result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user,
1003 conn->passwd, &rplyb64, &len);
1004 if(!result && rplyb64) {
1005 /* Send the response */
1006 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
1009 state(conn, SMTP_AUTH_FINAL);
1013 Curl_safefree(chlg);
1014 Curl_safefree(rplyb64);
1019 /* For AUTH DIGEST-MD5 challenge responses */
1020 static CURLcode smtp_state_auth_digest_resp(struct connectdata *conn,
1024 CURLcode result = CURLE_OK;
1025 struct SessionHandle *data = conn->data;
1026 char *chlg64 = NULL;
1027 char *rplyb64 = NULL;
1034 (void)instate; /* no use for this yet */
1036 if(smtpcode != 334) {
1037 failf(data, "Access denied: %d", smtpcode);
1038 return CURLE_LOGIN_DENIED;
1041 /* Get the challenge message */
1042 smtp_get_message(data->state.buffer, &chlg64);
1044 /* Decode the challange message */
1045 result = Curl_sasl_decode_digest_md5_message(chlg64, nonce, sizeof(nonce),
1046 realm, sizeof(realm),
1047 algorithm, sizeof(algorithm));
1048 if(result || strcmp(algorithm, "md5-sess") != 0) {
1049 /* Send the cancellation */
1050 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*");
1053 state(conn, SMTP_AUTH_CANCEL);
1056 /* Create the response message */
1057 result = Curl_sasl_create_digest_md5_message(data, nonce, realm,
1058 conn->user, conn->passwd,
1059 "smtp", &rplyb64, &len);
1060 if(!result && rplyb64) {
1061 /* Send the response */
1062 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
1065 state(conn, SMTP_AUTH_DIGESTMD5_RESP);
1069 Curl_safefree(rplyb64);
1074 /* For AUTH DIGEST-MD5 challenge-response responses */
1075 static CURLcode smtp_state_auth_digest_resp_resp(struct connectdata *conn,
1079 CURLcode result = CURLE_OK;
1080 struct SessionHandle *data = conn->data;
1082 (void)instate; /* no use for this yet */
1084 if(smtpcode != 334) {
1085 failf(data, "Authentication failed: %d", smtpcode);
1086 result = CURLE_LOGIN_DENIED;
1089 /* Send an empty response */
1090 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "");
1093 state(conn, SMTP_AUTH_FINAL);
1102 /* For AUTH NTLM (without initial response) responses */
1103 static CURLcode smtp_state_auth_ntlm_resp(struct connectdata *conn,
1107 CURLcode result = CURLE_OK;
1108 struct SessionHandle *data = conn->data;
1109 char *type1msg = NULL;
1112 (void)instate; /* no use for this yet */
1114 if(smtpcode != 334) {
1115 failf(data, "Access denied: %d", smtpcode);
1116 result = CURLE_LOGIN_DENIED;
1119 /* Create the type-1 message */
1120 result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
1123 if(!result && type1msg) {
1124 /* Send the message */
1125 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type1msg);
1128 state(conn, SMTP_AUTH_NTLM_TYPE2MSG);
1132 Curl_safefree(type1msg);
1137 /* For NTLM type-2 responses (sent in reponse to our type-1 message) */
1138 static CURLcode smtp_state_auth_ntlm_type2msg_resp(struct connectdata *conn,
1142 CURLcode result = CURLE_OK;
1143 struct SessionHandle *data = conn->data;
1144 char *type2msg = NULL;
1145 char *type3msg = NULL;
1148 (void)instate; /* no use for this yet */
1150 if(smtpcode != 334) {
1151 failf(data, "Access denied: %d", smtpcode);
1152 result = CURLE_LOGIN_DENIED;
1155 /* Get the type-2 message */
1156 smtp_get_message(data->state.buffer, &type2msg);
1158 /* Decode the type-2 message */
1159 result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm);
1161 /* Send the cancellation */
1162 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*");
1165 state(conn, SMTP_AUTH_CANCEL);
1168 /* Create the type-3 message */
1169 result = Curl_sasl_create_ntlm_type3_message(data, conn->user,
1170 conn->passwd, &conn->ntlm,
1172 if(!result && type3msg) {
1173 /* Send the message */
1174 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type3msg);
1177 state(conn, SMTP_AUTH_FINAL);
1182 Curl_safefree(type3msg);
1188 /* For AUTH XOAUTH2 (without initial response) responses */
1189 static CURLcode smtp_state_auth_xoauth2_resp(struct connectdata *conn,
1190 int smtpcode, smtpstate instate)
1192 CURLcode result = CURLE_OK;
1193 struct SessionHandle *data = conn->data;
1195 char *xoauth = NULL;
1197 (void)instate; /* no use for this yet */
1199 if(smtpcode != 334) {
1200 failf(data, "Access denied: %d", smtpcode);
1201 result = CURLE_LOGIN_DENIED;
1204 /* Create the authorisation message */
1205 result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
1206 conn->xoauth2_bearer,
1208 if(!result && xoauth) {
1209 /* Send the message */
1210 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", xoauth);
1213 state(conn, SMTP_AUTH_FINAL);
1217 Curl_safefree(xoauth);
1222 /* For AUTH cancellation responses */
1223 static CURLcode smtp_state_auth_cancel_resp(struct connectdata *conn,
1227 struct SessionHandle *data = conn->data;
1230 (void)instate; /* no use for this yet */
1232 failf(data, "Authentication cancelled");
1234 return CURLE_LOGIN_DENIED;
1237 /* For final responses in the AUTH sequence */
1238 static CURLcode smtp_state_auth_final_resp(struct connectdata *conn,
1242 CURLcode result = CURLE_OK;
1243 struct SessionHandle *data = conn->data;
1245 (void)instate; /* no use for this yet */
1247 if(smtpcode != 235) {
1248 failf(data, "Authentication failed: %d", smtpcode);
1249 result = CURLE_LOGIN_DENIED;
1252 /* End of connect phase */
1253 state(conn, SMTP_STOP);
1258 /* For command responses */
1259 static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
1262 CURLcode result = CURLE_OK;
1263 struct SessionHandle *data = conn->data;
1264 struct SMTP *smtp = data->req.protop;
1266 (void)instate; /* no use for this yet */
1268 if(smtpcode/100 != 2) {
1269 failf(data, "%s failed: %d",
1270 smtp->custom && smtp->custom[0] != '\0' ? smtp->custom : "NOOP",
1272 result = CURLE_RECV_ERROR;
1275 /* End of DO phase */
1276 state(conn, SMTP_STOP);
1281 /* For MAIL responses */
1282 static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
1285 CURLcode result = CURLE_OK;
1286 struct SessionHandle *data = conn->data;
1287 struct SMTP *smtp = data->req.protop;
1289 (void)instate; /* no use for this yet */
1291 if(smtpcode/100 != 2) {
1292 failf(data, "MAIL failed: %d", smtpcode);
1293 result = CURLE_SEND_ERROR;
1294 state(conn, SMTP_STOP);
1297 smtp->rcpt = data->set.mail_rcpt;
1299 result = smtp_perform_rcpt_to(conn);
1305 /* For RCPT responses */
1306 static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
1309 CURLcode result = CURLE_OK;
1310 struct SessionHandle *data = conn->data;
1311 struct SMTP *smtp = data->req.protop;
1313 (void)instate; /* no use for this yet */
1315 if(smtpcode/100 != 2) {
1316 failf(data, "RCPT failed: %d", smtpcode);
1317 result = CURLE_SEND_ERROR;
1318 state(conn, SMTP_STOP);
1322 smtp->rcpt = smtp->rcpt->next;
1323 result = smtp_perform_rcpt_to(conn);
1325 /* If we failed or still are sending RCPT data then return */
1326 if(result || smtp->rcpt)
1330 /* Send the DATA command */
1331 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA");
1334 state(conn, SMTP_DATA);
1340 /* For DATA response */
1341 static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
1344 struct SessionHandle *data = conn->data;
1346 (void)instate; /* no use for this yet */
1348 if(smtpcode != 354) {
1349 state(conn, SMTP_STOP);
1350 return CURLE_SEND_ERROR;
1353 /* Set the progress upload size */
1354 Curl_pgrsSetUploadSize(data, data->set.infilesize);
1357 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
1359 /* End of DO phase */
1360 state(conn, SMTP_STOP);
1365 /* For POSTDATA responses, which are received after the entire DATA
1366 part has been sent to the server */
1367 static CURLcode smtp_state_postdata_resp(struct connectdata *conn,
1371 CURLcode result = CURLE_OK;
1373 (void)instate; /* no use for this yet */
1376 result = CURLE_RECV_ERROR;
1378 /* End of DONE phase */
1379 state(conn, SMTP_STOP);
1384 static CURLcode smtp_statemach_act(struct connectdata *conn)
1386 CURLcode result = CURLE_OK;
1387 curl_socket_t sock = conn->sock[FIRSTSOCKET];
1388 struct SessionHandle *data = conn->data;
1390 struct smtp_conn *smtpc = &conn->proto.smtpc;
1391 struct pingpong *pp = &smtpc->pp;
1394 /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */
1395 if(smtpc->state == SMTP_UPGRADETLS)
1396 return smtp_perform_upgrade_tls(conn);
1398 /* Flush any data that needs to be sent */
1400 return Curl_pp_flushsend(pp);
1403 /* Read the response from the server */
1404 result = Curl_pp_readresp(sock, pp, &smtpcode, &nread);
1408 /* Store the latest response for later retrieval if necessary */
1409 if(smtpc->state != SMTP_QUIT && smtpcode != 1)
1410 data->info.httpcode = smtpcode;
1415 /* We have now received a full SMTP server response */
1416 switch(smtpc->state) {
1417 case SMTP_SERVERGREET:
1418 result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state);
1422 result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
1426 result = smtp_state_helo_resp(conn, smtpcode, smtpc->state);
1430 result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state);
1433 case SMTP_AUTH_PLAIN:
1434 result = smtp_state_auth_plain_resp(conn, smtpcode, smtpc->state);
1437 case SMTP_AUTH_LOGIN:
1438 result = smtp_state_auth_login_resp(conn, smtpcode, smtpc->state);
1441 case SMTP_AUTH_LOGIN_PASSWD:
1442 result = smtp_state_auth_login_password_resp(conn, smtpcode,
1446 #ifndef CURL_DISABLE_CRYPTO_AUTH
1447 case SMTP_AUTH_CRAMMD5:
1448 result = smtp_state_auth_cram_resp(conn, smtpcode, smtpc->state);
1451 case SMTP_AUTH_DIGESTMD5:
1452 result = smtp_state_auth_digest_resp(conn, smtpcode, smtpc->state);
1455 case SMTP_AUTH_DIGESTMD5_RESP:
1456 result = smtp_state_auth_digest_resp_resp(conn, smtpcode, smtpc->state);
1461 case SMTP_AUTH_NTLM:
1462 result = smtp_state_auth_ntlm_resp(conn, smtpcode, smtpc->state);
1465 case SMTP_AUTH_NTLM_TYPE2MSG:
1466 result = smtp_state_auth_ntlm_type2msg_resp(conn, smtpcode,
1471 case SMTP_AUTH_XOAUTH2:
1472 result = smtp_state_auth_xoauth2_resp(conn, smtpcode, smtpc->state);
1475 case SMTP_AUTH_CANCEL:
1476 result = smtp_state_auth_cancel_resp(conn, smtpcode, smtpc->state);
1479 case SMTP_AUTH_FINAL:
1480 result = smtp_state_auth_final_resp(conn, smtpcode, smtpc->state);
1484 result = smtp_state_command_resp(conn, smtpcode, smtpc->state);
1488 result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
1492 result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state);
1496 result = smtp_state_data_resp(conn, smtpcode, smtpc->state);
1500 result = smtp_state_postdata_resp(conn, smtpcode, smtpc->state);
1504 /* fallthrough, just stop! */
1506 /* internal error */
1507 state(conn, SMTP_STOP);
1510 } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp));
1515 /* Called repeatedly until done from multi.c */
1516 static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done)
1518 CURLcode result = CURLE_OK;
1519 struct smtp_conn *smtpc = &conn->proto.smtpc;
1521 if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) {
1522 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
1523 if(result || !smtpc->ssldone)
1527 result = Curl_pp_statemach(&smtpc->pp, FALSE);
1528 *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE;
1533 static CURLcode smtp_block_statemach(struct connectdata *conn)
1535 CURLcode result = CURLE_OK;
1536 struct smtp_conn *smtpc = &conn->proto.smtpc;
1538 while(smtpc->state != SMTP_STOP && !result)
1539 result = Curl_pp_statemach(&smtpc->pp, TRUE);
1544 /* Allocate and initialize the SMTP struct for the current SessionHandle if
1546 static CURLcode smtp_init(struct connectdata *conn)
1548 CURLcode result = CURLE_OK;
1549 struct SessionHandle *data = conn->data;
1552 smtp = data->req.protop = calloc(sizeof(struct SMTP), 1);
1554 result = CURLE_OUT_OF_MEMORY;
1559 /* For the SMTP "protocol connect" and "doing" phases only */
1560 static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
1563 return Curl_pp_getsock(&conn->proto.smtpc.pp, socks, numsocks);
1566 /***********************************************************************
1570 * This function should do everything that is to be considered a part of
1571 * the connection phase.
1573 * The variable pointed to by 'done' will be TRUE if the protocol-layer
1574 * connect phase is done when this function returns, or FALSE if not.
1576 static CURLcode smtp_connect(struct connectdata *conn, bool *done)
1578 CURLcode result = CURLE_OK;
1579 struct smtp_conn *smtpc = &conn->proto.smtpc;
1580 struct pingpong *pp = &smtpc->pp;
1582 *done = FALSE; /* default to not done yet */
1584 /* We always support persistent connections in SMTP */
1585 conn->bits.close = FALSE;
1587 /* Set the default response time-out */
1588 pp->response_time = RESP_TIMEOUT;
1589 pp->statemach_act = smtp_statemach_act;
1590 pp->endofresp = smtp_endofresp;
1593 /* Set the default preferred authentication mechanism */
1594 smtpc->prefmech = SASL_AUTH_ANY;
1596 /* Initialise the pingpong layer */
1599 /* Parse the URL options */
1600 result = smtp_parse_url_options(conn);
1604 /* Parse the URL path */
1605 result = smtp_parse_url_path(conn);
1609 /* Start off waiting for the server greeting response */
1610 state(conn, SMTP_SERVERGREET);
1612 result = smtp_multi_statemach(conn, done);
1617 /***********************************************************************
1621 * The DONE function. This does what needs to be done after a single DO has
1624 * Input argument is already checked for validity.
1626 static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
1629 CURLcode result = CURLE_OK;
1630 struct SessionHandle *data = conn->data;
1631 struct SMTP *smtp = data->req.protop;
1632 struct pingpong *pp = &conn->proto.smtpc.pp;
1635 ssize_t bytes_written;
1640 /* When the easy handle is removed from the multi interface while libcurl
1641 is still trying to resolve the host name, the SMTP struct is not yet
1642 initialized. However, the removal action calls Curl_done() which in
1643 turn calls this function, so we simply return success. */
1647 conn->bits.close = TRUE; /* marked for closure */
1648 result = status; /* use the already set error code */
1650 else if(!data->set.connect_only && data->set.upload && data->set.mail_rcpt) {
1651 /* Calculate the EOB taking into account any terminating CRLF from the
1652 previous line of the email or the CRLF of the DATA command when there
1653 is "no mail data". RFC-5321, sect. 4.1.1.4. */
1656 if(smtp->trailing_crlf || !conn->data->set.infilesize) {
1661 /* Send the end of block data */
1662 result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written);
1666 if(bytes_written != len) {
1667 /* The whole chunk was not sent so keep it around and adjust the
1668 pingpong structure accordingly */
1669 pp->sendthis = strdup(eob);
1671 pp->sendleft = len - bytes_written;
1674 /* Successfully sent so adjust the response timeout relative to now */
1675 pp->response = Curl_tvnow();
1677 state(conn, SMTP_POSTDATA);
1679 /* Run the state-machine
1681 TODO: when the multi interface is used, this _really_ should be using
1682 the smtp_multi_statemach function but we have no general support for
1683 non-blocking DONE operations, not in the multi state machine and with
1684 Curl_done() invokes on several places in the code!
1686 result = smtp_block_statemach(conn);
1689 /* Clear the transfer mode for the next request */
1690 smtp->transfer = FTPTRANSFER_BODY;
1695 /***********************************************************************
1699 * This is the actual DO function for SMTP. Transfer a mail or send a command
1700 * according to the options previously setup.
1702 static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
1705 /* This is SMTP and no proxy */
1706 CURLcode result = CURLE_OK;
1707 struct SessionHandle *data = conn->data;
1709 DEBUGF(infof(conn->data, "DO phase starts\n"));
1711 if(data->set.opt_no_body) {
1712 /* Requested no body means no transfer */
1713 struct SMTP *smtp = data->req.protop;
1714 smtp->transfer = FTPTRANSFER_INFO;
1717 *dophase_done = FALSE; /* not done yet */
1719 /* Start the first command in the DO phase */
1720 if(data->set.upload && data->set.mail_rcpt)
1722 result = smtp_perform_mail(conn);
1724 /* SMTP based command (NOOP or RSET) */
1725 result = smtp_perform_command(conn);
1730 /* Run the state-machine */
1731 result = smtp_multi_statemach(conn, dophase_done);
1733 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
1736 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1741 /***********************************************************************
1745 * This function is registered as 'curl_do' function. It decodes the path
1746 * parts etc as a wrapper to the actual DO function (smtp_perform).
1748 * The input argument is already checked for validity.
1750 static CURLcode smtp_do(struct connectdata *conn, bool *done)
1752 CURLcode result = CURLE_OK;
1754 *done = FALSE; /* default to false */
1756 /* Parse the custom request */
1757 result = smtp_parse_custom_request(conn);
1761 result = smtp_regular_transfer(conn, done);
1766 /***********************************************************************
1770 * Disconnect from an SMTP server. Cleanup protocol-specific per-connection
1771 * resources. BLOCKING.
1773 static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
1775 struct smtp_conn *smtpc = &conn->proto.smtpc;
1777 /* We cannot send quit unconditionally. If this connection is stale or
1778 bad in any way, sending quit and waiting around here will make the
1779 disconnect wait in vain and cause more problems than we need to. */
1781 /* The SMTP session may or may not have been allocated/setup at this
1783 if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart)
1784 if(!smtp_perform_quit(conn))
1785 (void)smtp_block_statemach(conn); /* ignore errors on QUIT */
1787 /* Disconnect from the server */
1788 Curl_pp_disconnect(&smtpc->pp);
1790 /* Cleanup the SASL module */
1791 Curl_sasl_cleanup(conn, smtpc->authused);
1793 /* Cleanup our connection based variables */
1794 Curl_safefree(smtpc->domain);
1799 /* Call this when the DO phase has completed */
1800 static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
1802 struct SMTP *smtp = conn->data->req.protop;
1806 if(smtp->transfer != FTPTRANSFER_BODY)
1807 /* no data to transfer */
1808 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1813 /* Called from multi.c while DOing */
1814 static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done)
1816 CURLcode result = smtp_multi_statemach(conn, dophase_done);
1819 DEBUGF(infof(conn->data, "DO phase failed\n"));
1820 else if(*dophase_done) {
1821 result = smtp_dophase_done(conn, FALSE /* not connected */);
1823 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1829 /***********************************************************************
1831 * smtp_regular_transfer()
1833 * The input argument is already checked for validity.
1835 * Performs all commands done before a regular transfer between a local and a
1838 static CURLcode smtp_regular_transfer(struct connectdata *conn,
1841 CURLcode result = CURLE_OK;
1842 bool connected = FALSE;
1843 struct SessionHandle *data = conn->data;
1845 /* Make sure size is unknown at this point */
1846 data->req.size = -1;
1848 /* Set the progress data */
1849 Curl_pgrsSetUploadCounter(data, 0);
1850 Curl_pgrsSetDownloadCounter(data, 0);
1851 Curl_pgrsSetUploadSize(data, 0);
1852 Curl_pgrsSetDownloadSize(data, 0);
1854 /* Carry out the perform */
1855 result = smtp_perform(conn, &connected, dophase_done);
1857 /* Perform post DO phase operations if necessary */
1858 if(!result && *dophase_done)
1859 result = smtp_dophase_done(conn, connected);
1864 static CURLcode smtp_setup_connection(struct connectdata *conn)
1866 struct SessionHandle *data = conn->data;
1869 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
1870 /* Unless we have asked to tunnel SMTP operations through the proxy, we
1871 switch and use HTTP operations only */
1872 #ifndef CURL_DISABLE_HTTP
1873 if(conn->handler == &Curl_handler_smtp)
1874 conn->handler = &Curl_handler_smtp_proxy;
1877 conn->handler = &Curl_handler_smtps_proxy;
1879 failf(data, "SMTPS not supported!");
1880 return CURLE_UNSUPPORTED_PROTOCOL;
1883 /* set it up as a HTTP connection instead */
1884 return conn->handler->setup_connection(conn);
1887 failf(data, "SMTP over http proxy requires HTTP support built-in!");
1888 return CURLE_UNSUPPORTED_PROTOCOL;
1892 /* Initialise the SMTP layer */
1893 result = smtp_init(conn);
1897 data->state.path++; /* don't include the initial slash */
1902 /***********************************************************************
1904 * smtp_parse_url_options()
1906 * Parse the URL login options.
1908 static CURLcode smtp_parse_url_options(struct connectdata *conn)
1910 CURLcode result = CURLE_OK;
1911 struct smtp_conn *smtpc = &conn->proto.smtpc;
1912 const char *options = conn->options;
1913 const char *ptr = options;
1916 const char *key = ptr;
1918 while(*ptr && *ptr != '=')
1921 if(strnequal(key, "AUTH", 4)) {
1922 const char *value = ptr + 1;
1924 if(strequal(value, "*"))
1925 smtpc->prefmech = SASL_AUTH_ANY;
1926 else if(strequal(value, SASL_MECH_STRING_LOGIN))
1927 smtpc->prefmech = SASL_MECH_LOGIN;
1928 else if(strequal(value, SASL_MECH_STRING_PLAIN))
1929 smtpc->prefmech = SASL_MECH_PLAIN;
1930 else if(strequal(value, SASL_MECH_STRING_CRAM_MD5))
1931 smtpc->prefmech = SASL_MECH_CRAM_MD5;
1932 else if(strequal(value, SASL_MECH_STRING_DIGEST_MD5))
1933 smtpc->prefmech = SASL_MECH_DIGEST_MD5;
1934 else if(strequal(value, SASL_MECH_STRING_GSSAPI))
1935 smtpc->prefmech = SASL_MECH_GSSAPI;
1936 else if(strequal(value, SASL_MECH_STRING_NTLM))
1937 smtpc->prefmech = SASL_MECH_NTLM;
1938 else if(strequal(value, SASL_MECH_STRING_XOAUTH2))
1939 smtpc->prefmech = SASL_MECH_XOAUTH2;
1941 smtpc->prefmech = SASL_AUTH_NONE;
1944 result = CURLE_URL_MALFORMAT;
1950 /***********************************************************************
1952 * smtp_parse_url_path()
1954 * Parse the URL path into separate path components.
1956 static CURLcode smtp_parse_url_path(struct connectdata *conn)
1958 /* The SMTP struct is already initialised in smtp_connect() */
1959 struct SessionHandle *data = conn->data;
1960 struct smtp_conn *smtpc = &conn->proto.smtpc;
1961 const char *path = data->state.path;
1962 char localhost[HOSTNAME_MAX + 1];
1964 /* Calculate the path if necessary */
1966 if(!Curl_gethostname(localhost, sizeof(localhost)))
1972 /* URL decode the path and use it as the domain in our EHLO */
1973 return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE);
1976 /***********************************************************************
1978 * smtp_parse_custom_request()
1980 * Parse the custom request.
1982 static CURLcode smtp_parse_custom_request(struct connectdata *conn)
1984 CURLcode result = CURLE_OK;
1985 struct SessionHandle *data = conn->data;
1986 struct SMTP *smtp = data->req.protop;
1987 const char *custom = data->set.str[STRING_CUSTOMREQUEST];
1989 /* URL decode the custom request */
1991 result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, TRUE);
1996 CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread)
1998 /* When sending a SMTP payload we must detect CRLF. sequences making sure
1999 they are sent as CRLF.. instead, as a . on the beginning of a line will
2000 be deleted by the server when not part of an EOB terminator and a
2001 genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of
2006 struct SessionHandle *data = conn->data;
2007 struct SMTP *smtp = data->req.protop;
2009 /* Do we need to allocate the scatch buffer? */
2010 if(!data->state.scratch) {
2011 data->state.scratch = malloc(2 * BUFSIZE);
2013 if(!data->state.scratch) {
2014 failf (data, "Failed to alloc scratch buffer!");
2015 return CURLE_OUT_OF_MEMORY;
2019 /* This loop can be improved by some kind of Boyer-Moore style of
2020 approach but that is saved for later... */
2021 for(i = 0, si = 0; i < nread; i++) {
2022 if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) {
2025 /* Is the EOB potentially the terminating CRLF? */
2026 if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob)
2027 smtp->trailing_crlf = TRUE;
2029 smtp->trailing_crlf = FALSE;
2031 else if(smtp->eob) {
2032 /* A previous substring matched so output that first */
2033 memcpy(&data->state.scratch[si], SMTP_EOB, smtp->eob);
2036 /* Then compare the first byte */
2037 if(SMTP_EOB[0] == data->req.upload_fromhere[i])
2042 /* Reset the trailing CRLF flag as there was more data */
2043 smtp->trailing_crlf = FALSE;
2046 /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */
2047 if(SMTP_EOB_FIND_LEN == smtp->eob) {
2048 /* Copy the replacement data to the target buffer */
2049 memcpy(&data->state.scratch[si], SMTP_EOB_REPL, SMTP_EOB_REPL_LEN);
2050 si += SMTP_EOB_REPL_LEN;
2054 data->state.scratch[si++] = data->req.upload_fromhere[i];
2058 /* A substring matched before processing ended so output that now */
2059 memcpy(&data->state.scratch[si], SMTP_EOB, smtp->eob);
2065 /* Only use the new buffer if we replaced something */
2068 /* Upload from the new (replaced) buffer instead */
2069 data->req.upload_fromhere = data->state.scratch;
2071 /* Set the new amount too */
2072 data->req.upload_present = nread;
2078 #endif /* CURL_DISABLE_SMTP */