1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel (at) haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * RFC1870 SMTP Service Extension for Message Size 22 * RFC2195 CRAM-MD5 authentication 23 * RFC2831 DIGEST-MD5 authentication 24 * RFC3207 SMTP over TLS 25 * RFC4422 Simple Authentication and Security Layer (SASL) 26 * RFC4616 PLAIN authentication 27 * 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> 33 * 34 ***************************************************************************/ 35 36 #include "curl_setup.h" 37 38 #ifndef CURL_DISABLE_SMTP 39 40 #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" 65 #include "hostip.h" 66 #include "progress.h" 67 #include "transfer.h" 68 #include "escape.h" 69 #include "http.h" /* for HTTP proxy tunnel stuff */ 70 #include "mime.h" 71 #include "socks.h" 72 #include "smtp.h" 73 #include "strtoofft.h" 74 #include "strcase.h" 75 #include "vtls/vtls.h" 76 #include "connect.h" 77 #include "strerror.h" 78 #include "select.h" 79 #include "multiif.h" 80 #include "url.h" 81 #include "curl_gethostname.h" 82 #include "curl_sasl.h" 83 #include "warnless.h" 84 /* The last 3 #include files should be in this order */ 85 #include "curl_printf.h" 86 #include "curl_memory.h" 87 #include "memdebug.h" 88 89 /* Local API functions */ 90 static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done); 91 static CURLcode smtp_do(struct connectdata *conn, bool *done); 92 static CURLcode smtp_done(struct connectdata *conn, CURLcode status, 93 bool premature); 94 static CURLcode smtp_connect(struct connectdata *conn, bool *done); 95 static CURLcode smtp_disconnect(struct connectdata *conn, bool dead); 96 static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done); 97 static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks, 98 int numsocks); 99 static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done); 100 static CURLcode smtp_setup_connection(struct connectdata *conn); 101 static CURLcode smtp_parse_url_options(struct connectdata *conn); 102 static CURLcode smtp_parse_url_path(struct connectdata *conn); 103 static CURLcode smtp_parse_custom_request(struct connectdata *conn); 104 static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech, 105 const char *initresp); 106 static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp); 107 static void smtp_get_message(char *buffer, char **outptr); 108 109 /* 110 * SMTP protocol handler. 111 */ 112 113 const 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 */ 124 ZERO_NULL, /* domore_getsock */ 125 ZERO_NULL, /* perform_getsock */ 126 smtp_disconnect, /* disconnect */ 127 ZERO_NULL, /* readwrite */ 128 ZERO_NULL, /* connection_check */ 129 PORT_SMTP, /* defport */ 130 CURLPROTO_SMTP, /* protocol */ 131 PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ 132 PROTOPT_URLOPTIONS 133 }; 134 135 #ifdef USE_SSL 136 /* 137 * SMTPS protocol handler. 138 */ 139 140 const 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 */ 151 ZERO_NULL, /* domore_getsock */ 152 ZERO_NULL, /* perform_getsock */ 153 smtp_disconnect, /* disconnect */ 154 ZERO_NULL, /* readwrite */ 155 ZERO_NULL, /* connection_check */ 156 PORT_SMTPS, /* defport */ 157 CURLPROTO_SMTPS, /* protocol */ 158 PROTOPT_CLOSEACTION | PROTOPT_SSL 159 | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */ 160 }; 161 #endif 162 163 /* SASL parameters for the smtp protocol */ 164 static 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 }; 173 174 #ifdef USE_SSL 175 static void smtp_to_smtps(struct connectdata *conn) 176 { 177 /* Change the connection handler */ 178 conn->handler = &Curl_handler_smtps; 179 180 /* Set the connection's upgraded to TLS flag */ 181 conn->tls_upgraded = TRUE; 182 } 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 */ 195 static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len, 196 int *resp) 197 { 198 struct smtp_conn *smtpc = &conn->proto.smtpc; 199 bool result = FALSE; 200 201 /* Nothing for us */ 202 if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2])) 203 return FALSE; 204 205 /* 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 char tmpline[6]; 211 212 result = TRUE; 213 memset(tmpline, '\0', sizeof(tmpline)); 214 memcpy(tmpline, line, (len == 5 ? 5 : 3)); 215 *resp = curlx_sltosi(strtol(tmpline, NULL, 10)); 216 217 /* Make sure real server never sends internal value */ 218 if(*resp == 1) 219 *resp = 0; 220 } 221 /* Do we have a multiline (continuation) response? */ 222 else if(line[3] == '-' && 223 (smtpc->state == SMTP_EHLO || smtpc->state == SMTP_COMMAND)) { 224 result = TRUE; 225 *resp = 1; /* Internal response code */ 226 } 227 228 return result; 229 } 230 231 /*********************************************************************** 232 * 233 * smtp_get_message() 234 * 235 * Gets the authentication message from the response buffer. 236 */ 237 static void smtp_get_message(char *buffer, char **outptr) 238 { 239 size_t len = strlen(buffer); 240 char *message = NULL; 241 242 if(len > 4) { 243 /* Find the start of the message */ 244 len -= 4; 245 for(message = buffer + 4; *message == ' ' || *message == '\t'; 246 message++, len--) 247 ; 248 249 /* Find the end of the message */ 250 for(; len--;) 251 if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && 252 message[len] != '\t') 253 break; 254 255 /* Terminate the message */ 256 if(++len) { 257 message[len] = '\0'; 258 } 259 } 260 else 261 /* junk input => zero length output */ 262 message = &buffer[len]; 263 264 *outptr = message; 265 } 266 267 /*********************************************************************** 268 * 269 * state() 270 * 271 * This is the ONLY way to change SMTP state! 272 */ 273 static void state(struct connectdata *conn, smtpstate newstate) 274 { 275 struct smtp_conn *smtpc = &conn->proto.smtpc; 276 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) 277 /* for debug purposes */ 278 static const char * const names[] = { 279 "STOP", 280 "SERVERGREET", 281 "EHLO", 282 "HELO", 283 "STARTTLS", 284 "UPGRADETLS", 285 "AUTH", 286 "COMMAND", 287 "MAIL", 288 "RCPT", 289 "DATA", 290 "POSTDATA", 291 "QUIT", 292 /* LAST */ 293 }; 294 295 if(smtpc->state != newstate) 296 infof(conn->data, "SMTP %p state change from %s to %s\n", 297 (void *)smtpc, names[smtpc->state], names[newstate]); 298 #endif 299 300 smtpc->state = newstate; 301 } 302 303 /*********************************************************************** 304 * 305 * smtp_perform_ehlo() 306 * 307 * Sends the EHLO command to not only initialise communication with the ESMTP 308 * server but to also obtain a list of server side supported capabilities. 309 */ 310 static CURLcode smtp_perform_ehlo(struct connectdata *conn) 311 { 312 CURLcode result = CURLE_OK; 313 struct smtp_conn *smtpc = &conn->proto.smtpc; 314 315 smtpc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanism yet */ 316 smtpc->sasl.authused = SASL_AUTH_NONE; /* Clear the authentication mechanism 317 used for esmtp connections */ 318 smtpc->tls_supported = FALSE; /* Clear the TLS capability */ 319 smtpc->auth_supported = FALSE; /* Clear the AUTH capability */ 320 321 /* Send the EHLO command */ 322 result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain); 323 324 if(!result) 325 state(conn, SMTP_EHLO); 326 327 return result; 328 } 329 330 /*********************************************************************** 331 * 332 * smtp_perform_helo() 333 * 334 * Sends the HELO command to initialise communication with the SMTP server. 335 */ 336 static CURLcode smtp_perform_helo(struct connectdata *conn) 337 { 338 CURLcode result = CURLE_OK; 339 struct smtp_conn *smtpc = &conn->proto.smtpc; 340 341 smtpc->sasl.authused = SASL_AUTH_NONE; /* No authentication mechanism used 342 in smtp connections */ 343 344 /* Send the HELO command */ 345 result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain); 346 347 if(!result) 348 state(conn, SMTP_HELO); 349 350 return result; 351 } 352 353 /*********************************************************************** 354 * 355 * smtp_perform_starttls() 356 * 357 * Sends the STLS command to start the upgrade to TLS. 358 */ 359 static CURLcode smtp_perform_starttls(struct connectdata *conn) 360 { 361 CURLcode result = CURLE_OK; 362 363 /* Send the STARTTLS command */ 364 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "STARTTLS"); 365 366 if(!result) 367 state(conn, SMTP_STARTTLS); 368 369 return result; 370 } 371 372 /*********************************************************************** 373 * 374 * smtp_perform_upgrade_tls() 375 * 376 * Performs the upgrade to TLS. 377 */ 378 static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn) 379 { 380 CURLcode result = CURLE_OK; 381 struct smtp_conn *smtpc = &conn->proto.smtpc; 382 383 /* Start the SSL connection */ 384 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone); 385 386 if(!result) { 387 if(smtpc->state != SMTP_UPGRADETLS) 388 state(conn, SMTP_UPGRADETLS); 389 390 if(smtpc->ssldone) { 391 smtp_to_smtps(conn); 392 result = smtp_perform_ehlo(conn); 393 } 394 } 395 396 return result; 397 } 398 399 /*********************************************************************** 400 * 401 * smtp_perform_auth() 402 * 403 * Sends an AUTH command allowing the client to login with the given SASL 404 * authentication mechanism. 405 */ 406 static CURLcode smtp_perform_auth(struct connectdata *conn, 407 const char *mech, 408 const char *initresp) 409 { 410 CURLcode result = CURLE_OK; 411 struct smtp_conn *smtpc = &conn->proto.smtpc; 412 413 if(initresp) { /* AUTH <mech> ...<crlf> */ 414 /* Send the AUTH command with the initial response */ 415 result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp); 416 } 417 else { 418 /* Send the AUTH command */ 419 result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech); 420 } 421 422 return result; 423 } 424 425 /*********************************************************************** 426 * 427 * smtp_continue_auth() 428 * 429 * Sends SASL continuation data or cancellation. 430 */ 431 static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp) 432 { 433 struct smtp_conn *smtpc = &conn->proto.smtpc; 434 435 return Curl_pp_sendf(&smtpc->pp, "%s", resp); 436 } 437 438 /*********************************************************************** 439 * 440 * smtp_perform_authentication() 441 * 442 * Initiates the authentication sequence, with the appropriate SASL 443 * authentication mechanism. 444 */ 445 static CURLcode smtp_perform_authentication(struct connectdata *conn) 446 { 447 CURLcode result = CURLE_OK; 448 struct smtp_conn *smtpc = &conn->proto.smtpc; 449 saslprogress progress; 450 451 /* Check we have enough data to authenticate with, and the 452 server supports authentiation, and end the connect phase if not */ 453 if(!smtpc->auth_supported || 454 !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) { 455 state(conn, SMTP_STOP); 456 return result; 457 } 458 459 /* Calculate the SASL login details */ 460 result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress); 461 462 if(!result) { 463 if(progress == SASL_INPROGRESS) 464 state(conn, SMTP_AUTH); 465 else { 466 /* Other mechanisms not supported */ 467 infof(conn->data, "No known authentication mechanisms supported!\n"); 468 result = CURLE_LOGIN_DENIED; 469 } 470 } 471 472 return result; 473 } 474 475 /*********************************************************************** 476 * 477 * smtp_perform_command() 478 * 479 * Sends a SMTP based command. 480 */ 481 static CURLcode smtp_perform_command(struct connectdata *conn) 482 { 483 CURLcode result = CURLE_OK; 484 struct Curl_easy *data = conn->data; 485 struct SMTP *smtp = data->req.protop; 486 487 /* Send the command */ 488 if(smtp->rcpt) 489 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s %s", 490 smtp->custom && smtp->custom[0] != '\0' ? 491 smtp->custom : "VRFY", 492 smtp->rcpt->data); 493 else 494 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", 495 smtp->custom && smtp->custom[0] != '\0' ? 496 smtp->custom : "HELP"); 497 498 if(!result) 499 state(conn, SMTP_COMMAND); 500 501 return result; 502 } 503 504 /*********************************************************************** 505 * 506 * smtp_perform_mail() 507 * 508 * Sends an MAIL command to initiate the upload of a message. 509 */ 510 static CURLcode smtp_perform_mail(struct connectdata *conn) 511 { 512 char *from = NULL; 513 char *auth = NULL; 514 char *size = NULL; 515 CURLcode result = CURLE_OK; 516 struct Curl_easy *data = conn->data; 517 518 /* Calculate the FROM parameter */ 519 if(!data->set.str[STRING_MAIL_FROM]) 520 /* Null reverse-path, RFC-5321, sect. 3.6.3 */ 521 from = strdup("<>"); 522 else if(data->set.str[STRING_MAIL_FROM][0] == '<') 523 from = aprintf("%s", data->set.str[STRING_MAIL_FROM]); 524 else 525 from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]); 526 527 if(!from) 528 return CURLE_OUT_OF_MEMORY; 529 530 /* Calculate the optional AUTH parameter */ 531 if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) { 532 if(data->set.str[STRING_MAIL_AUTH][0] != '\0') 533 auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]); 534 else 535 /* Empty AUTH, RFC-2554, sect. 5 */ 536 auth = strdup("<>"); 537 538 if(!auth) { 539 free(from); 540 541 return CURLE_OUT_OF_MEMORY; 542 } 543 } 544 545 /* Prepare the mime data if some. */ 546 if(data->set.mimepost.kind != MIMEKIND_NONE) { 547 /* Use the whole structure as data. */ 548 data->set.mimepost.flags &= ~MIME_BODY_ONLY; 549 550 /* Add external headers and mime version. */ 551 curl_mime_headers(&data->set.mimepost, data->set.headers, 0); 552 result = Curl_mime_prepare_headers(&data->set.mimepost, NULL, 553 NULL, MIMESTRATEGY_MAIL); 554 555 if(!result) 556 if(!Curl_checkheaders(conn, "Mime-Version")) 557 result = Curl_mime_add_header(&data->set.mimepost.curlheaders, 558 "Mime-Version: 1.0"); 559 560 /* Make sure we will read the entire mime structure. */ 561 if(!result) 562 result = Curl_mime_rewind(&data->set.mimepost); 563 564 if(result) { 565 free(from); 566 free(auth); 567 return result; 568 } 569 570 data->state.infilesize = Curl_mime_size(&data->set.mimepost); 571 572 /* Read from mime structure. */ 573 data->state.fread_func = (curl_read_callback) Curl_mime_read; 574 data->state.in = (void *) &data->set.mimepost; 575 } 576 577 /* Calculate the optional SIZE parameter */ 578 if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) { 579 size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize); 580 581 if(!size) { 582 free(from); 583 free(auth); 584 585 return CURLE_OUT_OF_MEMORY; 586 } 587 } 588 589 /* Send the MAIL command */ 590 if(!auth && !size) 591 result = Curl_pp_sendf(&conn->proto.smtpc.pp, 592 "MAIL FROM:%s", from); 593 else if(auth && !size) 594 result = Curl_pp_sendf(&conn->proto.smtpc.pp, 595 "MAIL FROM:%s AUTH=%s", from, auth); 596 else if(auth && size) 597 result = Curl_pp_sendf(&conn->proto.smtpc.pp, 598 "MAIL FROM:%s AUTH=%s SIZE=%s", from, auth, size); 599 else 600 result = Curl_pp_sendf(&conn->proto.smtpc.pp, 601 "MAIL FROM:%s SIZE=%s", from, size); 602 603 free(from); 604 free(auth); 605 free(size); 606 607 if(!result) 608 state(conn, SMTP_MAIL); 609 610 return result; 611 } 612 613 /*********************************************************************** 614 * 615 * smtp_perform_rcpt_to() 616 * 617 * Sends a RCPT TO command for a given recipient as part of the message upload 618 * process. 619 */ 620 static CURLcode smtp_perform_rcpt_to(struct connectdata *conn) 621 { 622 CURLcode result = CURLE_OK; 623 struct Curl_easy *data = conn->data; 624 struct SMTP *smtp = data->req.protop; 625 626 /* Send the RCPT TO command */ 627 if(smtp->rcpt->data[0] == '<') 628 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s", 629 smtp->rcpt->data); 630 else 631 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>", 632 smtp->rcpt->data); 633 if(!result) 634 state(conn, SMTP_RCPT); 635 636 return result; 637 } 638 639 /*********************************************************************** 640 * 641 * smtp_perform_quit() 642 * 643 * Performs the quit action prior to sclose() being called. 644 */ 645 static CURLcode smtp_perform_quit(struct connectdata *conn) 646 { 647 CURLcode result = CURLE_OK; 648 649 /* Send the QUIT command */ 650 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "QUIT"); 651 652 if(!result) 653 state(conn, SMTP_QUIT); 654 655 return result; 656 } 657 658 /* For the initial server greeting */ 659 static CURLcode smtp_state_servergreet_resp(struct connectdata *conn, 660 int smtpcode, 661 smtpstate instate) 662 { 663 CURLcode result = CURLE_OK; 664 struct Curl_easy *data = conn->data; 665 666 (void)instate; /* no use for this yet */ 667 668 if(smtpcode/100 != 2) { 669 failf(data, "Got unexpected smtp-server response: %d", smtpcode); 670 result = CURLE_WEIRD_SERVER_REPLY; 671 } 672 else 673 result = smtp_perform_ehlo(conn); 674 675 return result; 676 } 677 678 /* For STARTTLS responses */ 679 static CURLcode smtp_state_starttls_resp(struct connectdata *conn, 680 int smtpcode, 681 smtpstate instate) 682 { 683 CURLcode result = CURLE_OK; 684 struct Curl_easy *data = conn->data; 685 686 (void)instate; /* no use for this yet */ 687 688 if(smtpcode != 220) { 689 if(data->set.use_ssl != CURLUSESSL_TRY) { 690 failf(data, "STARTTLS denied, code %d", smtpcode); 691 result = CURLE_USE_SSL_FAILED; 692 } 693 else 694 result = smtp_perform_authentication(conn); 695 } 696 else 697 result = smtp_perform_upgrade_tls(conn); 698 699 return result; 700 } 701 702 /* For EHLO responses */ 703 static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode, 704 smtpstate instate) 705 { 706 CURLcode result = CURLE_OK; 707 struct Curl_easy *data = conn->data; 708 struct smtp_conn *smtpc = &conn->proto.smtpc; 709 const char *line = data->state.buffer; 710 size_t len = strlen(line); 711 712 (void)instate; /* no use for this yet */ 713 714 if(smtpcode/100 != 2 && smtpcode != 1) { 715 if(data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use) 716 result = smtp_perform_helo(conn); 717 else { 718 failf(data, "Remote access denied: %d", smtpcode); 719 result = CURLE_REMOTE_ACCESS_DENIED; 720 } 721 } 722 else { 723 line += 4; 724 len -= 4; 725 726 /* Does the server support the STARTTLS capability? */ 727 if(len >= 8 && !memcmp(line, "STARTTLS", 8)) 728 smtpc->tls_supported = TRUE; 729 730 /* Does the server support the SIZE capability? */ 731 else if(len >= 4 && !memcmp(line, "SIZE", 4)) 732 smtpc->size_supported = TRUE; 733 734 /* Does the server support authentication? */ 735 else if(len >= 5 && !memcmp(line, "AUTH ", 5)) { 736 smtpc->auth_supported = TRUE; 737 738 /* Advance past the AUTH keyword */ 739 line += 5; 740 len -= 5; 741 742 /* Loop through the data line */ 743 for(;;) { 744 size_t llen; 745 size_t wordlen; 746 unsigned int mechbit; 747 748 while(len && 749 (*line == ' ' || *line == '\t' || 750 *line == '\r' || *line == '\n')) { 751 752 line++; 753 len--; 754 } 755 756 if(!len) 757 break; 758 759 /* Extract the word */ 760 for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && 761 line[wordlen] != '\t' && line[wordlen] != '\r' && 762 line[wordlen] != '\n';) 763 wordlen++; 764 765 /* Test the word for a matching authentication mechanism */ 766 mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); 767 if(mechbit && llen == wordlen) 768 smtpc->sasl.authmechs |= mechbit; 769 770 line += wordlen; 771 len -= wordlen; 772 } 773 } 774 775 if(smtpcode != 1) { 776 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { 777 /* We don't have a SSL/TLS connection yet, but SSL is requested */ 778 if(smtpc->tls_supported) 779 /* Switch to TLS connection now */ 780 result = smtp_perform_starttls(conn); 781 else if(data->set.use_ssl == CURLUSESSL_TRY) 782 /* Fallback and carry on with authentication */ 783 result = smtp_perform_authentication(conn); 784 else { 785 failf(data, "STARTTLS not supported."); 786 result = CURLE_USE_SSL_FAILED; 787 } 788 } 789 else 790 result = smtp_perform_authentication(conn); 791 } 792 } 793 794 return result; 795 } 796 797 /* For HELO responses */ 798 static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode, 799 smtpstate instate) 800 { 801 CURLcode result = CURLE_OK; 802 struct Curl_easy *data = conn->data; 803 804 (void)instate; /* no use for this yet */ 805 806 if(smtpcode/100 != 2) { 807 failf(data, "Remote access denied: %d", smtpcode); 808 result = CURLE_REMOTE_ACCESS_DENIED; 809 } 810 else 811 /* End of connect phase */ 812 state(conn, SMTP_STOP); 813 814 return result; 815 } 816 817 /* For SASL authentication responses */ 818 static CURLcode smtp_state_auth_resp(struct connectdata *conn, 819 int smtpcode, 820 smtpstate instate) 821 { 822 CURLcode result = CURLE_OK; 823 struct Curl_easy *data = conn->data; 824 struct smtp_conn *smtpc = &conn->proto.smtpc; 825 saslprogress progress; 826 827 (void)instate; /* no use for this yet */ 828 829 result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress); 830 if(!result) 831 switch(progress) { 832 case SASL_DONE: 833 state(conn, SMTP_STOP); /* Authenticated */ 834 break; 835 case SASL_IDLE: /* No mechanism left after cancellation */ 836 failf(data, "Authentication cancelled"); 837 result = CURLE_LOGIN_DENIED; 838 break; 839 default: 840 break; 841 } 842 843 return result; 844 } 845 846 /* For command responses */ 847 static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode, 848 smtpstate instate) 849 { 850 CURLcode result = CURLE_OK; 851 struct Curl_easy *data = conn->data; 852 struct SMTP *smtp = data->req.protop; 853 char *line = data->state.buffer; 854 size_t len = strlen(line); 855 856 (void)instate; /* no use for this yet */ 857 858 if((smtp->rcpt && smtpcode/100 != 2 && smtpcode != 553 && smtpcode != 1) || 859 (!smtp->rcpt && smtpcode/100 != 2 && smtpcode != 1)) { 860 failf(data, "Command failed: %d", smtpcode); 861 result = CURLE_RECV_ERROR; 862 } 863 else { 864 /* Temporarily add the LF character back and send as body to the client */ 865 if(!data->set.opt_no_body) { 866 line[len] = '\n'; 867 result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1); 868 line[len] = '\0'; 869 } 870 871 if(smtpcode != 1) { 872 if(smtp->rcpt) { 873 smtp->rcpt = smtp->rcpt->next; 874 875 if(smtp->rcpt) { 876 /* Send the next command */ 877 result = smtp_perform_command(conn); 878 } 879 else 880 /* End of DO phase */ 881 state(conn, SMTP_STOP); 882 } 883 else 884 /* End of DO phase */ 885 state(conn, SMTP_STOP); 886 } 887 } 888 889 return result; 890 } 891 892 /* For MAIL responses */ 893 static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode, 894 smtpstate instate) 895 { 896 CURLcode result = CURLE_OK; 897 struct Curl_easy *data = conn->data; 898 899 (void)instate; /* no use for this yet */ 900 901 if(smtpcode/100 != 2) { 902 failf(data, "MAIL failed: %d", smtpcode); 903 result = CURLE_SEND_ERROR; 904 } 905 else 906 /* Start the RCPT TO command */ 907 result = smtp_perform_rcpt_to(conn); 908 909 return result; 910 } 911 912 /* For RCPT responses */ 913 static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode, 914 smtpstate instate) 915 { 916 CURLcode result = CURLE_OK; 917 struct Curl_easy *data = conn->data; 918 struct SMTP *smtp = data->req.protop; 919 920 (void)instate; /* no use for this yet */ 921 922 if(smtpcode/100 != 2) { 923 failf(data, "RCPT failed: %d", smtpcode); 924 result = CURLE_SEND_ERROR; 925 } 926 else { 927 smtp->rcpt = smtp->rcpt->next; 928 929 if(smtp->rcpt) 930 /* Send the next RCPT TO command */ 931 result = smtp_perform_rcpt_to(conn); 932 else { 933 /* Send the DATA command */ 934 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA"); 935 936 if(!result) 937 state(conn, SMTP_DATA); 938 } 939 } 940 941 return result; 942 } 943 944 /* For DATA response */ 945 static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode, 946 smtpstate instate) 947 { 948 CURLcode result = CURLE_OK; 949 struct Curl_easy *data = conn->data; 950 951 (void)instate; /* no use for this yet */ 952 953 if(smtpcode != 354) { 954 failf(data, "DATA failed: %d", smtpcode); 955 result = CURLE_SEND_ERROR; 956 } 957 else { 958 /* Set the progress upload size */ 959 Curl_pgrsSetUploadSize(data, data->state.infilesize); 960 961 /* SMTP upload */ 962 Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); 963 964 /* End of DO phase */ 965 state(conn, SMTP_STOP); 966 } 967 968 return result; 969 } 970 971 /* For POSTDATA responses, which are received after the entire DATA 972 part has been sent to the server */ 973 static CURLcode smtp_state_postdata_resp(struct connectdata *conn, 974 int smtpcode, 975 smtpstate instate) 976 { 977 CURLcode result = CURLE_OK; 978 979 (void)instate; /* no use for this yet */ 980 981 if(smtpcode != 250) 982 result = CURLE_RECV_ERROR; 983 984 /* End of DONE phase */ 985 state(conn, SMTP_STOP); 986 987 return result; 988 } 989 990 static CURLcode smtp_statemach_act(struct connectdata *conn) 991 { 992 CURLcode result = CURLE_OK; 993 curl_socket_t sock = conn->sock[FIRSTSOCKET]; 994 struct Curl_easy *data = conn->data; 995 int smtpcode; 996 struct smtp_conn *smtpc = &conn->proto.smtpc; 997 struct pingpong *pp = &smtpc->pp; 998 size_t nread = 0; 999 1000 /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */ 1001 if(smtpc->state == SMTP_UPGRADETLS) 1002 return smtp_perform_upgrade_tls(conn); 1003 1004 /* Flush any data that needs to be sent */ 1005 if(pp->sendleft) 1006 return Curl_pp_flushsend(pp); 1007 1008 do { 1009 /* Read the response from the server */ 1010 result = Curl_pp_readresp(sock, pp, &smtpcode, &nread); 1011 if(result) 1012 return result; 1013 1014 /* Store the latest response for later retrieval if necessary */ 1015 if(smtpc->state != SMTP_QUIT && smtpcode != 1) 1016 data->info.httpcode = smtpcode; 1017 1018 if(!smtpcode) 1019 break; 1020 1021 /* We have now received a full SMTP server response */ 1022 switch(smtpc->state) { 1023 case SMTP_SERVERGREET: 1024 result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state); 1025 break; 1026 1027 case SMTP_EHLO: 1028 result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state); 1029 break; 1030 1031 case SMTP_HELO: 1032 result = smtp_state_helo_resp(conn, smtpcode, smtpc->state); 1033 break; 1034 1035 case SMTP_STARTTLS: 1036 result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state); 1037 break; 1038 1039 case SMTP_AUTH: 1040 result = smtp_state_auth_resp(conn, smtpcode, smtpc->state); 1041 break; 1042 1043 case SMTP_COMMAND: 1044 result = smtp_state_command_resp(conn, smtpcode, smtpc->state); 1045 break; 1046 1047 case SMTP_MAIL: 1048 result = smtp_state_mail_resp(conn, smtpcode, smtpc->state); 1049 break; 1050 1051 case SMTP_RCPT: 1052 result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state); 1053 break; 1054 1055 case SMTP_DATA: 1056 result = smtp_state_data_resp(conn, smtpcode, smtpc->state); 1057 break; 1058 1059 case SMTP_POSTDATA: 1060 result = smtp_state_postdata_resp(conn, smtpcode, smtpc->state); 1061 break; 1062 1063 case SMTP_QUIT: 1064 /* fallthrough, just stop! */ 1065 default: 1066 /* internal error */ 1067 state(conn, SMTP_STOP); 1068 break; 1069 } 1070 } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp)); 1071 1072 return result; 1073 } 1074 1075 /* Called repeatedly until done from multi.c */ 1076 static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done) 1077 { 1078 CURLcode result = CURLE_OK; 1079 struct smtp_conn *smtpc = &conn->proto.smtpc; 1080 1081 if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) { 1082 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone); 1083 if(result || !smtpc->ssldone) 1084 return result; 1085 } 1086 1087 result = Curl_pp_statemach(&smtpc->pp, FALSE, FALSE); 1088 *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE; 1089 1090 return result; 1091 } 1092 1093 static CURLcode smtp_block_statemach(struct connectdata *conn, 1094 bool disconnecting) 1095 { 1096 CURLcode result = CURLE_OK; 1097 struct smtp_conn *smtpc = &conn->proto.smtpc; 1098 1099 while(smtpc->state != SMTP_STOP && !result) 1100 result = Curl_pp_statemach(&smtpc->pp, TRUE, disconnecting); 1101 1102 return result; 1103 } 1104 1105 /* Allocate and initialize the SMTP struct for the current Curl_easy if 1106 required */ 1107 static CURLcode smtp_init(struct connectdata *conn) 1108 { 1109 CURLcode result = CURLE_OK; 1110 struct Curl_easy *data = conn->data; 1111 struct SMTP *smtp; 1112 1113 smtp = data->req.protop = calloc(sizeof(struct SMTP), 1); 1114 if(!smtp) 1115 result = CURLE_OUT_OF_MEMORY; 1116 1117 return result; 1118 } 1119 1120 /* For the SMTP "protocol connect" and "doing" phases only */ 1121 static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks, 1122 int numsocks) 1123 { 1124 return Curl_pp_getsock(&conn->proto.smtpc.pp, socks, numsocks); 1125 } 1126 1127 /*********************************************************************** 1128 * 1129 * smtp_connect() 1130 * 1131 * This function should do everything that is to be considered a part of 1132 * the connection phase. 1133 * 1134 * The variable pointed to by 'done' will be TRUE if the protocol-layer 1135 * connect phase is done when this function returns, or FALSE if not. 1136 */ 1137 static CURLcode smtp_connect(struct connectdata *conn, bool *done) 1138 { 1139 CURLcode result = CURLE_OK; 1140 struct smtp_conn *smtpc = &conn->proto.smtpc; 1141 struct pingpong *pp = &smtpc->pp; 1142 1143 *done = FALSE; /* default to not done yet */ 1144 1145 /* We always support persistent connections in SMTP */ 1146 connkeep(conn, "SMTP default"); 1147 1148 /* Set the default response time-out */ 1149 pp->response_time = RESP_TIMEOUT; 1150 pp->statemach_act = smtp_statemach_act; 1151 pp->endofresp = smtp_endofresp; 1152 pp->conn = conn; 1153 1154 /* Initialize the SASL storage */ 1155 Curl_sasl_init(&smtpc->sasl, &saslsmtp); 1156 1157 /* Initialise the pingpong layer */ 1158 Curl_pp_init(pp); 1159 1160 /* Parse the URL options */ 1161 result = smtp_parse_url_options(conn); 1162 if(result) 1163 return result; 1164 1165 /* Parse the URL path */ 1166 result = smtp_parse_url_path(conn); 1167 if(result) 1168 return result; 1169 1170 /* Start off waiting for the server greeting response */ 1171 state(conn, SMTP_SERVERGREET); 1172 1173 result = smtp_multi_statemach(conn, done); 1174 1175 return result; 1176 } 1177 1178 /*********************************************************************** 1179 * 1180 * smtp_done() 1181 * 1182 * The DONE function. This does what needs to be done after a single DO has 1183 * performed. 1184 * 1185 * Input argument is already checked for validity. 1186 */ 1187 static CURLcode smtp_done(struct connectdata *conn, CURLcode status, 1188 bool premature) 1189 { 1190 CURLcode result = CURLE_OK; 1191 struct Curl_easy *data = conn->data; 1192 struct SMTP *smtp = data->req.protop; 1193 struct pingpong *pp = &conn->proto.smtpc.pp; 1194 char *eob; 1195 ssize_t len; 1196 ssize_t bytes_written; 1197 1198 (void)premature; 1199 1200 if(!smtp || !pp->conn) 1201 return CURLE_OK; 1202 1203 /* Cleanup our per-request based variables */ 1204 Curl_safefree(smtp->custom); 1205 1206 if(status) { 1207 connclose(conn, "SMTP done with bad status"); /* marked for closure */ 1208 result = status; /* use the already set error code */ 1209 } 1210 else if(!data->set.connect_only && data->set.mail_rcpt && 1211 (data->set.upload || data->set.mimepost.kind)) { 1212 /* Calculate the EOB taking into account any terminating CRLF from the 1213 previous line of the email or the CRLF of the DATA command when there 1214 is "no mail data". RFC-5321, sect. 4.1.1.4. 1215 1216 Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to 1217 fail when using a different pointer following a previous write, that 1218 returned CURLE_AGAIN, we duplicate the EOB now rather than when the 1219 bytes written doesn't equal len. */ 1220 if(smtp->trailing_crlf || !conn->data->state.infilesize) { 1221 eob = strdup(SMTP_EOB + 2); 1222 len = SMTP_EOB_LEN - 2; 1223 } 1224 else { 1225 eob = strdup(SMTP_EOB); 1226 len = SMTP_EOB_LEN; 1227 } 1228 1229 if(!eob) 1230 return CURLE_OUT_OF_MEMORY; 1231 1232 /* Send the end of block data */ 1233 result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written); 1234 if(result) { 1235 free(eob); 1236 return result; 1237 } 1238 1239 if(bytes_written != len) { 1240 /* The whole chunk was not sent so keep it around and adjust the 1241 pingpong structure accordingly */ 1242 pp->sendthis = eob; 1243 pp->sendsize = len; 1244 pp->sendleft = len - bytes_written; 1245 } 1246 else { 1247 /* Successfully sent so adjust the response timeout relative to now */ 1248 pp->response = Curl_now(); 1249 1250 free(eob); 1251 } 1252 1253 state(conn, SMTP_POSTDATA); 1254 1255 /* Run the state-machine 1256 1257 TODO: when the multi interface is used, this _really_ should be using 1258 the smtp_multi_statemach function but we have no general support for 1259 non-blocking DONE operations! 1260 */ 1261 result = smtp_block_statemach(conn, FALSE); 1262 } 1263 1264 /* Clear the transfer mode for the next request */ 1265 smtp->transfer = FTPTRANSFER_BODY; 1266 1267 return result; 1268 } 1269 1270 /*********************************************************************** 1271 * 1272 * smtp_perform() 1273 * 1274 * This is the actual DO function for SMTP. Transfer a mail, send a command 1275 * or get some data according to the options previously setup. 1276 */ 1277 static CURLcode smtp_perform(struct connectdata *conn, bool *connected, 1278 bool *dophase_done) 1279 { 1280 /* This is SMTP and no proxy */ 1281 CURLcode result = CURLE_OK; 1282 struct Curl_easy *data = conn->data; 1283 struct SMTP *smtp = data->req.protop; 1284 1285 DEBUGF(infof(conn->data, "DO phase starts\n")); 1286 1287 if(data->set.opt_no_body) { 1288 /* Requested no body means no transfer */ 1289 smtp->transfer = FTPTRANSFER_INFO; 1290 } 1291 1292 *dophase_done = FALSE; /* not done yet */ 1293 1294 /* Store the first recipient (or NULL if not specified) */ 1295 smtp->rcpt = data->set.mail_rcpt; 1296 1297 /* Initial data character is the first character in line: it is implicitly 1298 preceded by a virtual CRLF. */ 1299 smtp->trailing_crlf = TRUE; 1300 smtp->eob = 2; 1301 1302 /* Start the first command in the DO phase */ 1303 if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt) 1304 /* MAIL transfer */ 1305 result = smtp_perform_mail(conn); 1306 else 1307 /* SMTP based command (VRFY, EXPN, NOOP, RSET or HELP) */ 1308 result = smtp_perform_command(conn); 1309 1310 if(result) 1311 return result; 1312 1313 /* Run the state-machine */ 1314 result = smtp_multi_statemach(conn, dophase_done); 1315 1316 *connected = conn->bits.tcpconnect[FIRSTSOCKET]; 1317 1318 if(*dophase_done) 1319 DEBUGF(infof(conn->data, "DO phase is complete\n")); 1320 1321 return result; 1322 } 1323 1324 /*********************************************************************** 1325 * 1326 * smtp_do() 1327 * 1328 * This function is registered as 'curl_do' function. It decodes the path 1329 * parts etc as a wrapper to the actual DO function (smtp_perform). 1330 * 1331 * The input argument is already checked for validity. 1332 */ 1333 static CURLcode smtp_do(struct connectdata *conn, bool *done) 1334 { 1335 CURLcode result = CURLE_OK; 1336 1337 *done = FALSE; /* default to false */ 1338 1339 /* Parse the custom request */ 1340 result = smtp_parse_custom_request(conn); 1341 if(result) 1342 return result; 1343 1344 result = smtp_regular_transfer(conn, done); 1345 1346 return result; 1347 } 1348 1349 /*********************************************************************** 1350 * 1351 * smtp_disconnect() 1352 * 1353 * Disconnect from an SMTP server. Cleanup protocol-specific per-connection 1354 * resources. BLOCKING. 1355 */ 1356 static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection) 1357 { 1358 struct smtp_conn *smtpc = &conn->proto.smtpc; 1359 1360 /* We cannot send quit unconditionally. If this connection is stale or 1361 bad in any way, sending quit and waiting around here will make the 1362 disconnect wait in vain and cause more problems than we need to. */ 1363 1364 /* The SMTP session may or may not have been allocated/setup at this 1365 point! */ 1366 if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart) 1367 if(!smtp_perform_quit(conn)) 1368 (void)smtp_block_statemach(conn, TRUE); /* ignore errors on QUIT */ 1369 1370 /* Disconnect from the server */ 1371 Curl_pp_disconnect(&smtpc->pp); 1372 1373 /* Cleanup the SASL module */ 1374 Curl_sasl_cleanup(conn, smtpc->sasl.authused); 1375 1376 /* Cleanup our connection based variables */ 1377 Curl_safefree(smtpc->domain); 1378 1379 return CURLE_OK; 1380 } 1381 1382 /* Call this when the DO phase has completed */ 1383 static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected) 1384 { 1385 struct SMTP *smtp = conn->data->req.protop; 1386 1387 (void)connected; 1388 1389 if(smtp->transfer != FTPTRANSFER_BODY) 1390 /* no data to transfer */ 1391 Curl_setup_transfer(conn->data, -1, -1, FALSE, -1); 1392 1393 return CURLE_OK; 1394 } 1395 1396 /* Called from multi.c while DOing */ 1397 static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done) 1398 { 1399 CURLcode result = smtp_multi_statemach(conn, dophase_done); 1400 1401 if(result) 1402 DEBUGF(infof(conn->data, "DO phase failed\n")); 1403 else if(*dophase_done) { 1404 result = smtp_dophase_done(conn, FALSE /* not connected */); 1405 1406 DEBUGF(infof(conn->data, "DO phase is complete\n")); 1407 } 1408 1409 return result; 1410 } 1411 1412 /*********************************************************************** 1413 * 1414 * smtp_regular_transfer() 1415 * 1416 * The input argument is already checked for validity. 1417 * 1418 * Performs all commands done before a regular transfer between a local and a 1419 * remote host. 1420 */ 1421 static CURLcode smtp_regular_transfer(struct connectdata *conn, 1422 bool *dophase_done) 1423 { 1424 CURLcode result = CURLE_OK; 1425 bool connected = FALSE; 1426 struct Curl_easy *data = conn->data; 1427 1428 /* Make sure size is unknown at this point */ 1429 data->req.size = -1; 1430 1431 /* Set the progress data */ 1432 Curl_pgrsSetUploadCounter(data, 0); 1433 Curl_pgrsSetDownloadCounter(data, 0); 1434 Curl_pgrsSetUploadSize(data, -1); 1435 Curl_pgrsSetDownloadSize(data, -1); 1436 1437 /* Carry out the perform */ 1438 result = smtp_perform(conn, &connected, dophase_done); 1439 1440 /* Perform post DO phase operations if necessary */ 1441 if(!result && *dophase_done) 1442 result = smtp_dophase_done(conn, connected); 1443 1444 return result; 1445 } 1446 1447 static CURLcode smtp_setup_connection(struct connectdata *conn) 1448 { 1449 CURLcode result; 1450 1451 /* Clear the TLS upgraded flag */ 1452 conn->tls_upgraded = FALSE; 1453 1454 /* Initialise the SMTP layer */ 1455 result = smtp_init(conn); 1456 if(result) 1457 return result; 1458 1459 return CURLE_OK; 1460 } 1461 1462 /*********************************************************************** 1463 * 1464 * smtp_parse_url_options() 1465 * 1466 * Parse the URL login options. 1467 */ 1468 static CURLcode smtp_parse_url_options(struct connectdata *conn) 1469 { 1470 CURLcode result = CURLE_OK; 1471 struct smtp_conn *smtpc = &conn->proto.smtpc; 1472 const char *ptr = conn->options; 1473 1474 smtpc->sasl.resetprefs = TRUE; 1475 1476 while(!result && ptr && *ptr) { 1477 const char *key = ptr; 1478 const char *value; 1479 1480 while(*ptr && *ptr != '=') 1481 ptr++; 1482 1483 value = ptr + 1; 1484 1485 while(*ptr && *ptr != ';') 1486 ptr++; 1487 1488 if(strncasecompare(key, "AUTH=", 5)) 1489 result = Curl_sasl_parse_url_auth_option(&smtpc->sasl, 1490 value, ptr - value); 1491 else 1492 result = CURLE_URL_MALFORMAT; 1493 1494 if(*ptr == ';') 1495 ptr++; 1496 } 1497 1498 return result; 1499 } 1500 1501 /*********************************************************************** 1502 * 1503 * smtp_parse_url_path() 1504 * 1505 * Parse the URL path into separate path components. 1506 */ 1507 static CURLcode smtp_parse_url_path(struct connectdata *conn) 1508 { 1509 /* The SMTP struct is already initialised in smtp_connect() */ 1510 struct Curl_easy *data = conn->data; 1511 struct smtp_conn *smtpc = &conn->proto.smtpc; 1512 const char *path = &data->state.up.path[1]; /* skip leading path */ 1513 char localhost[HOSTNAME_MAX + 1]; 1514 1515 /* Calculate the path if necessary */ 1516 if(!*path) { 1517 if(!Curl_gethostname(localhost, sizeof(localhost))) 1518 path = localhost; 1519 else 1520 path = "localhost"; 1521 } 1522 1523 /* URL decode the path and use it as the domain in our EHLO */ 1524 return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE); 1525 } 1526 1527 /*********************************************************************** 1528 * 1529 * smtp_parse_custom_request() 1530 * 1531 * Parse the custom request. 1532 */ 1533 static CURLcode smtp_parse_custom_request(struct connectdata *conn) 1534 { 1535 CURLcode result = CURLE_OK; 1536 struct Curl_easy *data = conn->data; 1537 struct SMTP *smtp = data->req.protop; 1538 const char *custom = data->set.str[STRING_CUSTOMREQUEST]; 1539 1540 /* URL decode the custom request */ 1541 if(custom) 1542 result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, TRUE); 1543 1544 return result; 1545 } 1546 1547 CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread) 1548 { 1549 /* When sending a SMTP payload we must detect CRLF. sequences making sure 1550 they are sent as CRLF.. instead, as a . on the beginning of a line will 1551 be deleted by the server when not part of an EOB terminator and a 1552 genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of 1553 data by the server 1554 */ 1555 ssize_t i; 1556 ssize_t si; 1557 struct Curl_easy *data = conn->data; 1558 struct SMTP *smtp = data->req.protop; 1559 char *scratch = data->state.scratch; 1560 char *newscratch = NULL; 1561 char *oldscratch = NULL; 1562 size_t eob_sent; 1563 1564 /* Do we need to allocate a scratch buffer? */ 1565 if(!scratch || data->set.crlf) { 1566 oldscratch = scratch; 1567 1568 scratch = newscratch = malloc(2 * data->set.upload_buffer_size); 1569 if(!newscratch) { 1570 failf(data, "Failed to alloc scratch buffer!"); 1571 1572 return CURLE_OUT_OF_MEMORY; 1573 } 1574 } 1575 DEBUGASSERT(data->set.upload_buffer_size >= (size_t)nread); 1576 1577 /* Have we already sent part of the EOB? */ 1578 eob_sent = smtp->eob; 1579 1580 /* This loop can be improved by some kind of Boyer-Moore style of 1581 approach but that is saved for later... */ 1582 for(i = 0, si = 0; i < nread; i++) { 1583 if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) { 1584 smtp->eob++; 1585 1586 /* Is the EOB potentially the terminating CRLF? */ 1587 if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob) 1588 smtp->trailing_crlf = TRUE; 1589 else 1590 smtp->trailing_crlf = FALSE; 1591 } 1592 else if(smtp->eob) { 1593 /* A previous substring matched so output that first */ 1594 memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent); 1595 si += smtp->eob - eob_sent; 1596 1597 /* Then compare the first byte */ 1598 if(SMTP_EOB[0] == data->req.upload_fromhere[i]) 1599 smtp->eob = 1; 1600 else 1601 smtp->eob = 0; 1602 1603 eob_sent = 0; 1604 1605 /* Reset the trailing CRLF flag as there was more data */ 1606 smtp->trailing_crlf = FALSE; 1607 } 1608 1609 /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */ 1610 if(SMTP_EOB_FIND_LEN == smtp->eob) { 1611 /* Copy the replacement data to the target buffer */ 1612 memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent], 1613 SMTP_EOB_REPL_LEN - eob_sent); 1614 si += SMTP_EOB_REPL_LEN - eob_sent; 1615 smtp->eob = 0; 1616 eob_sent = 0; 1617 } 1618 else if(!smtp->eob) 1619 scratch[si++] = data->req.upload_fromhere[i]; 1620 } 1621 1622 if(smtp->eob - eob_sent) { 1623 /* A substring matched before processing ended so output that now */ 1624 memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent); 1625 si += smtp->eob - eob_sent; 1626 } 1627 1628 /* Only use the new buffer if we replaced something */ 1629 if(si != nread) { 1630 /* Upload from the new (replaced) buffer instead */ 1631 data->req.upload_fromhere = scratch; 1632 1633 /* Save the buffer so it can be freed later */ 1634 data->state.scratch = scratch; 1635 1636 /* Free the old scratch buffer */ 1637 free(oldscratch); 1638 1639 /* Set the new amount too */ 1640 data->req.upload_present = si; 1641 } 1642 else 1643 free(newscratch); 1644 1645 return CURLE_OK; 1646 } 1647 1648 #endif /* CURL_DISABLE_SMTP */ 1649