00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "curl_setup.h"
00037
00038 #ifndef CURL_DISABLE_SMTP
00039
00040 #ifdef HAVE_NETINET_IN_H
00041 #include <netinet/in.h>
00042 #endif
00043 #ifdef HAVE_ARPA_INET_H
00044 #include <arpa/inet.h>
00045 #endif
00046 #ifdef HAVE_UTSNAME_H
00047 #include <sys/utsname.h>
00048 #endif
00049 #ifdef HAVE_NETDB_H
00050 #include <netdb.h>
00051 #endif
00052 #ifdef __VMS
00053 #include <in.h>
00054 #include <inet.h>
00055 #endif
00056
00057 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
00058 #undef in_addr_t
00059 #define in_addr_t unsigned long
00060 #endif
00061
00062 #include <curl/curl.h>
00063 #include "urldata.h"
00064 #include "sendf.h"
00065 #include "hostip.h"
00066 #include "progress.h"
00067 #include "transfer.h"
00068 #include "escape.h"
00069 #include "http.h"
00070 #include "socks.h"
00071 #include "smtp.h"
00072 #include "strtoofft.h"
00073 #include "strcase.h"
00074 #include "vtls/vtls.h"
00075 #include "connect.h"
00076 #include "strerror.h"
00077 #include "select.h"
00078 #include "multiif.h"
00079 #include "url.h"
00080 #include "curl_gethostname.h"
00081 #include "curl_sasl.h"
00082 #include "warnless.h"
00083
00084 #include "curl_printf.h"
00085 #include "curl_memory.h"
00086 #include "memdebug.h"
00087
00088
00089 static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done);
00090 static CURLcode smtp_do(struct connectdata *conn, bool *done);
00091 static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
00092 bool premature);
00093 static CURLcode smtp_connect(struct connectdata *conn, bool *done);
00094 static CURLcode smtp_disconnect(struct connectdata *conn, bool dead);
00095 static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done);
00096 static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
00097 int numsocks);
00098 static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done);
00099 static CURLcode smtp_setup_connection(struct connectdata *conn);
00100 static CURLcode smtp_parse_url_options(struct connectdata *conn);
00101 static CURLcode smtp_parse_url_path(struct connectdata *conn);
00102 static CURLcode smtp_parse_custom_request(struct connectdata *conn);
00103 static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech,
00104 const char *initresp);
00105 static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp);
00106 static void smtp_get_message(char *buffer, char **outptr);
00107
00108
00109
00110
00111
00112 const struct Curl_handler Curl_handler_smtp = {
00113 "SMTP",
00114 smtp_setup_connection,
00115 smtp_do,
00116 smtp_done,
00117 ZERO_NULL,
00118 smtp_connect,
00119 smtp_multi_statemach,
00120 smtp_doing,
00121 smtp_getsock,
00122 smtp_getsock,
00123 ZERO_NULL,
00124 ZERO_NULL,
00125 smtp_disconnect,
00126 ZERO_NULL,
00127 PORT_SMTP,
00128 CURLPROTO_SMTP,
00129 PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY
00130 };
00131
00132 #ifdef USE_SSL
00133
00134
00135
00136
00137 const struct Curl_handler Curl_handler_smtps = {
00138 "SMTPS",
00139 smtp_setup_connection,
00140 smtp_do,
00141 smtp_done,
00142 ZERO_NULL,
00143 smtp_connect,
00144 smtp_multi_statemach,
00145 smtp_doing,
00146 smtp_getsock,
00147 smtp_getsock,
00148 ZERO_NULL,
00149 ZERO_NULL,
00150 smtp_disconnect,
00151 ZERO_NULL,
00152 PORT_SMTPS,
00153 CURLPROTO_SMTPS,
00154 PROTOPT_CLOSEACTION | PROTOPT_SSL
00155 | PROTOPT_NOURLQUERY
00156 };
00157 #endif
00158
00159 #ifndef CURL_DISABLE_HTTP
00160
00161
00162
00163
00164 static const struct Curl_handler Curl_handler_smtp_proxy = {
00165 "SMTP",
00166 Curl_http_setup_conn,
00167 Curl_http,
00168 Curl_http_done,
00169 ZERO_NULL,
00170 ZERO_NULL,
00171 ZERO_NULL,
00172 ZERO_NULL,
00173 ZERO_NULL,
00174 ZERO_NULL,
00175 ZERO_NULL,
00176 ZERO_NULL,
00177 ZERO_NULL,
00178 ZERO_NULL,
00179 PORT_SMTP,
00180 CURLPROTO_HTTP,
00181 PROTOPT_NONE
00182 };
00183
00184 #ifdef USE_SSL
00185
00186
00187
00188
00189 static const struct Curl_handler Curl_handler_smtps_proxy = {
00190 "SMTPS",
00191 Curl_http_setup_conn,
00192 Curl_http,
00193 Curl_http_done,
00194 ZERO_NULL,
00195 ZERO_NULL,
00196 ZERO_NULL,
00197 ZERO_NULL,
00198 ZERO_NULL,
00199 ZERO_NULL,
00200 ZERO_NULL,
00201 ZERO_NULL,
00202 ZERO_NULL,
00203 ZERO_NULL,
00204 PORT_SMTPS,
00205 CURLPROTO_HTTP,
00206 PROTOPT_NONE
00207 };
00208 #endif
00209 #endif
00210
00211
00212 static const struct SASLproto saslsmtp = {
00213 "smtp",
00214 334,
00215 235,
00216 512 - 8,
00217 smtp_perform_auth,
00218 smtp_continue_auth,
00219 smtp_get_message
00220 };
00221
00222 #ifdef USE_SSL
00223 static void smtp_to_smtps(struct connectdata *conn)
00224 {
00225
00226 conn->handler = &Curl_handler_smtps;
00227
00228
00229 conn->tls_upgraded = TRUE;
00230 }
00231 #else
00232 #define smtp_to_smtps(x) Curl_nop_stmt
00233 #endif
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
00244 int *resp)
00245 {
00246 struct smtp_conn *smtpc = &conn->proto.smtpc;
00247 bool result = FALSE;
00248
00249
00250 if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
00251 return FALSE;
00252
00253
00254
00255
00256
00257 if(line[3] == ' ' || len == 5) {
00258 result = TRUE;
00259 *resp = curlx_sltosi(strtol(line, NULL, 10));
00260
00261
00262 if(*resp == 1)
00263 *resp = 0;
00264 }
00265
00266 else if(line[3] == '-' &&
00267 (smtpc->state == SMTP_EHLO || smtpc->state == SMTP_COMMAND)) {
00268 result = TRUE;
00269 *resp = 1;
00270 }
00271
00272 return result;
00273 }
00274
00275
00276
00277
00278
00279
00280
00281 static void smtp_get_message(char *buffer, char **outptr)
00282 {
00283 size_t len = 0;
00284 char *message = NULL;
00285
00286
00287 for(message = buffer + 4; *message == ' ' || *message == '\t'; message++)
00288 ;
00289
00290
00291 for(len = strlen(message); len--;)
00292 if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
00293 message[len] != '\t')
00294 break;
00295
00296
00297 if(++len) {
00298 message[len] = '\0';
00299 }
00300
00301 *outptr = message;
00302 }
00303
00304
00305
00306
00307
00308
00309
00310 static void state(struct connectdata *conn, smtpstate newstate)
00311 {
00312 struct smtp_conn *smtpc = &conn->proto.smtpc;
00313 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
00314
00315 static const char * const names[] = {
00316 "STOP",
00317 "SERVERGREET",
00318 "EHLO",
00319 "HELO",
00320 "STARTTLS",
00321 "UPGRADETLS",
00322 "AUTH",
00323 "COMMAND",
00324 "MAIL",
00325 "RCPT",
00326 "DATA",
00327 "POSTDATA",
00328 "QUIT",
00329
00330 };
00331
00332 if(smtpc->state != newstate)
00333 infof(conn->data, "SMTP %p state change from %s to %s\n",
00334 (void *)smtpc, names[smtpc->state], names[newstate]);
00335 #endif
00336
00337 smtpc->state = newstate;
00338 }
00339
00340
00341
00342
00343
00344
00345
00346
00347 static CURLcode smtp_perform_ehlo(struct connectdata *conn)
00348 {
00349 CURLcode result = CURLE_OK;
00350 struct smtp_conn *smtpc = &conn->proto.smtpc;
00351
00352 smtpc->sasl.authmechs = SASL_AUTH_NONE;
00353 smtpc->sasl.authused = SASL_AUTH_NONE;
00354
00355 smtpc->tls_supported = FALSE;
00356 smtpc->auth_supported = FALSE;
00357
00358
00359 result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain);
00360
00361 if(!result)
00362 state(conn, SMTP_EHLO);
00363
00364 return result;
00365 }
00366
00367
00368
00369
00370
00371
00372
00373 static CURLcode smtp_perform_helo(struct connectdata *conn)
00374 {
00375 CURLcode result = CURLE_OK;
00376 struct smtp_conn *smtpc = &conn->proto.smtpc;
00377
00378 smtpc->sasl.authused = SASL_AUTH_NONE;
00379
00380
00381
00382 result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain);
00383
00384 if(!result)
00385 state(conn, SMTP_HELO);
00386
00387 return result;
00388 }
00389
00390
00391
00392
00393
00394
00395
00396 static CURLcode smtp_perform_starttls(struct connectdata *conn)
00397 {
00398 CURLcode result = CURLE_OK;
00399
00400
00401 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "STARTTLS");
00402
00403 if(!result)
00404 state(conn, SMTP_STARTTLS);
00405
00406 return result;
00407 }
00408
00409
00410
00411
00412
00413
00414
00415 static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn)
00416 {
00417 CURLcode result = CURLE_OK;
00418 struct smtp_conn *smtpc = &conn->proto.smtpc;
00419
00420
00421 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
00422
00423 if(!result) {
00424 if(smtpc->state != SMTP_UPGRADETLS)
00425 state(conn, SMTP_UPGRADETLS);
00426
00427 if(smtpc->ssldone) {
00428 smtp_to_smtps(conn);
00429 result = smtp_perform_ehlo(conn);
00430 }
00431 }
00432
00433 return result;
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443 static CURLcode smtp_perform_auth(struct connectdata *conn,
00444 const char *mech,
00445 const char *initresp)
00446 {
00447 CURLcode result = CURLE_OK;
00448 struct smtp_conn *smtpc = &conn->proto.smtpc;
00449
00450 if(initresp) {
00451
00452 result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
00453 }
00454 else {
00455
00456 result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
00457 }
00458
00459 return result;
00460 }
00461
00462
00463
00464
00465
00466
00467
00468 static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp)
00469 {
00470 struct smtp_conn *smtpc = &conn->proto.smtpc;
00471
00472 return Curl_pp_sendf(&smtpc->pp, "%s", resp);
00473 }
00474
00475
00476
00477
00478
00479
00480
00481
00482 static CURLcode smtp_perform_authentication(struct connectdata *conn)
00483 {
00484 CURLcode result = CURLE_OK;
00485 struct smtp_conn *smtpc = &conn->proto.smtpc;
00486 saslprogress progress;
00487
00488
00489
00490 if(!smtpc->auth_supported ||
00491 !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
00492 state(conn, SMTP_STOP);
00493 return result;
00494 }
00495
00496
00497 result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress);
00498
00499 if(!result) {
00500 if(progress == SASL_INPROGRESS)
00501 state(conn, SMTP_AUTH);
00502 else {
00503
00504 infof(conn->data, "No known authentication mechanisms supported!\n");
00505 result = CURLE_LOGIN_DENIED;
00506 }
00507 }
00508
00509 return result;
00510 }
00511
00512
00513
00514
00515
00516
00517
00518 static CURLcode smtp_perform_command(struct connectdata *conn)
00519 {
00520 CURLcode result = CURLE_OK;
00521 struct Curl_easy *data = conn->data;
00522 struct SMTP *smtp = data->req.protop;
00523
00524
00525 if(smtp->rcpt)
00526 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s %s",
00527 smtp->custom && smtp->custom[0] != '\0' ?
00528 smtp->custom : "VRFY",
00529 smtp->rcpt->data);
00530 else
00531 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s",
00532 smtp->custom && smtp->custom[0] != '\0' ?
00533 smtp->custom : "HELP");
00534
00535 if(!result)
00536 state(conn, SMTP_COMMAND);
00537
00538 return result;
00539 }
00540
00541
00542
00543
00544
00545
00546
00547 static CURLcode smtp_perform_mail(struct connectdata *conn)
00548 {
00549 char *from = NULL;
00550 char *auth = NULL;
00551 char *size = NULL;
00552 CURLcode result = CURLE_OK;
00553 struct Curl_easy *data = conn->data;
00554
00555
00556 if(!data->set.str[STRING_MAIL_FROM])
00557
00558 from = strdup("<>");
00559 else if(data->set.str[STRING_MAIL_FROM][0] == '<')
00560 from = aprintf("%s", data->set.str[STRING_MAIL_FROM]);
00561 else
00562 from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]);
00563
00564 if(!from)
00565 return CURLE_OUT_OF_MEMORY;
00566
00567
00568 if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) {
00569 if(data->set.str[STRING_MAIL_AUTH][0] != '\0')
00570 auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]);
00571 else
00572
00573 auth = strdup("<>");
00574
00575 if(!auth) {
00576 free(from);
00577
00578 return CURLE_OUT_OF_MEMORY;
00579 }
00580 }
00581
00582
00583 if(conn->proto.smtpc.size_supported && conn->data->state.infilesize > 0) {
00584 size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize);
00585
00586 if(!size) {
00587 free(from);
00588 free(auth);
00589
00590 return CURLE_OUT_OF_MEMORY;
00591 }
00592 }
00593
00594
00595 if(!auth && !size)
00596 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
00597 "MAIL FROM:%s", from);
00598 else if(auth && !size)
00599 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
00600 "MAIL FROM:%s AUTH=%s", from, auth);
00601 else if(auth && size)
00602 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
00603 "MAIL FROM:%s AUTH=%s SIZE=%s", from, auth, size);
00604 else
00605 result = Curl_pp_sendf(&conn->proto.smtpc.pp,
00606 "MAIL FROM:%s SIZE=%s", from, size);
00607
00608 free(from);
00609 free(auth);
00610 free(size);
00611
00612 if(!result)
00613 state(conn, SMTP_MAIL);
00614
00615 return result;
00616 }
00617
00618
00619
00620
00621
00622
00623
00624
00625 static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
00626 {
00627 CURLcode result = CURLE_OK;
00628 struct Curl_easy *data = conn->data;
00629 struct SMTP *smtp = data->req.protop;
00630
00631
00632 if(smtp->rcpt->data[0] == '<')
00633 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s",
00634 smtp->rcpt->data);
00635 else
00636 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>",
00637 smtp->rcpt->data);
00638 if(!result)
00639 state(conn, SMTP_RCPT);
00640
00641 return result;
00642 }
00643
00644
00645
00646
00647
00648
00649
00650 static CURLcode smtp_perform_quit(struct connectdata *conn)
00651 {
00652 CURLcode result = CURLE_OK;
00653
00654
00655 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "QUIT");
00656
00657 if(!result)
00658 state(conn, SMTP_QUIT);
00659
00660 return result;
00661 }
00662
00663
00664 static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
00665 int smtpcode,
00666 smtpstate instate)
00667 {
00668 CURLcode result = CURLE_OK;
00669 struct Curl_easy *data = conn->data;
00670
00671 (void)instate;
00672
00673 if(smtpcode/100 != 2) {
00674 failf(data, "Got unexpected smtp-server response: %d", smtpcode);
00675 result = CURLE_WEIRD_SERVER_REPLY;
00676 }
00677 else
00678 result = smtp_perform_ehlo(conn);
00679
00680 return result;
00681 }
00682
00683
00684 static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
00685 int smtpcode,
00686 smtpstate instate)
00687 {
00688 CURLcode result = CURLE_OK;
00689 struct Curl_easy *data = conn->data;
00690
00691 (void)instate;
00692
00693 if(smtpcode != 220) {
00694 if(data->set.use_ssl != CURLUSESSL_TRY) {
00695 failf(data, "STARTTLS denied. %c", smtpcode);
00696 result = CURLE_USE_SSL_FAILED;
00697 }
00698 else
00699 result = smtp_perform_authentication(conn);
00700 }
00701 else
00702 result = smtp_perform_upgrade_tls(conn);
00703
00704 return result;
00705 }
00706
00707
00708 static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
00709 smtpstate instate)
00710 {
00711 CURLcode result = CURLE_OK;
00712 struct Curl_easy *data = conn->data;
00713 struct smtp_conn *smtpc = &conn->proto.smtpc;
00714 const char *line = data->state.buffer;
00715 size_t len = strlen(line);
00716 size_t wordlen;
00717
00718 (void)instate;
00719
00720 if(smtpcode/100 != 2 && smtpcode != 1) {
00721 if(data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use)
00722 result = smtp_perform_helo(conn);
00723 else {
00724 failf(data, "Remote access denied: %d", smtpcode);
00725 result = CURLE_REMOTE_ACCESS_DENIED;
00726 }
00727 }
00728 else {
00729 line += 4;
00730 len -= 4;
00731
00732
00733 if(len >= 8 && !memcmp(line, "STARTTLS", 8))
00734 smtpc->tls_supported = TRUE;
00735
00736
00737 else if(len >= 4 && !memcmp(line, "SIZE", 4))
00738 smtpc->size_supported = TRUE;
00739
00740
00741 else if(len >= 5 && !memcmp(line, "AUTH ", 5)) {
00742 smtpc->auth_supported = TRUE;
00743
00744
00745 line += 5;
00746 len -= 5;
00747
00748
00749 for(;;) {
00750 size_t llen;
00751 unsigned int mechbit;
00752
00753 while(len &&
00754 (*line == ' ' || *line == '\t' ||
00755 *line == '\r' || *line == '\n')) {
00756
00757 line++;
00758 len--;
00759 }
00760
00761 if(!len)
00762 break;
00763
00764
00765 for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
00766 line[wordlen] != '\t' && line[wordlen] != '\r' &&
00767 line[wordlen] != '\n';)
00768 wordlen++;
00769
00770
00771 mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
00772 if(mechbit && llen == wordlen)
00773 smtpc->sasl.authmechs |= mechbit;
00774
00775 line += wordlen;
00776 len -= wordlen;
00777 }
00778 }
00779
00780 if(smtpcode != 1) {
00781 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
00782
00783 if(smtpc->tls_supported)
00784
00785 result = smtp_perform_starttls(conn);
00786 else if(data->set.use_ssl == CURLUSESSL_TRY)
00787
00788 result = smtp_perform_authentication(conn);
00789 else {
00790 failf(data, "STARTTLS not supported.");
00791 result = CURLE_USE_SSL_FAILED;
00792 }
00793 }
00794 else
00795 result = smtp_perform_authentication(conn);
00796 }
00797 }
00798
00799 return result;
00800 }
00801
00802
00803 static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode,
00804 smtpstate instate)
00805 {
00806 CURLcode result = CURLE_OK;
00807 struct Curl_easy *data = conn->data;
00808
00809 (void)instate;
00810
00811 if(smtpcode/100 != 2) {
00812 failf(data, "Remote access denied: %d", smtpcode);
00813 result = CURLE_REMOTE_ACCESS_DENIED;
00814 }
00815 else
00816
00817 state(conn, SMTP_STOP);
00818
00819 return result;
00820 }
00821
00822
00823 static CURLcode smtp_state_auth_resp(struct connectdata *conn,
00824 int smtpcode,
00825 smtpstate instate)
00826 {
00827 CURLcode result = CURLE_OK;
00828 struct Curl_easy *data = conn->data;
00829 struct smtp_conn *smtpc = &conn->proto.smtpc;
00830 saslprogress progress;
00831
00832 (void)instate;
00833
00834 result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress);
00835 if(!result)
00836 switch(progress) {
00837 case SASL_DONE:
00838 state(conn, SMTP_STOP);
00839 break;
00840 case SASL_IDLE:
00841 failf(data, "Authentication cancelled");
00842 result = CURLE_LOGIN_DENIED;
00843 break;
00844 default:
00845 break;
00846 }
00847
00848 return result;
00849 }
00850
00851
00852 static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
00853 smtpstate instate)
00854 {
00855 CURLcode result = CURLE_OK;
00856 struct Curl_easy *data = conn->data;
00857 struct SMTP *smtp = data->req.protop;
00858 char *line = data->state.buffer;
00859 size_t len = strlen(line);
00860
00861 (void)instate;
00862
00863 if((smtp->rcpt && smtpcode/100 != 2 && smtpcode != 553 && smtpcode != 1) ||
00864 (!smtp->rcpt && smtpcode/100 != 2 && smtpcode != 1)) {
00865 failf(data, "Command failed: %d", smtpcode);
00866 result = CURLE_RECV_ERROR;
00867 }
00868 else {
00869
00870 if(!data->set.opt_no_body) {
00871 line[len] = '\n';
00872 result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
00873 line[len] = '\0';
00874 }
00875
00876 if(smtpcode != 1) {
00877 if(smtp->rcpt) {
00878 smtp->rcpt = smtp->rcpt->next;
00879
00880 if(smtp->rcpt) {
00881
00882 result = smtp_perform_command(conn);
00883 }
00884 else
00885
00886 state(conn, SMTP_STOP);
00887 }
00888 else
00889
00890 state(conn, SMTP_STOP);
00891 }
00892 }
00893
00894 return result;
00895 }
00896
00897
00898 static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
00899 smtpstate instate)
00900 {
00901 CURLcode result = CURLE_OK;
00902 struct Curl_easy *data = conn->data;
00903
00904 (void)instate;
00905
00906 if(smtpcode/100 != 2) {
00907 failf(data, "MAIL failed: %d", smtpcode);
00908 result = CURLE_SEND_ERROR;
00909 }
00910 else
00911
00912 result = smtp_perform_rcpt_to(conn);
00913
00914 return result;
00915 }
00916
00917
00918 static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
00919 smtpstate instate)
00920 {
00921 CURLcode result = CURLE_OK;
00922 struct Curl_easy *data = conn->data;
00923 struct SMTP *smtp = data->req.protop;
00924
00925 (void)instate;
00926
00927 if(smtpcode/100 != 2) {
00928 failf(data, "RCPT failed: %d", smtpcode);
00929 result = CURLE_SEND_ERROR;
00930 }
00931 else {
00932 smtp->rcpt = smtp->rcpt->next;
00933
00934 if(smtp->rcpt)
00935
00936 result = smtp_perform_rcpt_to(conn);
00937 else {
00938
00939 result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA");
00940
00941 if(!result)
00942 state(conn, SMTP_DATA);
00943 }
00944 }
00945
00946 return result;
00947 }
00948
00949
00950 static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
00951 smtpstate instate)
00952 {
00953 CURLcode result = CURLE_OK;
00954 struct Curl_easy *data = conn->data;
00955
00956 (void)instate;
00957
00958 if(smtpcode != 354) {
00959 failf(data, "DATA failed: %d", smtpcode);
00960 result = CURLE_SEND_ERROR;
00961 }
00962 else {
00963
00964 Curl_pgrsSetUploadSize(data, data->state.infilesize);
00965
00966
00967 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
00968
00969
00970 state(conn, SMTP_STOP);
00971 }
00972
00973 return result;
00974 }
00975
00976
00977
00978 static CURLcode smtp_state_postdata_resp(struct connectdata *conn,
00979 int smtpcode,
00980 smtpstate instate)
00981 {
00982 CURLcode result = CURLE_OK;
00983
00984 (void)instate;
00985
00986 if(smtpcode != 250)
00987 result = CURLE_RECV_ERROR;
00988
00989
00990 state(conn, SMTP_STOP);
00991
00992 return result;
00993 }
00994
00995 static CURLcode smtp_statemach_act(struct connectdata *conn)
00996 {
00997 CURLcode result = CURLE_OK;
00998 curl_socket_t sock = conn->sock[FIRSTSOCKET];
00999 struct Curl_easy *data = conn->data;
01000 int smtpcode;
01001 struct smtp_conn *smtpc = &conn->proto.smtpc;
01002 struct pingpong *pp = &smtpc->pp;
01003 size_t nread = 0;
01004
01005
01006 if(smtpc->state == SMTP_UPGRADETLS)
01007 return smtp_perform_upgrade_tls(conn);
01008
01009
01010 if(pp->sendleft)
01011 return Curl_pp_flushsend(pp);
01012
01013 do {
01014
01015 result = Curl_pp_readresp(sock, pp, &smtpcode, &nread);
01016 if(result)
01017 return result;
01018
01019
01020 if(smtpc->state != SMTP_QUIT && smtpcode != 1)
01021 data->info.httpcode = smtpcode;
01022
01023 if(!smtpcode)
01024 break;
01025
01026
01027 switch(smtpc->state) {
01028 case SMTP_SERVERGREET:
01029 result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state);
01030 break;
01031
01032 case SMTP_EHLO:
01033 result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
01034 break;
01035
01036 case SMTP_HELO:
01037 result = smtp_state_helo_resp(conn, smtpcode, smtpc->state);
01038 break;
01039
01040 case SMTP_STARTTLS:
01041 result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state);
01042 break;
01043
01044 case SMTP_AUTH:
01045 result = smtp_state_auth_resp(conn, smtpcode, smtpc->state);
01046 break;
01047
01048 case SMTP_COMMAND:
01049 result = smtp_state_command_resp(conn, smtpcode, smtpc->state);
01050 break;
01051
01052 case SMTP_MAIL:
01053 result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
01054 break;
01055
01056 case SMTP_RCPT:
01057 result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state);
01058 break;
01059
01060 case SMTP_DATA:
01061 result = smtp_state_data_resp(conn, smtpcode, smtpc->state);
01062 break;
01063
01064 case SMTP_POSTDATA:
01065 result = smtp_state_postdata_resp(conn, smtpcode, smtpc->state);
01066 break;
01067
01068 case SMTP_QUIT:
01069
01070 default:
01071
01072 state(conn, SMTP_STOP);
01073 break;
01074 }
01075 } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp));
01076
01077 return result;
01078 }
01079
01080
01081 static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done)
01082 {
01083 CURLcode result = CURLE_OK;
01084 struct smtp_conn *smtpc = &conn->proto.smtpc;
01085
01086 if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) {
01087 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
01088 if(result || !smtpc->ssldone)
01089 return result;
01090 }
01091
01092 result = Curl_pp_statemach(&smtpc->pp, FALSE);
01093 *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE;
01094
01095 return result;
01096 }
01097
01098 static CURLcode smtp_block_statemach(struct connectdata *conn)
01099 {
01100 CURLcode result = CURLE_OK;
01101 struct smtp_conn *smtpc = &conn->proto.smtpc;
01102
01103 while(smtpc->state != SMTP_STOP && !result)
01104 result = Curl_pp_statemach(&smtpc->pp, TRUE);
01105
01106 return result;
01107 }
01108
01109
01110
01111 static CURLcode smtp_init(struct connectdata *conn)
01112 {
01113 CURLcode result = CURLE_OK;
01114 struct Curl_easy *data = conn->data;
01115 struct SMTP *smtp;
01116
01117 smtp = data->req.protop = calloc(sizeof(struct SMTP), 1);
01118 if(!smtp)
01119 result = CURLE_OUT_OF_MEMORY;
01120
01121 return result;
01122 }
01123
01124
01125 static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
01126 int numsocks)
01127 {
01128 return Curl_pp_getsock(&conn->proto.smtpc.pp, socks, numsocks);
01129 }
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141 static CURLcode smtp_connect(struct connectdata *conn, bool *done)
01142 {
01143 CURLcode result = CURLE_OK;
01144 struct smtp_conn *smtpc = &conn->proto.smtpc;
01145 struct pingpong *pp = &smtpc->pp;
01146
01147 *done = FALSE;
01148
01149
01150 connkeep(conn, "SMTP default");
01151
01152
01153 pp->response_time = RESP_TIMEOUT;
01154 pp->statemach_act = smtp_statemach_act;
01155 pp->endofresp = smtp_endofresp;
01156 pp->conn = conn;
01157
01158
01159 Curl_sasl_init(&smtpc->sasl, &saslsmtp);
01160
01161
01162 Curl_pp_init(pp);
01163
01164
01165 result = smtp_parse_url_options(conn);
01166 if(result)
01167 return result;
01168
01169
01170 result = smtp_parse_url_path(conn);
01171 if(result)
01172 return result;
01173
01174
01175 state(conn, SMTP_SERVERGREET);
01176
01177 result = smtp_multi_statemach(conn, done);
01178
01179 return result;
01180 }
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191 static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
01192 bool premature)
01193 {
01194 CURLcode result = CURLE_OK;
01195 struct Curl_easy *data = conn->data;
01196 struct SMTP *smtp = data->req.protop;
01197 struct pingpong *pp = &conn->proto.smtpc.pp;
01198 char *eob;
01199 ssize_t len;
01200 ssize_t bytes_written;
01201
01202 (void)premature;
01203
01204 if(!smtp || !pp->conn)
01205 return CURLE_OK;
01206
01207 if(status) {
01208 connclose(conn, "SMTP done with bad status");
01209 result = status;
01210 }
01211 else if(!data->set.connect_only && data->set.upload && data->set.mail_rcpt) {
01212
01213
01214
01215
01216
01217
01218
01219
01220 if(smtp->trailing_crlf || !conn->data->state.infilesize) {
01221 eob = strdup(SMTP_EOB + 2);
01222 len = SMTP_EOB_LEN - 2;
01223 }
01224 else {
01225 eob = strdup(SMTP_EOB);
01226 len = SMTP_EOB_LEN;
01227 }
01228
01229 if(!eob)
01230 return CURLE_OUT_OF_MEMORY;
01231
01232
01233 result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written);
01234 if(result) {
01235 free(eob);
01236 return result;
01237 }
01238
01239 if(bytes_written != len) {
01240
01241
01242 pp->sendthis = eob;
01243 pp->sendsize = len;
01244 pp->sendleft = len - bytes_written;
01245 }
01246 else {
01247
01248 pp->response = Curl_tvnow();
01249
01250 free(eob);
01251 }
01252
01253 state(conn, SMTP_POSTDATA);
01254
01255
01256
01257
01258
01259
01260
01261 result = smtp_block_statemach(conn);
01262 }
01263
01264
01265 Curl_safefree(smtp->custom);
01266
01267
01268 smtp->transfer = FTPTRANSFER_BODY;
01269
01270 return result;
01271 }
01272
01273
01274
01275
01276
01277
01278
01279
01280 static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
01281 bool *dophase_done)
01282 {
01283
01284 CURLcode result = CURLE_OK;
01285 struct Curl_easy *data = conn->data;
01286 struct SMTP *smtp = data->req.protop;
01287
01288 DEBUGF(infof(conn->data, "DO phase starts\n"));
01289
01290 if(data->set.opt_no_body) {
01291
01292 smtp->transfer = FTPTRANSFER_INFO;
01293 }
01294
01295 *dophase_done = FALSE;
01296
01297
01298 smtp->rcpt = data->set.mail_rcpt;
01299
01300
01301 if(data->set.upload && data->set.mail_rcpt)
01302
01303 result = smtp_perform_mail(conn);
01304 else
01305
01306 result = smtp_perform_command(conn);
01307
01308 if(result)
01309 return result;
01310
01311
01312 result = smtp_multi_statemach(conn, dophase_done);
01313
01314 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
01315
01316 if(*dophase_done)
01317 DEBUGF(infof(conn->data, "DO phase is complete\n"));
01318
01319 return result;
01320 }
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331 static CURLcode smtp_do(struct connectdata *conn, bool *done)
01332 {
01333 CURLcode result = CURLE_OK;
01334
01335 *done = FALSE;
01336
01337
01338 result = smtp_parse_custom_request(conn);
01339 if(result)
01340 return result;
01341
01342 result = smtp_regular_transfer(conn, done);
01343
01344 return result;
01345 }
01346
01347
01348
01349
01350
01351
01352
01353
01354 static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
01355 {
01356 struct smtp_conn *smtpc = &conn->proto.smtpc;
01357
01358
01359
01360
01361
01362
01363
01364 if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart)
01365 if(!smtp_perform_quit(conn))
01366 (void)smtp_block_statemach(conn);
01367
01368
01369 Curl_pp_disconnect(&smtpc->pp);
01370
01371
01372 Curl_sasl_cleanup(conn, smtpc->sasl.authused);
01373
01374
01375 Curl_safefree(smtpc->domain);
01376
01377 return CURLE_OK;
01378 }
01379
01380
01381 static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
01382 {
01383 struct SMTP *smtp = conn->data->req.protop;
01384
01385 (void)connected;
01386
01387 if(smtp->transfer != FTPTRANSFER_BODY)
01388
01389 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
01390
01391 return CURLE_OK;
01392 }
01393
01394
01395 static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done)
01396 {
01397 CURLcode result = smtp_multi_statemach(conn, dophase_done);
01398
01399 if(result)
01400 DEBUGF(infof(conn->data, "DO phase failed\n"));
01401 else if(*dophase_done) {
01402 result = smtp_dophase_done(conn, FALSE );
01403
01404 DEBUGF(infof(conn->data, "DO phase is complete\n"));
01405 }
01406
01407 return result;
01408 }
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419 static CURLcode smtp_regular_transfer(struct connectdata *conn,
01420 bool *dophase_done)
01421 {
01422 CURLcode result = CURLE_OK;
01423 bool connected = FALSE;
01424 struct Curl_easy *data = conn->data;
01425
01426
01427 data->req.size = -1;
01428
01429
01430 Curl_pgrsSetUploadCounter(data, 0);
01431 Curl_pgrsSetDownloadCounter(data, 0);
01432 Curl_pgrsSetUploadSize(data, -1);
01433 Curl_pgrsSetDownloadSize(data, -1);
01434
01435
01436 result = smtp_perform(conn, &connected, dophase_done);
01437
01438
01439 if(!result && *dophase_done)
01440 result = smtp_dophase_done(conn, connected);
01441
01442 return result;
01443 }
01444
01445 static CURLcode smtp_setup_connection(struct connectdata *conn)
01446 {
01447 struct Curl_easy *data = conn->data;
01448 CURLcode result;
01449
01450
01451 conn->tls_upgraded = FALSE;
01452
01453
01454 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
01455
01456
01457 #ifndef CURL_DISABLE_HTTP
01458 if(conn->handler == &Curl_handler_smtp)
01459 conn->handler = &Curl_handler_smtp_proxy;
01460 else {
01461 #ifdef USE_SSL
01462 conn->handler = &Curl_handler_smtps_proxy;
01463 #else
01464 failf(data, "SMTPS not supported!");
01465 return CURLE_UNSUPPORTED_PROTOCOL;
01466 #endif
01467 }
01468
01469 return conn->handler->setup_connection(conn);
01470
01471 #else
01472 failf(data, "SMTP over http proxy requires HTTP support built-in!");
01473 return CURLE_UNSUPPORTED_PROTOCOL;
01474 #endif
01475 }
01476
01477
01478 result = smtp_init(conn);
01479 if(result)
01480 return result;
01481
01482 data->state.path++;
01483
01484 return CURLE_OK;
01485 }
01486
01487
01488
01489
01490
01491
01492
01493 static CURLcode smtp_parse_url_options(struct connectdata *conn)
01494 {
01495 CURLcode result = CURLE_OK;
01496 struct smtp_conn *smtpc = &conn->proto.smtpc;
01497 const char *ptr = conn->options;
01498
01499 smtpc->sasl.resetprefs = TRUE;
01500
01501 while(!result && ptr && *ptr) {
01502 const char *key = ptr;
01503 const char *value;
01504
01505 while(*ptr && *ptr != '=')
01506 ptr++;
01507
01508 value = ptr + 1;
01509
01510 while(*ptr && *ptr != ';')
01511 ptr++;
01512
01513 if(strncasecompare(key, "AUTH=", 5))
01514 result = Curl_sasl_parse_url_auth_option(&smtpc->sasl,
01515 value, ptr - value);
01516 else
01517 result = CURLE_URL_MALFORMAT;
01518
01519 if(*ptr == ';')
01520 ptr++;
01521 }
01522
01523 return result;
01524 }
01525
01526
01527
01528
01529
01530
01531
01532 static CURLcode smtp_parse_url_path(struct connectdata *conn)
01533 {
01534
01535 struct Curl_easy *data = conn->data;
01536 struct smtp_conn *smtpc = &conn->proto.smtpc;
01537 const char *path = data->state.path;
01538 char localhost[HOSTNAME_MAX + 1];
01539
01540
01541 if(!*path) {
01542 if(!Curl_gethostname(localhost, sizeof(localhost)))
01543 path = localhost;
01544 else
01545 path = "localhost";
01546 }
01547
01548
01549 return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE);
01550 }
01551
01552
01553
01554
01555
01556
01557
01558 static CURLcode smtp_parse_custom_request(struct connectdata *conn)
01559 {
01560 CURLcode result = CURLE_OK;
01561 struct Curl_easy *data = conn->data;
01562 struct SMTP *smtp = data->req.protop;
01563 const char *custom = data->set.str[STRING_CUSTOMREQUEST];
01564
01565
01566 if(custom)
01567 result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, TRUE);
01568
01569 return result;
01570 }
01571
01572 CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
01573 {
01574
01575
01576
01577
01578
01579
01580 ssize_t i;
01581 ssize_t si;
01582 struct Curl_easy *data = conn->data;
01583 struct SMTP *smtp = data->req.protop;
01584 char *scratch = data->state.scratch;
01585 char *newscratch = NULL;
01586 char *oldscratch = NULL;
01587 size_t eob_sent;
01588
01589
01590 if(!scratch || data->set.crlf) {
01591 oldscratch = scratch;
01592
01593 scratch = newscratch = malloc(2 * BUFSIZE);
01594 if(!newscratch) {
01595 failf(data, "Failed to alloc scratch buffer!");
01596
01597 return CURLE_OUT_OF_MEMORY;
01598 }
01599 }
01600
01601
01602 eob_sent = smtp->eob;
01603
01604
01605
01606 for(i = 0, si = 0; i < nread; i++) {
01607 if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) {
01608 smtp->eob++;
01609
01610
01611 if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob)
01612 smtp->trailing_crlf = TRUE;
01613 else
01614 smtp->trailing_crlf = FALSE;
01615 }
01616 else if(smtp->eob) {
01617
01618 memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
01619 si += smtp->eob - eob_sent;
01620
01621
01622 if(SMTP_EOB[0] == data->req.upload_fromhere[i])
01623 smtp->eob = 1;
01624 else
01625 smtp->eob = 0;
01626
01627 eob_sent = 0;
01628
01629
01630 smtp->trailing_crlf = FALSE;
01631 }
01632
01633
01634 if(SMTP_EOB_FIND_LEN == smtp->eob) {
01635
01636 memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent],
01637 SMTP_EOB_REPL_LEN - eob_sent);
01638 si += SMTP_EOB_REPL_LEN - eob_sent;
01639 smtp->eob = 0;
01640 eob_sent = 0;
01641 }
01642 else if(!smtp->eob)
01643 scratch[si++] = data->req.upload_fromhere[i];
01644 }
01645
01646 if(smtp->eob - eob_sent) {
01647
01648 memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
01649 si += smtp->eob - eob_sent;
01650 }
01651
01652
01653 if(si != nread) {
01654
01655 data->req.upload_fromhere = scratch;
01656
01657
01658 data->state.scratch = scratch;
01659
01660
01661 free(oldscratch);
01662
01663
01664 data->req.upload_present = si;
01665 }
01666 else
01667 free(newscratch);
01668
01669 return CURLE_OK;
01670 }
01671
01672 #endif