blob: 3f3b45a9546eaee33e177a5e41b620c395320944 [file] [log] [blame]
Kristian Monsen5ab50182010-05-14 18:53:44 +01001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
Elliott Hughes0128fe42018-02-27 14:57:55 -08008 * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
Kristian Monsen5ab50182010-05-14 18:53:44 +01009 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
Alex Deymod15eaac2016-06-28 14:49:26 -070012 * are also available at https://curl.haxx.se/docs/copyright.html.
Kristian Monsen5ab50182010-05-14 18:53:44 +010013 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070021 * RFC1870 SMTP Service Extension for Message Size
Lucas Eckels9bd90e62012-08-06 15:07:02 -070022 * RFC2195 CRAM-MD5 authentication
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070023 * RFC2831 DIGEST-MD5 authentication
24 * RFC3207 SMTP over TLS
25 * RFC4422 Simple Authentication and Security Layer (SASL)
Lucas Eckels9bd90e62012-08-06 15:07:02 -070026 * RFC4616 PLAIN authentication
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070027 * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
28 * RFC4954 SMTP Authentication
29 * RFC5321 SMTP protocol
30 * RFC6749 OAuth 2.0 Authorization Framework
31 * Draft SMTP URL Interface <draft-earhart-url-smtp-00.txt>
32 * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
Kristian Monsen5ab50182010-05-14 18:53:44 +010033 *
34 ***************************************************************************/
35
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070036#include "curl_setup.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010037
38#ifndef CURL_DISABLE_SMTP
Kristian Monsen5ab50182010-05-14 18:53:44 +010039
Kristian Monsen5ab50182010-05-14 18:53:44 +010040#ifdef HAVE_NETINET_IN_H
41#include <netinet/in.h>
42#endif
43#ifdef HAVE_ARPA_INET_H
44#include <arpa/inet.h>
45#endif
46#ifdef HAVE_UTSNAME_H
47#include <sys/utsname.h>
48#endif
49#ifdef HAVE_NETDB_H
50#include <netdb.h>
51#endif
52#ifdef __VMS
53#include <in.h>
54#include <inet.h>
55#endif
56
57#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
58#undef in_addr_t
59#define in_addr_t unsigned long
60#endif
61
62#include <curl/curl.h>
63#include "urldata.h"
64#include "sendf.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010065#include "hostip.h"
66#include "progress.h"
67#include "transfer.h"
68#include "escape.h"
69#include "http.h" /* for HTTP proxy tunnel stuff */
Alex Deymo486467e2017-12-19 19:04:07 +010070#include "mime.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010071#include "socks.h"
72#include "smtp.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010073#include "strtoofft.h"
Elliott Hughescee03382017-06-23 12:17:18 -070074#include "strcase.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070075#include "vtls/vtls.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010076#include "connect.h"
77#include "strerror.h"
78#include "select.h"
79#include "multiif.h"
80#include "url.h"
Lucas Eckels9bd90e62012-08-06 15:07:02 -070081#include "curl_gethostname.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070082#include "curl_sasl.h"
83#include "warnless.h"
Alex Deymod15eaac2016-06-28 14:49:26 -070084/* The last 3 #include files should be in this order */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070085#include "curl_printf.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010086#include "curl_memory.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010087#include "memdebug.h"
88
89/* Local API functions */
90static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done);
91static CURLcode smtp_do(struct connectdata *conn, bool *done);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070092static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
93 bool premature);
Kristian Monsen5ab50182010-05-14 18:53:44 +010094static CURLcode smtp_connect(struct connectdata *conn, bool *done);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070095static CURLcode smtp_disconnect(struct connectdata *conn, bool dead);
Kristian Monsen5ab50182010-05-14 18:53:44 +010096static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070097static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
Kristian Monsen5ab50182010-05-14 18:53:44 +010098 int numsocks);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070099static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done);
100static CURLcode smtp_setup_connection(struct connectdata *conn);
101static CURLcode smtp_parse_url_options(struct connectdata *conn);
102static CURLcode smtp_parse_url_path(struct connectdata *conn);
103static CURLcode smtp_parse_custom_request(struct connectdata *conn);
104static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech,
105 const char *initresp);
106static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp);
Elliott Hughescee03382017-06-23 12:17:18 -0700107static void smtp_get_message(char *buffer, char **outptr);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100108
109/*
110 * SMTP protocol handler.
111 */
112
113const struct Curl_handler Curl_handler_smtp = {
114 "SMTP", /* scheme */
115 smtp_setup_connection, /* setup_connection */
116 smtp_do, /* do_it */
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 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700124 ZERO_NULL, /* domore_getsock */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100125 ZERO_NULL, /* perform_getsock */
126 smtp_disconnect, /* disconnect */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700127 ZERO_NULL, /* readwrite */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700128 ZERO_NULL, /* connection_check */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100129 PORT_SMTP, /* defport */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700130 CURLPROTO_SMTP, /* protocol */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700131 PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
132 PROTOPT_URLOPTIONS
Kristian Monsen5ab50182010-05-14 18:53:44 +0100133};
134
Kristian Monsen5ab50182010-05-14 18:53:44 +0100135#ifdef USE_SSL
136/*
137 * SMTPS protocol handler.
138 */
139
140const struct Curl_handler Curl_handler_smtps = {
141 "SMTPS", /* scheme */
142 smtp_setup_connection, /* setup_connection */
143 smtp_do, /* do_it */
144 smtp_done, /* done */
145 ZERO_NULL, /* do_more */
146 smtp_connect, /* connect_it */
147 smtp_multi_statemach, /* connecting */
148 smtp_doing, /* doing */
149 smtp_getsock, /* proto_getsock */
150 smtp_getsock, /* doing_getsock */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700151 ZERO_NULL, /* domore_getsock */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100152 ZERO_NULL, /* perform_getsock */
153 smtp_disconnect, /* disconnect */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700154 ZERO_NULL, /* readwrite */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700155 ZERO_NULL, /* connection_check */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100156 PORT_SMTPS, /* defport */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700157 CURLPROTO_SMTPS, /* protocol */
158 PROTOPT_CLOSEACTION | PROTOPT_SSL
Elliott Hughes82be86d2017-09-20 17:00:17 -0700159 | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100160};
161#endif
162
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700163/* SASL parameters for the smtp protocol */
164static const struct SASLproto saslsmtp = {
165 "smtp", /* The service name */
166 334, /* Code received when continuation is expected */
167 235, /* Code to receive upon authentication success */
168 512 - 8, /* Maximum initial response length (no max) */
169 smtp_perform_auth, /* Send authentication command */
170 smtp_continue_auth, /* Send authentication continuation */
171 smtp_get_message /* Get SASL response message */
172};
Kristian Monsen5ab50182010-05-14 18:53:44 +0100173
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700174#ifdef USE_SSL
175static void smtp_to_smtps(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100176{
Alex Deymod15eaac2016-06-28 14:49:26 -0700177 /* Change the connection handler */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700178 conn->handler = &Curl_handler_smtps;
Alex Deymod15eaac2016-06-28 14:49:26 -0700179
180 /* Set the connection's upgraded to TLS flag */
181 conn->tls_upgraded = TRUE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700182}
183#else
184#define smtp_to_smtps(x) Curl_nop_stmt
185#endif
186
187/***********************************************************************
188 *
189 * smtp_endofresp()
190 *
191 * Checks for an ending SMTP status code at the start of the given string, but
192 * also detects various capabilities from the EHLO response including the
193 * supported authentication mechanisms.
194 */
195static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
196 int *resp)
197{
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700198 struct smtp_conn *smtpc = &conn->proto.smtpc;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700199 bool result = FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100200
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700201 /* Nothing for us */
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700202 if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700203 return FALSE;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700204
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700205 /* Do we have a command response? This should be the response code followed
206 by a space and optionally some text as per RFC-5321 and as outlined in
207 Section 4. Examples of RFC-4954 but some e-mail servers ignore this and
208 only send the response code instead as per Section 4.2. */
209 if(line[3] == ' ' || len == 5) {
210 result = TRUE;
211 *resp = curlx_sltosi(strtol(line, NULL, 10));
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700212
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700213 /* Make sure real server never sends internal value */
214 if(*resp == 1)
215 *resp = 0;
216 }
217 /* Do we have a multiline (continuation) response? */
218 else if(line[3] == '-' &&
219 (smtpc->state == SMTP_EHLO || smtpc->state == SMTP_COMMAND)) {
220 result = TRUE;
221 *resp = 1; /* Internal response code */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100222 }
223
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700224 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100225}
226
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700227/***********************************************************************
228 *
229 * smtp_get_message()
230 *
231 * Gets the authentication message from the response buffer.
232 */
Elliott Hughescee03382017-06-23 12:17:18 -0700233static void smtp_get_message(char *buffer, char **outptr)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700234{
Elliott Hughes0128fe42018-02-27 14:57:55 -0800235 size_t len = strlen(buffer);
Elliott Hughescee03382017-06-23 12:17:18 -0700236 char *message = NULL;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700237
Elliott Hughes0128fe42018-02-27 14:57:55 -0800238 if(len > 4) {
239 /* Find the start of the message */
240 len -= 4;
241 for(message = buffer + 4; *message == ' ' || *message == '\t';
242 message++, len--)
243 ;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700244
Elliott Hughes0128fe42018-02-27 14:57:55 -0800245 /* Find the end of the message */
246 for(; len--;)
247 if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
248 message[len] != '\t')
249 break;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700250
Elliott Hughes0128fe42018-02-27 14:57:55 -0800251 /* Terminate the message */
252 if(++len) {
253 message[len] = '\0';
254 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700255 }
Elliott Hughes0128fe42018-02-27 14:57:55 -0800256 else
257 /* junk input => zero length output */
258 message = &buffer[len];
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700259
260 *outptr = message;
261}
262
263/***********************************************************************
264 *
265 * state()
266 *
267 * This is the ONLY way to change SMTP state!
268 */
269static void state(struct connectdata *conn, smtpstate newstate)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100270{
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700271 struct smtp_conn *smtpc = &conn->proto.smtpc;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100272#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
273 /* for debug purposes */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700274 static const char * const names[] = {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100275 "STOP",
276 "SERVERGREET",
277 "EHLO",
278 "HELO",
279 "STARTTLS",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700280 "UPGRADETLS",
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700281 "AUTH",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700282 "COMMAND",
Kristian Monsen5ab50182010-05-14 18:53:44 +0100283 "MAIL",
284 "RCPT",
285 "DATA",
286 "POSTDATA",
287 "QUIT",
288 /* LAST */
289 };
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700290
Kristian Monsen5ab50182010-05-14 18:53:44 +0100291 if(smtpc->state != newstate)
292 infof(conn->data, "SMTP %p state change from %s to %s\n",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700293 (void *)smtpc, names[smtpc->state], names[newstate]);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100294#endif
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700295
Kristian Monsen5ab50182010-05-14 18:53:44 +0100296 smtpc->state = newstate;
297}
298
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700299/***********************************************************************
300 *
301 * smtp_perform_ehlo()
302 *
303 * Sends the EHLO command to not only initialise communication with the ESMTP
304 * server but to also obtain a list of server side supported capabilities.
305 */
306static CURLcode smtp_perform_ehlo(struct connectdata *conn)
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700307{
308 CURLcode result = CURLE_OK;
309 struct smtp_conn *smtpc = &conn->proto.smtpc;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700310
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700311 smtpc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanism yet */
312 smtpc->sasl.authused = SASL_AUTH_NONE; /* Clear the authentication mechanism
313 used for esmtp connections */
314 smtpc->tls_supported = FALSE; /* Clear the TLS capability */
315 smtpc->auth_supported = FALSE; /* Clear the AUTH capability */
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700316
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700317 /* Send the EHLO command */
318 result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain);
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700319
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700320 if(!result)
321 state(conn, SMTP_EHLO);
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700322
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700323 return result;
324}
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700325
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700326/***********************************************************************
327 *
328 * smtp_perform_helo()
329 *
330 * Sends the HELO command to initialise communication with the SMTP server.
331 */
332static CURLcode smtp_perform_helo(struct connectdata *conn)
333{
334 CURLcode result = CURLE_OK;
335 struct smtp_conn *smtpc = &conn->proto.smtpc;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700336
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700337 smtpc->sasl.authused = SASL_AUTH_NONE; /* No authentication mechanism used
338 in smtp connections */
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700339
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700340 /* Send the HELO command */
341 result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain);
342
343 if(!result)
344 state(conn, SMTP_HELO);
345
346 return result;
347}
348
349/***********************************************************************
350 *
351 * smtp_perform_starttls()
352 *
353 * Sends the STLS command to start the upgrade to TLS.
354 */
355static CURLcode smtp_perform_starttls(struct connectdata *conn)
356{
357 CURLcode result = CURLE_OK;
358
359 /* Send the STARTTLS command */
360 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "STARTTLS");
361
362 if(!result)
363 state(conn, SMTP_STARTTLS);
364
365 return result;
366}
367
368/***********************************************************************
369 *
370 * smtp_perform_upgrade_tls()
371 *
372 * Performs the upgrade to TLS.
373 */
374static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn)
375{
376 CURLcode result = CURLE_OK;
377 struct smtp_conn *smtpc = &conn->proto.smtpc;
378
379 /* Start the SSL connection */
380 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
381
382 if(!result) {
383 if(smtpc->state != SMTP_UPGRADETLS)
384 state(conn, SMTP_UPGRADETLS);
385
386 if(smtpc->ssldone) {
387 smtp_to_smtps(conn);
388 result = smtp_perform_ehlo(conn);
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700389 }
390 }
391
392 return result;
393}
394
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700395/***********************************************************************
396 *
397 * smtp_perform_auth()
398 *
399 * Sends an AUTH command allowing the client to login with the given SASL
400 * authentication mechanism.
401 */
402static CURLcode smtp_perform_auth(struct connectdata *conn,
403 const char *mech,
404 const char *initresp)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100405{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700406 CURLcode result = CURLE_OK;
407 struct smtp_conn *smtpc = &conn->proto.smtpc;
408
409 if(initresp) { /* AUTH <mech> ...<crlf> */
410 /* Send the AUTH command with the initial response */
411 result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
412 }
413 else {
414 /* Send the AUTH command */
415 result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
416 }
417
418 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100419}
420
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700421/***********************************************************************
422 *
423 * smtp_continue_auth()
424 *
425 * Sends SASL continuation data or cancellation.
426 */
427static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp)
428{
429 struct smtp_conn *smtpc = &conn->proto.smtpc;
430
431 return Curl_pp_sendf(&smtpc->pp, "%s", resp);
432}
433
434/***********************************************************************
435 *
436 * smtp_perform_authentication()
437 *
438 * Initiates the authentication sequence, with the appropriate SASL
439 * authentication mechanism.
440 */
441static CURLcode smtp_perform_authentication(struct connectdata *conn)
442{
443 CURLcode result = CURLE_OK;
444 struct smtp_conn *smtpc = &conn->proto.smtpc;
445 saslprogress progress;
446
447 /* Check we have enough data to authenticate with, and the
448 server supports authentiation, and end the connect phase if not */
449 if(!smtpc->auth_supported ||
Alex Deymod15eaac2016-06-28 14:49:26 -0700450 !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700451 state(conn, SMTP_STOP);
452 return result;
453 }
454
455 /* Calculate the SASL login details */
456 result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress);
457
458 if(!result) {
459 if(progress == SASL_INPROGRESS)
460 state(conn, SMTP_AUTH);
461 else {
462 /* Other mechanisms not supported */
463 infof(conn->data, "No known authentication mechanisms supported!\n");
464 result = CURLE_LOGIN_DENIED;
465 }
466 }
467
468 return result;
469}
470
471/***********************************************************************
472 *
473 * smtp_perform_command()
474 *
475 * Sends a SMTP based command.
476 */
477static CURLcode smtp_perform_command(struct connectdata *conn)
478{
479 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700480 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700481 struct SMTP *smtp = data->req.protop;
482
483 /* Send the command */
484 if(smtp->rcpt)
485 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s %s",
Alex Deymod15eaac2016-06-28 14:49:26 -0700486 smtp->custom && smtp->custom[0] != '\0' ?
487 smtp->custom : "VRFY",
488 smtp->rcpt->data);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700489 else
490 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s",
491 smtp->custom && smtp->custom[0] != '\0' ?
492 smtp->custom : "HELP");
493
494 if(!result)
495 state(conn, SMTP_COMMAND);
496
497 return result;
498}
499
500/***********************************************************************
501 *
502 * smtp_perform_mail()
503 *
504 * Sends an MAIL command to initiate the upload of a message.
505 */
506static CURLcode smtp_perform_mail(struct connectdata *conn)
507{
508 char *from = NULL;
509 char *auth = NULL;
510 char *size = NULL;
511 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700512 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700513
514 /* Calculate the FROM parameter */
515 if(!data->set.str[STRING_MAIL_FROM])
516 /* Null reverse-path, RFC-5321, sect. 3.6.3 */
517 from = strdup("<>");
518 else if(data->set.str[STRING_MAIL_FROM][0] == '<')
519 from = aprintf("%s", data->set.str[STRING_MAIL_FROM]);
520 else
521 from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]);
522
523 if(!from)
524 return CURLE_OUT_OF_MEMORY;
525
526 /* Calculate the optional AUTH parameter */
527 if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) {
528 if(data->set.str[STRING_MAIL_AUTH][0] != '\0')
529 auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]);
530 else
531 /* Empty AUTH, RFC-2554, sect. 5 */
532 auth = strdup("<>");
533
534 if(!auth) {
535 free(from);
536
537 return CURLE_OUT_OF_MEMORY;
538 }
539 }
540
Alex Deymo486467e2017-12-19 19:04:07 +0100541 /* Prepare the mime data if some. */
542 if(data->set.mimepost.kind != MIMEKIND_NONE) {
543 /* Use the whole structure as data. */
544 data->set.mimepost.flags &= ~MIME_BODY_ONLY;
545
546 /* Add external headers and mime version. */
547 curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
548 result = Curl_mime_prepare_headers(&data->set.mimepost, NULL,
549 NULL, MIMESTRATEGY_MAIL);
550
551 if(!result)
552 if(!Curl_checkheaders(conn, "Mime-Version"))
553 result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
554 "Mime-Version: 1.0");
555
556 /* Make sure we will read the entire mime structure. */
557 if(!result)
558 result = Curl_mime_rewind(&data->set.mimepost);
559
560 if(result) {
561 free(from);
562 free(auth);
563 return result;
564 }
565
566 data->state.infilesize = Curl_mime_size(&data->set.mimepost);
567
568 /* Read from mime structure. */
569 data->state.fread_func = (curl_read_callback) Curl_mime_read;
570 data->state.in = (void *) &data->set.mimepost;
571 }
572
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700573 /* Calculate the optional SIZE parameter */
Alex Deymo486467e2017-12-19 19:04:07 +0100574 if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700575 size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize);
576
577 if(!size) {
578 free(from);
579 free(auth);
580
581 return CURLE_OUT_OF_MEMORY;
582 }
583 }
584
585 /* Send the MAIL command */
586 if(!auth && !size)
587 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
588 "MAIL FROM:%s", from);
589 else if(auth && !size)
590 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
591 "MAIL FROM:%s AUTH=%s", from, auth);
592 else if(auth && size)
593 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
594 "MAIL FROM:%s AUTH=%s SIZE=%s", from, auth, size);
595 else
596 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
597 "MAIL FROM:%s SIZE=%s", from, size);
598
599 free(from);
600 free(auth);
601 free(size);
602
603 if(!result)
604 state(conn, SMTP_MAIL);
605
606 return result;
607}
608
609/***********************************************************************
610 *
611 * smtp_perform_rcpt_to()
612 *
613 * Sends a RCPT TO command for a given recipient as part of the message upload
614 * process.
615 */
616static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
617{
618 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700619 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700620 struct SMTP *smtp = data->req.protop;
621
622 /* Send the RCPT TO command */
623 if(smtp->rcpt->data[0] == '<')
624 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s",
Alex Deymod15eaac2016-06-28 14:49:26 -0700625 smtp->rcpt->data);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700626 else
627 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>",
Alex Deymod15eaac2016-06-28 14:49:26 -0700628 smtp->rcpt->data);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700629 if(!result)
630 state(conn, SMTP_RCPT);
631
632 return result;
633}
634
635/***********************************************************************
636 *
637 * smtp_perform_quit()
638 *
639 * Performs the quit action prior to sclose() being called.
640 */
641static CURLcode smtp_perform_quit(struct connectdata *conn)
642{
643 CURLcode result = CURLE_OK;
644
645 /* Send the QUIT command */
646 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "QUIT");
647
648 if(!result)
649 state(conn, SMTP_QUIT);
650
651 return result;
652}
653
654/* For the initial server greeting */
655static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
656 int smtpcode,
657 smtpstate instate)
658{
659 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700660 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700661
662 (void)instate; /* no use for this yet */
663
664 if(smtpcode/100 != 2) {
665 failf(data, "Got unexpected smtp-server response: %d", smtpcode);
Elliott Hughescee03382017-06-23 12:17:18 -0700666 result = CURLE_WEIRD_SERVER_REPLY;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700667 }
668 else
669 result = smtp_perform_ehlo(conn);
670
671 return result;
672}
673
674/* For STARTTLS responses */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100675static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
676 int smtpcode,
677 smtpstate instate)
678{
679 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700680 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700681
Kristian Monsen5ab50182010-05-14 18:53:44 +0100682 (void)instate; /* no use for this yet */
683
684 if(smtpcode != 220) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700685 if(data->set.use_ssl != CURLUSESSL_TRY) {
Elliott Hughes82be86d2017-09-20 17:00:17 -0700686 failf(data, "STARTTLS denied, code %d", smtpcode);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700687 result = CURLE_USE_SSL_FAILED;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100688 }
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700689 else
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700690 result = smtp_perform_authentication(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100691 }
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700692 else
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700693 result = smtp_perform_upgrade_tls(conn);
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700694
Kristian Monsen5ab50182010-05-14 18:53:44 +0100695 return result;
696}
697
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700698/* For EHLO responses */
699static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
700 smtpstate instate)
701{
702 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700703 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700704 struct smtp_conn *smtpc = &conn->proto.smtpc;
705 const char *line = data->state.buffer;
706 size_t len = strlen(line);
707 size_t wordlen;
708
709 (void)instate; /* no use for this yet */
710
711 if(smtpcode/100 != 2 && smtpcode != 1) {
712 if(data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use)
713 result = smtp_perform_helo(conn);
714 else {
715 failf(data, "Remote access denied: %d", smtpcode);
716 result = CURLE_REMOTE_ACCESS_DENIED;
717 }
718 }
719 else {
720 line += 4;
721 len -= 4;
722
723 /* Does the server support the STARTTLS capability? */
724 if(len >= 8 && !memcmp(line, "STARTTLS", 8))
725 smtpc->tls_supported = TRUE;
726
727 /* Does the server support the SIZE capability? */
728 else if(len >= 4 && !memcmp(line, "SIZE", 4))
729 smtpc->size_supported = TRUE;
730
731 /* Does the server support authentication? */
732 else if(len >= 5 && !memcmp(line, "AUTH ", 5)) {
733 smtpc->auth_supported = TRUE;
734
735 /* Advance past the AUTH keyword */
736 line += 5;
737 len -= 5;
738
739 /* Loop through the data line */
740 for(;;) {
741 size_t llen;
742 unsigned int mechbit;
743
744 while(len &&
745 (*line == ' ' || *line == '\t' ||
746 *line == '\r' || *line == '\n')) {
747
748 line++;
749 len--;
750 }
751
752 if(!len)
753 break;
754
755 /* Extract the word */
756 for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
757 line[wordlen] != '\t' && line[wordlen] != '\r' &&
758 line[wordlen] != '\n';)
759 wordlen++;
760
761 /* Test the word for a matching authentication mechanism */
Alex Deymod15eaac2016-06-28 14:49:26 -0700762 mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
763 if(mechbit && llen == wordlen)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700764 smtpc->sasl.authmechs |= mechbit;
765
766 line += wordlen;
767 len -= wordlen;
768 }
769 }
770
771 if(smtpcode != 1) {
772 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
773 /* We don't have a SSL/TLS connection yet, but SSL is requested */
774 if(smtpc->tls_supported)
775 /* Switch to TLS connection now */
776 result = smtp_perform_starttls(conn);
777 else if(data->set.use_ssl == CURLUSESSL_TRY)
778 /* Fallback and carry on with authentication */
779 result = smtp_perform_authentication(conn);
780 else {
781 failf(data, "STARTTLS not supported.");
782 result = CURLE_USE_SSL_FAILED;
783 }
784 }
785 else
786 result = smtp_perform_authentication(conn);
787 }
788 }
789
790 return result;
791}
792
793/* For HELO responses */
794static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode,
Kristian Monsen5ab50182010-05-14 18:53:44 +0100795 smtpstate instate)
796{
797 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700798 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100799
800 (void)instate; /* no use for this yet */
801
802 if(smtpcode/100 != 2) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700803 failf(data, "Remote access denied: %d", smtpcode);
804 result = CURLE_REMOTE_ACCESS_DENIED;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700805 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700806 else
807 /* End of connect phase */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100808 state(conn, SMTP_STOP);
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700809
810 return result;
811}
812
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700813/* For SASL authentication responses */
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700814static CURLcode smtp_state_auth_resp(struct connectdata *conn,
815 int smtpcode,
816 smtpstate instate)
817{
818 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700819 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100820 struct smtp_conn *smtpc = &conn->proto.smtpc;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700821 saslprogress progress;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100822
Kristian Monsen5ab50182010-05-14 18:53:44 +0100823 (void)instate; /* no use for this yet */
824
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700825 result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress);
826 if(!result)
827 switch(progress) {
828 case SASL_DONE:
829 state(conn, SMTP_STOP); /* Authenticated */
830 break;
831 case SASL_IDLE: /* No mechanism left after cancellation */
832 failf(data, "Authentication cancelled");
833 result = CURLE_LOGIN_DENIED;
834 break;
835 default:
836 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100837 }
838
Kristian Monsen5ab50182010-05-14 18:53:44 +0100839 return result;
840}
841
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700842/* For command responses */
843static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
844 smtpstate instate)
845{
846 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700847 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700848 struct SMTP *smtp = data->req.protop;
849 char *line = data->state.buffer;
850 size_t len = strlen(line);
851
852 (void)instate; /* no use for this yet */
853
854 if((smtp->rcpt && smtpcode/100 != 2 && smtpcode != 553 && smtpcode != 1) ||
855 (!smtp->rcpt && smtpcode/100 != 2 && smtpcode != 1)) {
856 failf(data, "Command failed: %d", smtpcode);
857 result = CURLE_RECV_ERROR;
858 }
859 else {
860 /* Temporarily add the LF character back and send as body to the client */
861 if(!data->set.opt_no_body) {
862 line[len] = '\n';
863 result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
864 line[len] = '\0';
865 }
866
867 if(smtpcode != 1) {
868 if(smtp->rcpt) {
869 smtp->rcpt = smtp->rcpt->next;
870
871 if(smtp->rcpt) {
872 /* Send the next command */
873 result = smtp_perform_command(conn);
874 }
875 else
876 /* End of DO phase */
877 state(conn, SMTP_STOP);
878 }
879 else
880 /* End of DO phase */
881 state(conn, SMTP_STOP);
882 }
883 }
884
885 return result;
886}
887
888/* For MAIL responses */
889static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
Kristian Monsen5ab50182010-05-14 18:53:44 +0100890 smtpstate instate)
891{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700892 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700893 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700894
895 (void)instate; /* no use for this yet */
896
897 if(smtpcode/100 != 2) {
898 failf(data, "MAIL failed: %d", smtpcode);
899 result = CURLE_SEND_ERROR;
900 }
901 else
902 /* Start the RCPT TO command */
903 result = smtp_perform_rcpt_to(conn);
904
905 return result;
906}
907
908/* For RCPT responses */
909static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
910 smtpstate instate)
911{
912 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700913 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700914 struct SMTP *smtp = data->req.protop;
915
916 (void)instate; /* no use for this yet */
917
918 if(smtpcode/100 != 2) {
919 failf(data, "RCPT failed: %d", smtpcode);
920 result = CURLE_SEND_ERROR;
921 }
922 else {
923 smtp->rcpt = smtp->rcpt->next;
924
925 if(smtp->rcpt)
926 /* Send the next RCPT TO command */
927 result = smtp_perform_rcpt_to(conn);
928 else {
929 /* Send the DATA command */
930 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA");
931
932 if(!result)
933 state(conn, SMTP_DATA);
934 }
935 }
936
937 return result;
938}
939
940/* For DATA response */
941static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
942 smtpstate instate)
943{
944 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700945 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100946
947 (void)instate; /* no use for this yet */
948
949 if(smtpcode != 354) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700950 failf(data, "DATA failed: %d", smtpcode);
951 result = CURLE_SEND_ERROR;
952 }
953 else {
954 /* Set the progress upload size */
955 Curl_pgrsSetUploadSize(data, data->state.infilesize);
956
957 /* SMTP upload */
958 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
959
960 /* End of DO phase */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100961 state(conn, SMTP_STOP);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100962 }
963
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700964 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100965}
966
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700967/* For POSTDATA responses, which are received after the entire DATA
968 part has been sent to the server */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100969static CURLcode smtp_state_postdata_resp(struct connectdata *conn,
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700970 int smtpcode,
971 smtpstate instate)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100972{
973 CURLcode result = CURLE_OK;
974
975 (void)instate; /* no use for this yet */
976
977 if(smtpcode != 250)
978 result = CURLE_RECV_ERROR;
979
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700980 /* End of DONE phase */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100981 state(conn, SMTP_STOP);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700982
Kristian Monsen5ab50182010-05-14 18:53:44 +0100983 return result;
984}
985
986static CURLcode smtp_statemach_act(struct connectdata *conn)
987{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700988 CURLcode result = CURLE_OK;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100989 curl_socket_t sock = conn->sock[FIRSTSOCKET];
Alex Deymoe3149cc2016-10-05 11:18:42 -0700990 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100991 int smtpcode;
992 struct smtp_conn *smtpc = &conn->proto.smtpc;
993 struct pingpong *pp = &smtpc->pp;
994 size_t nread = 0;
995
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700996 /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */
997 if(smtpc->state == SMTP_UPGRADETLS)
998 return smtp_perform_upgrade_tls(conn);
999
1000 /* Flush any data that needs to be sent */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001001 if(pp->sendleft)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001002 return Curl_pp_flushsend(pp);
1003
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001004 do {
1005 /* Read the response from the server */
1006 result = Curl_pp_readresp(sock, pp, &smtpcode, &nread);
1007 if(result)
1008 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001009
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001010 /* Store the latest response for later retrieval if necessary */
1011 if(smtpc->state != SMTP_QUIT && smtpcode != 1)
1012 data->info.httpcode = smtpcode;
1013
1014 if(!smtpcode)
1015 break;
1016
1017 /* We have now received a full SMTP server response */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001018 switch(smtpc->state) {
1019 case SMTP_SERVERGREET:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001020 result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001021 break;
1022
1023 case SMTP_EHLO:
1024 result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
1025 break;
1026
1027 case SMTP_HELO:
1028 result = smtp_state_helo_resp(conn, smtpcode, smtpc->state);
1029 break;
1030
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001031 case SMTP_STARTTLS:
1032 result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state);
1033 break;
1034
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001035 case SMTP_AUTH:
1036 result = smtp_state_auth_resp(conn, smtpcode, smtpc->state);
1037 break;
1038
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001039 case SMTP_COMMAND:
1040 result = smtp_state_command_resp(conn, smtpcode, smtpc->state);
1041 break;
1042
Kristian Monsen5ab50182010-05-14 18:53:44 +01001043 case SMTP_MAIL:
1044 result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
1045 break;
1046
1047 case SMTP_RCPT:
1048 result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state);
1049 break;
1050
Kristian Monsen5ab50182010-05-14 18:53:44 +01001051 case SMTP_DATA:
1052 result = smtp_state_data_resp(conn, smtpcode, smtpc->state);
1053 break;
1054
1055 case SMTP_POSTDATA:
1056 result = smtp_state_postdata_resp(conn, smtpcode, smtpc->state);
1057 break;
1058
1059 case SMTP_QUIT:
1060 /* fallthrough, just stop! */
1061 default:
1062 /* internal error */
1063 state(conn, SMTP_STOP);
1064 break;
1065 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001066 } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp));
Kristian Monsen5ab50182010-05-14 18:53:44 +01001067
1068 return result;
1069}
1070
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001071/* Called repeatedly until done from multi.c */
1072static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001073{
Kristian Monsen5ab50182010-05-14 18:53:44 +01001074 CURLcode result = CURLE_OK;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001075 struct smtp_conn *smtpc = &conn->proto.smtpc;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001076
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001077 if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) {
1078 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
1079 if(result || !smtpc->ssldone)
1080 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001081 }
1082
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001083 result = Curl_pp_statemach(&smtpc->pp, FALSE);
1084 *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE;
1085
Kristian Monsen5ab50182010-05-14 18:53:44 +01001086 return result;
1087}
1088
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001089static CURLcode smtp_block_statemach(struct connectdata *conn)
1090{
1091 CURLcode result = CURLE_OK;
1092 struct smtp_conn *smtpc = &conn->proto.smtpc;
1093
1094 while(smtpc->state != SMTP_STOP && !result)
1095 result = Curl_pp_statemach(&smtpc->pp, TRUE);
1096
1097 return result;
1098}
1099
Alex Deymoe3149cc2016-10-05 11:18:42 -07001100/* Allocate and initialize the SMTP struct for the current Curl_easy if
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001101 required */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001102static CURLcode smtp_init(struct connectdata *conn)
1103{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001104 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001105 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001106 struct SMTP *smtp;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001107
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001108 smtp = data->req.protop = calloc(sizeof(struct SMTP), 1);
1109 if(!smtp)
1110 result = CURLE_OUT_OF_MEMORY;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001111
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001112 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001113}
1114
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001115/* For the SMTP "protocol connect" and "doing" phases only */
1116static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
1117 int numsocks)
1118{
1119 return Curl_pp_getsock(&conn->proto.smtpc.pp, socks, numsocks);
1120}
1121
1122/***********************************************************************
1123 *
1124 * smtp_connect()
1125 *
1126 * This function should do everything that is to be considered a part of
Kristian Monsen5ab50182010-05-14 18:53:44 +01001127 * the connection phase.
1128 *
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001129 * The variable pointed to by 'done' will be TRUE if the protocol-layer
1130 * connect phase is done when this function returns, or FALSE if not.
Kristian Monsen5ab50182010-05-14 18:53:44 +01001131 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001132static CURLcode smtp_connect(struct connectdata *conn, bool *done)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001133{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001134 CURLcode result = CURLE_OK;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001135 struct smtp_conn *smtpc = &conn->proto.smtpc;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001136 struct pingpong *pp = &smtpc->pp;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001137
1138 *done = FALSE; /* default to not done yet */
1139
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001140 /* We always support persistent connections in SMTP */
1141 connkeep(conn, "SMTP default");
Kristian Monsen5ab50182010-05-14 18:53:44 +01001142
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001143 /* Set the default response time-out */
1144 pp->response_time = RESP_TIMEOUT;
1145 pp->statemach_act = smtp_statemach_act;
1146 pp->endofresp = smtp_endofresp;
1147 pp->conn = conn;
1148
1149 /* Initialize the SASL storage */
1150 Curl_sasl_init(&smtpc->sasl, &saslsmtp);
1151
1152 /* Initialise the pingpong layer */
1153 Curl_pp_init(pp);
1154
1155 /* Parse the URL options */
1156 result = smtp_parse_url_options(conn);
1157 if(result)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001158 return result;
1159
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001160 /* Parse the URL path */
1161 result = smtp_parse_url_path(conn);
1162 if(result)
1163 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001164
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001165 /* Start off waiting for the server greeting response */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001166 state(conn, SMTP_SERVERGREET);
1167
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001168 result = smtp_multi_statemach(conn, done);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001169
1170 return result;
1171}
1172
1173/***********************************************************************
1174 *
1175 * smtp_done()
1176 *
1177 * The DONE function. This does what needs to be done after a single DO has
1178 * performed.
1179 *
1180 * Input argument is already checked for validity.
1181 */
1182static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
1183 bool premature)
1184{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001185 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001186 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001187 struct SMTP *smtp = data->req.protop;
1188 struct pingpong *pp = &conn->proto.smtpc.pp;
1189 char *eob;
1190 ssize_t len;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001191 ssize_t bytes_written;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001192
Kristian Monsen5ab50182010-05-14 18:53:44 +01001193 (void)premature;
1194
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001195 if(!smtp || !pp->conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001196 return CURLE_OK;
1197
Alex Deymo486467e2017-12-19 19:04:07 +01001198 /* Cleanup our per-request based variables */
1199 Curl_safefree(smtp->custom);
1200
Kristian Monsen5ab50182010-05-14 18:53:44 +01001201 if(status) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001202 connclose(conn, "SMTP done with bad status"); /* marked for closure */
1203 result = status; /* use the already set error code */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001204 }
Alex Deymo486467e2017-12-19 19:04:07 +01001205 else if(!data->set.connect_only && data->set.mail_rcpt &&
1206 (data->set.upload || data->set.mimepost.kind)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001207 /* Calculate the EOB taking into account any terminating CRLF from the
1208 previous line of the email or the CRLF of the DATA command when there
1209 is "no mail data". RFC-5321, sect. 4.1.1.4.
Kristian Monsen5ab50182010-05-14 18:53:44 +01001210
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001211 Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to
1212 fail when using a different pointer following a previous write, that
1213 returned CURLE_AGAIN, we duplicate the EOB now rather than when the
1214 bytes written doesn't equal len. */
1215 if(smtp->trailing_crlf || !conn->data->state.infilesize) {
1216 eob = strdup(SMTP_EOB + 2);
1217 len = SMTP_EOB_LEN - 2;
1218 }
1219 else {
1220 eob = strdup(SMTP_EOB);
1221 len = SMTP_EOB_LEN;
1222 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001223
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001224 if(!eob)
1225 return CURLE_OUT_OF_MEMORY;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001226
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001227 /* Send the end of block data */
1228 result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written);
1229 if(result) {
1230 free(eob);
1231 return result;
1232 }
1233
1234 if(bytes_written != len) {
1235 /* The whole chunk was not sent so keep it around and adjust the
1236 pingpong structure accordingly */
1237 pp->sendthis = eob;
1238 pp->sendsize = len;
1239 pp->sendleft = len - bytes_written;
1240 }
1241 else {
1242 /* Successfully sent so adjust the response timeout relative to now */
Alex Deymo486467e2017-12-19 19:04:07 +01001243 pp->response = Curl_now();
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001244
1245 free(eob);
1246 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001247
1248 state(conn, SMTP_POSTDATA);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001249
1250 /* Run the state-machine
Kristian Monsen5ab50182010-05-14 18:53:44 +01001251
1252 TODO: when the multi interface is used, this _really_ should be using
1253 the smtp_multi_statemach function but we have no general support for
Alex Deymod15eaac2016-06-28 14:49:26 -07001254 non-blocking DONE operations!
Kristian Monsen5ab50182010-05-14 18:53:44 +01001255 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001256 result = smtp_block_statemach(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001257 }
1258
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001259 /* Clear the transfer mode for the next request */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001260 smtp->transfer = FTPTRANSFER_BODY;
1261
1262 return result;
1263}
1264
1265/***********************************************************************
1266 *
1267 * smtp_perform()
1268 *
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001269 * This is the actual DO function for SMTP. Transfer a mail, send a command
1270 * or get some data according to the options previously setup.
Kristian Monsen5ab50182010-05-14 18:53:44 +01001271 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001272static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
1273 bool *dophase_done)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001274{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001275 /* This is SMTP and no proxy */
1276 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001277 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001278 struct SMTP *smtp = data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001279
1280 DEBUGF(infof(conn->data, "DO phase starts\n"));
1281
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001282 if(data->set.opt_no_body) {
1283 /* Requested no body means no transfer */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001284 smtp->transfer = FTPTRANSFER_INFO;
1285 }
1286
1287 *dophase_done = FALSE; /* not done yet */
1288
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001289 /* Store the first recipient (or NULL if not specified) */
1290 smtp->rcpt = data->set.mail_rcpt;
1291
Elliott Hughescac39802018-04-27 16:19:43 -07001292 /* Initial data character is the first character in line: it is implicitly
1293 preceded by a virtual CRLF. */
1294 smtp->trailing_crlf = TRUE;
1295 smtp->eob = 2;
1296
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001297 /* Start the first command in the DO phase */
Alex Deymo486467e2017-12-19 19:04:07 +01001298 if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001299 /* MAIL transfer */
1300 result = smtp_perform_mail(conn);
1301 else
1302 /* SMTP based command (VRFY, EXPN, NOOP, RSET or HELP) */
1303 result = smtp_perform_command(conn);
1304
Kristian Monsen5ab50182010-05-14 18:53:44 +01001305 if(result)
1306 return result;
1307
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001308 /* Run the state-machine */
1309 result = smtp_multi_statemach(conn, dophase_done);
1310
1311 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
Kristian Monsen5ab50182010-05-14 18:53:44 +01001312
1313 if(*dophase_done)
1314 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1315
1316 return result;
1317}
1318
1319/***********************************************************************
1320 *
1321 * smtp_do()
1322 *
1323 * This function is registered as 'curl_do' function. It decodes the path
1324 * parts etc as a wrapper to the actual DO function (smtp_perform).
1325 *
1326 * The input argument is already checked for validity.
1327 */
1328static CURLcode smtp_do(struct connectdata *conn, bool *done)
1329{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001330 CURLcode result = CURLE_OK;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001331
1332 *done = FALSE; /* default to false */
1333
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001334 /* Parse the custom request */
1335 result = smtp_parse_custom_request(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001336 if(result)
1337 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001338
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001339 result = smtp_regular_transfer(conn, done);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001340
1341 return result;
1342}
1343
1344/***********************************************************************
1345 *
1346 * smtp_disconnect()
1347 *
1348 * Disconnect from an SMTP server. Cleanup protocol-specific per-connection
1349 * resources. BLOCKING.
1350 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001351static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001352{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001353 struct smtp_conn *smtpc = &conn->proto.smtpc;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001354
1355 /* We cannot send quit unconditionally. If this connection is stale or
1356 bad in any way, sending quit and waiting around here will make the
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001357 disconnect wait in vain and cause more problems than we need to. */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001358
1359 /* The SMTP session may or may not have been allocated/setup at this
1360 point! */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001361 if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart)
1362 if(!smtp_perform_quit(conn))
1363 (void)smtp_block_statemach(conn); /* ignore errors on QUIT */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001364
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001365 /* Disconnect from the server */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001366 Curl_pp_disconnect(&smtpc->pp);
1367
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001368 /* Cleanup the SASL module */
1369 Curl_sasl_cleanup(conn, smtpc->sasl.authused);
1370
1371 /* Cleanup our connection based variables */
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001372 Curl_safefree(smtpc->domain);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001373
Kristian Monsen5ab50182010-05-14 18:53:44 +01001374 return CURLE_OK;
1375}
1376
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001377/* Call this when the DO phase has completed */
1378static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001379{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001380 struct SMTP *smtp = conn->data->req.protop;
1381
Kristian Monsen5ab50182010-05-14 18:53:44 +01001382 (void)connected;
1383
1384 if(smtp->transfer != FTPTRANSFER_BODY)
1385 /* no data to transfer */
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001386 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001387
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001388 return CURLE_OK;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001389}
1390
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001391/* Called from multi.c while DOing */
1392static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001393{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001394 CURLcode result = smtp_multi_statemach(conn, dophase_done);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001395
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001396 if(result)
1397 DEBUGF(infof(conn->data, "DO phase failed\n"));
1398 else if(*dophase_done) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001399 result = smtp_dophase_done(conn, FALSE /* not connected */);
1400
1401 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1402 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001403
Kristian Monsen5ab50182010-05-14 18:53:44 +01001404 return result;
1405}
1406
1407/***********************************************************************
1408 *
1409 * smtp_regular_transfer()
1410 *
1411 * The input argument is already checked for validity.
1412 *
1413 * Performs all commands done before a regular transfer between a local and a
1414 * remote host.
1415 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001416static CURLcode smtp_regular_transfer(struct connectdata *conn,
1417 bool *dophase_done)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001418{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001419 CURLcode result = CURLE_OK;
1420 bool connected = FALSE;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001421 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001422
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001423 /* Make sure size is unknown at this point */
1424 data->req.size = -1;
1425
1426 /* Set the progress data */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001427 Curl_pgrsSetUploadCounter(data, 0);
1428 Curl_pgrsSetDownloadCounter(data, 0);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001429 Curl_pgrsSetUploadSize(data, -1);
1430 Curl_pgrsSetDownloadSize(data, -1);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001431
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001432 /* Carry out the perform */
1433 result = smtp_perform(conn, &connected, dophase_done);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001434
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001435 /* Perform post DO phase operations if necessary */
1436 if(!result && *dophase_done)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001437 result = smtp_dophase_done(conn, connected);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001438
1439 return result;
1440}
1441
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001442static CURLcode smtp_setup_connection(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001443{
Alex Deymoe3149cc2016-10-05 11:18:42 -07001444 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001445 CURLcode result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001446
Alex Deymod15eaac2016-06-28 14:49:26 -07001447 /* Clear the TLS upgraded flag */
1448 conn->tls_upgraded = FALSE;
1449
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001450 /* Initialise the SMTP layer */
1451 result = smtp_init(conn);
1452 if(result)
1453 return result;
1454
Kristian Monsen5ab50182010-05-14 18:53:44 +01001455 data->state.path++; /* don't include the initial slash */
1456
1457 return CURLE_OK;
1458}
1459
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001460/***********************************************************************
1461 *
1462 * smtp_parse_url_options()
1463 *
1464 * Parse the URL login options.
1465 */
1466static CURLcode smtp_parse_url_options(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001467{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001468 CURLcode result = CURLE_OK;
1469 struct smtp_conn *smtpc = &conn->proto.smtpc;
1470 const char *ptr = conn->options;
1471
1472 smtpc->sasl.resetprefs = TRUE;
1473
1474 while(!result && ptr && *ptr) {
1475 const char *key = ptr;
1476 const char *value;
1477
1478 while(*ptr && *ptr != '=')
Alex Deymod15eaac2016-06-28 14:49:26 -07001479 ptr++;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001480
1481 value = ptr + 1;
1482
1483 while(*ptr && *ptr != ';')
1484 ptr++;
1485
Elliott Hughescee03382017-06-23 12:17:18 -07001486 if(strncasecompare(key, "AUTH=", 5))
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001487 result = Curl_sasl_parse_url_auth_option(&smtpc->sasl,
1488 value, ptr - value);
1489 else
1490 result = CURLE_URL_MALFORMAT;
1491
1492 if(*ptr == ';')
1493 ptr++;
1494 }
1495
1496 return result;
1497}
1498
1499/***********************************************************************
1500 *
1501 * smtp_parse_url_path()
1502 *
1503 * Parse the URL path into separate path components.
1504 */
1505static CURLcode smtp_parse_url_path(struct connectdata *conn)
1506{
1507 /* The SMTP struct is already initialised in smtp_connect() */
Alex Deymoe3149cc2016-10-05 11:18:42 -07001508 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001509 struct smtp_conn *smtpc = &conn->proto.smtpc;
1510 const char *path = data->state.path;
1511 char localhost[HOSTNAME_MAX + 1];
1512
1513 /* Calculate the path if necessary */
1514 if(!*path) {
1515 if(!Curl_gethostname(localhost, sizeof(localhost)))
1516 path = localhost;
1517 else
1518 path = "localhost";
1519 }
1520
1521 /* URL decode the path and use it as the domain in our EHLO */
1522 return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE);
1523}
1524
1525/***********************************************************************
1526 *
1527 * smtp_parse_custom_request()
1528 *
1529 * Parse the custom request.
1530 */
1531static CURLcode smtp_parse_custom_request(struct connectdata *conn)
1532{
1533 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001534 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001535 struct SMTP *smtp = data->req.protop;
1536 const char *custom = data->set.str[STRING_CUSTOMREQUEST];
1537
1538 /* URL decode the custom request */
1539 if(custom)
1540 result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, TRUE);
1541
1542 return result;
1543}
1544
1545CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
1546{
1547 /* When sending a SMTP payload we must detect CRLF. sequences making sure
1548 they are sent as CRLF.. instead, as a . on the beginning of a line will
1549 be deleted by the server when not part of an EOB terminator and a
1550 genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of
1551 data by the server
1552 */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001553 ssize_t i;
1554 ssize_t si;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001555 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001556 struct SMTP *smtp = data->req.protop;
1557 char *scratch = data->state.scratch;
1558 char *newscratch = NULL;
1559 char *oldscratch = NULL;
1560 size_t eob_sent;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001561
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001562 /* Do we need to allocate a scratch buffer? */
1563 if(!scratch || data->set.crlf) {
1564 oldscratch = scratch;
1565
Elliott Hughes82be86d2017-09-20 17:00:17 -07001566 scratch = newscratch = malloc(2 * data->set.buffer_size);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001567 if(!newscratch) {
1568 failf(data, "Failed to alloc scratch buffer!");
1569
1570 return CURLE_OUT_OF_MEMORY;
1571 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001572 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001573
1574 /* Have we already sent part of the EOB? */
1575 eob_sent = smtp->eob;
1576
Kristian Monsen5ab50182010-05-14 18:53:44 +01001577 /* This loop can be improved by some kind of Boyer-Moore style of
1578 approach but that is saved for later... */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001579 for(i = 0, si = 0; i < nread; i++) {
1580 if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) {
1581 smtp->eob++;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001582
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001583 /* Is the EOB potentially the terminating CRLF? */
1584 if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob)
1585 smtp->trailing_crlf = TRUE;
1586 else
1587 smtp->trailing_crlf = FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001588 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001589 else if(smtp->eob) {
1590 /* A previous substring matched so output that first */
1591 memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
1592 si += smtp->eob - eob_sent;
1593
1594 /* Then compare the first byte */
1595 if(SMTP_EOB[0] == data->req.upload_fromhere[i])
1596 smtp->eob = 1;
1597 else
1598 smtp->eob = 0;
1599
1600 eob_sent = 0;
1601
1602 /* Reset the trailing CRLF flag as there was more data */
1603 smtp->trailing_crlf = FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001604 }
1605
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001606 /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */
1607 if(SMTP_EOB_FIND_LEN == smtp->eob) {
1608 /* Copy the replacement data to the target buffer */
1609 memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent],
1610 SMTP_EOB_REPL_LEN - eob_sent);
1611 si += SMTP_EOB_REPL_LEN - eob_sent;
1612 smtp->eob = 0;
1613 eob_sent = 0;
1614 }
1615 else if(!smtp->eob)
1616 scratch[si++] = data->req.upload_fromhere[i];
Kristian Monsen5ab50182010-05-14 18:53:44 +01001617 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001618
1619 if(smtp->eob - eob_sent) {
1620 /* A substring matched before processing ended so output that now */
1621 memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
1622 si += smtp->eob - eob_sent;
1623 }
1624
1625 /* Only use the new buffer if we replaced something */
1626 if(si != nread) {
1627 /* Upload from the new (replaced) buffer instead */
1628 data->req.upload_fromhere = scratch;
1629
1630 /* Save the buffer so it can be freed later */
1631 data->state.scratch = scratch;
1632
1633 /* Free the old scratch buffer */
1634 free(oldscratch);
1635
1636 /* Set the new amount too */
1637 data->req.upload_present = si;
1638 }
1639 else
1640 free(newscratch);
1641
Kristian Monsen5ab50182010-05-14 18:53:44 +01001642 return CURLE_OK;
1643}
1644
1645#endif /* CURL_DISABLE_SMTP */