1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2018, 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 result = TRUE; 211 *resp = curlx_sltosi(strtol(line, NULL, 10)); 212 213 /* 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 */ 222 } 223 224 return result; 225 } 226 227 /*********************************************************************** 228 * 229 * smtp_get_message() 230 * 231 * Gets the authentication message from the response buffer. 232 */ 233 static void smtp_get_message(char *buffer, char **outptr) 234 { 235 size_t len = strlen(buffer); 236 char *message = NULL; 237 238 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 ; 244 245 /* 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; 250 251 /* Terminate the message */ 252 if(++len) { 253 message[len] = '\0'; 254 } 255 } 256 else 257 /* junk input => zero length output */ 258 message = &buffer[len]; 259 260 *outptr = message; 261 } 262 263 /*********************************************************************** 264 * 265 * state() 266 * 267 * This is the ONLY way to change SMTP state! 268 */ 269 static void state(struct connectdata *conn, smtpstate newstate) 270 { 271 struct smtp_conn *smtpc = &conn->proto.smtpc; 272 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) 273 /* for debug purposes */ 274 static const char * const names[] = { 275 "STOP", 276 "SERVERGREET", 277 "EHLO", 278 "HELO", 279 "STARTTLS", 280 "UPGRADETLS", 281 "AUTH", 282 "COMMAND", 283 "MAIL", 284 "RCPT", 285 "DATA", 286 "POSTDATA", 287 "QUIT", 288 /* LAST */ 289 }; 290 291 if(smtpc->state != newstate) 292 infof(conn->data, "SMTP %p state change from %s to %s\n", 293 (void *)smtpc, names[smtpc->state], names[newstate]); 294 #endif 295 296 smtpc->state = newstate; 297 } 298 299 /*********************************************************************** 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 */ 306 static CURLcode smtp_perform_ehlo(struct connectdata *conn) 307 { 308 CURLcode result = CURLE_OK; 309 struct smtp_conn *smtpc = &conn->proto.smtpc; 310 311 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 */ 316 317 /* Send the EHLO command */ 318 result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain); 319 320 if(!result) 321 state(conn, SMTP_EHLO); 322 323 return result; 324 } 325 326 /*********************************************************************** 327 * 328 * smtp_perform_helo() 329 * 330 * Sends the HELO command to initialise communication with the SMTP server. 331 */ 332 static CURLcode smtp_perform_helo(struct connectdata *conn) 333 { 334 CURLcode result = CURLE_OK; 335 struct smtp_conn *smtpc = &conn->proto.smtpc; 336 337 smtpc->sasl.authused = SASL_AUTH_NONE; /* No authentication mechanism used 338 in smtp connections */ 339 340 /* 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 */ 355 static 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 */ 374 static 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); 389 } 390 } 391 392 return result; 393 } 394 395 /*********************************************************************** 396 * 397 * smtp_perform_auth() 398 * 399 * Sends an AUTH command allowing the client to login with the given SASL 400 * authentication mechanism. 401 */ 402 static CURLcode smtp_perform_auth(struct connectdata *conn, 403 const char *mech, 404 const char *initresp) 405 { 406 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; 419 } 420 421 /*********************************************************************** 422 * 423 * smtp_continue_auth() 424 * 425 * Sends SASL continuation data or cancellation. 426 */ 427 static 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 */ 441 static 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 || 450 !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) { 451 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 */ 477 static CURLcode smtp_perform_command(struct connectdata *conn) 478 { 479 CURLcode result = CURLE_OK; 480 struct Curl_easy *data = conn->data; 481 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", 486 smtp->custom && smtp->custom[0] != '\0' ? 487 smtp->custom : "VRFY", 488 smtp->rcpt->data); 489 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 */ 506 static 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; 512 struct Curl_easy *data = conn->data; 513 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 541 /* 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 573 /* Calculate the optional SIZE parameter */ 574 if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) { 575 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 */ 616 static CURLcode smtp_perform_rcpt_to(struct connectdata *conn) 617 { 618 CURLcode result = CURLE_OK; 619 struct Curl_easy *data = conn->data; 620 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", 625 smtp->rcpt->data); 626 else 627 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>", 628 smtp->rcpt->data); 629 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 */ 641 static 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 */ 655 static CURLcode smtp_state_servergreet_resp(struct connectdata *conn, 656 int smtpcode, 657 smtpstate instate) 658 { 659 CURLcode result = CURLE_OK; 660 struct Curl_easy *data = conn->data; 661 662 (void)instate; /* no use for this yet */ 663 664 if(smtpcode/100 != 2) { 665 failf(data, "Got unexpected smtp-server response: %d", smtpcode); 666 result = CURLE_WEIRD_SERVER_REPLY; 667 } 668 else 669 result = smtp_perform_ehlo(conn); 670 671 return result; 672 } 673 674 /* For STARTTLS responses */ 675 static CURLcode smtp_state_starttls_resp(struct connectdata *conn, 676 int smtpcode, 677 smtpstate instate) 678 { 679 CURLcode result = CURLE_OK; 680 struct Curl_easy *data = conn->data; 681 682 (void)instate; /* no use for this yet */ 683 684 if(smtpcode != 220) { 685 if(data->set.use_ssl != CURLUSESSL_TRY) { 686 failf(data, "STARTTLS denied, code %d", smtpcode); 687 result = CURLE_USE_SSL_FAILED; 688 } 689 else 690 result = smtp_perform_authentication(conn); 691 } 692 else 693 result = smtp_perform_upgrade_tls(conn); 694 695 return result; 696 } 697 698 /* For EHLO responses */ 699 static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode, 700 smtpstate instate) 701 { 702 CURLcode result = CURLE_OK; 703 struct Curl_easy *data = conn->data; 704 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 */ 762 mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); 763 if(mechbit && llen == wordlen) 764 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 */ 794 static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode, 795 smtpstate instate) 796 { 797 CURLcode result = CURLE_OK; 798 struct Curl_easy *data = conn->data; 799 800 (void)instate; /* no use for this yet */ 801 802 if(smtpcode/100 != 2) { 803 failf(data, "Remote access denied: %d", smtpcode); 804 result = CURLE_REMOTE_ACCESS_DENIED; 805 } 806 else 807 /* End of connect phase */ 808 state(conn, SMTP_STOP); 809 810 return result; 811 } 812 813 /* For SASL authentication responses */ 814 static CURLcode smtp_state_auth_resp(struct connectdata *conn, 815 int smtpcode, 816 smtpstate instate) 817 { 818 CURLcode result = CURLE_OK; 819 struct Curl_easy *data = conn->data; 820 struct smtp_conn *smtpc = &conn->proto.smtpc; 821 saslprogress progress; 822 823 (void)instate; /* no use for this yet */ 824 825 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; 837 } 838 839 return result; 840 } 841 842 /* For command responses */ 843 static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode, 844 smtpstate instate) 845 { 846 CURLcode result = CURLE_OK; 847 struct Curl_easy *data = conn->data; 848 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 */ 889 static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode, 890 smtpstate instate) 891 { 892 CURLcode result = CURLE_OK; 893 struct Curl_easy *data = conn->data; 894 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 */ 909 static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode, 910 smtpstate instate) 911 { 912 CURLcode result = CURLE_OK; 913 struct Curl_easy *data = conn->data; 914 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 */ 941 static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode, 942 smtpstate instate) 943 { 944 CURLcode result = CURLE_OK; 945 struct Curl_easy *data = conn->data; 946 947 (void)instate; /* no use for this yet */ 948 949 if(smtpcode != 354) { 950 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 */ 961 state(conn, SMTP_STOP); 962 } 963 964 return result; 965 } 966 967 /* For POSTDATA responses, which are received after the entire DATA 968 part has been sent to the server */ 969 static CURLcode smtp_state_postdata_resp(struct connectdata *conn, 970 int smtpcode, 971 smtpstate instate) 972 { 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 980 /* End of DONE phase */ 981 state(conn, SMTP_STOP); 982 983 return result; 984 } 985 986 static CURLcode smtp_statemach_act(struct connectdata *conn) 987 { 988 CURLcode result = CURLE_OK; 989 curl_socket_t sock = conn->sock[FIRSTSOCKET]; 990 struct Curl_easy *data = conn->data; 991 int smtpcode; 992 struct smtp_conn *smtpc = &conn->proto.smtpc; 993 struct pingpong *pp = &smtpc->pp; 994 size_t nread = 0; 995 996 /* 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 */ 1001 if(pp->sendleft) 1002 return Curl_pp_flushsend(pp); 1003 1004 do { 1005 /* Read the response from the server */ 1006 result = Curl_pp_readresp(sock, pp, &smtpcode, &nread); 1007 if(result) 1008 return result; 1009 1010 /* 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 */ 1018 switch(smtpc->state) { 1019 case SMTP_SERVERGREET: 1020 result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state); 1021 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 1031 case SMTP_STARTTLS: 1032 result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state); 1033 break; 1034 1035 case SMTP_AUTH: 1036 result = smtp_state_auth_resp(conn, smtpcode, smtpc->state); 1037 break; 1038 1039 case SMTP_COMMAND: 1040 result = smtp_state_command_resp(conn, smtpcode, smtpc->state); 1041 break; 1042 1043 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 1051 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 } 1066 } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp)); 1067 1068 return result; 1069 } 1070 1071 /* Called repeatedly until done from multi.c */ 1072 static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done) 1073 { 1074 CURLcode result = CURLE_OK; 1075 struct smtp_conn *smtpc = &conn->proto.smtpc; 1076 1077 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; 1081 } 1082 1083 result = Curl_pp_statemach(&smtpc->pp, FALSE); 1084 *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE; 1085 1086 return result; 1087 } 1088 1089 static 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 1100 /* Allocate and initialize the SMTP struct for the current Curl_easy if 1101 required */ 1102 static CURLcode smtp_init(struct connectdata *conn) 1103 { 1104 CURLcode result = CURLE_OK; 1105 struct Curl_easy *data = conn->data; 1106 struct SMTP *smtp; 1107 1108 smtp = data->req.protop = calloc(sizeof(struct SMTP), 1); 1109 if(!smtp) 1110 result = CURLE_OUT_OF_MEMORY; 1111 1112 return result; 1113 } 1114 1115 /* For the SMTP "protocol connect" and "doing" phases only */ 1116 static 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 1127 * the connection phase. 1128 * 1129 * 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. 1131 */ 1132 static CURLcode smtp_connect(struct connectdata *conn, bool *done) 1133 { 1134 CURLcode result = CURLE_OK; 1135 struct smtp_conn *smtpc = &conn->proto.smtpc; 1136 struct pingpong *pp = &smtpc->pp; 1137 1138 *done = FALSE; /* default to not done yet */ 1139 1140 /* We always support persistent connections in SMTP */ 1141 connkeep(conn, "SMTP default"); 1142 1143 /* 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) 1158 return result; 1159 1160 /* Parse the URL path */ 1161 result = smtp_parse_url_path(conn); 1162 if(result) 1163 return result; 1164 1165 /* Start off waiting for the server greeting response */ 1166 state(conn, SMTP_SERVERGREET); 1167 1168 result = smtp_multi_statemach(conn, done); 1169 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 */ 1182 static CURLcode smtp_done(struct connectdata *conn, CURLcode status, 1183 bool premature) 1184 { 1185 CURLcode result = CURLE_OK; 1186 struct Curl_easy *data = conn->data; 1187 struct SMTP *smtp = data->req.protop; 1188 struct pingpong *pp = &conn->proto.smtpc.pp; 1189 char *eob; 1190 ssize_t len; 1191 ssize_t bytes_written; 1192 1193 (void)premature; 1194 1195 if(!smtp || !pp->conn) 1196 return CURLE_OK; 1197 1198 /* Cleanup our per-request based variables */ 1199 Curl_safefree(smtp->custom); 1200 1201 if(status) { 1202 connclose(conn, "SMTP done with bad status"); /* marked for closure */ 1203 result = status; /* use the already set error code */ 1204 } 1205 else if(!data->set.connect_only && data->set.mail_rcpt && 1206 (data->set.upload || data->set.mimepost.kind)) { 1207 /* 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. 1210 1211 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 } 1223 1224 if(!eob) 1225 return CURLE_OUT_OF_MEMORY; 1226 1227 /* 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 */ 1243 pp->response = Curl_now(); 1244 1245 free(eob); 1246 } 1247 1248 state(conn, SMTP_POSTDATA); 1249 1250 /* Run the state-machine 1251 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 1254 non-blocking DONE operations! 1255 */ 1256 result = smtp_block_statemach(conn); 1257 } 1258 1259 /* Clear the transfer mode for the next request */ 1260 smtp->transfer = FTPTRANSFER_BODY; 1261 1262 return result; 1263 } 1264 1265 /*********************************************************************** 1266 * 1267 * smtp_perform() 1268 * 1269 * 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. 1271 */ 1272 static CURLcode smtp_perform(struct connectdata *conn, bool *connected, 1273 bool *dophase_done) 1274 { 1275 /* This is SMTP and no proxy */ 1276 CURLcode result = CURLE_OK; 1277 struct Curl_easy *data = conn->data; 1278 struct SMTP *smtp = data->req.protop; 1279 1280 DEBUGF(infof(conn->data, "DO phase starts\n")); 1281 1282 if(data->set.opt_no_body) { 1283 /* Requested no body means no transfer */ 1284 smtp->transfer = FTPTRANSFER_INFO; 1285 } 1286 1287 *dophase_done = FALSE; /* not done yet */ 1288 1289 /* Store the first recipient (or NULL if not specified) */ 1290 smtp->rcpt = data->set.mail_rcpt; 1291 1292 /* Start the first command in the DO phase */ 1293 if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt) 1294 /* MAIL transfer */ 1295 result = smtp_perform_mail(conn); 1296 else 1297 /* SMTP based command (VRFY, EXPN, NOOP, RSET or HELP) */ 1298 result = smtp_perform_command(conn); 1299 1300 if(result) 1301 return result; 1302 1303 /* Run the state-machine */ 1304 result = smtp_multi_statemach(conn, dophase_done); 1305 1306 *connected = conn->bits.tcpconnect[FIRSTSOCKET]; 1307 1308 if(*dophase_done) 1309 DEBUGF(infof(conn->data, "DO phase is complete\n")); 1310 1311 return result; 1312 } 1313 1314 /*********************************************************************** 1315 * 1316 * smtp_do() 1317 * 1318 * This function is registered as 'curl_do' function. It decodes the path 1319 * parts etc as a wrapper to the actual DO function (smtp_perform). 1320 * 1321 * The input argument is already checked for validity. 1322 */ 1323 static CURLcode smtp_do(struct connectdata *conn, bool *done) 1324 { 1325 CURLcode result = CURLE_OK; 1326 1327 *done = FALSE; /* default to false */ 1328 1329 /* Parse the custom request */ 1330 result = smtp_parse_custom_request(conn); 1331 if(result) 1332 return result; 1333 1334 result = smtp_regular_transfer(conn, done); 1335 1336 return result; 1337 } 1338 1339 /*********************************************************************** 1340 * 1341 * smtp_disconnect() 1342 * 1343 * Disconnect from an SMTP server. Cleanup protocol-specific per-connection 1344 * resources. BLOCKING. 1345 */ 1346 static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection) 1347 { 1348 struct smtp_conn *smtpc = &conn->proto.smtpc; 1349 1350 /* We cannot send quit unconditionally. If this connection is stale or 1351 bad in any way, sending quit and waiting around here will make the 1352 disconnect wait in vain and cause more problems than we need to. */ 1353 1354 /* The SMTP session may or may not have been allocated/setup at this 1355 point! */ 1356 if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart) 1357 if(!smtp_perform_quit(conn)) 1358 (void)smtp_block_statemach(conn); /* ignore errors on QUIT */ 1359 1360 /* Disconnect from the server */ 1361 Curl_pp_disconnect(&smtpc->pp); 1362 1363 /* Cleanup the SASL module */ 1364 Curl_sasl_cleanup(conn, smtpc->sasl.authused); 1365 1366 /* Cleanup our connection based variables */ 1367 Curl_safefree(smtpc->domain); 1368 1369 return CURLE_OK; 1370 } 1371 1372 /* Call this when the DO phase has completed */ 1373 static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected) 1374 { 1375 struct SMTP *smtp = conn->data->req.protop; 1376 1377 (void)connected; 1378 1379 if(smtp->transfer != FTPTRANSFER_BODY) 1380 /* no data to transfer */ 1381 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); 1382 1383 return CURLE_OK; 1384 } 1385 1386 /* Called from multi.c while DOing */ 1387 static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done) 1388 { 1389 CURLcode result = smtp_multi_statemach(conn, dophase_done); 1390 1391 if(result) 1392 DEBUGF(infof(conn->data, "DO phase failed\n")); 1393 else if(*dophase_done) { 1394 result = smtp_dophase_done(conn, FALSE /* not connected */); 1395 1396 DEBUGF(infof(conn->data, "DO phase is complete\n")); 1397 } 1398 1399 return result; 1400 } 1401 1402 /*********************************************************************** 1403 * 1404 * smtp_regular_transfer() 1405 * 1406 * The input argument is already checked for validity. 1407 * 1408 * Performs all commands done before a regular transfer between a local and a 1409 * remote host. 1410 */ 1411 static CURLcode smtp_regular_transfer(struct connectdata *conn, 1412 bool *dophase_done) 1413 { 1414 CURLcode result = CURLE_OK; 1415 bool connected = FALSE; 1416 struct Curl_easy *data = conn->data; 1417 1418 /* Make sure size is unknown at this point */ 1419 data->req.size = -1; 1420 1421 /* Set the progress data */ 1422 Curl_pgrsSetUploadCounter(data, 0); 1423 Curl_pgrsSetDownloadCounter(data, 0); 1424 Curl_pgrsSetUploadSize(data, -1); 1425 Curl_pgrsSetDownloadSize(data, -1); 1426 1427 /* Carry out the perform */ 1428 result = smtp_perform(conn, &connected, dophase_done); 1429 1430 /* Perform post DO phase operations if necessary */ 1431 if(!result && *dophase_done) 1432 result = smtp_dophase_done(conn, connected); 1433 1434 return result; 1435 } 1436 1437 static CURLcode smtp_setup_connection(struct connectdata *conn) 1438 { 1439 struct Curl_easy *data = conn->data; 1440 CURLcode result; 1441 1442 /* Clear the TLS upgraded flag */ 1443 conn->tls_upgraded = FALSE; 1444 1445 /* Initialise the SMTP layer */ 1446 result = smtp_init(conn); 1447 if(result) 1448 return result; 1449 1450 data->state.path++; /* don't include the initial slash */ 1451 1452 return CURLE_OK; 1453 } 1454 1455 /*********************************************************************** 1456 * 1457 * smtp_parse_url_options() 1458 * 1459 * Parse the URL login options. 1460 */ 1461 static CURLcode smtp_parse_url_options(struct connectdata *conn) 1462 { 1463 CURLcode result = CURLE_OK; 1464 struct smtp_conn *smtpc = &conn->proto.smtpc; 1465 const char *ptr = conn->options; 1466 1467 smtpc->sasl.resetprefs = TRUE; 1468 1469 while(!result && ptr && *ptr) { 1470 const char *key = ptr; 1471 const char *value; 1472 1473 while(*ptr && *ptr != '=') 1474 ptr++; 1475 1476 value = ptr + 1; 1477 1478 while(*ptr && *ptr != ';') 1479 ptr++; 1480 1481 if(strncasecompare(key, "AUTH=", 5)) 1482 result = Curl_sasl_parse_url_auth_option(&smtpc->sasl, 1483 value, ptr - value); 1484 else 1485 result = CURLE_URL_MALFORMAT; 1486 1487 if(*ptr == ';') 1488 ptr++; 1489 } 1490 1491 return result; 1492 } 1493 1494 /*********************************************************************** 1495 * 1496 * smtp_parse_url_path() 1497 * 1498 * Parse the URL path into separate path components. 1499 */ 1500 static CURLcode smtp_parse_url_path(struct connectdata *conn) 1501 { 1502 /* The SMTP struct is already initialised in smtp_connect() */ 1503 struct Curl_easy *data = conn->data; 1504 struct smtp_conn *smtpc = &conn->proto.smtpc; 1505 const char *path = data->state.path; 1506 char localhost[HOSTNAME_MAX + 1]; 1507 1508 /* Calculate the path if necessary */ 1509 if(!*path) { 1510 if(!Curl_gethostname(localhost, sizeof(localhost))) 1511 path = localhost; 1512 else 1513 path = "localhost"; 1514 } 1515 1516 /* URL decode the path and use it as the domain in our EHLO */ 1517 return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE); 1518 } 1519 1520 /*********************************************************************** 1521 * 1522 * smtp_parse_custom_request() 1523 * 1524 * Parse the custom request. 1525 */ 1526 static CURLcode smtp_parse_custom_request(struct connectdata *conn) 1527 { 1528 CURLcode result = CURLE_OK; 1529 struct Curl_easy *data = conn->data; 1530 struct SMTP *smtp = data->req.protop; 1531 const char *custom = data->set.str[STRING_CUSTOMREQUEST]; 1532 1533 /* URL decode the custom request */ 1534 if(custom) 1535 result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, TRUE); 1536 1537 return result; 1538 } 1539 1540 CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread) 1541 { 1542 /* When sending a SMTP payload we must detect CRLF. sequences making sure 1543 they are sent as CRLF.. instead, as a . on the beginning of a line will 1544 be deleted by the server when not part of an EOB terminator and a 1545 genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of 1546 data by the server 1547 */ 1548 ssize_t i; 1549 ssize_t si; 1550 struct Curl_easy *data = conn->data; 1551 struct SMTP *smtp = data->req.protop; 1552 char *scratch = data->state.scratch; 1553 char *newscratch = NULL; 1554 char *oldscratch = NULL; 1555 size_t eob_sent; 1556 1557 /* Do we need to allocate a scratch buffer? */ 1558 if(!scratch || data->set.crlf) { 1559 oldscratch = scratch; 1560 1561 scratch = newscratch = malloc(2 * data->set.buffer_size); 1562 if(!newscratch) { 1563 failf(data, "Failed to alloc scratch buffer!"); 1564 1565 return CURLE_OUT_OF_MEMORY; 1566 } 1567 } 1568 1569 /* Have we already sent part of the EOB? */ 1570 eob_sent = smtp->eob; 1571 1572 /* This loop can be improved by some kind of Boyer-Moore style of 1573 approach but that is saved for later... */ 1574 for(i = 0, si = 0; i < nread; i++) { 1575 if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) { 1576 smtp->eob++; 1577 1578 /* Is the EOB potentially the terminating CRLF? */ 1579 if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob) 1580 smtp->trailing_crlf = TRUE; 1581 else 1582 smtp->trailing_crlf = FALSE; 1583 } 1584 else if(smtp->eob) { 1585 /* A previous substring matched so output that first */ 1586 memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent); 1587 si += smtp->eob - eob_sent; 1588 1589 /* Then compare the first byte */ 1590 if(SMTP_EOB[0] == data->req.upload_fromhere[i]) 1591 smtp->eob = 1; 1592 else 1593 smtp->eob = 0; 1594 1595 eob_sent = 0; 1596 1597 /* Reset the trailing CRLF flag as there was more data */ 1598 smtp->trailing_crlf = FALSE; 1599 } 1600 1601 /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */ 1602 if(SMTP_EOB_FIND_LEN == smtp->eob) { 1603 /* Copy the replacement data to the target buffer */ 1604 memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent], 1605 SMTP_EOB_REPL_LEN - eob_sent); 1606 si += SMTP_EOB_REPL_LEN - eob_sent; 1607 smtp->eob = 0; 1608 eob_sent = 0; 1609 } 1610 else if(!smtp->eob) 1611 scratch[si++] = data->req.upload_fromhere[i]; 1612 } 1613 1614 if(smtp->eob - eob_sent) { 1615 /* A substring matched before processing ended so output that now */ 1616 memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent); 1617 si += smtp->eob - eob_sent; 1618 } 1619 1620 /* Only use the new buffer if we replaced something */ 1621 if(si != nread) { 1622 /* Upload from the new (replaced) buffer instead */ 1623 data->req.upload_fromhere = scratch; 1624 1625 /* Save the buffer so it can be freed later */ 1626 data->state.scratch = scratch; 1627 1628 /* Free the old scratch buffer */ 1629 free(oldscratch); 1630 1631 /* Set the new amount too */ 1632 data->req.upload_present = si; 1633 } 1634 else 1635 free(newscratch); 1636 1637 return CURLE_OK; 1638 } 1639 1640 #endif /* CURL_DISABLE_SMTP */ 1641