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);
109 * SMTP protocol handler.
112 const struct Curl_handler Curl_handler_smtp = {
114 smtp_setup_connection, /* setup_connection */
116 smtp_done, /* done */
117 ZERO_NULL, /* do_more */
118 smtp_connect, /* connect_it */
119 smtp_multi_statemach, /* connecting */
120 smtp_doing, /* doing */
121 smtp_getsock, /* proto_getsock */
122 smtp_getsock, /* doing_getsock */
123 ZERO_NULL, /* domore_getsock */
124 ZERO_NULL, /* perform_getsock */
125 smtp_disconnect, /* disconnect */
126 ZERO_NULL, /* readwrite */
127 PORT_SMTP, /* defport */
128 CURLPROTO_SMTP, /* protocol */
129 PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
134 * SMTPS protocol handler.
137 const struct Curl_handler Curl_handler_smtps = {
138 "SMTPS", /* scheme */
139 smtp_setup_connection, /* setup_connection */
141 smtp_done, /* done */
142 ZERO_NULL, /* do_more */
143 smtp_connect, /* connect_it */
144 smtp_multi_statemach, /* connecting */
145 smtp_doing, /* doing */
146 smtp_getsock, /* proto_getsock */
147 smtp_getsock, /* doing_getsock */
148 ZERO_NULL, /* domore_getsock */
149 ZERO_NULL, /* perform_getsock */
150 smtp_disconnect, /* disconnect */
151 ZERO_NULL, /* readwrite */
152 PORT_SMTPS, /* defport */
153 CURLPROTO_SMTP | CURLPROTO_SMTPS, /* protocol */
154 PROTOPT_CLOSEACTION | PROTOPT_SSL
155 | PROTOPT_NOURLQUERY /* flags */
159 #ifndef CURL_DISABLE_HTTP
161 * HTTP-proxyed SMTP protocol handler.
164 static const struct Curl_handler Curl_handler_smtp_proxy = {
166 Curl_http_setup_conn, /* setup_connection */
167 Curl_http, /* do_it */
168 Curl_http_done, /* done */
169 ZERO_NULL, /* do_more */
170 ZERO_NULL, /* connect_it */
171 ZERO_NULL, /* connecting */
172 ZERO_NULL, /* doing */
173 ZERO_NULL, /* proto_getsock */
174 ZERO_NULL, /* doing_getsock */
175 ZERO_NULL, /* domore_getsock */
176 ZERO_NULL, /* perform_getsock */
177 ZERO_NULL, /* disconnect */
178 ZERO_NULL, /* readwrite */
179 PORT_SMTP, /* defport */
180 CURLPROTO_HTTP, /* protocol */
181 PROTOPT_NONE /* flags */
186 * HTTP-proxyed SMTPS protocol handler.
189 static const struct Curl_handler Curl_handler_smtps_proxy = {
190 "SMTPS", /* scheme */
191 Curl_http_setup_conn, /* setup_connection */
192 Curl_http, /* do_it */
193 Curl_http_done, /* done */
194 ZERO_NULL, /* do_more */
195 ZERO_NULL, /* connect_it */
196 ZERO_NULL, /* connecting */
197 ZERO_NULL, /* doing */
198 ZERO_NULL, /* proto_getsock */
199 ZERO_NULL, /* doing_getsock */
200 ZERO_NULL, /* domore_getsock */
201 ZERO_NULL, /* perform_getsock */
202 ZERO_NULL, /* disconnect */
203 ZERO_NULL, /* readwrite */
204 PORT_SMTPS, /* defport */
205 CURLPROTO_HTTP, /* protocol */
206 PROTOPT_NONE /* flags */
212 static void smtp_to_smtps(struct connectdata *conn)
214 conn->handler = &Curl_handler_smtps;
217 #define smtp_to_smtps(x) Curl_nop_stmt
220 /***********************************************************************
224 * Checks for an ending SMTP status code at the start of the given string, but
225 * also detects various capabilities from the EHLO response including the
226 * supported authentication mechanisms.
228 static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
231 struct smtp_conn *smtpc = &conn->proto.smtpc;
235 if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
236 return FALSE; /* Nothing for us */
238 /* Do we have a command response? This should be the response code followed
239 by a space and optionally some text as per RFC-5321 and as outlined in
240 Section 4. Examples of RFC-4954 but some e-mail servers ignore this and
241 only send the response code instead. */
242 result = (line[3] == ' ' || len == 5) ? TRUE : FALSE;
244 *resp = curlx_sltosi(strtol(line, NULL, 10));
246 /* Are we processing EHLO command data? */
247 if(smtpc->state == SMTP_EHLO && (!result || (result && *resp/100 == 2))) {
251 /* Does the server support the STARTTLS capability? */
252 if(len >= 8 && !memcmp(line, "STARTTLS", 8))
253 smtpc->tls_supported = TRUE;
255 /* Does the server support the SIZE capability? */
256 else if(len >= 4 && !memcmp(line, "SIZE", 4))
257 smtpc->size_supported = TRUE;
259 /* Do we have the authentication mechanism list? */
260 else if(len >= 5 && !memcmp(line, "AUTH ", 5)) {
264 /* Loop through the data line */
267 (*line == ' ' || *line == '\t' ||
268 *line == '\r' || *line == '\n')) {
277 /* Extract the word */
278 for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
279 line[wordlen] != '\t' && line[wordlen] != '\r' &&
280 line[wordlen] != '\n';)
283 /* Test the word for a matching authentication mechanism */
284 if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
285 smtpc->authmechs |= SASL_MECH_LOGIN;
286 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
287 smtpc->authmechs |= SASL_MECH_PLAIN;
288 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
289 smtpc->authmechs |= SASL_MECH_CRAM_MD5;
290 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
291 smtpc->authmechs |= SASL_MECH_DIGEST_MD5;
292 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
293 smtpc->authmechs |= SASL_MECH_GSSAPI;
294 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
295 smtpc->authmechs |= SASL_MECH_EXTERNAL;
296 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
297 smtpc->authmechs |= SASL_MECH_NTLM;
298 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
299 smtpc->authmechs |= SASL_MECH_XOAUTH2;
310 /***********************************************************************
314 * Gets the authentication message from the response buffer.
316 static void smtp_get_message(char *buffer, char** outptr)
319 char* message = NULL;
321 /* Find the start of the message */
322 for(message = buffer + 4; *message == ' ' || *message == '\t'; message++)
325 /* Find the end of the message */
326 for(len = strlen(message); len--;)
327 if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
328 message[len] != '\t')
331 /* Terminate the challenge */
339 /***********************************************************************
343 * This is the ONLY way to change SMTP state!
345 static void state(struct connectdata *conn, smtpstate newstate)
347 struct smtp_conn *smtpc = &conn->proto.smtpc;
348 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
349 /* for debug purposes */
350 static const char * const names[] = {
362 "AUTH_DIGESTMD5_RESP",
364 "AUTH_NTLM_TYPE2MSG",
376 if(smtpc->state != newstate)
377 infof(conn->data, "SMTP %p state change from %s to %s\n",
378 (void *)smtpc, names[smtpc->state], names[newstate]);
381 smtpc->state = newstate;
384 /***********************************************************************
386 * smtp_perform_ehlo()
388 * Sends the EHLO command to not only initialise communication with the ESMTP
389 * server but to also obtain a list of server side supported capabilities.
391 static CURLcode smtp_perform_ehlo(struct connectdata *conn)
393 CURLcode result = CURLE_OK;
394 struct smtp_conn *smtpc = &conn->proto.smtpc;
396 smtpc->authmechs = 0; /* No known authentication mechanisms yet */
397 smtpc->authused = 0; /* Clear the authentication mechanism used
398 for esmtp connections */
399 smtpc->tls_supported = FALSE; /* Clear the TLS capability */
401 /* Send the EHLO command */
402 result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain);
405 state(conn, SMTP_EHLO);
410 /***********************************************************************
412 * smtp_perform_helo()
414 * Sends the HELO command to initialise communication with the SMTP server.
416 static CURLcode smtp_perform_helo(struct connectdata *conn)
418 CURLcode result = CURLE_OK;
419 struct smtp_conn *smtpc = &conn->proto.smtpc;
421 smtpc->authused = 0; /* No authentication mechanism used in smtp
424 /* Send the HELO command */
425 result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain);
428 state(conn, SMTP_HELO);
433 /***********************************************************************
435 * smtp_perform_starttls()
437 * Sends the STLS command to start the upgrade to TLS.
439 static CURLcode smtp_perform_starttls(struct connectdata *conn)
441 CURLcode result = CURLE_OK;
443 /* Send the STARTTLS command */
444 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "STARTTLS");
447 state(conn, SMTP_STARTTLS);
452 /***********************************************************************
454 * smtp_perform_upgrade_tls()
456 * Performs the upgrade to TLS.
458 static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn)
460 CURLcode result = CURLE_OK;
461 struct smtp_conn *smtpc = &conn->proto.smtpc;
463 /* Start the SSL connection */
464 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
467 if(smtpc->state != SMTP_UPGRADETLS)
468 state(conn, SMTP_UPGRADETLS);
472 result = smtp_perform_ehlo(conn);
479 /***********************************************************************
481 * smtp_perform_authenticate()
483 * Sends an AUTH command allowing the client to login with the appropriate
484 * SASL authentication mechanism.
486 static CURLcode smtp_perform_authenticate(struct connectdata *conn)
488 CURLcode result = CURLE_OK;
489 struct SessionHandle *data = conn->data;
490 struct smtp_conn *smtpc = &conn->proto.smtpc;
491 const char *mech = NULL;
492 char *initresp = NULL;
494 smtpstate state1 = SMTP_STOP;
495 smtpstate state2 = SMTP_STOP;
497 /* Check we have a username and password to authenticate with and end the
498 connect phase if we don't */
499 if(!conn->bits.user_passwd) {
500 state(conn, SMTP_STOP);
505 /* Calculate the supported authentication mechanism, by decreasing order of
506 security, as well as the initial response where appropriate */
507 #ifndef CURL_DISABLE_CRYPTO_AUTH
508 if((smtpc->authmechs & SASL_MECH_DIGEST_MD5) &&
509 (smtpc->prefmech & SASL_MECH_DIGEST_MD5)) {
510 mech = SASL_MECH_STRING_DIGEST_MD5;
511 state1 = SMTP_AUTH_DIGESTMD5;
512 smtpc->authused = SASL_MECH_DIGEST_MD5;
514 else if((smtpc->authmechs & SASL_MECH_CRAM_MD5) &&
515 (smtpc->prefmech & SASL_MECH_CRAM_MD5)) {
516 mech = SASL_MECH_STRING_CRAM_MD5;
517 state1 = SMTP_AUTH_CRAMMD5;
518 smtpc->authused = SASL_MECH_CRAM_MD5;
523 if((smtpc->authmechs & SASL_MECH_NTLM) &&
524 (smtpc->prefmech & SASL_MECH_NTLM)) {
525 mech = SASL_MECH_STRING_NTLM;
526 state1 = SMTP_AUTH_NTLM;
527 state2 = SMTP_AUTH_NTLM_TYPE2MSG;
528 smtpc->authused = SASL_MECH_NTLM;
530 if(data->set.sasl_ir)
531 result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
537 if(((smtpc->authmechs & SASL_MECH_XOAUTH2) &&
538 (smtpc->prefmech & SASL_MECH_XOAUTH2) &&
539 (smtpc->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
540 mech = SASL_MECH_STRING_XOAUTH2;
541 state1 = SMTP_AUTH_XOAUTH2;
542 state2 = SMTP_AUTH_FINAL;
543 smtpc->authused = SASL_MECH_XOAUTH2;
545 if(data->set.sasl_ir)
546 result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
547 conn->xoauth2_bearer,
550 else if((smtpc->authmechs & SASL_MECH_LOGIN) &&
551 (smtpc->prefmech & SASL_MECH_LOGIN)) {
552 mech = SASL_MECH_STRING_LOGIN;
553 state1 = SMTP_AUTH_LOGIN;
554 state2 = SMTP_AUTH_LOGIN_PASSWD;
555 smtpc->authused = SASL_MECH_LOGIN;
557 if(data->set.sasl_ir)
558 result = Curl_sasl_create_login_message(conn->data, conn->user,
561 else if((smtpc->authmechs & SASL_MECH_PLAIN) &&
562 (smtpc->prefmech & SASL_MECH_PLAIN)) {
563 mech = SASL_MECH_STRING_PLAIN;
564 state1 = SMTP_AUTH_PLAIN;
565 state2 = SMTP_AUTH_FINAL;
566 smtpc->authused = SASL_MECH_PLAIN;
568 if(data->set.sasl_ir)
569 result = Curl_sasl_create_plain_message(conn->data, conn->user,
570 conn->passwd, &initresp, &len);
575 /* Perform SASL based authentication */
577 8 + strlen(mech) + len <= 512) { /* AUTH <mech> ...<crlf> */
578 result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
584 result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
590 Curl_safefree(initresp);
593 /* Other mechanisms not supported */
594 infof(conn->data, "No known authentication mechanisms supported!\n");
595 result = CURLE_LOGIN_DENIED;
602 /***********************************************************************
604 * smtp_perform_mail()
606 * Sends an MAIL command to initiate the upload of a message.
608 static CURLcode smtp_perform_mail(struct connectdata *conn)
613 CURLcode result = CURLE_OK;
614 struct SessionHandle *data = conn->data;
616 /* Calculate the FROM parameter */
617 if(!data->set.str[STRING_MAIL_FROM])
618 /* Null reverse-path, RFC-5321, sect. 3.6.3 */
620 else if(data->set.str[STRING_MAIL_FROM][0] == '<')
621 from = aprintf("%s", data->set.str[STRING_MAIL_FROM]);
623 from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]);
626 return CURLE_OUT_OF_MEMORY;
628 /* Calculate the optional AUTH parameter */
629 if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.authused) {
630 if(data->set.str[STRING_MAIL_AUTH][0] != '\0')
631 auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]);
633 /* Empty AUTH, RFC-2554, sect. 5 */
639 return CURLE_OUT_OF_MEMORY;
643 /* Calculate the optional SIZE parameter */
644 if(conn->proto.smtpc.size_supported && conn->data->set.infilesize > 0) {
645 size = aprintf("%" FORMAT_OFF_T, data->set.infilesize);
651 return CURLE_OUT_OF_MEMORY;
655 /* Send the MAIL command */
657 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
658 "MAIL FROM:%s", from);
659 else if(auth && !size)
660 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
661 "MAIL FROM:%s AUTH=%s", from, auth);
662 else if(auth && size)
663 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
664 "MAIL FROM:%s AUTH=%s SIZE=%s", from, auth, size);
666 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
667 "MAIL FROM:%s SIZE=%s", from, size);
674 state(conn, SMTP_MAIL);
679 /***********************************************************************
681 * smtp_perform_rcpt_to()
683 * Sends a RCPT TO command for a given recipient as part of the message upload
686 static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
688 CURLcode result = CURLE_OK;
689 struct SessionHandle *data = conn->data;
690 struct SMTP *smtp = data->req.protop;
692 /* Send the RCPT TO command */
694 if(smtp->rcpt->data[0] == '<')
695 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s",
698 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>",
701 state(conn, SMTP_RCPT);
707 /***********************************************************************
709 * smtp_perform_quit()
711 * Performs the quit action prior to sclose() being called.
713 static CURLcode smtp_perform_quit(struct connectdata *conn)
715 CURLcode result = CURLE_OK;
717 /* Send the QUIT command */
718 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "QUIT");
721 state(conn, SMTP_QUIT);
726 /* For the initial server greeting */
727 static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
731 CURLcode result = CURLE_OK;
732 struct SessionHandle *data = conn->data;
734 (void)instate; /* no use for this yet */
736 if(smtpcode/100 != 2) {
737 failf(data, "Got unexpected smtp-server response: %d", smtpcode);
738 result = CURLE_FTP_WEIRD_SERVER_REPLY;
741 result = smtp_perform_ehlo(conn);
746 /* For STARTTLS responses */
747 static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
751 CURLcode result = CURLE_OK;
752 struct SessionHandle *data = conn->data;
754 (void)instate; /* no use for this yet */
756 if(smtpcode != 220) {
757 if(data->set.use_ssl != CURLUSESSL_TRY) {
758 failf(data, "STARTTLS denied. %c", smtpcode);
759 result = CURLE_USE_SSL_FAILED;
762 result = smtp_perform_authenticate(conn);
765 result = smtp_perform_upgrade_tls(conn);
770 /* For EHLO responses */
771 static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
774 CURLcode result = CURLE_OK;
775 struct SessionHandle *data = conn->data;
776 struct smtp_conn *smtpc = &conn->proto.smtpc;
778 (void)instate; /* no use for this yet */
780 if(smtpcode/100 != 2) {
781 if((data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use) &&
782 !conn->bits.user_passwd)
783 result = smtp_perform_helo(conn);
785 failf(data, "Remote access denied: %d", smtpcode);
786 result = CURLE_REMOTE_ACCESS_DENIED;
789 else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
790 /* We don't have a SSL/TLS connection yet, but SSL is requested */
791 if(smtpc->tls_supported)
792 /* Switch to TLS connection now */
793 result = smtp_perform_starttls(conn);
794 else if(data->set.use_ssl == CURLUSESSL_TRY)
795 /* Fallback and carry on with authentication */
796 result = smtp_perform_authenticate(conn);
798 failf(data, "STARTTLS not supported.");
799 result = CURLE_USE_SSL_FAILED;
803 result = smtp_perform_authenticate(conn);
808 /* For HELO responses */
809 static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode,
812 CURLcode result = CURLE_OK;
813 struct SessionHandle *data = conn->data;
815 (void)instate; /* no use for this yet */
817 if(smtpcode/100 != 2) {
818 failf(data, "Remote access denied: %d", smtpcode);
819 result = CURLE_REMOTE_ACCESS_DENIED;
822 /* End of connect phase */
823 state(conn, SMTP_STOP);
828 /* For AUTH PLAIN (without initial response) responses */
829 static CURLcode smtp_state_auth_plain_resp(struct connectdata *conn,
833 CURLcode result = CURLE_OK;
834 struct SessionHandle *data = conn->data;
836 char *plainauth = NULL;
838 (void)instate; /* no use for this yet */
840 if(smtpcode != 334) {
841 failf(data, "Access denied: %d", smtpcode);
842 result = CURLE_LOGIN_DENIED;
845 /* Create the authorisation message */
846 result = Curl_sasl_create_plain_message(conn->data, conn->user,
847 conn->passwd, &plainauth, &len);
849 /* Send the message */
852 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth);
855 state(conn, SMTP_AUTH_FINAL);
858 Curl_safefree(plainauth);
865 /* For AUTH LOGIN (without initial response) responses */
866 static CURLcode smtp_state_auth_login_resp(struct connectdata *conn,
870 CURLcode result = CURLE_OK;
871 struct SessionHandle *data = conn->data;
873 char *authuser = NULL;
875 (void)instate; /* no use for this yet */
877 if(smtpcode != 334) {
878 failf(data, "Access denied: %d", smtpcode);
879 result = CURLE_LOGIN_DENIED;
882 /* Create the user message */
883 result = Curl_sasl_create_login_message(conn->data, conn->user,
889 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser);
892 state(conn, SMTP_AUTH_LOGIN_PASSWD);
895 Curl_safefree(authuser);
902 /* For AUTH LOGIN user entry responses */
903 static CURLcode smtp_state_auth_login_password_resp(struct connectdata *conn,
907 CURLcode result = CURLE_OK;
908 struct SessionHandle *data = conn->data;
910 char *authpasswd = NULL;
912 (void)instate; /* no use for this yet */
914 if(smtpcode != 334) {
915 failf(data, "Access denied: %d", smtpcode);
916 result = CURLE_LOGIN_DENIED;
919 /* Create the password message */
920 result = Curl_sasl_create_login_message(conn->data, conn->passwd,
923 /* Send the password */
926 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd);
929 state(conn, SMTP_AUTH_FINAL);
932 Curl_safefree(authpasswd);
939 #ifndef CURL_DISABLE_CRYPTO_AUTH
940 /* For AUTH CRAM-MD5 responses */
941 static CURLcode smtp_state_auth_cram_resp(struct connectdata *conn,
945 CURLcode result = CURLE_OK;
946 struct SessionHandle *data = conn->data;
949 char *rplyb64 = NULL;
952 (void)instate; /* no use for this yet */
954 if(smtpcode != 334) {
955 failf(data, "Access denied: %d", smtpcode);
956 return CURLE_LOGIN_DENIED;
959 /* Get the challenge message */
960 smtp_get_message(data->state.buffer, &chlg64);
962 /* Decode the challenge message */
963 result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len);
965 /* Send the cancellation */
966 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*");
969 state(conn, SMTP_AUTH_CANCEL);
972 /* Create the response message */
973 result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user,
974 conn->passwd, &rplyb64, &len);
975 if(!result && rplyb64) {
976 /* Send the response */
977 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
980 state(conn, SMTP_AUTH_FINAL);
985 Curl_safefree(rplyb64);
990 /* For AUTH DIGEST-MD5 challenge responses */
991 static CURLcode smtp_state_auth_digest_resp(struct connectdata *conn,
995 CURLcode result = CURLE_OK;
996 struct SessionHandle *data = conn->data;
998 char *rplyb64 = NULL;
1005 (void)instate; /* no use for this yet */
1007 if(smtpcode != 334) {
1008 failf(data, "Access denied: %d", smtpcode);
1009 return CURLE_LOGIN_DENIED;
1012 /* Get the challenge message */
1013 smtp_get_message(data->state.buffer, &chlg64);
1015 /* Decode the challange message */
1016 result = Curl_sasl_decode_digest_md5_message(chlg64, nonce, sizeof(nonce),
1017 realm, sizeof(realm),
1018 algorithm, sizeof(algorithm));
1019 if(result || strcmp(algorithm, "md5-sess") != 0) {
1020 /* Send the cancellation */
1021 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*");
1024 state(conn, SMTP_AUTH_CANCEL);
1027 /* Create the response message */
1028 result = Curl_sasl_create_digest_md5_message(data, nonce, realm,
1029 conn->user, conn->passwd,
1030 "smtp", &rplyb64, &len);
1031 if(!result && rplyb64) {
1032 /* Send the response */
1033 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
1036 state(conn, SMTP_AUTH_DIGESTMD5_RESP);
1040 Curl_safefree(rplyb64);
1045 /* For AUTH DIGEST-MD5 challenge-response responses */
1046 static CURLcode smtp_state_auth_digest_resp_resp(struct connectdata *conn,
1050 CURLcode result = CURLE_OK;
1051 struct SessionHandle *data = conn->data;
1053 (void)instate; /* no use for this yet */
1055 if(smtpcode != 334) {
1056 failf(data, "Authentication failed: %d", smtpcode);
1057 result = CURLE_LOGIN_DENIED;
1060 /* Send an empty response */
1061 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "");
1064 state(conn, SMTP_AUTH_FINAL);
1073 /* For AUTH NTLM (without initial response) responses */
1074 static CURLcode smtp_state_auth_ntlm_resp(struct connectdata *conn,
1078 CURLcode result = CURLE_OK;
1079 struct SessionHandle *data = conn->data;
1080 char *type1msg = NULL;
1083 (void)instate; /* no use for this yet */
1085 if(smtpcode != 334) {
1086 failf(data, "Access denied: %d", smtpcode);
1087 result = CURLE_LOGIN_DENIED;
1090 /* Create the type-1 message */
1091 result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
1095 /* Send the message */
1098 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type1msg);
1101 state(conn, SMTP_AUTH_NTLM_TYPE2MSG);
1104 Curl_safefree(type1msg);
1111 /* For NTLM type-2 responses (sent in reponse to our type-1 message) */
1112 static CURLcode smtp_state_auth_ntlm_type2msg_resp(struct connectdata *conn,
1116 CURLcode result = CURLE_OK;
1117 struct SessionHandle *data = conn->data;
1118 char *type2msg = NULL;
1119 char *type3msg = NULL;
1122 (void)instate; /* no use for this yet */
1124 if(smtpcode != 334) {
1125 failf(data, "Access denied: %d", smtpcode);
1126 result = CURLE_LOGIN_DENIED;
1129 /* Get the type-2 message */
1130 smtp_get_message(data->state.buffer, &type2msg);
1132 /* Create the type-3 message */
1133 result = Curl_sasl_create_ntlm_type3_message(data, type2msg, conn->user,
1134 conn->passwd, &conn->ntlm,
1137 /* Send the message */
1140 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type3msg);
1143 state(conn, SMTP_AUTH_FINAL);
1146 Curl_safefree(type3msg);
1154 /* For AUTH XOAUTH2 (without initial response) responses */
1155 static CURLcode smtp_state_auth_xoauth2_resp(struct connectdata *conn,
1156 int smtpcode, smtpstate instate)
1158 CURLcode result = CURLE_OK;
1159 struct SessionHandle *data = conn->data;
1161 char *xoauth = NULL;
1163 (void)instate; /* no use for this yet */
1165 if(smtpcode != 334) {
1166 failf(data, "Access denied: %d", smtpcode);
1167 result = CURLE_LOGIN_DENIED;
1170 /* Create the authorisation message */
1171 result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
1172 conn->xoauth2_bearer,
1175 /* Send the message */
1178 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", xoauth);
1181 state(conn, SMTP_AUTH_FINAL);
1184 Curl_safefree(xoauth);
1191 /* For AUTH cancellation responses */
1192 static CURLcode smtp_state_auth_cancel_resp(struct connectdata *conn,
1196 struct SessionHandle *data = conn->data;
1199 (void)instate; /* no use for this yet */
1201 failf(data, "Authentication cancelled");
1203 return CURLE_LOGIN_DENIED;
1206 /* For final responses in the AUTH sequence */
1207 static CURLcode smtp_state_auth_final_resp(struct connectdata *conn,
1211 CURLcode result = CURLE_OK;
1212 struct SessionHandle *data = conn->data;
1214 (void)instate; /* no use for this yet */
1216 if(smtpcode != 235) {
1217 failf(data, "Authentication failed: %d", smtpcode);
1218 result = CURLE_LOGIN_DENIED;
1221 /* End of connect phase */
1222 state(conn, SMTP_STOP);
1227 /* For MAIL responses */
1228 static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
1231 CURLcode result = CURLE_OK;
1232 struct SessionHandle *data = conn->data;
1233 struct SMTP *smtp = data->req.protop;
1235 (void)instate; /* no use for this yet */
1237 if(smtpcode/100 != 2) {
1238 failf(data, "MAIL failed: %d", smtpcode);
1239 result = CURLE_SEND_ERROR;
1240 state(conn, SMTP_STOP);
1243 smtp->rcpt = data->set.mail_rcpt;
1245 result = smtp_perform_rcpt_to(conn);
1251 /* For RCPT responses */
1252 static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
1255 CURLcode result = CURLE_OK;
1256 struct SessionHandle *data = conn->data;
1257 struct SMTP *smtp = data->req.protop;
1259 (void)instate; /* no use for this yet */
1261 if(smtpcode/100 != 2) {
1262 failf(data, "RCPT failed: %d", smtpcode);
1263 result = CURLE_SEND_ERROR;
1264 state(conn, SMTP_STOP);
1268 smtp->rcpt = smtp->rcpt->next;
1269 result = smtp_perform_rcpt_to(conn);
1271 /* If we failed or still are sending RCPT data then return */
1272 if(result || smtp->rcpt)
1276 /* Send the DATA command */
1277 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA");
1280 state(conn, SMTP_DATA);
1286 /* For DATA response */
1287 static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
1290 struct SessionHandle *data = conn->data;
1292 (void)instate; /* no use for this yet */
1294 if(smtpcode != 354) {
1295 state(conn, SMTP_STOP);
1296 return CURLE_SEND_ERROR;
1299 /* Set the progress upload size */
1300 Curl_pgrsSetUploadSize(data, data->set.infilesize);
1303 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
1305 /* End of DO phase */
1306 state(conn, SMTP_STOP);
1311 /* For POSTDATA responses, which are received after the entire DATA
1312 part has been sent to the server */
1313 static CURLcode smtp_state_postdata_resp(struct connectdata *conn,
1317 CURLcode result = CURLE_OK;
1319 (void)instate; /* no use for this yet */
1322 result = CURLE_RECV_ERROR;
1324 /* End of DONE phase */
1325 state(conn, SMTP_STOP);
1330 static CURLcode smtp_statemach_act(struct connectdata *conn)
1332 CURLcode result = CURLE_OK;
1333 curl_socket_t sock = conn->sock[FIRSTSOCKET];
1334 struct SessionHandle *data = conn->data;
1336 struct smtp_conn *smtpc = &conn->proto.smtpc;
1337 struct pingpong *pp = &smtpc->pp;
1340 /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */
1341 if(smtpc->state == SMTP_UPGRADETLS)
1342 return smtp_perform_upgrade_tls(conn);
1344 /* Flush any data that needs to be sent */
1346 return Curl_pp_flushsend(pp);
1348 /* Read the response from the server */
1349 result = Curl_pp_readresp(sock, pp, &smtpcode, &nread);
1353 /* Store the latest response for later retrieval */
1354 if(smtpc->state != SMTP_QUIT)
1355 data->info.httpcode = smtpcode;
1358 /* We have now received a full SMTP server response */
1359 switch(smtpc->state) {
1360 case SMTP_SERVERGREET:
1361 result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state);
1365 result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
1369 result = smtp_state_helo_resp(conn, smtpcode, smtpc->state);
1373 result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state);
1376 case SMTP_AUTH_PLAIN:
1377 result = smtp_state_auth_plain_resp(conn, smtpcode, smtpc->state);
1380 case SMTP_AUTH_LOGIN:
1381 result = smtp_state_auth_login_resp(conn, smtpcode, smtpc->state);
1384 case SMTP_AUTH_LOGIN_PASSWD:
1385 result = smtp_state_auth_login_password_resp(conn, smtpcode,
1389 #ifndef CURL_DISABLE_CRYPTO_AUTH
1390 case SMTP_AUTH_CRAMMD5:
1391 result = smtp_state_auth_cram_resp(conn, smtpcode, smtpc->state);
1394 case SMTP_AUTH_DIGESTMD5:
1395 result = smtp_state_auth_digest_resp(conn, smtpcode, smtpc->state);
1398 case SMTP_AUTH_DIGESTMD5_RESP:
1399 result = smtp_state_auth_digest_resp_resp(conn, smtpcode, smtpc->state);
1404 case SMTP_AUTH_NTLM:
1405 result = smtp_state_auth_ntlm_resp(conn, smtpcode, smtpc->state);
1408 case SMTP_AUTH_NTLM_TYPE2MSG:
1409 result = smtp_state_auth_ntlm_type2msg_resp(conn, smtpcode,
1414 case SMTP_AUTH_XOAUTH2:
1415 result = smtp_state_auth_xoauth2_resp(conn, smtpcode, smtpc->state);
1418 case SMTP_AUTH_CANCEL:
1419 result = smtp_state_auth_cancel_resp(conn, smtpcode, smtpc->state);
1422 case SMTP_AUTH_FINAL:
1423 result = smtp_state_auth_final_resp(conn, smtpcode, smtpc->state);
1427 result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
1431 result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state);
1435 result = smtp_state_data_resp(conn, smtpcode, smtpc->state);
1439 result = smtp_state_postdata_resp(conn, smtpcode, smtpc->state);
1443 /* fallthrough, just stop! */
1445 /* internal error */
1446 state(conn, SMTP_STOP);
1454 /* Called repeatedly until done from multi.c */
1455 static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done)
1457 CURLcode result = CURLE_OK;
1458 struct smtp_conn *smtpc = &conn->proto.smtpc;
1460 if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) {
1461 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
1462 if(result || !smtpc->ssldone)
1466 result = Curl_pp_statemach(&smtpc->pp, FALSE);
1467 *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE;
1472 static CURLcode smtp_block_statemach(struct connectdata *conn)
1474 CURLcode result = CURLE_OK;
1475 struct smtp_conn *smtpc = &conn->proto.smtpc;
1477 while(smtpc->state != SMTP_STOP && !result)
1478 result = Curl_pp_statemach(&smtpc->pp, TRUE);
1483 /* Allocate and initialize the SMTP struct for the current SessionHandle if
1485 static CURLcode smtp_init(struct connectdata *conn)
1487 CURLcode result = CURLE_OK;
1488 struct SessionHandle *data = conn->data;
1491 smtp = data->req.protop = calloc(sizeof(struct SMTP), 1);
1493 result = CURLE_OUT_OF_MEMORY;
1498 /* For the SMTP "protocol connect" and "doing" phases only */
1499 static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
1502 return Curl_pp_getsock(&conn->proto.smtpc.pp, socks, numsocks);
1505 /***********************************************************************
1509 * This function should do everything that is to be considered a part of
1510 * the connection phase.
1512 * The variable pointed to by 'done' will be TRUE if the protocol-layer
1513 * connect phase is done when this function returns, or FALSE if not.
1515 static CURLcode smtp_connect(struct connectdata *conn, bool *done)
1517 CURLcode result = CURLE_OK;
1518 struct smtp_conn *smtpc = &conn->proto.smtpc;
1519 struct pingpong *pp = &smtpc->pp;
1521 *done = FALSE; /* default to not done yet */
1523 /* We always support persistent connections in SMTP */
1524 conn->bits.close = FALSE;
1526 /* Set the default response time-out */
1527 pp->response_time = RESP_TIMEOUT;
1528 pp->statemach_act = smtp_statemach_act;
1529 pp->endofresp = smtp_endofresp;
1532 /* Set the default preferred authentication mechanism */
1533 smtpc->prefmech = SASL_AUTH_ANY;
1535 /* Initialise the pingpong layer */
1538 /* Parse the URL options */
1539 result = smtp_parse_url_options(conn);
1543 /* Parse the URL path */
1544 result = smtp_parse_url_path(conn);
1548 /* Start off waiting for the server greeting response */
1549 state(conn, SMTP_SERVERGREET);
1551 result = smtp_multi_statemach(conn, done);
1556 /***********************************************************************
1560 * The DONE function. This does what needs to be done after a single DO has
1563 * Input argument is already checked for validity.
1565 static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
1568 CURLcode result = CURLE_OK;
1569 struct SessionHandle *data = conn->data;
1570 struct SMTP *smtp = data->req.protop;
1571 struct pingpong *pp = &conn->proto.smtpc.pp;
1574 ssize_t bytes_written;
1579 /* When the easy handle is removed from the multi interface while libcurl
1580 is still trying to resolve the host name, the SMTP struct is not yet
1581 initialized. However, the removal action calls Curl_done() which in
1582 turn calls this function, so we simply return success. */
1586 conn->bits.close = TRUE; /* marked for closure */
1587 result = status; /* use the already set error code */
1589 else if(!data->set.connect_only) {
1590 /* Calculate the EOB taking into account any terminating CRLF from the
1591 previous line of the email or the CRLF of the DATA command when there
1592 is "no mail data". RFC-5321, sect. 4.1.1.4. */
1595 if(smtp->trailing_crlf || !conn->data->set.infilesize) {
1600 /* Send the end of block data */
1601 result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written);
1605 if(bytes_written != len) {
1606 /* The whole chunk was not sent so keep it around and adjust the
1607 pingpong structure accordingly */
1608 pp->sendthis = strdup(eob);
1610 pp->sendleft = len - bytes_written;
1613 /* Successfully sent so adjust the response timeout relative to now */
1614 pp->response = Curl_tvnow();
1616 state(conn, SMTP_POSTDATA);
1618 /* Run the state-machine
1620 TODO: when the multi interface is used, this _really_ should be using
1621 the smtp_multi_statemach function but we have no general support for
1622 non-blocking DONE operations, not in the multi state machine and with
1623 Curl_done() invokes on several places in the code!
1625 result = smtp_block_statemach(conn);
1628 /* Clear the transfer mode for the next request */
1629 smtp->transfer = FTPTRANSFER_BODY;
1634 /***********************************************************************
1638 * This is the actual DO function for SMTP. Send a mail according to the
1639 * options previously setup.
1641 static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
1644 /* This is SMTP and no proxy */
1645 CURLcode result = CURLE_OK;
1647 DEBUGF(infof(conn->data, "DO phase starts\n"));
1649 if(conn->data->set.opt_no_body) {
1650 /* Requested no body means no transfer */
1651 struct SMTP *smtp = conn->data->req.protop;
1652 smtp->transfer = FTPTRANSFER_INFO;
1655 *dophase_done = FALSE; /* not done yet */
1657 /* Start the first command in the DO phase */
1658 result = smtp_perform_mail(conn);
1662 /* run the state-machine */
1663 result = smtp_multi_statemach(conn, dophase_done);
1665 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
1668 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1673 /***********************************************************************
1677 * This function is registered as 'curl_do' function. It decodes the path
1678 * parts etc as a wrapper to the actual DO function (smtp_perform).
1680 * The input argument is already checked for validity.
1682 static CURLcode smtp_do(struct connectdata *conn, bool *done)
1684 CURLcode result = CURLE_OK;
1686 *done = FALSE; /* default to false */
1688 result = smtp_regular_transfer(conn, done);
1693 /***********************************************************************
1697 * Disconnect from an SMTP server. Cleanup protocol-specific per-connection
1698 * resources. BLOCKING.
1700 static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
1702 struct smtp_conn *smtpc = &conn->proto.smtpc;
1704 /* We cannot send quit unconditionally. If this connection is stale or
1705 bad in any way, sending quit and waiting around here will make the
1706 disconnect wait in vain and cause more problems than we need to. */
1708 /* The SMTP session may or may not have been allocated/setup at this
1710 if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart)
1711 if(!smtp_perform_quit(conn))
1712 (void)smtp_block_statemach(conn); /* ignore errors on QUIT */
1714 /* Disconnect from the server */
1715 Curl_pp_disconnect(&smtpc->pp);
1717 /* Cleanup the SASL module */
1718 Curl_sasl_cleanup(conn, smtpc->authused);
1720 /* Cleanup our connection based variables */
1721 Curl_safefree(smtpc->domain);
1726 /* Call this when the DO phase has completed */
1727 static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
1729 struct SMTP *smtp = conn->data->req.protop;
1733 if(smtp->transfer != FTPTRANSFER_BODY)
1734 /* no data to transfer */
1735 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1740 /* Called from multi.c while DOing */
1741 static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done)
1743 CURLcode result = smtp_multi_statemach(conn, dophase_done);
1746 DEBUGF(infof(conn->data, "DO phase failed\n"));
1747 else if(*dophase_done) {
1748 result = smtp_dophase_done(conn, FALSE /* not connected */);
1750 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1756 /***********************************************************************
1758 * smtp_regular_transfer()
1760 * The input argument is already checked for validity.
1762 * Performs all commands done before a regular transfer between a local and a
1765 static CURLcode smtp_regular_transfer(struct connectdata *conn,
1768 CURLcode result = CURLE_OK;
1769 bool connected = FALSE;
1770 struct SessionHandle *data = conn->data;
1772 /* Make sure size is unknown at this point */
1773 data->req.size = -1;
1775 /* Set the progress data */
1776 Curl_pgrsSetUploadCounter(data, 0);
1777 Curl_pgrsSetDownloadCounter(data, 0);
1778 Curl_pgrsSetUploadSize(data, 0);
1779 Curl_pgrsSetDownloadSize(data, 0);
1781 /* Carry out the perform */
1782 result = smtp_perform(conn, &connected, dophase_done);
1784 /* Perform post DO phase operations if necessary */
1785 if(!result && *dophase_done)
1786 result = smtp_dophase_done(conn, connected);
1791 static CURLcode smtp_setup_connection(struct connectdata *conn)
1793 struct SessionHandle *data = conn->data;
1796 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
1797 /* Unless we have asked to tunnel SMTP operations through the proxy, we
1798 switch and use HTTP operations only */
1799 #ifndef CURL_DISABLE_HTTP
1800 if(conn->handler == &Curl_handler_smtp)
1801 conn->handler = &Curl_handler_smtp_proxy;
1804 conn->handler = &Curl_handler_smtps_proxy;
1806 failf(data, "SMTPS not supported!");
1807 return CURLE_UNSUPPORTED_PROTOCOL;
1810 /* set it up as a HTTP connection instead */
1811 return conn->handler->setup_connection(conn);
1814 failf(data, "SMTP over http proxy requires HTTP support built-in!");
1815 return CURLE_UNSUPPORTED_PROTOCOL;
1819 /* Initialise the SMTP layer */
1820 result = smtp_init(conn);
1824 data->state.path++; /* don't include the initial slash */
1829 /***********************************************************************
1831 * smtp_parse_url_options()
1833 * Parse the URL login options.
1835 static CURLcode smtp_parse_url_options(struct connectdata *conn)
1837 CURLcode result = CURLE_OK;
1838 struct smtp_conn *smtpc = &conn->proto.smtpc;
1839 const char *options = conn->options;
1840 const char *ptr = options;
1843 const char *key = ptr;
1845 while(*ptr && *ptr != '=')
1848 if(strnequal(key, "AUTH", 4)) {
1849 const char *value = ptr + 1;
1851 if(strequal(value, "*"))
1852 smtpc->prefmech = SASL_AUTH_ANY;
1853 else if(strequal(value, SASL_MECH_STRING_LOGIN))
1854 smtpc->prefmech = SASL_MECH_LOGIN;
1855 else if(strequal(value, SASL_MECH_STRING_PLAIN))
1856 smtpc->prefmech = SASL_MECH_PLAIN;
1857 else if(strequal(value, SASL_MECH_STRING_CRAM_MD5))
1858 smtpc->prefmech = SASL_MECH_CRAM_MD5;
1859 else if(strequal(value, SASL_MECH_STRING_DIGEST_MD5))
1860 smtpc->prefmech = SASL_MECH_DIGEST_MD5;
1861 else if(strequal(value, SASL_MECH_STRING_GSSAPI))
1862 smtpc->prefmech = SASL_MECH_GSSAPI;
1863 else if(strequal(value, SASL_MECH_STRING_NTLM))
1864 smtpc->prefmech = SASL_MECH_NTLM;
1865 else if(strequal(value, SASL_MECH_STRING_XOAUTH2))
1866 smtpc->prefmech = SASL_MECH_XOAUTH2;
1868 smtpc->prefmech = SASL_AUTH_NONE;
1871 result = CURLE_URL_MALFORMAT;
1877 /***********************************************************************
1879 * smtp_parse_url_path()
1881 * Parse the URL path into separate path components.
1883 static CURLcode smtp_parse_url_path(struct connectdata *conn)
1885 /* The SMTP struct is already initialised in smtp_connect() */
1886 struct SessionHandle *data = conn->data;
1887 struct smtp_conn *smtpc = &conn->proto.smtpc;
1888 const char *path = data->state.path;
1889 char localhost[HOSTNAME_MAX + 1];
1891 /* Calculate the path if necessary */
1893 if(!Curl_gethostname(localhost, sizeof(localhost)))
1899 /* URL decode the path and use it as the domain in our EHLO */
1900 return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE);
1903 CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread)
1905 /* When sending a SMTP payload we must detect CRLF. sequences making sure
1906 they are sent as CRLF.. instead, as a . on the beginning of a line will
1907 be deleted by the server when not part of an EOB terminator and a
1908 genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of
1913 struct SessionHandle *data = conn->data;
1914 struct SMTP *smtp = data->req.protop;
1916 /* Do we need to allocate the scatch buffer? */
1917 if(!data->state.scratch) {
1918 data->state.scratch = malloc(2 * BUFSIZE);
1920 if(!data->state.scratch) {
1921 failf (data, "Failed to alloc scratch buffer!");
1922 return CURLE_OUT_OF_MEMORY;
1926 /* This loop can be improved by some kind of Boyer-Moore style of
1927 approach but that is saved for later... */
1928 for(i = 0, si = 0; i < nread; i++) {
1929 if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) {
1932 /* Is the EOB potentially the terminating CRLF? */
1933 if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob)
1934 smtp->trailing_crlf = TRUE;
1936 smtp->trailing_crlf = FALSE;
1938 else if(smtp->eob) {
1939 /* A previous substring matched so output that first */
1940 memcpy(&data->state.scratch[si], SMTP_EOB, smtp->eob);
1943 /* Then compare the first byte */
1944 if(SMTP_EOB[0] == data->req.upload_fromhere[i])
1949 /* Reset the trailing CRLF flag as there was more data */
1950 smtp->trailing_crlf = FALSE;
1953 /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */
1954 if(SMTP_EOB_FIND_LEN == smtp->eob) {
1955 /* Copy the replacement data to the target buffer */
1956 memcpy(&data->state.scratch[si], SMTP_EOB_REPL, SMTP_EOB_REPL_LEN);
1957 si += SMTP_EOB_REPL_LEN;
1961 data->state.scratch[si++] = data->req.upload_fromhere[i];
1965 /* A substring matched before processing ended so output that now */
1966 memcpy(&data->state.scratch[si], SMTP_EOB, smtp->eob);
1972 /* Only use the new buffer if we replaced something */
1975 /* Upload from the new (replaced) buffer instead */
1976 data->req.upload_fromhere = data->state.scratch;
1978 /* Set the new amount too */
1979 data->req.upload_present = nread;
1985 #endif /* CURL_DISABLE_SMTP */