ftp.c (143189B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@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.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 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25 #include "curl_setup.h" 26 27 #ifndef CURL_DISABLE_FTP 28 29 #ifdef HAVE_NETINET_IN_H 30 #include <netinet/in.h> 31 #endif 32 #ifdef HAVE_ARPA_INET_H 33 #include <arpa/inet.h> 34 #endif 35 #ifdef HAVE_NETDB_H 36 #include <netdb.h> 37 #endif 38 #ifdef __VMS 39 #include <in.h> 40 #include <inet.h> 41 #endif 42 43 #include <curl/curl.h> 44 #include "urldata.h" 45 #include "sendf.h" 46 #include "if2ip.h" 47 #include "hostip.h" 48 #include "progress.h" 49 #include "transfer.h" 50 #include "escape.h" 51 #include "http.h" /* for HTTP proxy tunnel stuff */ 52 #include "ftp.h" 53 #include "fileinfo.h" 54 #include "ftplistparser.h" 55 #include "curl_range.h" 56 #include "curl_krb5.h" 57 #include "strcase.h" 58 #include "vtls/vtls.h" 59 #include "cfilters.h" 60 #include "cf-socket.h" 61 #include "connect.h" 62 #include "strerror.h" 63 #include "curlx/inet_ntop.h" 64 #include "curlx/inet_pton.h" 65 #include "select.h" 66 #include "parsedate.h" /* for the week day and month names */ 67 #include "sockaddr.h" /* required for Curl_sockaddr_storage */ 68 #include "multiif.h" 69 #include "url.h" 70 #include "speedcheck.h" 71 #include "curlx/warnless.h" 72 #include "http_proxy.h" 73 #include "socks.h" 74 #include "strdup.h" 75 #include "curlx/strparse.h" 76 /* The last 3 #include files should be in this order */ 77 #include "curl_printf.h" 78 #include "curl_memory.h" 79 #include "memdebug.h" 80 81 #ifndef NI_MAXHOST 82 #define NI_MAXHOST 1025 83 #endif 84 #ifndef INET_ADDRSTRLEN 85 #define INET_ADDRSTRLEN 16 86 #endif 87 88 /* macro to check for a three-digit ftp status code at the start of the 89 given string */ 90 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \ 91 ISDIGIT(line[2])) 92 93 /* macro to check for the last line in an FTP server response */ 94 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3])) 95 96 #ifdef CURL_DISABLE_VERBOSE_STRINGS 97 #define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt 98 #define FTP_CSTATE(c) ((void)(c), "") 99 #else /* CURL_DISABLE_VERBOSE_STRINGS */ 100 /* for tracing purposes */ 101 static const char * const ftp_state_names[]={ 102 "STOP", 103 "WAIT220", 104 "AUTH", 105 "USER", 106 "PASS", 107 "ACCT", 108 "PBSZ", 109 "PROT", 110 "CCC", 111 "PWD", 112 "SYST", 113 "NAMEFMT", 114 "QUOTE", 115 "RETR_PREQUOTE", 116 "STOR_PREQUOTE", 117 "LIST_PREQUOTE", 118 "POSTQUOTE", 119 "CWD", 120 "MKD", 121 "MDTM", 122 "TYPE", 123 "LIST_TYPE", 124 "RETR_LIST_TYPE", 125 "RETR_TYPE", 126 "STOR_TYPE", 127 "SIZE", 128 "RETR_SIZE", 129 "STOR_SIZE", 130 "REST", 131 "RETR_REST", 132 "PORT", 133 "PRET", 134 "PASV", 135 "LIST", 136 "RETR", 137 "STOR", 138 "QUIT" 139 }; 140 #define FTP_CSTATE(ftpc) ((ftpc)? ftp_state_names[(ftpc)->state] : "???") 141 142 #endif /* !CURL_DISABLE_VERBOSE_STRINGS */ 143 144 /* This is the ONLY way to change FTP state! */ 145 static void _ftp_state(struct Curl_easy *data, 146 struct ftp_conn *ftpc, 147 ftpstate newstate 148 #ifdef DEBUGBUILD 149 , int lineno 150 #endif 151 ) 152 { 153 #if defined(CURL_DISABLE_VERBOSE_STRINGS) 154 #ifdef DEBUGBUILD 155 (void)lineno; 156 #endif 157 #else /* CURL_DISABLE_VERBOSE_STRINGS */ 158 if(ftpc->state != newstate) 159 #ifdef DEBUGBUILD 160 CURL_TRC_FTP(data, "[%s] -> [%s] (line %d)", FTP_CSTATE(ftpc), 161 ftp_state_names[newstate], lineno); 162 #else 163 CURL_TRC_FTP(data, "[%s] -> [%s]", FTP_CSTATE(ftpc), 164 ftp_state_names[newstate]); 165 #endif 166 #endif /* !CURL_DISABLE_VERBOSE_STRINGS */ 167 168 ftpc->state = newstate; 169 } 170 171 172 /* Local API functions */ 173 #ifndef DEBUGBUILD 174 #define ftp_state(x,y,z) _ftp_state(x,y,z) 175 #else /* !DEBUGBUILD */ 176 #define ftp_state(x,y,z) _ftp_state(x,y,z,__LINE__) 177 #endif /* DEBUGBUILD */ 178 179 static CURLcode ftp_sendquote(struct Curl_easy *data, 180 struct ftp_conn *ftpc, 181 struct curl_slist *quote); 182 static CURLcode ftp_quit(struct Curl_easy *data, struct ftp_conn *ftpc); 183 static CURLcode ftp_parse_url_path(struct Curl_easy *data, 184 struct ftp_conn *ftpc, 185 struct FTP *ftp); 186 static CURLcode ftp_regular_transfer(struct Curl_easy *data, 187 struct ftp_conn *ftpc, 188 struct FTP *ftp, 189 bool *done); 190 #ifndef CURL_DISABLE_VERBOSE_STRINGS 191 static void ftp_pasv_verbose(struct Curl_easy *data, 192 struct Curl_addrinfo *ai, 193 char *newhost, /* ASCII version */ 194 int port); 195 #endif 196 static CURLcode ftp_state_mdtm(struct Curl_easy *data, 197 struct ftp_conn *ftpc, 198 struct FTP *ftp); 199 static CURLcode ftp_state_quote(struct Curl_easy *data, 200 struct ftp_conn *ftpc, 201 struct FTP *ftp, 202 bool init, ftpstate instate); 203 static CURLcode ftp_nb_type(struct Curl_easy *data, 204 struct ftp_conn *ftpc, 205 struct FTP *ftp, 206 bool ascii, ftpstate newstate); 207 static int ftp_need_type(struct ftp_conn *ftpc, bool ascii); 208 static CURLcode ftp_do(struct Curl_easy *data, bool *done); 209 static CURLcode ftp_done(struct Curl_easy *data, 210 CURLcode, bool premature); 211 static CURLcode ftp_connect(struct Curl_easy *data, bool *done); 212 static CURLcode ftp_disconnect(struct Curl_easy *data, 213 struct connectdata *conn, bool dead_connection); 214 static CURLcode ftp_do_more(struct Curl_easy *data, int *completed); 215 static CURLcode ftp_multi_statemach(struct Curl_easy *data, bool *done); 216 static int ftp_getsock(struct Curl_easy *data, struct connectdata *conn, 217 curl_socket_t *socks); 218 static int ftp_domore_getsock(struct Curl_easy *data, 219 struct connectdata *conn, curl_socket_t *socks); 220 static CURLcode ftp_doing(struct Curl_easy *data, 221 bool *dophase_done); 222 static CURLcode ftp_setup_connection(struct Curl_easy *data, 223 struct connectdata *conn); 224 static CURLcode init_wc_data(struct Curl_easy *data, 225 struct ftp_conn *ftpc, 226 struct FTP *ftp); 227 static CURLcode wc_statemach(struct Curl_easy *data, 228 struct ftp_conn *ftpc, 229 struct FTP *ftp); 230 static void wc_data_dtor(void *ptr); 231 static CURLcode ftp_state_retr(struct Curl_easy *data, 232 struct ftp_conn *ftpc, 233 struct FTP *ftp, 234 curl_off_t filesize); 235 static CURLcode ftp_readresp(struct Curl_easy *data, 236 struct ftp_conn *ftpc, 237 int sockindex, 238 struct pingpong *pp, 239 int *ftpcode, 240 size_t *size); 241 static CURLcode ftp_dophase_done(struct Curl_easy *data, 242 struct ftp_conn *ftpc, 243 struct FTP *ftp, 244 bool connected); 245 246 /* 247 * FTP protocol handler. 248 */ 249 250 const struct Curl_handler Curl_handler_ftp = { 251 "ftp", /* scheme */ 252 ftp_setup_connection, /* setup_connection */ 253 ftp_do, /* do_it */ 254 ftp_done, /* done */ 255 ftp_do_more, /* do_more */ 256 ftp_connect, /* connect_it */ 257 ftp_multi_statemach, /* connecting */ 258 ftp_doing, /* doing */ 259 ftp_getsock, /* proto_getsock */ 260 ftp_getsock, /* doing_getsock */ 261 ftp_domore_getsock, /* domore_getsock */ 262 ZERO_NULL, /* perform_getsock */ 263 ftp_disconnect, /* disconnect */ 264 ZERO_NULL, /* write_resp */ 265 ZERO_NULL, /* write_resp_hd */ 266 ZERO_NULL, /* connection_check */ 267 ZERO_NULL, /* attach connection */ 268 ZERO_NULL, /* follow */ 269 PORT_FTP, /* defport */ 270 CURLPROTO_FTP, /* protocol */ 271 CURLPROTO_FTP, /* family */ 272 PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD | 273 PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP | 274 PROTOPT_WILDCARD /* flags */ 275 }; 276 277 278 #ifdef USE_SSL 279 /* 280 * FTPS protocol handler. 281 */ 282 283 const struct Curl_handler Curl_handler_ftps = { 284 "ftps", /* scheme */ 285 ftp_setup_connection, /* setup_connection */ 286 ftp_do, /* do_it */ 287 ftp_done, /* done */ 288 ftp_do_more, /* do_more */ 289 ftp_connect, /* connect_it */ 290 ftp_multi_statemach, /* connecting */ 291 ftp_doing, /* doing */ 292 ftp_getsock, /* proto_getsock */ 293 ftp_getsock, /* doing_getsock */ 294 ftp_domore_getsock, /* domore_getsock */ 295 ZERO_NULL, /* perform_getsock */ 296 ftp_disconnect, /* disconnect */ 297 ZERO_NULL, /* write_resp */ 298 ZERO_NULL, /* write_resp_hd */ 299 ZERO_NULL, /* connection_check */ 300 ZERO_NULL, /* attach connection */ 301 ZERO_NULL, /* follow */ 302 PORT_FTPS, /* defport */ 303 CURLPROTO_FTPS, /* protocol */ 304 CURLPROTO_FTP, /* family */ 305 PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION | 306 PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */ 307 }; 308 #endif 309 310 static void close_secondarysocket(struct Curl_easy *data, 311 struct ftp_conn *ftpc) 312 { 313 (void)ftpc; 314 CURL_TRC_FTP(data, "[%s] closing DATA connection", FTP_CSTATE(ftpc)); 315 Curl_conn_close(data, SECONDARYSOCKET); 316 Curl_conn_cf_discard_all(data, data->conn, SECONDARYSOCKET); 317 } 318 319 /* 320 * NOTE: back in the old days, we added code in the FTP code that made NOBODY 321 * requests on files respond with headers passed to the client/stdout that 322 * looked like HTTP ones. 323 * 324 * This approach is not elegant, it causes confusion and is error-prone. It is 325 * subject for removal at the next (or at least a future) soname bump. Until 326 * then you can test the effects of the removal by undefining the following 327 * define named CURL_FTP_HTTPSTYLE_HEAD. 328 */ 329 #define CURL_FTP_HTTPSTYLE_HEAD 1 330 331 static void freedirs(struct ftp_conn *ftpc) 332 { 333 if(ftpc->dirs) { 334 int i; 335 for(i = 0; i < ftpc->dirdepth; i++) { 336 free(ftpc->dirs[i]); 337 ftpc->dirs[i] = NULL; 338 } 339 free(ftpc->dirs); 340 ftpc->dirs = NULL; 341 ftpc->dirdepth = 0; 342 } 343 Curl_safefree(ftpc->file); 344 345 /* no longer of any use */ 346 Curl_safefree(ftpc->newhost); 347 } 348 349 #ifdef CURL_PREFER_LF_LINEENDS 350 /* 351 * Lineend Conversions 352 * On ASCII transfers, e.g. directory listings, we might get lines 353 * ending in '\r\n' and we prefer just '\n'. 354 * We might also get a lonely '\r' which we convert into a '\n'. 355 */ 356 struct ftp_cw_lc_ctx { 357 struct Curl_cwriter super; 358 bool newline_pending; 359 }; 360 361 static CURLcode ftp_cw_lc_write(struct Curl_easy *data, 362 struct Curl_cwriter *writer, int type, 363 const char *buf, size_t blen) 364 { 365 static const char nl = '\n'; 366 struct ftp_cw_lc_ctx *ctx = writer->ctx; 367 struct ftp_conn *ftpc = Curl_conn_meta_get(data->conn, CURL_META_FTP_CONN); 368 369 if(!ftpc) 370 return CURLE_FAILED_INIT; 371 372 if(!(type & CLIENTWRITE_BODY) || ftpc->transfertype != 'A') 373 return Curl_cwriter_write(data, writer->next, type, buf, blen); 374 375 /* ASCII mode BODY data, convert lineends */ 376 while(blen) { 377 /* do not pass EOS when writing parts */ 378 int chunk_type = (type & ~CLIENTWRITE_EOS); 379 const char *cp; 380 size_t chunk_len; 381 CURLcode result; 382 383 if(ctx->newline_pending) { 384 if(buf[0] != '\n') { 385 /* previous chunk ended in '\r' and we do not see a '\n' in this one, 386 * need to write a newline. */ 387 result = Curl_cwriter_write(data, writer->next, chunk_type, &nl, 1); 388 if(result) 389 return result; 390 } 391 /* either we just wrote the newline or it is part of the next 392 * chunk of bytes we write. */ 393 ctx->newline_pending = FALSE; 394 } 395 396 cp = memchr(buf, '\r', blen); 397 if(!cp) 398 break; 399 400 /* write the bytes before the '\r', excluding the '\r' */ 401 chunk_len = cp - buf; 402 if(chunk_len) { 403 result = Curl_cwriter_write(data, writer->next, chunk_type, 404 buf, chunk_len); 405 if(result) 406 return result; 407 } 408 /* skip the '\r', we now have a newline pending */ 409 buf = cp + 1; 410 blen = blen - chunk_len - 1; 411 ctx->newline_pending = TRUE; 412 } 413 414 /* Any remaining data does not contain a '\r' */ 415 if(blen) { 416 DEBUGASSERT(!ctx->newline_pending); 417 return Curl_cwriter_write(data, writer->next, type, buf, blen); 418 } 419 else if(type & CLIENTWRITE_EOS) { 420 /* EndOfStream, if we have a trailing cr, now is the time to write it */ 421 if(ctx->newline_pending) { 422 ctx->newline_pending = FALSE; 423 return Curl_cwriter_write(data, writer->next, type, &nl, 1); 424 } 425 /* Always pass on the EOS type indicator */ 426 return Curl_cwriter_write(data, writer->next, type, buf, 0); 427 } 428 return CURLE_OK; 429 } 430 431 static const struct Curl_cwtype ftp_cw_lc = { 432 "ftp-lineconv", 433 NULL, 434 Curl_cwriter_def_init, 435 ftp_cw_lc_write, 436 Curl_cwriter_def_close, 437 sizeof(struct ftp_cw_lc_ctx) 438 }; 439 440 #endif /* CURL_PREFER_LF_LINEENDS */ 441 /*********************************************************************** 442 * 443 * ftp_check_ctrl_on_data_wait() 444 * 445 */ 446 static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data, 447 struct ftp_conn *ftpc) 448 { 449 struct connectdata *conn = data->conn; 450 curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET]; 451 struct pingpong *pp = &ftpc->pp; 452 ssize_t nread; 453 int ftpcode; 454 bool response = FALSE; 455 456 /* First check whether there is a cached response from server */ 457 if(curlx_dyn_len(&pp->recvbuf) && (*curlx_dyn_ptr(&pp->recvbuf) > '3')) { 458 /* Data connection could not be established, let's return */ 459 infof(data, "There is negative response in cache while serv connect"); 460 (void)Curl_GetFTPResponse(data, &nread, &ftpcode); 461 return CURLE_FTP_ACCEPT_FAILED; 462 } 463 464 if(pp->overflow) 465 /* there is pending control data still in the buffer to read */ 466 response = TRUE; 467 else { 468 int socketstate = Curl_socket_check(ctrl_sock, CURL_SOCKET_BAD, 469 CURL_SOCKET_BAD, 0); 470 /* see if the connection request is already here */ 471 switch(socketstate) { 472 case -1: /* error */ 473 /* let's die here */ 474 failf(data, "Error while waiting for server connect"); 475 return CURLE_FTP_ACCEPT_FAILED; 476 default: 477 if(socketstate & CURL_CSELECT_IN) 478 response = TRUE; 479 break; 480 } 481 } 482 483 if(response) { 484 infof(data, "Ctrl conn has data while waiting for data conn"); 485 if(pp->overflow > 3) { 486 const char *r = curlx_dyn_ptr(&pp->recvbuf); 487 488 DEBUGASSERT((pp->overflow + pp->nfinal) <= 489 curlx_dyn_len(&pp->recvbuf)); 490 /* move over the most recently handled response line */ 491 r += pp->nfinal; 492 493 if(LASTLINE(r)) { 494 curl_off_t status; 495 if(!curlx_str_number(&r, &status, 999) && (status == 226)) { 496 /* funny timing situation where we get the final message on the 497 control connection before traffic on the data connection has been 498 noticed. Leave the 226 in there and use this as a trigger to read 499 the data socket. */ 500 infof(data, "Got 226 before data activity"); 501 return CURLE_OK; 502 } 503 } 504 } 505 506 (void)Curl_GetFTPResponse(data, &nread, &ftpcode); 507 508 infof(data, "FTP code: %03d", ftpcode); 509 510 if(ftpcode/100 > 3) 511 return CURLE_FTP_ACCEPT_FAILED; 512 513 return CURLE_WEIRD_SERVER_REPLY; 514 } 515 516 return CURLE_OK; 517 } 518 519 /*********************************************************************** 520 * 521 * ftp_initiate_transfer() 522 * 523 * After connection from server is accepted this function is called to 524 * setup transfer parameters and initiate the data transfer. 525 * 526 */ 527 static CURLcode ftp_initiate_transfer(struct Curl_easy *data, 528 struct ftp_conn *ftpc) 529 { 530 CURLcode result = CURLE_OK; 531 bool connected; 532 533 CURL_TRC_FTP(data, "ftp_initiate_transfer()"); 534 result = Curl_conn_connect(data, SECONDARYSOCKET, TRUE, &connected); 535 if(result || !connected) 536 return result; 537 538 if(ftpc->state_saved == FTP_STOR) { 539 /* When we know we are uploading a specified file, we can get the file 540 size prior to the actual upload. */ 541 Curl_pgrsSetUploadSize(data, data->state.infilesize); 542 543 /* set the SO_SNDBUF for the secondary socket for those who need it */ 544 Curl_sndbuf_init(data->conn->sock[SECONDARYSOCKET]); 545 546 /* FTP upload, shutdown DATA, ignore shutdown errors, as we rely 547 * on the server response on the CONTROL connection. */ 548 Curl_xfer_setup2(data, CURL_XFER_SEND, -1, TRUE, TRUE); 549 } 550 else { 551 /* FTP download, shutdown, do not ignore errors */ 552 Curl_xfer_setup2(data, CURL_XFER_RECV, 553 ftpc->retr_size_saved, TRUE, FALSE); 554 } 555 556 ftpc->pp.pending_resp = TRUE; /* expect server response */ 557 ftp_state(data, ftpc, FTP_STOP); 558 559 return CURLE_OK; 560 } 561 562 static bool ftp_endofresp(struct Curl_easy *data, struct connectdata *conn, 563 const char *line, size_t len, int *code) 564 { 565 curl_off_t status; 566 (void)data; 567 (void)conn; 568 569 if((len > 3) && LASTLINE(line) && !curlx_str_number(&line, &status, 999)) { 570 *code = (int)status; 571 return TRUE; 572 } 573 574 return FALSE; 575 } 576 577 static CURLcode ftp_readresp(struct Curl_easy *data, 578 struct ftp_conn *ftpc, 579 int sockindex, 580 struct pingpong *pp, 581 int *ftpcode, /* return the ftp-code if done */ 582 size_t *size) /* size of the response */ 583 { 584 int code; 585 CURLcode result = Curl_pp_readresp(data, sockindex, pp, &code, size); 586 587 #ifdef HAVE_GSSAPI 588 { 589 struct connectdata *conn = data->conn; 590 char * const buf = curlx_dyn_ptr(&ftpc->pp.recvbuf); 591 592 /* handle the security-oriented responses 6xx ***/ 593 switch(code) { 594 case 631: 595 code = Curl_sec_read_msg(data, conn, buf, PROT_SAFE); 596 break; 597 case 632: 598 code = Curl_sec_read_msg(data, conn, buf, PROT_PRIVATE); 599 break; 600 case 633: 601 code = Curl_sec_read_msg(data, conn, buf, PROT_CONFIDENTIAL); 602 break; 603 default: 604 /* normal ftp stuff we pass through! */ 605 break; 606 } 607 } 608 #endif 609 610 /* store the latest code for later retrieval, except during shutdown */ 611 if(!ftpc->shutdown) 612 data->info.httpcode = code; 613 614 if(ftpcode) 615 *ftpcode = code; 616 617 if(421 == code) { 618 /* 421 means "Service not available, closing control connection." and FTP 619 * servers use it to signal that idle session timeout has been exceeded. 620 * If we ignored the response, it could end up hanging in some cases. 621 * 622 * This response code can come at any point so having it treated 623 * generically is a good idea. 624 */ 625 infof(data, "We got a 421 - timeout"); 626 ftp_state(data, ftpc, FTP_STOP); 627 return CURLE_OPERATION_TIMEDOUT; 628 } 629 630 return result; 631 } 632 633 /* --- parse FTP server responses --- */ 634 635 /* 636 * Curl_GetFTPResponse() is a BLOCKING function to read the full response 637 * from a server after a command. 638 * 639 */ 640 641 CURLcode Curl_GetFTPResponse(struct Curl_easy *data, 642 ssize_t *nreadp, /* return number of bytes read */ 643 int *ftpcode) /* return the ftp-code */ 644 { 645 /* 646 * We cannot read just one byte per read() and then go back to select() as 647 * the OpenSSL read() does not grok that properly. 648 * 649 * Alas, read as much as possible, split up into lines, use the ending 650 * line in a response or continue reading. */ 651 652 struct connectdata *conn = data->conn; 653 curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; 654 CURLcode result = CURLE_OK; 655 struct ftp_conn *ftpc = Curl_conn_meta_get(data->conn, CURL_META_FTP_CONN); 656 struct pingpong *pp = &ftpc->pp; 657 size_t nread; 658 int cache_skip = 0; 659 int value_to_be_ignored = 0; 660 661 CURL_TRC_FTP(data, "getFTPResponse start"); 662 *nreadp = 0; 663 if(ftpcode) 664 *ftpcode = 0; /* 0 for errors */ 665 else 666 /* make the pointer point to something for the rest of this function */ 667 ftpcode = &value_to_be_ignored; 668 669 if(!ftpc) 670 return CURLE_FAILED_INIT; 671 672 while(!*ftpcode && !result) { 673 /* check and reset timeout value every lap */ 674 timediff_t timeout = Curl_pp_state_timeout(data, pp, FALSE); 675 timediff_t interval_ms; 676 677 if(timeout <= 0) { 678 failf(data, "FTP response timeout"); 679 return CURLE_OPERATION_TIMEDOUT; /* already too little time */ 680 } 681 682 interval_ms = 1000; /* use 1 second timeout intervals */ 683 if(timeout < interval_ms) 684 interval_ms = timeout; 685 686 /* 687 * Since this function is blocking, we need to wait here for input on the 688 * connection and only then we call the response reading function. We do 689 * timeout at least every second to make the timeout check run. 690 * 691 * A caution here is that the ftp_readresp() function has a cache that may 692 * contain pieces of a response from the previous invoke and we need to 693 * make sure we do not just wait for input while there is unhandled data in 694 * that cache. But also, if the cache is there, we call ftp_readresp() and 695 * the cache was not good enough to continue we must not just busy-loop 696 * around this function. 697 * 698 */ 699 700 if(curlx_dyn_len(&pp->recvbuf) && (cache_skip < 2)) { 701 /* 702 * There is a cache left since before. We then skipping the wait for 703 * socket action, unless this is the same cache like the previous round 704 * as then the cache was deemed not enough to act on and we then need to 705 * wait for more data anyway. 706 */ 707 } 708 else if(!Curl_conn_data_pending(data, FIRSTSOCKET)) { 709 curl_socket_t wsock = Curl_pp_needs_flush(data, pp) ? 710 sockfd : CURL_SOCKET_BAD; 711 int ev = Curl_socket_check(sockfd, CURL_SOCKET_BAD, wsock, interval_ms); 712 if(ev < 0) { 713 failf(data, "FTP response aborted due to select/poll error: %d", 714 SOCKERRNO); 715 return CURLE_RECV_ERROR; 716 } 717 else if(ev == 0) { 718 if(Curl_pgrsUpdate(data)) 719 return CURLE_ABORTED_BY_CALLBACK; 720 continue; /* just continue in our loop for the timeout duration */ 721 } 722 } 723 724 if(Curl_pp_needs_flush(data, pp)) { 725 result = Curl_pp_flushsend(data, pp); 726 if(result) 727 break; 728 } 729 730 result = ftp_readresp(data, ftpc, FIRSTSOCKET, pp, ftpcode, &nread); 731 if(result) 732 break; 733 734 if(!nread && curlx_dyn_len(&pp->recvbuf)) 735 /* bump cache skip counter as on repeated skips we must wait for more 736 data */ 737 cache_skip++; 738 else 739 /* when we got data or there is no cache left, we reset the cache skip 740 counter */ 741 cache_skip = 0; 742 743 *nreadp += nread; 744 745 } /* while there is buffer left and loop is requested */ 746 747 pp->pending_resp = FALSE; 748 CURL_TRC_FTP(data, "getFTPResponse -> result=%d, nread=%zd, ftpcode=%d", 749 result, *nreadp, *ftpcode); 750 751 return result; 752 } 753 754 static CURLcode ftp_state_user(struct Curl_easy *data, 755 struct ftp_conn *ftpc, 756 struct connectdata *conn) 757 { 758 CURLcode result = Curl_pp_sendf(data, &ftpc->pp, "USER %s", 759 conn->user ? conn->user : ""); 760 if(!result) { 761 ftpc->ftp_trying_alternative = FALSE; 762 ftp_state(data, ftpc, FTP_USER); 763 } 764 return result; 765 } 766 767 static CURLcode ftp_state_pwd(struct Curl_easy *data, 768 struct ftp_conn *ftpc) 769 { 770 CURLcode result; 771 #ifdef DEBUGBUILD 772 if(!data->id && getenv("CURL_FTP_PWD_STOP")) 773 return CURLE_OK; 774 #endif 775 result = Curl_pp_sendf(data, &ftpc->pp, "%s", "PWD"); 776 if(!result) 777 ftp_state(data, ftpc, FTP_PWD); 778 779 return result; 780 } 781 782 /* For the FTP "protocol connect" and "doing" phases only */ 783 static int ftp_getsock(struct Curl_easy *data, 784 struct connectdata *conn, 785 curl_socket_t *socks) 786 { 787 struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN); 788 return ftpc ? Curl_pp_getsock(data, &ftpc->pp, socks) : GETSOCK_BLANK; 789 } 790 791 /* For the FTP "DO_MORE" phase only */ 792 static int ftp_domore_getsock(struct Curl_easy *data, 793 struct connectdata *conn, curl_socket_t *socks) 794 { 795 struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN); 796 (void)data; 797 798 if(!ftpc) 799 return GETSOCK_BLANK; 800 801 /* When in DO_MORE state, we could be either waiting for us to connect to a 802 * remote site, or we could wait for that site to connect to us. Or just 803 * handle ordinary commands. 804 */ 805 CURL_TRC_FTP(data, "[%s] ftp_domore_getsock()", FTP_CSTATE(ftpc)); 806 807 if(FTP_STOP == ftpc->state) { 808 /* if stopped and still in this state, then we are also waiting for a 809 connect on the secondary connection */ 810 DEBUGASSERT(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD || 811 (conn->cfilter[SECONDARYSOCKET] && 812 !Curl_conn_is_connected(conn, SECONDARYSOCKET))); 813 socks[0] = conn->sock[FIRSTSOCKET]; 814 /* An unconnected SECONDARY will add its socket by itself 815 * via its adjust_pollset() */ 816 return GETSOCK_READSOCK(0); 817 } 818 return Curl_pp_getsock(data, &ftpc->pp, socks); 819 } 820 821 /* This is called after the FTP_QUOTE state is passed. 822 823 ftp_state_cwd() sends the range of CWD commands to the server to change to 824 the correct directory. It may also need to send MKD commands to create 825 missing ones, if that option is enabled. 826 */ 827 static CURLcode ftp_state_cwd(struct Curl_easy *data, 828 struct ftp_conn *ftpc, 829 struct FTP *ftp) 830 { 831 CURLcode result = CURLE_OK; 832 833 if(ftpc->cwddone) 834 /* already done and fine */ 835 result = ftp_state_mdtm(data, ftpc, ftp); 836 else { 837 /* FTPFILE_NOCWD with full path: expect ftpc->cwddone! */ 838 DEBUGASSERT((data->set.ftp_filemethod != FTPFILE_NOCWD) || 839 !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')); 840 841 ftpc->count2 = 0; /* count2 counts failed CWDs */ 842 843 if(data->conn->bits.reuse && ftpc->entrypath && 844 /* no need to go to entrypath when we have an absolute path */ 845 !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) { 846 /* This is a reused connection. Since we change directory to where the 847 transfer is taking place, we must first get back to the original dir 848 where we ended up after login: */ 849 ftpc->cwdcount = 0; /* we count this as the first path, then we add one 850 for all upcoming ones in the ftp->dirs[] array */ 851 result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", ftpc->entrypath); 852 if(!result) 853 ftp_state(data, ftpc, FTP_CWD); 854 } 855 else { 856 if(ftpc->dirdepth) { 857 ftpc->cwdcount = 1; 858 /* issue the first CWD, the rest is sent when the CWD responses are 859 received... */ 860 result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", 861 ftpc->dirs[ftpc->cwdcount -1]); 862 if(!result) 863 ftp_state(data, ftpc, FTP_CWD); 864 } 865 else { 866 /* No CWD necessary */ 867 result = ftp_state_mdtm(data, ftpc, ftp); 868 } 869 } 870 } 871 return result; 872 } 873 874 typedef enum { 875 EPRT, 876 PORT, 877 DONE 878 } ftpport; 879 880 static CURLcode ftp_state_use_port(struct Curl_easy *data, 881 struct ftp_conn *ftpc, 882 ftpport fcmd) /* start with this */ 883 { 884 CURLcode result = CURLE_FTP_PORT_FAILED; 885 struct connectdata *conn = data->conn; 886 curl_socket_t portsock = CURL_SOCKET_BAD; 887 char myhost[MAX_IPADR_LEN + 1] = ""; 888 889 struct Curl_sockaddr_storage ss; 890 struct Curl_addrinfo *res, *ai; 891 curl_socklen_t sslen; 892 char hbuf[NI_MAXHOST]; 893 struct sockaddr *sa = (struct sockaddr *)&ss; 894 struct sockaddr_in * const sa4 = (void *)sa; 895 #ifdef USE_IPV6 896 struct sockaddr_in6 * const sa6 = (void *)sa; 897 #endif 898 static const char mode[][5] = { "EPRT", "PORT" }; 899 int error; 900 char *host = NULL; 901 char *string_ftpport = data->set.str[STRING_FTPPORT]; 902 struct Curl_dns_entry *dns_entry = NULL; 903 unsigned short port_min = 0; 904 unsigned short port_max = 0; 905 unsigned short port; 906 bool possibly_non_local = TRUE; 907 char buffer[STRERROR_LEN]; 908 char *addr = NULL; 909 size_t addrlen = 0; 910 char ipstr[50]; 911 912 /* Step 1, figure out what is requested, 913 * accepted format : 914 * (ipv4|ipv6|domain|interface)?(:port(-range)?)? 915 */ 916 917 if(data->set.str[STRING_FTPPORT] && 918 (strlen(data->set.str[STRING_FTPPORT]) > 1)) { 919 char *ip_end = NULL; 920 921 #ifdef USE_IPV6 922 if(*string_ftpport == '[') { 923 /* [ipv6]:port(-range) */ 924 char *ip_start = string_ftpport + 1; 925 ip_end = strchr(ip_start, ']'); 926 if(ip_end) { 927 addrlen = ip_end - ip_start; 928 addr = ip_start; 929 } 930 } 931 else 932 #endif 933 if(*string_ftpport == ':') { 934 /* :port */ 935 ip_end = string_ftpport; 936 } 937 else { 938 ip_end = strchr(string_ftpport, ':'); 939 addr = string_ftpport; 940 if(ip_end) { 941 /* either ipv6 or (ipv4|domain|interface):port(-range) */ 942 addrlen = ip_end - string_ftpport; 943 #ifdef USE_IPV6 944 if(curlx_inet_pton(AF_INET6, string_ftpport, &sa6->sin6_addr) == 1) { 945 /* ipv6 */ 946 port_min = port_max = 0; 947 ip_end = NULL; /* this got no port ! */ 948 } 949 #endif 950 } 951 else 952 /* ipv4|interface */ 953 addrlen = strlen(string_ftpport); 954 } 955 956 /* parse the port */ 957 if(ip_end) { 958 const char *portp = strchr(ip_end, ':'); 959 if(portp) { 960 curl_off_t start; 961 curl_off_t end; 962 portp++; 963 if(!curlx_str_number(&portp, &start, 0xffff)) { 964 /* got the first number */ 965 port_min = (unsigned short)start; 966 if(!curlx_str_single(&portp, '-')) { 967 /* got the dash */ 968 if(!curlx_str_number(&portp, &end, 0xffff)) 969 /* got the second number */ 970 port_max = (unsigned short)end; 971 } 972 } 973 else 974 port_max = port_min; 975 } 976 } 977 978 /* correct errors like: 979 * :1234-1230 980 * :-4711, in this case port_min is (unsigned)-1, 981 * therefore port_min > port_max for all cases 982 * but port_max = (unsigned)-1 983 */ 984 if(port_min > port_max) 985 port_min = port_max = 0; 986 987 if(addrlen) { 988 const struct Curl_sockaddr_ex *remote_addr = 989 Curl_conn_get_remote_addr(data, FIRSTSOCKET); 990 991 DEBUGASSERT(remote_addr); 992 if(!remote_addr) 993 goto out; 994 DEBUGASSERT(addr); 995 if(addrlen >= sizeof(ipstr)) 996 goto out; 997 memcpy(ipstr, addr, addrlen); 998 ipstr[addrlen] = 0; 999 1000 /* attempt to get the address of the given interface name */ 1001 switch(Curl_if2ip(remote_addr->family, 1002 #ifdef USE_IPV6 1003 Curl_ipv6_scope(&remote_addr->curl_sa_addr), 1004 conn->scope_id, 1005 #endif 1006 ipstr, hbuf, sizeof(hbuf))) { 1007 case IF2IP_NOT_FOUND: 1008 /* not an interface, use the given string as hostname instead */ 1009 host = ipstr; 1010 break; 1011 case IF2IP_AF_NOT_SUPPORTED: 1012 goto out; 1013 case IF2IP_FOUND: 1014 host = hbuf; /* use the hbuf for hostname */ 1015 break; 1016 } 1017 } 1018 else 1019 /* there was only a port(-range) given, default the host */ 1020 host = NULL; 1021 } /* data->set.ftpport */ 1022 1023 if(!host) { 1024 const char *r; 1025 /* not an interface and not a hostname, get default by extracting 1026 the IP from the control connection */ 1027 sslen = sizeof(ss); 1028 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { 1029 failf(data, "getsockname() failed: %s", 1030 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); 1031 goto out; 1032 } 1033 switch(sa->sa_family) { 1034 #ifdef USE_IPV6 1035 case AF_INET6: 1036 r = curlx_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf)); 1037 break; 1038 #endif 1039 default: 1040 r = curlx_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf)); 1041 break; 1042 } 1043 if(!r) { 1044 goto out; 1045 } 1046 host = hbuf; /* use this hostname */ 1047 possibly_non_local = FALSE; /* we know it is local now */ 1048 } 1049 1050 /* resolv ip/host to ip */ 1051 res = NULL; 1052 result = Curl_resolv_blocking(data, host, 0, conn->ip_version, &dns_entry); 1053 if(!result) { 1054 DEBUGASSERT(dns_entry); 1055 res = dns_entry->addr; 1056 } 1057 1058 if(!res) { 1059 failf(data, "failed to resolve the address provided to PORT: %s", host); 1060 goto out; 1061 } 1062 1063 host = NULL; 1064 1065 /* step 2, create a socket for the requested address */ 1066 error = 0; 1067 for(ai = res; ai; ai = ai->ai_next) { 1068 if(Curl_socket_open(data, ai, NULL, 1069 Curl_conn_get_transport(data, conn), &portsock)) { 1070 error = SOCKERRNO; 1071 continue; 1072 } 1073 break; 1074 } 1075 if(!ai) { 1076 failf(data, "socket failure: %s", 1077 Curl_strerror(error, buffer, sizeof(buffer))); 1078 goto out; 1079 } 1080 CURL_TRC_FTP(data, "[%s] ftp_state_use_port(), opened socket", 1081 FTP_CSTATE(ftpc)); 1082 1083 /* step 3, bind to a suitable local address */ 1084 1085 memcpy(sa, ai->ai_addr, ai->ai_addrlen); 1086 sslen = ai->ai_addrlen; 1087 1088 for(port = port_min; port <= port_max;) { 1089 if(sa->sa_family == AF_INET) 1090 sa4->sin_port = htons(port); 1091 #ifdef USE_IPV6 1092 else 1093 sa6->sin6_port = htons(port); 1094 #endif 1095 /* Try binding the given address. */ 1096 if(bind(portsock, sa, sslen) ) { 1097 /* It failed. */ 1098 error = SOCKERRNO; 1099 if(possibly_non_local && (error == SOCKEADDRNOTAVAIL)) { 1100 /* The requested bind address is not local. Use the address used for 1101 * the control connection instead and restart the port loop 1102 */ 1103 infof(data, "bind(port=%hu) on non-local address failed: %s", port, 1104 Curl_strerror(error, buffer, sizeof(buffer))); 1105 1106 sslen = sizeof(ss); 1107 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { 1108 failf(data, "getsockname() failed: %s", 1109 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); 1110 goto out; 1111 } 1112 port = port_min; 1113 possibly_non_local = FALSE; /* do not try this again */ 1114 continue; 1115 } 1116 if(error != SOCKEADDRINUSE && error != SOCKEACCES) { 1117 failf(data, "bind(port=%hu) failed: %s", port, 1118 Curl_strerror(error, buffer, sizeof(buffer))); 1119 goto out; 1120 } 1121 } 1122 else 1123 break; 1124 1125 port++; 1126 } 1127 1128 /* maybe all ports were in use already */ 1129 if(port > port_max) { 1130 failf(data, "bind() failed, we ran out of ports"); 1131 goto out; 1132 } 1133 1134 /* get the name again after the bind() so that we can extract the 1135 port number it uses now */ 1136 sslen = sizeof(ss); 1137 if(getsockname(portsock, sa, &sslen)) { 1138 failf(data, "getsockname() failed: %s", 1139 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); 1140 goto out; 1141 } 1142 CURL_TRC_FTP(data, "[%s] ftp_state_use_port(), socket bound to port %d", 1143 FTP_CSTATE(ftpc), port); 1144 1145 /* step 4, listen on the socket */ 1146 1147 if(listen(portsock, 1)) { 1148 failf(data, "socket failure: %s", 1149 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); 1150 goto out; 1151 } 1152 CURL_TRC_FTP(data, "[%s] ftp_state_use_port(), listening on %d", 1153 FTP_CSTATE(ftpc), port); 1154 1155 /* step 5, send the proper FTP command */ 1156 1157 /* get a plain printable version of the numerical address to work with 1158 below */ 1159 Curl_printable_address(ai, myhost, sizeof(myhost)); 1160 1161 #ifdef USE_IPV6 1162 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6) 1163 /* EPRT is disabled but we are connected to an IPv6 host, so we ignore the 1164 request and enable EPRT again! */ 1165 conn->bits.ftp_use_eprt = TRUE; 1166 #endif 1167 1168 for(; fcmd != DONE; fcmd++) { 1169 1170 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd)) 1171 /* if disabled, goto next */ 1172 continue; 1173 1174 if((PORT == fcmd) && sa->sa_family != AF_INET) 1175 /* PORT is IPv4 only */ 1176 continue; 1177 1178 switch(sa->sa_family) { 1179 case AF_INET: 1180 port = ntohs(sa4->sin_port); 1181 break; 1182 #ifdef USE_IPV6 1183 case AF_INET6: 1184 port = ntohs(sa6->sin6_port); 1185 break; 1186 #endif 1187 default: 1188 continue; /* might as well skip this */ 1189 } 1190 1191 if(EPRT == fcmd) { 1192 /* 1193 * Two fine examples from RFC2428; 1194 * 1195 * EPRT |1|132.235.1.2|6275| 1196 * 1197 * EPRT |2|1080::8:800:200C:417A|5282| 1198 */ 1199 1200 result = Curl_pp_sendf(data, &ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd], 1201 sa->sa_family == AF_INET ? 1 : 2, 1202 myhost, port); 1203 if(result) { 1204 failf(data, "Failure sending EPRT command: %s", 1205 curl_easy_strerror(result)); 1206 goto out; 1207 } 1208 break; 1209 } 1210 if(PORT == fcmd) { 1211 /* large enough for [IP address],[num],[num] */ 1212 char target[sizeof(myhost) + 20]; 1213 char *source = myhost; 1214 char *dest = target; 1215 1216 /* translate x.x.x.x to x,x,x,x */ 1217 while(*source) { 1218 if(*source == '.') 1219 *dest = ','; 1220 else 1221 *dest = *source; 1222 dest++; 1223 source++; 1224 } 1225 *dest = 0; 1226 msnprintf(dest, 20, ",%d,%d", (int)(port >> 8), (int)(port & 0xff)); 1227 1228 result = Curl_pp_sendf(data, &ftpc->pp, "%s %s", mode[fcmd], target); 1229 if(result) { 1230 failf(data, "Failure sending PORT command: %s", 1231 curl_easy_strerror(result)); 1232 goto out; 1233 } 1234 break; 1235 } 1236 } 1237 1238 /* store which command was sent */ 1239 ftpc->count1 = fcmd; 1240 ftp_state(data, ftpc, FTP_PORT); 1241 1242 /* Replace any filter on SECONDARY with one listening on this socket */ 1243 result = Curl_conn_tcp_listen_set(data, conn, SECONDARYSOCKET, &portsock); 1244 if(!result) 1245 portsock = CURL_SOCKET_BAD; /* now held in filter */ 1246 1247 out: 1248 /* If we looked up a dns_entry, now is the time to safely release it */ 1249 if(dns_entry) 1250 Curl_resolv_unlink(data, &dns_entry); 1251 if(result) { 1252 ftp_state(data, ftpc, FTP_STOP); 1253 } 1254 else { 1255 /* successfully setup the list socket filter. Do we need more? */ 1256 if(conn->bits.ftp_use_data_ssl && data->set.ftp_use_port && 1257 !Curl_conn_is_ssl(conn, SECONDARYSOCKET)) { 1258 result = Curl_ssl_cfilter_add(data, conn, SECONDARYSOCKET); 1259 } 1260 data->conn->bits.do_more = FALSE; 1261 Curl_pgrsTime(data, TIMER_STARTACCEPT); 1262 Curl_expire(data, (data->set.accepttimeout > 0) ? 1263 data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, 1264 EXPIRE_FTP_ACCEPT); 1265 } 1266 if(portsock != CURL_SOCKET_BAD) 1267 Curl_socket_close(data, conn, portsock); 1268 return result; 1269 } 1270 1271 static CURLcode ftp_state_use_pasv(struct Curl_easy *data, 1272 struct ftp_conn *ftpc, 1273 struct connectdata *conn) 1274 { 1275 CURLcode result = CURLE_OK; 1276 /* 1277 Here's the executive summary on what to do: 1278 1279 PASV is RFC959, expect: 1280 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2) 1281 1282 LPSV is RFC1639, expect: 1283 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2) 1284 1285 EPSV is RFC2428, expect: 1286 229 Entering Extended Passive Mode (|||port|) 1287 1288 */ 1289 1290 static const char mode[][5] = { "EPSV", "PASV" }; 1291 int modeoff; 1292 1293 #ifdef PF_INET6 1294 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6) 1295 /* EPSV is disabled but we are connected to an IPv6 host, so we ignore the 1296 request and enable EPSV again! */ 1297 conn->bits.ftp_use_epsv = TRUE; 1298 #endif 1299 1300 modeoff = conn->bits.ftp_use_epsv ? 0 : 1; 1301 1302 result = Curl_pp_sendf(data, &ftpc->pp, "%s", mode[modeoff]); 1303 if(!result) { 1304 ftpc->count1 = modeoff; 1305 ftp_state(data, ftpc, FTP_PASV); 1306 infof(data, "Connect data stream passively"); 1307 } 1308 return result; 1309 } 1310 1311 /* 1312 * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc. 1313 * 1314 * REST is the last command in the chain of commands when a "head"-like 1315 * request is made. Thus, if an actual transfer is to be made this is where we 1316 * take off for real. 1317 */ 1318 static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data, 1319 struct ftp_conn *ftpc, 1320 struct FTP *ftp) 1321 { 1322 CURLcode result = CURLE_OK; 1323 struct connectdata *conn = data->conn; 1324 1325 if(ftp->transfer != PPTRANSFER_BODY) { 1326 /* does not transfer any data */ 1327 1328 /* still possibly do PRE QUOTE jobs */ 1329 ftp_state(data, ftpc, FTP_RETR_PREQUOTE); 1330 result = ftp_state_quote(data, ftpc, ftp, TRUE, FTP_RETR_PREQUOTE); 1331 } 1332 else if(data->set.ftp_use_port) { 1333 /* We have chosen to use the PORT (or similar) command */ 1334 result = ftp_state_use_port(data, ftpc, EPRT); 1335 } 1336 else { 1337 /* We have chosen (this is default) to use the PASV (or similar) command */ 1338 if(data->set.ftp_use_pret) { 1339 /* The user has requested that we send a PRET command 1340 to prepare the server for the upcoming PASV */ 1341 if(!ftpc->file) 1342 result = Curl_pp_sendf(data, &ftpc->pp, "PRET %s", 1343 data->set.str[STRING_CUSTOMREQUEST] ? 1344 data->set.str[STRING_CUSTOMREQUEST] : 1345 (data->state.list_only ? "NLST" : "LIST")); 1346 else if(data->state.upload) 1347 result = Curl_pp_sendf(data, &ftpc->pp, "PRET STOR %s", ftpc->file); 1348 else 1349 result = Curl_pp_sendf(data, &ftpc->pp, "PRET RETR %s", ftpc->file); 1350 if(!result) 1351 ftp_state(data, ftpc, FTP_PRET); 1352 } 1353 else 1354 result = ftp_state_use_pasv(data, ftpc, conn); 1355 } 1356 return result; 1357 } 1358 1359 static CURLcode ftp_state_rest(struct Curl_easy *data, 1360 struct ftp_conn *ftpc, 1361 struct FTP *ftp) 1362 { 1363 CURLcode result = CURLE_OK; 1364 1365 if((ftp->transfer != PPTRANSFER_BODY) && ftpc->file) { 1366 /* if a "head"-like request is being made (on a file) */ 1367 1368 /* Determine if server can respond to REST command and therefore 1369 whether it supports range */ 1370 result = Curl_pp_sendf(data, &ftpc->pp, "REST %d", 0); 1371 if(!result) 1372 ftp_state(data, ftpc, FTP_REST); 1373 } 1374 else 1375 result = ftp_state_prepare_transfer(data, ftpc, ftp); 1376 1377 return result; 1378 } 1379 1380 static CURLcode ftp_state_size(struct Curl_easy *data, 1381 struct ftp_conn *ftpc, 1382 struct FTP *ftp) 1383 { 1384 CURLcode result = CURLE_OK; 1385 1386 if((ftp->transfer == PPTRANSFER_INFO) && ftpc->file) { 1387 /* if a "head"-like request is being made (on a file) */ 1388 1389 /* we know ftpc->file is a valid pointer to a filename */ 1390 result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file); 1391 if(!result) 1392 ftp_state(data, ftpc, FTP_SIZE); 1393 } 1394 else 1395 result = ftp_state_rest(data, ftpc, ftp); 1396 1397 return result; 1398 } 1399 1400 static CURLcode ftp_state_list(struct Curl_easy *data, 1401 struct ftp_conn *ftpc, 1402 struct FTP *ftp) 1403 { 1404 CURLcode result = CURLE_OK; 1405 1406 /* If this output is to be machine-parsed, the NLST command might be better 1407 to use, since the LIST command output is not specified or standard in any 1408 way. It has turned out that the NLST list output is not the same on all 1409 servers either... */ 1410 1411 /* 1412 if FTPFILE_NOCWD was specified, we should add the path 1413 as argument for the LIST / NLST / or custom command. 1414 Whether the server will support this, is uncertain. 1415 1416 The other ftp_filemethods will CWD into dir/dir/ first and 1417 then just do LIST (in that case: nothing to do here) 1418 */ 1419 char *lstArg = NULL; 1420 char *cmd; 1421 1422 if((data->set.ftp_filemethod == FTPFILE_NOCWD) && ftp->path) { 1423 /* url-decode before evaluation: e.g. paths starting/ending with %2f */ 1424 const char *slashPos = NULL; 1425 char *rawPath = NULL; 1426 result = Curl_urldecode(ftp->path, 0, &rawPath, NULL, REJECT_CTRL); 1427 if(result) 1428 return result; 1429 1430 slashPos = strrchr(rawPath, '/'); 1431 if(slashPos) { 1432 /* chop off the file part if format is dir/file otherwise remove 1433 the trailing slash for dir/dir/ except for absolute path / */ 1434 size_t n = slashPos - rawPath; 1435 if(n == 0) 1436 ++n; 1437 1438 lstArg = rawPath; 1439 lstArg[n] = '\0'; 1440 } 1441 else 1442 free(rawPath); 1443 } 1444 1445 cmd = aprintf("%s%s%s", 1446 data->set.str[STRING_CUSTOMREQUEST] ? 1447 data->set.str[STRING_CUSTOMREQUEST] : 1448 (data->state.list_only ? "NLST" : "LIST"), 1449 lstArg ? " " : "", 1450 lstArg ? lstArg : ""); 1451 free(lstArg); 1452 1453 if(!cmd) 1454 return CURLE_OUT_OF_MEMORY; 1455 1456 result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd); 1457 free(cmd); 1458 1459 if(!result) 1460 ftp_state(data, ftpc, FTP_LIST); 1461 1462 return result; 1463 } 1464 1465 static CURLcode ftp_state_list_prequote(struct Curl_easy *data, 1466 struct ftp_conn *ftpc, 1467 struct FTP *ftp) 1468 { 1469 /* We have sent the TYPE, now we must send the list of prequote strings */ 1470 return ftp_state_quote(data, ftpc, ftp, TRUE, FTP_LIST_PREQUOTE); 1471 } 1472 1473 static CURLcode ftp_state_retr_prequote(struct Curl_easy *data, 1474 struct ftp_conn *ftpc, 1475 struct FTP *ftp) 1476 { 1477 /* We have sent the TYPE, now we must send the list of prequote strings */ 1478 return ftp_state_quote(data, ftpc, ftp, TRUE, FTP_RETR_PREQUOTE); 1479 } 1480 1481 static CURLcode ftp_state_stor_prequote(struct Curl_easy *data, 1482 struct ftp_conn *ftpc, 1483 struct FTP *ftp) 1484 { 1485 /* We have sent the TYPE, now we must send the list of prequote strings */ 1486 return ftp_state_quote(data, ftpc, ftp, TRUE, FTP_STOR_PREQUOTE); 1487 } 1488 1489 static CURLcode ftp_state_type(struct Curl_easy *data, 1490 struct ftp_conn *ftpc, 1491 struct FTP *ftp) 1492 { 1493 CURLcode result = CURLE_OK; 1494 1495 /* If we have selected NOBODY and HEADER, it means that we only want file 1496 information. Which in FTP cannot be much more than the file size and 1497 date. */ 1498 if(data->req.no_body && ftpc->file && 1499 ftp_need_type(ftpc, data->state.prefer_ascii)) { 1500 /* The SIZE command is _not_ RFC 959 specified, and therefore many servers 1501 may not support it! It is however the only way we have to get a file's 1502 size! */ 1503 1504 ftp->transfer = PPTRANSFER_INFO; 1505 /* this means no actual transfer will be made */ 1506 1507 /* Some servers return different sizes for different modes, and thus we 1508 must set the proper type before we check the size */ 1509 result = ftp_nb_type(data, ftpc, ftp, data->state.prefer_ascii, FTP_TYPE); 1510 if(result) 1511 return result; 1512 } 1513 else 1514 result = ftp_state_size(data, ftpc, ftp); 1515 1516 return result; 1517 } 1518 1519 /* This is called after the CWD commands have been done in the beginning of 1520 the DO phase */ 1521 static CURLcode ftp_state_mdtm(struct Curl_easy *data, 1522 struct ftp_conn *ftpc, 1523 struct FTP *ftp) 1524 { 1525 CURLcode result = CURLE_OK; 1526 1527 /* Requested time of file or time-depended transfer? */ 1528 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) { 1529 1530 /* we have requested to get the modified-time of the file, this is a white 1531 spot as the MDTM is not mentioned in RFC959 */ 1532 result = Curl_pp_sendf(data, &ftpc->pp, "MDTM %s", ftpc->file); 1533 1534 if(!result) 1535 ftp_state(data, ftpc, FTP_MDTM); 1536 } 1537 else 1538 result = ftp_state_type(data, ftpc, ftp); 1539 1540 return result; 1541 } 1542 1543 1544 /* This is called after the TYPE and possible quote commands have been sent */ 1545 static CURLcode ftp_state_ul_setup(struct Curl_easy *data, 1546 struct ftp_conn *ftpc, 1547 struct FTP *ftp, 1548 bool sizechecked) 1549 { 1550 CURLcode result = CURLE_OK; 1551 bool append = data->set.remote_append; 1552 1553 if((data->state.resume_from && !sizechecked) || 1554 ((data->state.resume_from > 0) && sizechecked)) { 1555 /* we are about to continue the uploading of a file */ 1556 /* 1. get already existing file's size. We use the SIZE command for this 1557 which may not exist in the server! The SIZE command is not in 1558 RFC959. */ 1559 1560 /* 2. This used to set REST. But since we can do append, we 1561 do not another ftp command. We just skip the source file 1562 offset and then we APPEND the rest on the file instead */ 1563 1564 /* 3. pass file-size number of bytes in the source file */ 1565 /* 4. lower the infilesize counter */ 1566 /* => transfer as usual */ 1567 int seekerr = CURL_SEEKFUNC_OK; 1568 1569 if(data->state.resume_from < 0) { 1570 /* Got no given size to start from, figure it out */ 1571 result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file); 1572 if(!result) 1573 ftp_state(data, ftpc, FTP_STOR_SIZE); 1574 return result; 1575 } 1576 1577 /* enable append */ 1578 append = TRUE; 1579 1580 /* Let's read off the proper amount of bytes from the input. */ 1581 if(data->set.seek_func) { 1582 Curl_set_in_callback(data, TRUE); 1583 seekerr = data->set.seek_func(data->set.seek_client, 1584 data->state.resume_from, SEEK_SET); 1585 Curl_set_in_callback(data, FALSE); 1586 } 1587 1588 if(seekerr != CURL_SEEKFUNC_OK) { 1589 curl_off_t passed = 0; 1590 if(seekerr != CURL_SEEKFUNC_CANTSEEK) { 1591 failf(data, "Could not seek stream"); 1592 return CURLE_FTP_COULDNT_USE_REST; 1593 } 1594 /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */ 1595 do { 1596 char scratch[4*1024]; 1597 size_t readthisamountnow = 1598 (data->state.resume_from - passed > (curl_off_t)sizeof(scratch)) ? 1599 sizeof(scratch) : 1600 curlx_sotouz(data->state.resume_from - passed); 1601 1602 size_t actuallyread = 1603 data->state.fread_func(scratch, 1, readthisamountnow, 1604 data->state.in); 1605 1606 passed += actuallyread; 1607 if((actuallyread == 0) || (actuallyread > readthisamountnow)) { 1608 /* this checks for greater-than only to make sure that the 1609 CURL_READFUNC_ABORT return code still aborts */ 1610 failf(data, "Failed to read data"); 1611 return CURLE_FTP_COULDNT_USE_REST; 1612 } 1613 } while(passed < data->state.resume_from); 1614 } 1615 /* now, decrease the size of the read */ 1616 if(data->state.infilesize > 0) { 1617 data->state.infilesize -= data->state.resume_from; 1618 1619 if(data->state.infilesize <= 0) { 1620 infof(data, "File already completely uploaded"); 1621 1622 /* no data to transfer */ 1623 Curl_xfer_setup_nop(data); 1624 1625 /* Set ->transfer so that we will not get any error in 1626 * ftp_done() because we did not transfer anything! */ 1627 ftp->transfer = PPTRANSFER_NONE; 1628 1629 ftp_state(data, ftpc, FTP_STOP); 1630 return CURLE_OK; 1631 } 1632 } 1633 /* we have passed, proceed as normal */ 1634 } /* resume_from */ 1635 1636 result = Curl_pp_sendf(data, &ftpc->pp, append ? "APPE %s" : "STOR %s", 1637 ftpc->file); 1638 if(!result) 1639 ftp_state(data, ftpc, FTP_STOR); 1640 1641 return result; 1642 } 1643 1644 static CURLcode ftp_state_quote(struct Curl_easy *data, 1645 struct ftp_conn *ftpc, 1646 struct FTP *ftp, 1647 bool init, 1648 ftpstate instate) 1649 { 1650 CURLcode result = CURLE_OK; 1651 bool quote = FALSE; 1652 struct curl_slist *item; 1653 1654 switch(instate) { 1655 case FTP_QUOTE: 1656 default: 1657 item = data->set.quote; 1658 break; 1659 case FTP_RETR_PREQUOTE: 1660 case FTP_STOR_PREQUOTE: 1661 case FTP_LIST_PREQUOTE: 1662 item = data->set.prequote; 1663 break; 1664 case FTP_POSTQUOTE: 1665 item = data->set.postquote; 1666 break; 1667 } 1668 1669 /* 1670 * This state uses: 1671 * 'count1' to iterate over the commands to send 1672 * 'count2' to store whether to allow commands to fail 1673 */ 1674 1675 if(init) 1676 ftpc->count1 = 0; 1677 else 1678 ftpc->count1++; 1679 1680 if(item) { 1681 int i = 0; 1682 1683 /* Skip count1 items in the linked list */ 1684 while((i < ftpc->count1) && item) { 1685 item = item->next; 1686 i++; 1687 } 1688 if(item) { 1689 char *cmd = item->data; 1690 if(cmd[0] == '*') { 1691 cmd++; 1692 ftpc->count2 = 1; /* the sent command is allowed to fail */ 1693 } 1694 else 1695 ftpc->count2 = 0; /* failure means cancel operation */ 1696 1697 result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd); 1698 if(result) 1699 return result; 1700 ftp_state(data, ftpc, instate); 1701 quote = TRUE; 1702 } 1703 } 1704 1705 if(!quote) { 1706 /* No more quote to send, continue to ... */ 1707 switch(instate) { 1708 case FTP_QUOTE: 1709 default: 1710 result = ftp_state_cwd(data, ftpc, ftp); 1711 break; 1712 case FTP_RETR_PREQUOTE: 1713 if(ftp->transfer != PPTRANSFER_BODY) 1714 ftp_state(data, ftpc, FTP_STOP); 1715 else { 1716 if(ftpc->known_filesize != -1) { 1717 Curl_pgrsSetDownloadSize(data, ftpc->known_filesize); 1718 result = ftp_state_retr(data, ftpc, ftp, ftpc->known_filesize); 1719 } 1720 else { 1721 if(data->set.ignorecl || data->state.prefer_ascii) { 1722 /* 'ignorecl' is used to support download of growing files. It 1723 prevents the state machine from requesting the file size from 1724 the server. With an unknown file size the download continues 1725 until the server terminates it, otherwise the client stops if 1726 the received byte count exceeds the reported file size. Set 1727 option CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this 1728 behavior. 1729 1730 In addition: asking for the size for 'TYPE A' transfers is not 1731 constructive since servers do not report the converted size. So 1732 skip it. 1733 */ 1734 result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file); 1735 if(!result) 1736 ftp_state(data, ftpc, FTP_RETR); 1737 } 1738 else { 1739 result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file); 1740 if(!result) 1741 ftp_state(data, ftpc, FTP_RETR_SIZE); 1742 } 1743 } 1744 } 1745 break; 1746 case FTP_STOR_PREQUOTE: 1747 result = ftp_state_ul_setup(data, ftpc, ftp, FALSE); 1748 break; 1749 case FTP_POSTQUOTE: 1750 break; 1751 case FTP_LIST_PREQUOTE: 1752 ftp_state(data, ftpc, FTP_LIST_TYPE); 1753 result = ftp_state_list(data, ftpc, ftp); 1754 break; 1755 } 1756 } 1757 1758 return result; 1759 } 1760 1761 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV 1762 problems */ 1763 static CURLcode ftp_epsv_disable(struct Curl_easy *data, 1764 struct ftp_conn *ftpc, 1765 struct connectdata *conn) 1766 { 1767 CURLcode result = CURLE_OK; 1768 1769 if(conn->bits.ipv6 1770 #ifndef CURL_DISABLE_PROXY 1771 && !(conn->bits.tunnel_proxy || conn->bits.socksproxy) 1772 #endif 1773 ) { 1774 /* We cannot disable EPSV when doing IPv6, so this is instead a fail */ 1775 failf(data, "Failed EPSV attempt, exiting"); 1776 return CURLE_WEIRD_SERVER_REPLY; 1777 } 1778 1779 infof(data, "Failed EPSV attempt. Disabling EPSV"); 1780 /* disable it for next transfer */ 1781 conn->bits.ftp_use_epsv = FALSE; 1782 close_secondarysocket(data, ftpc); 1783 data->state.errorbuf = FALSE; /* allow error message to get 1784 rewritten */ 1785 result = Curl_pp_sendf(data, &ftpc->pp, "%s", "PASV"); 1786 if(!result) { 1787 ftpc->count1++; 1788 /* remain in/go to the FTP_PASV state */ 1789 ftp_state(data, ftpc, FTP_PASV); 1790 } 1791 return result; 1792 } 1793 1794 1795 static char *control_address(struct connectdata *conn) 1796 { 1797 /* Returns the control connection IP address. 1798 If a proxy tunnel is used, returns the original hostname instead, because 1799 the effective control connection address is the proxy address, 1800 not the ftp host. */ 1801 #ifndef CURL_DISABLE_PROXY 1802 if(conn->bits.tunnel_proxy || conn->bits.socksproxy) 1803 return conn->host.name; 1804 #endif 1805 return conn->primary.remote_ip; 1806 } 1807 1808 static bool match_pasv_6nums(const char *p, 1809 unsigned int *array) /* 6 numbers */ 1810 { 1811 int i; 1812 for(i = 0; i < 6; i++) { 1813 curl_off_t num; 1814 if(i) { 1815 if(*p != ',') 1816 return FALSE; 1817 p++; 1818 } 1819 if(curlx_str_number(&p, &num, 0xff)) 1820 return FALSE; 1821 array[i] = (unsigned int)num; 1822 } 1823 return TRUE; 1824 } 1825 1826 static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, 1827 struct ftp_conn *ftpc, 1828 int ftpcode) 1829 { 1830 struct connectdata *conn = data->conn; 1831 CURLcode result; 1832 struct Curl_dns_entry *dns = NULL; 1833 unsigned short connectport; /* the local port connect() should use! */ 1834 struct pingpong *pp = &ftpc->pp; 1835 char *str = 1836 curlx_dyn_ptr(&pp->recvbuf) + 4; /* start on the first letter */ 1837 1838 /* if we come here again, make sure the former name is cleared */ 1839 Curl_safefree(ftpc->newhost); 1840 1841 if((ftpc->count1 == 0) && 1842 (ftpcode == 229)) { 1843 /* positive EPSV response */ 1844 char *ptr = strchr(str, '('); 1845 if(ptr) { 1846 char sep; 1847 ptr++; 1848 /* |||12345| */ 1849 sep = ptr[0]; 1850 if((ptr[1] == sep) && (ptr[2] == sep) && ISDIGIT(ptr[3])) { 1851 const char *p = &ptr[3]; 1852 curl_off_t num; 1853 if(curlx_str_number(&p, &num, 0xffff) || (*p != sep)) { 1854 failf(data, "Illegal port number in EPSV reply"); 1855 return CURLE_FTP_WEIRD_PASV_REPLY; 1856 } 1857 ftpc->newport = (unsigned short)num; 1858 ftpc->newhost = strdup(control_address(conn)); 1859 if(!ftpc->newhost) 1860 return CURLE_OUT_OF_MEMORY; 1861 } 1862 else 1863 ptr = NULL; 1864 } 1865 if(!ptr) { 1866 failf(data, "Weirdly formatted EPSV reply"); 1867 return CURLE_FTP_WEIRD_PASV_REPLY; 1868 } 1869 } 1870 else if((ftpc->count1 == 1) && 1871 (ftpcode == 227)) { 1872 /* positive PASV response */ 1873 unsigned int ip[6]; 1874 1875 /* 1876 * Scan for a sequence of six comma-separated numbers and use them as 1877 * IP+port indicators. 1878 * 1879 * Found reply-strings include: 1880 * "227 Entering Passive Mode (127,0,0,1,4,51)" 1881 * "227 Data transfer will passively listen to 127,0,0,1,4,51" 1882 * "227 Entering passive mode. 127,0,0,1,4,51" 1883 */ 1884 while(*str) { 1885 if(match_pasv_6nums(str, ip)) 1886 break; 1887 str++; 1888 } 1889 1890 if(!*str) { 1891 failf(data, "Couldn't interpret the 227-response"); 1892 return CURLE_FTP_WEIRD_227_FORMAT; 1893 } 1894 1895 /* we got OK from server */ 1896 if(data->set.ftp_skip_ip) { 1897 /* told to ignore the remotely given IP but instead use the host we used 1898 for the control connection */ 1899 infof(data, "Skip %u.%u.%u.%u for data connection, reuse %s instead", 1900 ip[0], ip[1], ip[2], ip[3], 1901 conn->host.name); 1902 ftpc->newhost = strdup(control_address(conn)); 1903 } 1904 else 1905 ftpc->newhost = aprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); 1906 1907 if(!ftpc->newhost) 1908 return CURLE_OUT_OF_MEMORY; 1909 1910 ftpc->newport = (unsigned short)(((ip[4] << 8) + ip[5]) & 0xffff); 1911 } 1912 else if(ftpc->count1 == 0) { 1913 /* EPSV failed, move on to PASV */ 1914 return ftp_epsv_disable(data, ftpc, conn); 1915 } 1916 else { 1917 failf(data, "Bad PASV/EPSV response: %03d", ftpcode); 1918 return CURLE_FTP_WEIRD_PASV_REPLY; 1919 } 1920 1921 #ifndef CURL_DISABLE_PROXY 1922 if(conn->bits.proxy) { 1923 /* 1924 * This connection uses a proxy and we need to connect to the proxy again 1925 * here. We do not want to rely on a former host lookup that might've 1926 * expired now, instead we remake the lookup here and now! 1927 */ 1928 const char * const host_name = conn->bits.socksproxy ? 1929 conn->socks_proxy.host.name : conn->http_proxy.host.name; 1930 (void)Curl_resolv_blocking(data, host_name, conn->primary.remote_port, 1931 conn->ip_version, &dns); 1932 /* we connect to the proxy's port */ 1933 connectport = (unsigned short)conn->primary.remote_port; 1934 1935 if(!dns) { 1936 failf(data, "cannot resolve proxy host %s:%hu", host_name, connectport); 1937 return CURLE_COULDNT_RESOLVE_PROXY; 1938 } 1939 } 1940 else 1941 #endif 1942 { 1943 /* normal, direct, ftp connection */ 1944 DEBUGASSERT(ftpc->newhost); 1945 1946 /* postponed address resolution in case of tcp fastopen */ 1947 if(conn->bits.tcp_fastopen && !conn->bits.reuse && !ftpc->newhost[0]) { 1948 free(ftpc->newhost); 1949 ftpc->newhost = strdup(control_address(conn)); 1950 if(!ftpc->newhost) 1951 return CURLE_OUT_OF_MEMORY; 1952 } 1953 1954 (void)Curl_resolv_blocking(data, ftpc->newhost, ftpc->newport, 1955 conn->ip_version, &dns); 1956 connectport = ftpc->newport; /* we connect to the remote port */ 1957 1958 if(!dns) { 1959 failf(data, "cannot resolve new host %s:%hu", 1960 ftpc->newhost, connectport); 1961 return CURLE_FTP_CANT_GET_HOST; 1962 } 1963 } 1964 1965 result = Curl_conn_setup(data, conn, SECONDARYSOCKET, dns, 1966 conn->bits.ftp_use_data_ssl ? 1967 CURL_CF_SSL_ENABLE : CURL_CF_SSL_DISABLE); 1968 1969 if(result) { 1970 if(ftpc->count1 == 0 && ftpcode == 229) 1971 return ftp_epsv_disable(data, ftpc, conn); 1972 1973 return result; 1974 } 1975 1976 1977 /* 1978 * When this is used from the multi interface, this might've returned with 1979 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking 1980 * connect to connect. 1981 */ 1982 1983 if(data->set.verbose) 1984 /* this just dumps information about this second connection */ 1985 ftp_pasv_verbose(data, dns->addr, ftpc->newhost, connectport); 1986 1987 free(conn->secondaryhostname); 1988 conn->secondary_port = ftpc->newport; 1989 conn->secondaryhostname = strdup(ftpc->newhost); 1990 if(!conn->secondaryhostname) 1991 return CURLE_OUT_OF_MEMORY; 1992 1993 conn->bits.do_more = TRUE; 1994 ftp_state(data, ftpc, FTP_STOP); /* this phase is completed */ 1995 1996 return result; 1997 } 1998 1999 static CURLcode ftp_state_port_resp(struct Curl_easy *data, 2000 struct ftp_conn *ftpc, 2001 struct FTP *ftp, 2002 int ftpcode) 2003 { 2004 struct connectdata *conn = data->conn; 2005 ftpport fcmd = (ftpport)ftpc->count1; 2006 CURLcode result = CURLE_OK; 2007 2008 /* The FTP spec tells a positive response should have code 200. 2009 Be more permissive here to tolerate deviant servers. */ 2010 if(ftpcode / 100 != 2) { 2011 /* the command failed */ 2012 2013 if(EPRT == fcmd) { 2014 infof(data, "disabling EPRT usage"); 2015 conn->bits.ftp_use_eprt = FALSE; 2016 } 2017 fcmd++; 2018 2019 if(fcmd == DONE) { 2020 failf(data, "Failed to do PORT"); 2021 result = CURLE_FTP_PORT_FAILED; 2022 } 2023 else 2024 /* try next */ 2025 result = ftp_state_use_port(data, ftpc, fcmd); 2026 } 2027 else { 2028 infof(data, "Connect data stream actively"); 2029 ftp_state(data, ftpc, FTP_STOP); /* end of DO phase */ 2030 result = ftp_dophase_done(data, ftpc, ftp, FALSE); 2031 } 2032 2033 return result; 2034 } 2035 2036 static int twodigit(const char *p) 2037 { 2038 return (p[0]-'0') * 10 + (p[1]-'0'); 2039 } 2040 2041 static bool ftp_213_date(const char *p, int *year, int *month, int *day, 2042 int *hour, int *minute, int *second) 2043 { 2044 size_t len = strlen(p); 2045 if(len < 14) 2046 return FALSE; 2047 *year = twodigit(&p[0]) * 100 + twodigit(&p[2]); 2048 *month = twodigit(&p[4]); 2049 *day = twodigit(&p[6]); 2050 *hour = twodigit(&p[8]); 2051 *minute = twodigit(&p[10]); 2052 *second = twodigit(&p[12]); 2053 2054 if((*month > 12) || (*day > 31) || (*hour > 23) || (*minute > 59) || 2055 (*second > 60)) 2056 return FALSE; 2057 return TRUE; 2058 } 2059 2060 static CURLcode client_write_header(struct Curl_easy *data, 2061 char *buf, size_t blen) 2062 { 2063 /* Some replies from an FTP server are written to the client 2064 * as CLIENTWRITE_HEADER, formatted as if they came from a 2065 * HTTP conversation. 2066 * In all protocols, CLIENTWRITE_HEADER data is only passed to 2067 * the body write callback when data->set.include_header is set 2068 * via CURLOPT_HEADER. 2069 * For historic reasons, FTP never played this game and expects 2070 * all its HEADERs to do that always. Set that flag during the 2071 * call to Curl_client_write() so it does the right thing. 2072 * 2073 * Notice that we cannot enable this flag for FTP in general, 2074 * as an FTP transfer might involve an HTTP proxy connection and 2075 * headers from CONNECT should not automatically be part of the 2076 * output. */ 2077 CURLcode result; 2078 bool save = data->set.include_header; 2079 data->set.include_header = TRUE; 2080 result = Curl_client_write(data, CLIENTWRITE_HEADER, buf, blen); 2081 data->set.include_header = save; 2082 return result; 2083 } 2084 2085 static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, 2086 struct ftp_conn *ftpc, 2087 struct FTP *ftp, 2088 int ftpcode) 2089 { 2090 CURLcode result = CURLE_OK; 2091 2092 switch(ftpcode) { 2093 case 213: 2094 { 2095 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the 2096 last .sss part is optional and means fractions of a second */ 2097 int year, month, day, hour, minute, second; 2098 struct pingpong *pp = &ftpc->pp; 2099 char *resp = curlx_dyn_ptr(&pp->recvbuf) + 4; 2100 if(ftp_213_date(resp, &year, &month, &day, &hour, &minute, &second)) { 2101 /* we have a time, reformat it */ 2102 char timebuf[24]; 2103 msnprintf(timebuf, sizeof(timebuf), 2104 "%04d%02d%02d %02d:%02d:%02d GMT", 2105 year, month, day, hour, minute, second); 2106 /* now, convert this into a time() value: */ 2107 data->info.filetime = Curl_getdate_capped(timebuf); 2108 } 2109 2110 #ifdef CURL_FTP_HTTPSTYLE_HEAD 2111 /* If we asked for a time of the file and we actually got one as well, 2112 we "emulate" an HTTP-style header in our output. */ 2113 2114 #if defined(__GNUC__) && (defined(__DJGPP__) || defined(__AMIGA__)) 2115 #pragma GCC diagnostic push 2116 /* 'time_t' is unsigned in MSDOS and AmigaOS. Silence: 2117 warning: comparison of unsigned expression in '>= 0' is always true */ 2118 #pragma GCC diagnostic ignored "-Wtype-limits" 2119 #endif 2120 if(data->req.no_body && 2121 ftpc->file && 2122 data->set.get_filetime && 2123 (data->info.filetime >= 0) ) { 2124 #if defined(__GNUC__) && (defined(__DJGPP__) || defined(__AMIGA__)) 2125 #pragma GCC diagnostic pop 2126 #endif 2127 char headerbuf[128]; 2128 int headerbuflen; 2129 time_t filetime = data->info.filetime; 2130 struct tm buffer; 2131 const struct tm *tm = &buffer; 2132 2133 result = Curl_gmtime(filetime, &buffer); 2134 if(result) 2135 return result; 2136 2137 /* format: "Tue, 15 Nov 1994 12:45:26" */ 2138 headerbuflen = 2139 msnprintf(headerbuf, sizeof(headerbuf), 2140 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", 2141 Curl_wkday[tm->tm_wday ? tm->tm_wday-1 : 6], 2142 tm->tm_mday, 2143 Curl_month[tm->tm_mon], 2144 tm->tm_year + 1900, 2145 tm->tm_hour, 2146 tm->tm_min, 2147 tm->tm_sec); 2148 result = client_write_header(data, headerbuf, headerbuflen); 2149 if(result) 2150 return result; 2151 } /* end of a ridiculous amount of conditionals */ 2152 #endif 2153 } 2154 break; 2155 default: 2156 infof(data, "unsupported MDTM reply format"); 2157 break; 2158 case 550: /* 550 is used for several different problems, e.g. 2159 "No such file or directory" or "Permission denied". 2160 It does not mean that the file does not exist at all. */ 2161 infof(data, "MDTM failed: file does not exist or permission problem," 2162 " continuing"); 2163 break; 2164 } 2165 2166 if(data->set.timecondition) { 2167 if((data->info.filetime > 0) && (data->set.timevalue > 0)) { 2168 switch(data->set.timecondition) { 2169 case CURL_TIMECOND_IFMODSINCE: 2170 default: 2171 if(data->info.filetime <= data->set.timevalue) { 2172 infof(data, "The requested document is not new enough"); 2173 ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */ 2174 data->info.timecond = TRUE; 2175 ftp_state(data, ftpc, FTP_STOP); 2176 return CURLE_OK; 2177 } 2178 break; 2179 case CURL_TIMECOND_IFUNMODSINCE: 2180 if(data->info.filetime > data->set.timevalue) { 2181 infof(data, "The requested document is not old enough"); 2182 ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */ 2183 data->info.timecond = TRUE; 2184 ftp_state(data, ftpc, FTP_STOP); 2185 return CURLE_OK; 2186 } 2187 break; 2188 } /* switch */ 2189 } 2190 else { 2191 infof(data, "Skipping time comparison"); 2192 } 2193 } 2194 2195 if(!result) 2196 result = ftp_state_type(data, ftpc, ftp); 2197 2198 return result; 2199 } 2200 2201 static CURLcode ftp_state_type_resp(struct Curl_easy *data, 2202 struct ftp_conn *ftpc, 2203 struct FTP *ftp, 2204 int ftpcode, 2205 ftpstate instate) 2206 { 2207 CURLcode result = CURLE_OK; 2208 2209 if(ftpcode/100 != 2) { 2210 /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a 2211 successful 'TYPE I'. While that is not as RFC959 says, it is still a 2212 positive response code and we allow that. */ 2213 failf(data, "Couldn't set desired mode"); 2214 return CURLE_FTP_COULDNT_SET_TYPE; 2215 } 2216 if(ftpcode != 200) 2217 infof(data, "Got a %03d response code instead of the assumed 200", 2218 ftpcode); 2219 2220 if(instate == FTP_TYPE) 2221 result = ftp_state_size(data, ftpc, ftp); 2222 else if(instate == FTP_LIST_TYPE) 2223 result = ftp_state_list(data, ftpc, ftp); 2224 else if(instate == FTP_RETR_TYPE) 2225 result = ftp_state_retr_prequote(data, ftpc, ftp); 2226 else if(instate == FTP_STOR_TYPE) 2227 result = ftp_state_stor_prequote(data, ftpc, ftp); 2228 else if(instate == FTP_RETR_LIST_TYPE) 2229 result = ftp_state_list_prequote(data, ftpc, ftp); 2230 2231 return result; 2232 } 2233 2234 static CURLcode ftp_state_retr(struct Curl_easy *data, 2235 struct ftp_conn *ftpc, 2236 struct FTP *ftp, 2237 curl_off_t filesize) 2238 { 2239 CURLcode result = CURLE_OK; 2240 2241 CURL_TRC_FTP(data, "[%s] ftp_state_retr()", FTP_CSTATE(ftpc)); 2242 if(data->set.max_filesize && (filesize > data->set.max_filesize)) { 2243 failf(data, "Maximum file size exceeded"); 2244 return CURLE_FILESIZE_EXCEEDED; 2245 } 2246 ftp->downloadsize = filesize; 2247 2248 if(data->state.resume_from) { 2249 /* We always (attempt to) get the size of downloads, so it is done before 2250 this even when not doing resumes. */ 2251 if(filesize == -1) { 2252 infof(data, "ftp server does not support SIZE"); 2253 /* We could not get the size and therefore we cannot know if there really 2254 is a part of the file left to get, although the server will just 2255 close the connection when we start the connection so it will not cause 2256 us any harm, just not make us exit as nicely. */ 2257 } 2258 else { 2259 /* We got a file size report, so we check that there actually is a 2260 part of the file left to get, or else we go home. */ 2261 if(data->state.resume_from < 0) { 2262 /* We are supposed to download the last abs(from) bytes */ 2263 if(filesize < -data->state.resume_from) { 2264 failf(data, "Offset (%" FMT_OFF_T 2265 ") was beyond file size (%" FMT_OFF_T ")", 2266 data->state.resume_from, filesize); 2267 return CURLE_BAD_DOWNLOAD_RESUME; 2268 } 2269 /* convert to size to download */ 2270 ftp->downloadsize = -data->state.resume_from; 2271 /* download from where? */ 2272 data->state.resume_from = filesize - ftp->downloadsize; 2273 } 2274 else { 2275 if(filesize < data->state.resume_from) { 2276 failf(data, "Offset (%" FMT_OFF_T 2277 ") was beyond file size (%" FMT_OFF_T ")", 2278 data->state.resume_from, filesize); 2279 return CURLE_BAD_DOWNLOAD_RESUME; 2280 } 2281 /* Now store the number of bytes we are expected to download */ 2282 ftp->downloadsize = filesize-data->state.resume_from; 2283 } 2284 } 2285 2286 if(ftp->downloadsize == 0) { 2287 /* no data to transfer */ 2288 Curl_xfer_setup_nop(data); 2289 infof(data, "File already completely downloaded"); 2290 2291 /* Set ->transfer so that we will not get any error in ftp_done() 2292 * because we did not transfer the any file */ 2293 ftp->transfer = PPTRANSFER_NONE; 2294 ftp_state(data, ftpc, FTP_STOP); 2295 return CURLE_OK; 2296 } 2297 2298 /* Set resume file transfer offset */ 2299 infof(data, "Instructs server to resume from offset %" FMT_OFF_T, 2300 data->state.resume_from); 2301 2302 result = Curl_pp_sendf(data, &ftpc->pp, "REST %" FMT_OFF_T, 2303 data->state.resume_from); 2304 if(!result) 2305 ftp_state(data, ftpc, FTP_RETR_REST); 2306 } 2307 else { 2308 /* no resume */ 2309 result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file); 2310 if(!result) 2311 ftp_state(data, ftpc, FTP_RETR); 2312 } 2313 2314 return result; 2315 } 2316 2317 static CURLcode ftp_state_size_resp(struct Curl_easy *data, 2318 struct ftp_conn *ftpc, 2319 struct FTP *ftp, 2320 int ftpcode, 2321 ftpstate instate) 2322 { 2323 CURLcode result = CURLE_OK; 2324 curl_off_t filesize = -1; 2325 char *buf = curlx_dyn_ptr(&ftpc->pp.recvbuf); 2326 size_t len = ftpc->pp.nfinal; 2327 2328 /* get the size from the ascii string: */ 2329 if(ftpcode == 213) { 2330 /* To allow servers to prepend "rubbish" in the response string, we scan 2331 for all the digits at the end of the response and parse only those as a 2332 number. */ 2333 char *start = &buf[4]; 2334 const char *fdigit = memchr(start, '\r', len); 2335 if(fdigit) { 2336 fdigit--; 2337 if(*fdigit == '\n') 2338 fdigit--; 2339 while(ISDIGIT(fdigit[-1]) && (fdigit > start)) 2340 fdigit--; 2341 } 2342 else 2343 fdigit = start; 2344 if(curlx_str_number(&fdigit, &filesize, CURL_OFF_T_MAX)) 2345 filesize = -1; /* size remain unknown */ 2346 } 2347 else if(ftpcode == 550) { /* "No such file or directory" */ 2348 /* allow a SIZE failure for (resumed) uploads, when probing what command 2349 to use */ 2350 if(instate != FTP_STOR_SIZE) { 2351 failf(data, "The file does not exist"); 2352 return CURLE_REMOTE_FILE_NOT_FOUND; 2353 } 2354 } 2355 2356 if(instate == FTP_SIZE) { 2357 #ifdef CURL_FTP_HTTPSTYLE_HEAD 2358 if(-1 != filesize) { 2359 char clbuf[128]; 2360 int clbuflen = msnprintf(clbuf, sizeof(clbuf), 2361 "Content-Length: %" FMT_OFF_T "\r\n", filesize); 2362 result = client_write_header(data, clbuf, clbuflen); 2363 if(result) 2364 return result; 2365 } 2366 #endif 2367 Curl_pgrsSetDownloadSize(data, filesize); 2368 result = ftp_state_rest(data, ftpc, ftp); 2369 } 2370 else if(instate == FTP_RETR_SIZE) { 2371 Curl_pgrsSetDownloadSize(data, filesize); 2372 result = ftp_state_retr(data, ftpc, ftp, filesize); 2373 } 2374 else if(instate == FTP_STOR_SIZE) { 2375 data->state.resume_from = filesize; 2376 result = ftp_state_ul_setup(data, ftpc, ftp, TRUE); 2377 } 2378 2379 return result; 2380 } 2381 2382 static CURLcode ftp_state_rest_resp(struct Curl_easy *data, 2383 struct ftp_conn *ftpc, 2384 struct FTP *ftp, 2385 int ftpcode, 2386 ftpstate instate) 2387 { 2388 CURLcode result = CURLE_OK; 2389 2390 switch(instate) { 2391 case FTP_REST: 2392 default: 2393 #ifdef CURL_FTP_HTTPSTYLE_HEAD 2394 if(ftpcode == 350) { 2395 char buffer[24]= { "Accept-ranges: bytes\r\n" }; 2396 result = client_write_header(data, buffer, strlen(buffer)); 2397 if(result) 2398 return result; 2399 } 2400 #endif 2401 result = ftp_state_prepare_transfer(data, ftpc, ftp); 2402 break; 2403 2404 case FTP_RETR_REST: 2405 if(ftpcode != 350) { 2406 failf(data, "Couldn't use REST"); 2407 result = CURLE_FTP_COULDNT_USE_REST; 2408 } 2409 else { 2410 result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file); 2411 if(!result) 2412 ftp_state(data, ftpc, FTP_RETR); 2413 } 2414 break; 2415 } 2416 2417 return result; 2418 } 2419 2420 static CURLcode ftp_state_stor_resp(struct Curl_easy *data, 2421 struct ftp_conn *ftpc, 2422 int ftpcode, ftpstate instate) 2423 { 2424 CURLcode result = CURLE_OK; 2425 2426 if(ftpcode >= 400) { 2427 failf(data, "Failed FTP upload: %0d", ftpcode); 2428 ftp_state(data, ftpc, FTP_STOP); 2429 /* oops, we never close the sockets! */ 2430 return CURLE_UPLOAD_FAILED; 2431 } 2432 2433 ftpc->state_saved = instate; 2434 2435 /* PORT means we are now awaiting the server to connect to us. */ 2436 if(data->set.ftp_use_port) { 2437 bool connected; 2438 2439 ftp_state(data, ftpc, FTP_STOP); /* no longer in STOR state */ 2440 2441 result = Curl_conn_connect(data, SECONDARYSOCKET, FALSE, &connected); 2442 if(result) 2443 return result; 2444 2445 if(!connected) { 2446 infof(data, "Data conn was not available immediately"); 2447 ftpc->wait_data_conn = TRUE; 2448 return ftp_check_ctrl_on_data_wait(data, ftpc); 2449 } 2450 ftpc->wait_data_conn = FALSE; 2451 } 2452 return ftp_initiate_transfer(data, ftpc); 2453 } 2454 2455 /* for LIST and RETR responses */ 2456 static CURLcode ftp_state_get_resp(struct Curl_easy *data, 2457 struct ftp_conn *ftpc, 2458 struct FTP *ftp, 2459 int ftpcode, 2460 ftpstate instate) 2461 { 2462 CURLcode result = CURLE_OK; 2463 2464 if((ftpcode == 150) || (ftpcode == 125)) { 2465 2466 /* 2467 A; 2468 150 Opening BINARY mode data connection for /etc/passwd (2241 2469 bytes). (ok, the file is being transferred) 2470 2471 B: 2472 150 Opening ASCII mode data connection for /bin/ls 2473 2474 C: 2475 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes). 2476 2477 D: 2478 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes) 2479 2480 E: 2481 125 Data connection already open; Transfer starting. */ 2482 2483 curl_off_t size = -1; /* default unknown size */ 2484 2485 2486 /* 2487 * It appears that there are FTP-servers that return size 0 for files when 2488 * SIZE is used on the file while being in BINARY mode. To work around 2489 * that (stupid) behavior, we attempt to parse the RETR response even if 2490 * the SIZE returned size zero. 2491 * 2492 * Debugging help from Salvatore Sorrentino on February 26, 2003. 2493 */ 2494 2495 if((instate != FTP_LIST) && 2496 !data->state.prefer_ascii && 2497 !data->set.ignorecl && 2498 (ftp->downloadsize < 1)) { 2499 /* 2500 * It seems directory listings either do not show the size or often uses 2501 * size 0 anyway. ASCII transfers may cause that the transferred amount 2502 * of data is not the same as this line tells, why using this number in 2503 * those cases only confuses us. 2504 * 2505 * Example D above makes this parsing a little tricky */ 2506 const char *bytes; 2507 char *buf = curlx_dyn_ptr(&ftpc->pp.recvbuf); 2508 bytes = strstr(buf, " bytes"); 2509 if(bytes) { 2510 long in = (long)(--bytes-buf); 2511 /* this is a hint there is size information in there! ;-) */ 2512 while(--in) { 2513 /* scan for the left parenthesis and break there */ 2514 if('(' == *bytes) 2515 break; 2516 /* skip only digits */ 2517 if(!ISDIGIT(*bytes)) { 2518 bytes = NULL; 2519 break; 2520 } 2521 /* one more estep backwards */ 2522 bytes--; 2523 } 2524 /* if we have nothing but digits: */ 2525 if(bytes) { 2526 ++bytes; 2527 /* get the number! */ 2528 if(curlx_str_number(&bytes, &size, CURL_OFF_T_MAX)) 2529 size = 1; 2530 } 2531 } 2532 } 2533 else if(ftp->downloadsize > -1) 2534 size = ftp->downloadsize; 2535 2536 if(size > data->req.maxdownload && data->req.maxdownload > 0) 2537 size = data->req.size = data->req.maxdownload; 2538 else if((instate != FTP_LIST) && (data->state.prefer_ascii)) 2539 size = -1; /* kludge for servers that understate ASCII mode file size */ 2540 2541 infof(data, "Maxdownload = %" FMT_OFF_T, data->req.maxdownload); 2542 2543 if(instate != FTP_LIST) 2544 infof(data, "Getting file with size: %" FMT_OFF_T, size); 2545 2546 /* FTP download: */ 2547 ftpc->state_saved = instate; 2548 ftpc->retr_size_saved = size; 2549 2550 if(data->set.ftp_use_port) { 2551 bool connected; 2552 2553 result = Curl_conn_connect(data, SECONDARYSOCKET, FALSE, &connected); 2554 if(result) 2555 return result; 2556 2557 if(!connected) { 2558 infof(data, "Data conn was not available immediately"); 2559 ftp_state(data, ftpc, FTP_STOP); 2560 ftpc->wait_data_conn = TRUE; 2561 return ftp_check_ctrl_on_data_wait(data, ftpc); 2562 } 2563 ftpc->wait_data_conn = FALSE; 2564 } 2565 return ftp_initiate_transfer(data, ftpc); 2566 } 2567 else { 2568 if((instate == FTP_LIST) && (ftpcode == 450)) { 2569 /* simply no matching files in the dir listing */ 2570 ftp->transfer = PPTRANSFER_NONE; /* do not download anything */ 2571 ftp_state(data, ftpc, FTP_STOP); /* this phase is over */ 2572 } 2573 else { 2574 failf(data, "RETR response: %03d", ftpcode); 2575 return instate == FTP_RETR && ftpcode == 550 ? 2576 CURLE_REMOTE_FILE_NOT_FOUND : 2577 CURLE_FTP_COULDNT_RETR_FILE; 2578 } 2579 } 2580 2581 return result; 2582 } 2583 2584 /* after USER, PASS and ACCT */ 2585 static CURLcode ftp_state_loggedin(struct Curl_easy *data, 2586 struct ftp_conn *ftpc) 2587 { 2588 CURLcode result = CURLE_OK; 2589 2590 if(data->conn->bits.ftp_use_control_ssl) { 2591 /* PBSZ = PROTECTION BUFFER SIZE. 2592 2593 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says: 2594 2595 Specifically, the PROT command MUST be preceded by a PBSZ 2596 command and a PBSZ command MUST be preceded by a successful 2597 security data exchange (the TLS negotiation in this case) 2598 2599 ... (and on page 8): 2600 2601 Thus the PBSZ command must still be issued, but must have a 2602 parameter of '0' to indicate that no buffering is taking place 2603 and the data connection should not be encapsulated. 2604 */ 2605 result = Curl_pp_sendf(data, &ftpc->pp, "PBSZ %d", 0); 2606 if(!result) 2607 ftp_state(data, ftpc, FTP_PBSZ); 2608 } 2609 else { 2610 result = ftp_state_pwd(data, ftpc); 2611 } 2612 return result; 2613 } 2614 2615 /* for USER and PASS responses */ 2616 static CURLcode ftp_state_user_resp(struct Curl_easy *data, 2617 struct ftp_conn *ftpc, 2618 int ftpcode) 2619 { 2620 CURLcode result = CURLE_OK; 2621 2622 /* some need password anyway, and others just return 2xx ignored */ 2623 if((ftpcode == 331) && (ftpc->state == FTP_USER)) { 2624 /* 331 Password required for ... 2625 (the server requires to send the user's password too) */ 2626 result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s", 2627 data->conn->passwd ? data->conn->passwd : ""); 2628 if(!result) 2629 ftp_state(data, ftpc, FTP_PASS); 2630 } 2631 else if(ftpcode/100 == 2) { 2632 /* 230 User ... logged in. 2633 (the user logged in with or without password) */ 2634 result = ftp_state_loggedin(data, ftpc); 2635 } 2636 else if(ftpcode == 332) { 2637 if(data->set.str[STRING_FTP_ACCOUNT]) { 2638 result = Curl_pp_sendf(data, &ftpc->pp, "ACCT %s", 2639 data->set.str[STRING_FTP_ACCOUNT]); 2640 if(!result) 2641 ftp_state(data, ftpc, FTP_ACCT); 2642 } 2643 else { 2644 failf(data, "ACCT requested but none available"); 2645 result = CURLE_LOGIN_DENIED; 2646 } 2647 } 2648 else { 2649 /* All other response codes, like: 2650 2651 530 User ... access denied 2652 (the server denies to log the specified user) */ 2653 2654 if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] && 2655 !ftpc->ftp_trying_alternative) { 2656 /* Ok, USER failed. Let's try the supplied command. */ 2657 result = 2658 Curl_pp_sendf(data, &ftpc->pp, "%s", 2659 data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); 2660 if(!result) { 2661 ftpc->ftp_trying_alternative = TRUE; 2662 ftp_state(data, ftpc, FTP_USER); 2663 } 2664 } 2665 else { 2666 failf(data, "Access denied: %03d", ftpcode); 2667 result = CURLE_LOGIN_DENIED; 2668 } 2669 } 2670 return result; 2671 } 2672 2673 /* for ACCT response */ 2674 static CURLcode ftp_state_acct_resp(struct Curl_easy *data, 2675 struct ftp_conn *ftpc, 2676 int ftpcode) 2677 { 2678 CURLcode result = CURLE_OK; 2679 if(ftpcode != 230) { 2680 failf(data, "ACCT rejected by server: %03d", ftpcode); 2681 result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */ 2682 } 2683 else 2684 result = ftp_state_loggedin(data, ftpc); 2685 2686 return result; 2687 } 2688 2689 2690 static CURLcode ftp_pp_statemachine(struct Curl_easy *data, 2691 struct connectdata *conn) 2692 { 2693 CURLcode result; 2694 int ftpcode; 2695 struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN); 2696 struct FTP *ftp = Curl_meta_get(data, CURL_META_FTP_EASY); 2697 struct pingpong *pp; 2698 static const char * const ftpauth[] = { "SSL", "TLS" }; 2699 size_t nread = 0; 2700 2701 if(!ftpc || !ftp) 2702 return CURLE_FAILED_INIT; 2703 pp = &ftpc->pp; 2704 if(pp->sendleft) 2705 return Curl_pp_flushsend(data, pp); 2706 2707 result = ftp_readresp(data, ftpc, FIRSTSOCKET, pp, &ftpcode, &nread); 2708 if(result) 2709 return result; 2710 2711 if(ftpcode) { 2712 /* we have now received a full FTP server response */ 2713 switch(ftpc->state) { 2714 case FTP_WAIT220: 2715 if(ftpcode == 230) { 2716 /* 230 User logged in - already! Take as 220 if TLS required. */ 2717 if(data->set.use_ssl <= CURLUSESSL_TRY || 2718 conn->bits.ftp_use_control_ssl) 2719 return ftp_state_user_resp(data, ftpc, ftpcode); 2720 } 2721 else if(ftpcode != 220) { 2722 failf(data, "Got a %03d ftp-server response when 220 was expected", 2723 ftpcode); 2724 return CURLE_WEIRD_SERVER_REPLY; 2725 } 2726 2727 /* We have received a 220 response fine, now we proceed. */ 2728 #ifdef HAVE_GSSAPI 2729 if(data->set.krb) { 2730 /* If not anonymous login, try a secure login. Note that this 2731 procedure is still BLOCKING. */ 2732 2733 Curl_sec_request_prot(conn, "private"); 2734 /* We set private first as default, in case the line below fails to 2735 set a valid level */ 2736 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); 2737 2738 if(Curl_sec_login(data, conn)) { 2739 failf(data, "secure login failed"); 2740 return CURLE_WEIRD_SERVER_REPLY; 2741 } 2742 infof(data, "Authentication successful"); 2743 } 2744 #endif 2745 2746 if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) { 2747 /* We do not have an SSL/TLS control connection yet, but FTPS is 2748 requested. Try an FTPS connection now */ 2749 2750 ftpc->count3 = 0; 2751 switch(data->set.ftpsslauth) { 2752 case CURLFTPAUTH_DEFAULT: 2753 case CURLFTPAUTH_SSL: 2754 ftpc->count2 = 1; /* add one to get next */ 2755 ftpc->count1 = 0; 2756 break; 2757 case CURLFTPAUTH_TLS: 2758 ftpc->count2 = -1; /* subtract one to get next */ 2759 ftpc->count1 = 1; 2760 break; 2761 default: 2762 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d", 2763 (int)data->set.ftpsslauth); 2764 return CURLE_UNKNOWN_OPTION; /* we do not know what to do */ 2765 } 2766 result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", 2767 ftpauth[ftpc->count1]); 2768 if(!result) 2769 ftp_state(data, ftpc, FTP_AUTH); 2770 } 2771 else 2772 result = ftp_state_user(data, ftpc, conn); 2773 break; 2774 2775 case FTP_AUTH: 2776 /* we have gotten the response to a previous AUTH command */ 2777 2778 if(pp->overflow) 2779 return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */ 2780 2781 /* RFC2228 (page 5) says: 2782 * 2783 * If the server is willing to accept the named security mechanism, 2784 * and does not require any security data, it must respond with 2785 * reply code 234/334. 2786 */ 2787 2788 if((ftpcode == 234) || (ftpcode == 334)) { 2789 /* this was BLOCKING, keep it so for now */ 2790 bool done; 2791 if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) { 2792 result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET); 2793 if(result) { 2794 /* we failed and bail out */ 2795 return CURLE_USE_SSL_FAILED; 2796 } 2797 } 2798 result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, &done); 2799 if(!result) { 2800 conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ 2801 conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */ 2802 result = ftp_state_user(data, ftpc, conn); 2803 } 2804 } 2805 else if(ftpc->count3 < 1) { 2806 ftpc->count3++; 2807 ftpc->count1 += ftpc->count2; /* get next attempt */ 2808 result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", 2809 ftpauth[ftpc->count1]); 2810 /* remain in this same state */ 2811 } 2812 else { 2813 if(data->set.use_ssl > CURLUSESSL_TRY) 2814 /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */ 2815 result = CURLE_USE_SSL_FAILED; 2816 else 2817 /* ignore the failure and continue */ 2818 result = ftp_state_user(data, ftpc, conn); 2819 } 2820 break; 2821 2822 case FTP_USER: 2823 case FTP_PASS: 2824 result = ftp_state_user_resp(data, ftpc, ftpcode); 2825 break; 2826 2827 case FTP_ACCT: 2828 result = ftp_state_acct_resp(data, ftpc, ftpcode); 2829 break; 2830 2831 case FTP_PBSZ: 2832 result = 2833 Curl_pp_sendf(data, &ftpc->pp, "PROT %c", 2834 data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); 2835 if(!result) 2836 ftp_state(data, ftpc, FTP_PROT); 2837 break; 2838 2839 case FTP_PROT: 2840 if(ftpcode/100 == 2) 2841 /* We have enabled SSL for the data connection! */ 2842 conn->bits.ftp_use_data_ssl = 2843 (data->set.use_ssl != CURLUSESSL_CONTROL); 2844 /* FTP servers typically responds with 500 if they decide to reject 2845 our 'P' request */ 2846 else if(data->set.use_ssl > CURLUSESSL_CONTROL) 2847 /* we failed and bails out */ 2848 return CURLE_USE_SSL_FAILED; 2849 2850 if(data->set.ftp_ccc) { 2851 /* CCC - Clear Command Channel 2852 */ 2853 result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC"); 2854 if(!result) 2855 ftp_state(data, ftpc, FTP_CCC); 2856 } 2857 else 2858 result = ftp_state_pwd(data, ftpc); 2859 break; 2860 2861 case FTP_CCC: 2862 if(ftpcode < 500) { 2863 /* First shut down the SSL layer (note: this call will block) */ 2864 /* This has only been tested on the proftpd server, and the mod_tls 2865 * code sends a close notify alert without waiting for a close notify 2866 * alert in response. Thus we wait for a close notify alert from the 2867 * server, but we do not send one. Let's hope other servers do 2868 * the same... */ 2869 result = Curl_ssl_cfilter_remove(data, FIRSTSOCKET, 2870 (data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)); 2871 2872 if(result) 2873 failf(data, "Failed to clear the command channel (CCC)"); 2874 } 2875 if(!result) 2876 /* Then continue as normal */ 2877 result = ftp_state_pwd(data, ftpc); 2878 break; 2879 2880 case FTP_PWD: 2881 if(ftpcode == 257) { 2882 char *ptr = curlx_dyn_ptr(&pp->recvbuf) + 4; /* start on the first 2883 letter */ 2884 bool entry_extracted = FALSE; 2885 struct dynbuf out; 2886 curlx_dyn_init(&out, 1000); 2887 2888 /* Reply format is like 2889 257<space>[rubbish]"<directory-name>"<space><commentary> and the 2890 RFC959 says 2891 2892 The directory name can contain any character; embedded 2893 double-quotes should be escaped by double-quotes (the 2894 "quote-doubling" convention). 2895 */ 2896 2897 /* scan for the first double-quote for non-standard responses */ 2898 while(*ptr != '\n' && *ptr != '\0' && *ptr != '"') 2899 ptr++; 2900 2901 if('\"' == *ptr) { 2902 /* it started good */ 2903 for(ptr++; *ptr; ptr++) { 2904 if('\"' == *ptr) { 2905 if('\"' == ptr[1]) { 2906 /* "quote-doubling" */ 2907 result = curlx_dyn_addn(&out, &ptr[1], 1); 2908 ptr++; 2909 } 2910 else { 2911 /* end of path */ 2912 if(curlx_dyn_len(&out)) 2913 entry_extracted = TRUE; 2914 break; /* get out of this loop */ 2915 } 2916 } 2917 else 2918 result = curlx_dyn_addn(&out, ptr, 1); 2919 if(result) 2920 return result; 2921 } 2922 } 2923 if(entry_extracted) { 2924 /* If the path name does not look like an absolute path (i.e.: it 2925 does not start with a '/'), we probably need some server-dependent 2926 adjustments. For example, this is the case when connecting to 2927 an OS400 FTP server: this server supports two name syntaxes, 2928 the default one being incompatible with standard paths. In 2929 addition, this server switches automatically to the regular path 2930 syntax when one is encountered in a command: this results in 2931 having an entrypath in the wrong syntax when later used in CWD. 2932 The method used here is to check the server OS: we do it only 2933 if the path name looks strange to minimize overhead on other 2934 systems. */ 2935 char *dir = curlx_dyn_ptr(&out); 2936 2937 if(!ftpc->server_os && dir[0] != '/') { 2938 result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST"); 2939 if(result) { 2940 free(dir); 2941 return result; 2942 } 2943 free(ftpc->entrypath); 2944 ftpc->entrypath = dir; /* remember this */ 2945 infof(data, "Entry path is '%s'", ftpc->entrypath); 2946 /* also save it where getinfo can access it: */ 2947 free(data->state.most_recent_ftp_entrypath); 2948 data->state.most_recent_ftp_entrypath = strdup(ftpc->entrypath); 2949 if(!data->state.most_recent_ftp_entrypath) 2950 return CURLE_OUT_OF_MEMORY; 2951 ftp_state(data, ftpc, FTP_SYST); 2952 break; 2953 } 2954 2955 free(ftpc->entrypath); 2956 ftpc->entrypath = dir; /* remember this */ 2957 infof(data, "Entry path is '%s'", ftpc->entrypath); 2958 /* also save it where getinfo can access it: */ 2959 free(data->state.most_recent_ftp_entrypath); 2960 data->state.most_recent_ftp_entrypath = strdup(ftpc->entrypath); 2961 if(!data->state.most_recent_ftp_entrypath) 2962 return CURLE_OUT_OF_MEMORY; 2963 } 2964 else { 2965 /* could not get the path */ 2966 curlx_dyn_free(&out); 2967 infof(data, "Failed to figure out path"); 2968 } 2969 } 2970 ftp_state(data, ftpc, FTP_STOP); /* we are done with CONNECT phase! */ 2971 CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_CSTATE(ftpc)); 2972 break; 2973 2974 case FTP_SYST: 2975 if(ftpcode == 215) { 2976 char *ptr = curlx_dyn_ptr(&pp->recvbuf) + 4; /* start on the first 2977 letter */ 2978 char *os; 2979 char *start; 2980 2981 /* Reply format is like 2982 215<space><OS-name><space><commentary> 2983 */ 2984 while(*ptr == ' ') 2985 ptr++; 2986 for(start = ptr; *ptr && *ptr != ' '; ptr++) 2987 ; 2988 os = Curl_memdup0(start, ptr - start); 2989 if(!os) 2990 return CURLE_OUT_OF_MEMORY; 2991 2992 /* Check for special servers here. */ 2993 if(curl_strequal(os, "OS/400")) { 2994 /* Force OS400 name format 1. */ 2995 result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1"); 2996 if(result) { 2997 free(os); 2998 return result; 2999 } 3000 /* remember target server OS */ 3001 free(ftpc->server_os); 3002 ftpc->server_os = os; 3003 ftp_state(data, ftpc, FTP_NAMEFMT); 3004 break; 3005 } 3006 /* Nothing special for the target server. */ 3007 /* remember target server OS */ 3008 free(ftpc->server_os); 3009 ftpc->server_os = os; 3010 } 3011 else { 3012 /* Cannot identify server OS. Continue anyway and cross fingers. */ 3013 } 3014 3015 ftp_state(data, ftpc, FTP_STOP); /* we are done with CONNECT phase! */ 3016 CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_CSTATE(ftpc)); 3017 break; 3018 3019 case FTP_NAMEFMT: 3020 if(ftpcode == 250) { 3021 /* Name format change successful: reload initial path. */ 3022 ftp_state_pwd(data, ftpc); 3023 break; 3024 } 3025 3026 ftp_state(data, ftpc, FTP_STOP); /* we are done with CONNECT phase! */ 3027 CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_CSTATE(ftpc)); 3028 break; 3029 3030 case FTP_QUOTE: 3031 case FTP_POSTQUOTE: 3032 case FTP_RETR_PREQUOTE: 3033 case FTP_STOR_PREQUOTE: 3034 case FTP_LIST_PREQUOTE: 3035 if((ftpcode >= 400) && !ftpc->count2) { 3036 /* failure response code, and not allowed to fail */ 3037 failf(data, "QUOT command failed with %03d", ftpcode); 3038 result = CURLE_QUOTE_ERROR; 3039 } 3040 else 3041 result = ftp_state_quote(data, ftpc, ftp, FALSE, ftpc->state); 3042 break; 3043 3044 case FTP_CWD: 3045 if(ftpcode/100 != 2) { 3046 /* failure to CWD there */ 3047 if(data->set.ftp_create_missing_dirs && 3048 ftpc->cwdcount && !ftpc->count2) { 3049 /* try making it */ 3050 ftpc->count2++; /* counter to prevent CWD-MKD loops */ 3051 3052 /* count3 is set to allow MKD to fail once per dir. In the case when 3053 CWD fails and then MKD fails (due to another session raced it to 3054 create the dir) this then allows for a second try to CWD to it. */ 3055 ftpc->count3 = (data->set.ftp_create_missing_dirs == 2) ? 1 : 0; 3056 3057 result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s", 3058 ftpc->dirs[ftpc->cwdcount - 1]); 3059 if(!result) 3060 ftp_state(data, ftpc, FTP_MKD); 3061 } 3062 else { 3063 /* return failure */ 3064 failf(data, "Server denied you to change to the given directory"); 3065 ftpc->cwdfail = TRUE; /* do not remember this path as we failed 3066 to enter it */ 3067 result = CURLE_REMOTE_ACCESS_DENIED; 3068 } 3069 } 3070 else { 3071 /* success */ 3072 ftpc->count2 = 0; 3073 if(++ftpc->cwdcount <= ftpc->dirdepth) 3074 /* send next CWD */ 3075 result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", 3076 ftpc->dirs[ftpc->cwdcount - 1]); 3077 else 3078 result = ftp_state_mdtm(data, ftpc, ftp); 3079 } 3080 break; 3081 3082 case FTP_MKD: 3083 if((ftpcode/100 != 2) && !ftpc->count3--) { 3084 /* failure to MKD the dir */ 3085 failf(data, "Failed to MKD dir: %03d", ftpcode); 3086 result = CURLE_REMOTE_ACCESS_DENIED; 3087 } 3088 else { 3089 ftp_state(data, ftpc, FTP_CWD); 3090 /* send CWD */ 3091 result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", 3092 ftpc->dirs[ftpc->cwdcount - 1]); 3093 } 3094 break; 3095 3096 case FTP_MDTM: 3097 result = ftp_state_mdtm_resp(data, ftpc, ftp, ftpcode); 3098 break; 3099 3100 case FTP_TYPE: 3101 case FTP_LIST_TYPE: 3102 case FTP_RETR_TYPE: 3103 case FTP_STOR_TYPE: 3104 case FTP_RETR_LIST_TYPE: 3105 result = ftp_state_type_resp(data, ftpc, ftp, ftpcode, ftpc->state); 3106 break; 3107 3108 case FTP_SIZE: 3109 case FTP_RETR_SIZE: 3110 case FTP_STOR_SIZE: 3111 result = ftp_state_size_resp(data, ftpc, ftp, ftpcode, ftpc->state); 3112 break; 3113 3114 case FTP_REST: 3115 case FTP_RETR_REST: 3116 result = ftp_state_rest_resp(data, ftpc, ftp, ftpcode, ftpc->state); 3117 break; 3118 3119 case FTP_PRET: 3120 if(ftpcode != 200) { 3121 /* there only is this one standard OK return code. */ 3122 failf(data, "PRET command not accepted: %03d", ftpcode); 3123 return CURLE_FTP_PRET_FAILED; 3124 } 3125 result = ftp_state_use_pasv(data, ftpc, conn); 3126 break; 3127 3128 case FTP_PASV: 3129 result = ftp_state_pasv_resp(data, ftpc, ftpcode); 3130 break; 3131 3132 case FTP_PORT: 3133 result = ftp_state_port_resp(data, ftpc, ftp, ftpcode); 3134 break; 3135 3136 case FTP_LIST: 3137 case FTP_RETR: 3138 result = ftp_state_get_resp(data, ftpc, ftp, ftpcode, ftpc->state); 3139 break; 3140 3141 case FTP_STOR: 3142 result = ftp_state_stor_resp(data, ftpc, ftpcode, ftpc->state); 3143 break; 3144 3145 case FTP_QUIT: 3146 default: 3147 /* internal error */ 3148 ftp_state(data, ftpc, FTP_STOP); 3149 break; 3150 } 3151 } /* if(ftpcode) */ 3152 3153 return result; 3154 } 3155 3156 3157 /* called repeatedly until done from multi.c */ 3158 static CURLcode ftp_statemach(struct Curl_easy *data, 3159 struct ftp_conn *ftpc, 3160 bool *done) 3161 { 3162 CURLcode result = Curl_pp_statemach(data, &ftpc->pp, FALSE, FALSE); 3163 3164 /* Check for the state outside of the Curl_socket_check() return code checks 3165 since at times we are in fact already in this state when this function 3166 gets called. */ 3167 *done = (ftpc->state == FTP_STOP); 3168 3169 return result; 3170 } 3171 3172 /* called repeatedly until done from multi.c */ 3173 static CURLcode ftp_multi_statemach(struct Curl_easy *data, 3174 bool *done) 3175 { 3176 struct ftp_conn *ftpc = Curl_conn_meta_get(data->conn, CURL_META_FTP_CONN); 3177 return ftpc ? ftp_statemach(data, ftpc, done) : CURLE_FAILED_INIT; 3178 } 3179 3180 static CURLcode ftp_block_statemach(struct Curl_easy *data, 3181 struct ftp_conn *ftpc) 3182 { 3183 struct pingpong *pp = &ftpc->pp; 3184 CURLcode result = CURLE_OK; 3185 3186 while(ftpc->state != FTP_STOP) { 3187 if(ftpc->shutdown) 3188 CURL_TRC_FTP(data, "in shutdown, waiting for server response"); 3189 result = Curl_pp_statemach(data, pp, TRUE, TRUE /* disconnecting */); 3190 if(result) 3191 break; 3192 } 3193 3194 return result; 3195 } 3196 3197 /* 3198 * ftp_connect() should do everything that is to be considered a part of 3199 * the connection phase. 3200 * 3201 * The variable 'done' points to will be TRUE if the protocol-layer connect 3202 * phase is done when this function returns, or FALSE if not. 3203 * 3204 */ 3205 static CURLcode ftp_connect(struct Curl_easy *data, 3206 bool *done) /* see description above */ 3207 { 3208 CURLcode result; 3209 struct connectdata *conn = data->conn; 3210 struct ftp_conn *ftpc = Curl_conn_meta_get(data->conn, CURL_META_FTP_CONN); 3211 struct pingpong *pp; 3212 3213 *done = FALSE; /* default to not done yet */ 3214 if(!ftpc) 3215 return CURLE_FAILED_INIT; 3216 pp = &ftpc->pp; 3217 /* We always support persistent connections on ftp */ 3218 connkeep(conn, "FTP default"); 3219 3220 PINGPONG_SETUP(pp, ftp_pp_statemachine, ftp_endofresp); 3221 3222 if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) { 3223 /* BLOCKING */ 3224 result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, done); 3225 if(result) 3226 return result; 3227 conn->bits.ftp_use_control_ssl = TRUE; 3228 } 3229 3230 Curl_pp_init(pp); /* once per transfer */ 3231 3232 /* When we connect, we start in the state where we await the 220 3233 response */ 3234 ftp_state(data, ftpc, FTP_WAIT220); 3235 3236 result = ftp_statemach(data, ftpc, done); 3237 3238 return result; 3239 } 3240 3241 /*********************************************************************** 3242 * 3243 * ftp_done() 3244 * 3245 * The DONE function. This does what needs to be done after a single DO has 3246 * performed. 3247 * 3248 * Input argument is already checked for validity. 3249 */ 3250 static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, 3251 bool premature) 3252 { 3253 struct connectdata *conn = data->conn; 3254 struct FTP *ftp = Curl_meta_get(data, CURL_META_FTP_EASY); 3255 struct ftp_conn *ftpc = Curl_conn_meta_get(data->conn, CURL_META_FTP_CONN); 3256 struct pingpong *pp; 3257 ssize_t nread; 3258 int ftpcode; 3259 CURLcode result = CURLE_OK; 3260 char *rawPath = NULL; 3261 size_t pathLen = 0; 3262 3263 if(!ftp || !ftpc) 3264 return CURLE_OK; 3265 3266 pp = &ftpc->pp; 3267 switch(status) { 3268 case CURLE_BAD_DOWNLOAD_RESUME: 3269 case CURLE_FTP_WEIRD_PASV_REPLY: 3270 case CURLE_FTP_PORT_FAILED: 3271 case CURLE_FTP_ACCEPT_FAILED: 3272 case CURLE_FTP_ACCEPT_TIMEOUT: 3273 case CURLE_FTP_COULDNT_SET_TYPE: 3274 case CURLE_FTP_COULDNT_RETR_FILE: 3275 case CURLE_PARTIAL_FILE: 3276 case CURLE_UPLOAD_FAILED: 3277 case CURLE_REMOTE_ACCESS_DENIED: 3278 case CURLE_FILESIZE_EXCEEDED: 3279 case CURLE_REMOTE_FILE_NOT_FOUND: 3280 case CURLE_WRITE_ERROR: 3281 /* the connection stays alive fine even though this happened */ 3282 case CURLE_OK: /* does not affect the control connection's status */ 3283 if(!premature) 3284 break; 3285 3286 /* until we cope better with prematurely ended requests, let them 3287 * fallback as if in complete failure */ 3288 FALLTHROUGH(); 3289 default: /* by default, an error means the control connection is 3290 wedged and should not be used anymore */ 3291 ftpc->ctl_valid = FALSE; 3292 ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the 3293 current path, as this connection is going */ 3294 connclose(conn, "FTP ended with bad error code"); 3295 result = status; /* use the already set error code */ 3296 break; 3297 } 3298 3299 if(data->state.wildcardmatch) { 3300 if(data->set.chunk_end && ftpc->file) { 3301 Curl_set_in_callback(data, TRUE); 3302 data->set.chunk_end(data->set.wildcardptr); 3303 Curl_set_in_callback(data, FALSE); 3304 } 3305 ftpc->known_filesize = -1; 3306 } 3307 3308 if(!result) 3309 /* get the url-decoded "raw" path */ 3310 result = Curl_urldecode(ftp->path, 0, &rawPath, &pathLen, 3311 REJECT_CTRL); 3312 if(result) { 3313 /* We can limp along anyway (and should try to since we may already be in 3314 * the error path) */ 3315 ftpc->ctl_valid = FALSE; /* mark control connection as bad */ 3316 connclose(conn, "FTP: out of memory!"); /* mark for connection closure */ 3317 free(ftpc->prevpath); 3318 ftpc->prevpath = NULL; /* no path remembering */ 3319 } 3320 else { /* remember working directory for connection reuse */ 3321 if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/')) 3322 free(rawPath); /* full path => no CWDs happened => keep ftpc->prevpath */ 3323 else { 3324 free(ftpc->prevpath); 3325 3326 if(!ftpc->cwdfail) { 3327 if(data->set.ftp_filemethod == FTPFILE_NOCWD) 3328 pathLen = 0; /* relative path => working directory is FTP home */ 3329 else 3330 /* file is url-decoded */ 3331 pathLen -= ftpc->file ? strlen(ftpc->file) : 0; 3332 3333 rawPath[pathLen] = '\0'; 3334 ftpc->prevpath = rawPath; 3335 } 3336 else { 3337 free(rawPath); 3338 ftpc->prevpath = NULL; /* no path */ 3339 } 3340 } 3341 3342 if(ftpc->prevpath) 3343 infof(data, "Remembering we are in dir \"%s\"", ftpc->prevpath); 3344 } 3345 3346 /* free the dir tree and file parts */ 3347 freedirs(ftpc); 3348 3349 /* shut down the socket to inform the server we are done */ 3350 3351 #ifdef UNDER_CE 3352 shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */ 3353 #endif 3354 3355 if(Curl_conn_is_setup(conn, SECONDARYSOCKET)) { 3356 if(!result && ftpc->dont_check && data->req.maxdownload > 0) { 3357 /* partial download completed */ 3358 result = Curl_pp_sendf(data, pp, "%s", "ABOR"); 3359 if(result) { 3360 failf(data, "Failure sending ABOR command: %s", 3361 curl_easy_strerror(result)); 3362 ftpc->ctl_valid = FALSE; /* mark control connection as bad */ 3363 connclose(conn, "ABOR command failed"); /* connection closure */ 3364 } 3365 } 3366 3367 close_secondarysocket(data, ftpc); 3368 } 3369 3370 if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid && 3371 pp->pending_resp && !premature) { 3372 /* 3373 * Let's see what the server says about the transfer we just performed, 3374 * but lower the timeout as sometimes this connection has died while the 3375 * data has been transferred. This happens when doing through NATs etc that 3376 * abandon old silent connections. 3377 */ 3378 timediff_t old_time = pp->response_time; 3379 3380 pp->response_time = 60*1000; /* give it only a minute for now */ 3381 pp->response = curlx_now(); /* timeout relative now */ 3382 3383 result = Curl_GetFTPResponse(data, &nread, &ftpcode); 3384 3385 pp->response_time = old_time; /* set this back to previous value */ 3386 3387 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) { 3388 failf(data, "control connection looks dead"); 3389 ftpc->ctl_valid = FALSE; /* mark control connection as bad */ 3390 connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */ 3391 } 3392 3393 if(result) 3394 return result; 3395 3396 if(ftpc->dont_check && data->req.maxdownload > 0) { 3397 /* we have just sent ABOR and there is no reliable way to check if it was 3398 * successful or not; we have to close the connection now */ 3399 infof(data, "partial download completed, closing connection"); 3400 connclose(conn, "Partial download with no ability to check"); 3401 return result; 3402 } 3403 3404 if(!ftpc->dont_check) { 3405 /* 226 Transfer complete, 250 Requested file action okay, completed. */ 3406 switch(ftpcode) { 3407 case 226: 3408 case 250: 3409 break; 3410 case 552: 3411 failf(data, "Exceeded storage allocation"); 3412 result = CURLE_REMOTE_DISK_FULL; 3413 break; 3414 default: 3415 failf(data, "server did not report OK, got %d", ftpcode); 3416 result = CURLE_PARTIAL_FILE; 3417 break; 3418 } 3419 } 3420 } 3421 3422 if(result || premature) 3423 /* the response code from the transfer showed an error already so no 3424 use checking further */ 3425 ; 3426 else if(data->state.upload) { 3427 if((ftp->transfer == PPTRANSFER_BODY) && 3428 (data->state.infilesize != -1) && /* upload with known size */ 3429 ((!data->set.crlf && !data->state.prefer_ascii && /* no conversion */ 3430 (data->state.infilesize != data->req.writebytecount)) || 3431 ((data->set.crlf || data->state.prefer_ascii) && /* maybe crlf conv */ 3432 (data->state.infilesize > data->req.writebytecount)) 3433 )) { 3434 failf(data, "Uploaded unaligned file size (%" FMT_OFF_T 3435 " out of %" FMT_OFF_T " bytes)", 3436 data->req.writebytecount, data->state.infilesize); 3437 result = CURLE_PARTIAL_FILE; 3438 } 3439 } 3440 else { 3441 if((-1 != data->req.size) && 3442 (data->req.size != data->req.bytecount) && 3443 (data->req.maxdownload != data->req.bytecount)) { 3444 failf(data, "Received only partial file: %" FMT_OFF_T " bytes", 3445 data->req.bytecount); 3446 result = CURLE_PARTIAL_FILE; 3447 } 3448 else if(!ftpc->dont_check && 3449 !data->req.bytecount && 3450 (data->req.size > 0)) { 3451 failf(data, "No data was received"); 3452 result = CURLE_FTP_COULDNT_RETR_FILE; 3453 } 3454 } 3455 3456 /* clear these for next connection */ 3457 ftp->transfer = PPTRANSFER_BODY; 3458 ftpc->dont_check = FALSE; 3459 3460 /* Send any post-transfer QUOTE strings? */ 3461 if(!status && !result && !premature && data->set.postquote) 3462 result = ftp_sendquote(data, ftpc, data->set.postquote); 3463 CURL_TRC_FTP(data, "[%s] done, result=%d", FTP_CSTATE(ftpc), result); 3464 return result; 3465 } 3466 3467 /*********************************************************************** 3468 * 3469 * ftp_sendquote() 3470 * 3471 * Where a 'quote' means a list of custom commands to send to the server. 3472 * The quote list is passed as an argument. 3473 * 3474 * BLOCKING 3475 */ 3476 3477 static 3478 CURLcode ftp_sendquote(struct Curl_easy *data, 3479 struct ftp_conn *ftpc, 3480 struct curl_slist *quote) 3481 { 3482 struct curl_slist *item; 3483 struct pingpong *pp = &ftpc->pp; 3484 3485 item = quote; 3486 while(item) { 3487 if(item->data) { 3488 ssize_t nread; 3489 char *cmd = item->data; 3490 bool acceptfail = FALSE; 3491 CURLcode result; 3492 int ftpcode = 0; 3493 3494 /* if a command starts with an asterisk, which a legal FTP command never 3495 can, the command will be allowed to fail without it causing any 3496 aborts or cancels etc. It will cause libcurl to act as if the command 3497 is successful, whatever the server responds. */ 3498 3499 if(cmd[0] == '*') { 3500 cmd++; 3501 acceptfail = TRUE; 3502 } 3503 3504 result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd); 3505 if(!result) { 3506 pp->response = curlx_now(); /* timeout relative now */ 3507 result = Curl_GetFTPResponse(data, &nread, &ftpcode); 3508 } 3509 if(result) 3510 return result; 3511 3512 if(!acceptfail && (ftpcode >= 400)) { 3513 failf(data, "QUOT string not accepted: %s", cmd); 3514 return CURLE_QUOTE_ERROR; 3515 } 3516 } 3517 3518 item = item->next; 3519 } 3520 3521 return CURLE_OK; 3522 } 3523 3524 /*********************************************************************** 3525 * 3526 * ftp_need_type() 3527 * 3528 * Returns TRUE if we in the current situation should send TYPE 3529 */ 3530 static int ftp_need_type(struct ftp_conn *ftpc, 3531 bool ascii_wanted) 3532 { 3533 return ftpc->transfertype != (ascii_wanted ? 'A' : 'I'); 3534 } 3535 3536 /*********************************************************************** 3537 * 3538 * ftp_nb_type() 3539 * 3540 * Set TYPE. We only deal with ASCII or BINARY so this function 3541 * sets one of them. 3542 * If the transfer type is not sent, simulate on OK response in newstate 3543 */ 3544 static CURLcode ftp_nb_type(struct Curl_easy *data, 3545 struct ftp_conn *ftpc, 3546 struct FTP *ftp, 3547 bool ascii, ftpstate newstate) 3548 { 3549 CURLcode result; 3550 char want = (char)(ascii ? 'A' : 'I'); 3551 3552 if(ftpc->transfertype == want) { 3553 ftp_state(data, ftpc, newstate); 3554 return ftp_state_type_resp(data, ftpc, ftp, 200, newstate); 3555 } 3556 3557 result = Curl_pp_sendf(data, &ftpc->pp, "TYPE %c", want); 3558 if(!result) { 3559 ftp_state(data, ftpc, newstate); 3560 3561 /* keep track of our current transfer type */ 3562 ftpc->transfertype = want; 3563 } 3564 return result; 3565 } 3566 3567 /*************************************************************************** 3568 * 3569 * ftp_pasv_verbose() 3570 * 3571 * This function only outputs some informationals about this second connection 3572 * when we have issued a PASV command before and thus we have connected to a 3573 * possibly new IP address. 3574 * 3575 */ 3576 #ifndef CURL_DISABLE_VERBOSE_STRINGS 3577 static void 3578 ftp_pasv_verbose(struct Curl_easy *data, 3579 struct Curl_addrinfo *ai, 3580 char *newhost, /* ASCII version */ 3581 int port) 3582 { 3583 char buf[256]; 3584 Curl_printable_address(ai, buf, sizeof(buf)); 3585 infof(data, "Connecting to %s (%s) port %d", newhost, buf, port); 3586 } 3587 #endif 3588 3589 /* 3590 * ftp_do_more() 3591 * 3592 * This function shall be called when the second FTP (data) connection is 3593 * connected. 3594 * 3595 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back 3596 * (which basically is only for when PASV is being sent to retry a failed 3597 * EPSV). 3598 */ 3599 3600 static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) 3601 { 3602 struct connectdata *conn = data->conn; 3603 struct ftp_conn *ftpc = Curl_conn_meta_get(data->conn, CURL_META_FTP_CONN); 3604 struct FTP *ftp = Curl_meta_get(data, CURL_META_FTP_EASY); 3605 CURLcode result = CURLE_OK; 3606 bool connected = FALSE; 3607 bool complete = FALSE; 3608 /* the ftp struct is inited in ftp_connect(). If we are connecting to an HTTP 3609 * proxy then the state will not be valid until after that connection is 3610 * complete */ 3611 3612 if(!ftpc || !ftp) 3613 return CURLE_FAILED_INIT; 3614 /* if the second connection has been set up, try to connect it fully 3615 * to the remote host. This may not complete at this time, for several 3616 * reasons: 3617 * - we do EPTR and the server will not connect to our listen socket 3618 * until we send more FTP commands 3619 * - an SSL filter is in place and the server will not start the TLS 3620 * handshake until we send more FTP commands 3621 */ 3622 if(conn->cfilter[SECONDARYSOCKET]) { 3623 bool is_eptr = Curl_conn_is_tcp_listen(data, SECONDARYSOCKET); 3624 result = Curl_conn_connect(data, SECONDARYSOCKET, FALSE, &connected); 3625 if(result || (!connected && !is_eptr && 3626 !Curl_conn_is_ip_connected(data, SECONDARYSOCKET))) { 3627 if(result && !is_eptr && (ftpc->count1 == 0)) { 3628 *completep = -1; /* go back to DOING please */ 3629 /* this is a EPSV connect failing, try PASV instead */ 3630 return ftp_epsv_disable(data, ftpc, conn); 3631 } 3632 *completep = (int)complete; 3633 return result; 3634 } 3635 } 3636 3637 if(ftpc->state) { 3638 /* already in a state so skip the initial commands. 3639 They are only done to kickstart the do_more state */ 3640 result = ftp_statemach(data, ftpc, &complete); 3641 3642 *completep = (int)complete; 3643 3644 /* if we got an error or if we do not wait for a data connection return 3645 immediately */ 3646 if(result || !ftpc->wait_data_conn) 3647 return result; 3648 3649 /* if we reach the end of the FTP state machine here, *complete will be 3650 TRUE but so is ftpc->wait_data_conn, which says we need to wait for the 3651 data connection and therefore we are not actually complete */ 3652 *completep = 0; 3653 } 3654 3655 if(ftp->transfer <= PPTRANSFER_INFO) { 3656 /* a transfer is about to take place, or if not a filename was given so we 3657 will do a SIZE on it later and then we need the right TYPE first */ 3658 3659 if(ftpc->wait_data_conn) { 3660 bool serv_conned; 3661 3662 result = Curl_conn_connect(data, SECONDARYSOCKET, FALSE, &serv_conned); 3663 if(result) 3664 return result; /* Failed to accept data connection */ 3665 3666 if(serv_conned) { 3667 /* It looks data connection is established */ 3668 ftpc->wait_data_conn = FALSE; 3669 result = ftp_initiate_transfer(data, ftpc); 3670 3671 if(result) 3672 return result; 3673 3674 *completep = 1; /* this state is now complete when the server has 3675 connected back to us */ 3676 } 3677 else { 3678 result = ftp_check_ctrl_on_data_wait(data, ftpc); 3679 if(result) 3680 return result; 3681 } 3682 } 3683 else if(data->state.upload) { 3684 result = ftp_nb_type(data, ftpc, ftp, data->state.prefer_ascii, 3685 FTP_STOR_TYPE); 3686 if(result) 3687 return result; 3688 3689 result = ftp_statemach(data, ftpc, &complete); 3690 /* ftp_nb_type() might have skipped sending `TYPE A|I` when not 3691 * deemed necessary and directly sent `STORE name`. If this was 3692 * then complete, but we are still waiting on the data connection, 3693 * the transfer has not been initiated yet. */ 3694 *completep = (int)(ftpc->wait_data_conn ? 0 : complete); 3695 } 3696 else { 3697 /* download */ 3698 ftp->downloadsize = -1; /* unknown as of yet */ 3699 3700 result = Curl_range(data); 3701 3702 if(result == CURLE_OK && data->req.maxdownload >= 0) { 3703 /* Do not check for successful transfer */ 3704 ftpc->dont_check = TRUE; 3705 } 3706 3707 if(result) 3708 ; 3709 else if((data->state.list_only || !ftpc->file) && 3710 !(data->set.prequote)) { 3711 /* The specified path ends with a slash, and therefore we think this 3712 is a directory that is requested, use LIST. But before that we 3713 need to set ASCII transfer mode. */ 3714 3715 /* But only if a body transfer was requested. */ 3716 if(ftp->transfer == PPTRANSFER_BODY) { 3717 result = ftp_nb_type(data, ftpc, ftp, TRUE, FTP_LIST_TYPE); 3718 if(result) 3719 return result; 3720 } 3721 /* otherwise just fall through */ 3722 } 3723 else { 3724 if(data->set.prequote && !ftpc->file) { 3725 result = ftp_nb_type(data, ftpc, ftp, TRUE, 3726 FTP_RETR_LIST_TYPE); 3727 } 3728 else { 3729 result = ftp_nb_type(data, ftpc, ftp, data->state.prefer_ascii, 3730 FTP_RETR_TYPE); 3731 } 3732 if(result) 3733 return result; 3734 } 3735 3736 result = ftp_statemach(data, ftpc, &complete); 3737 *completep = (int)complete; 3738 } 3739 return result; 3740 } 3741 3742 /* no data to transfer */ 3743 Curl_xfer_setup_nop(data); 3744 3745 if(!ftpc->wait_data_conn) { 3746 /* no waiting for the data connection so this is now complete */ 3747 *completep = 1; 3748 CURL_TRC_FTP(data, "[%s] DO-MORE phase ends with %d", FTP_CSTATE(ftpc), 3749 (int)result); 3750 } 3751 3752 return result; 3753 } 3754 3755 3756 3757 /*********************************************************************** 3758 * 3759 * ftp_perform() 3760 * 3761 * This is the actual DO function for FTP. Get a file/directory according to 3762 * the options previously setup. 3763 */ 3764 3765 static 3766 CURLcode ftp_perform(struct Curl_easy *data, 3767 struct ftp_conn *ftpc, 3768 struct FTP *ftp, 3769 bool *connected, /* connect status after PASV / PORT */ 3770 bool *dophase_done) 3771 { 3772 /* this is FTP and no proxy */ 3773 CURLcode result = CURLE_OK; 3774 3775 CURL_TRC_FTP(data, "[%s] DO phase starts", FTP_CSTATE(ftpc)); 3776 3777 if(data->req.no_body) { 3778 /* requested no body means no transfer... */ 3779 ftp->transfer = PPTRANSFER_INFO; 3780 } 3781 3782 *dophase_done = FALSE; /* not done yet */ 3783 3784 /* start the first command in the DO phase */ 3785 result = ftp_state_quote(data, ftpc, ftp, TRUE, FTP_QUOTE); 3786 if(result) 3787 return result; 3788 3789 /* run the state-machine */ 3790 result = ftp_statemach(data, ftpc, dophase_done); 3791 3792 *connected = Curl_conn_is_connected(data->conn, SECONDARYSOCKET); 3793 3794 if(*connected) 3795 infof(data, "[FTP] [%s] perform, DATA connection established", 3796 FTP_CSTATE(ftpc)); 3797 else 3798 CURL_TRC_FTP(data, "[%s] perform, awaiting DATA connect", 3799 FTP_CSTATE(ftpc)); 3800 3801 if(*dophase_done) 3802 CURL_TRC_FTP(data, "[%s] DO phase is complete1", FTP_CSTATE(ftpc)); 3803 3804 return result; 3805 } 3806 3807 static void wc_data_dtor(void *ptr) 3808 { 3809 struct ftp_wc *ftpwc = ptr; 3810 if(ftpwc && ftpwc->parser) 3811 Curl_ftp_parselist_data_free(&ftpwc->parser); 3812 free(ftpwc); 3813 } 3814 3815 static CURLcode init_wc_data(struct Curl_easy *data, 3816 struct ftp_conn *ftpc, 3817 struct FTP *ftp) 3818 { 3819 char *last_slash; 3820 char *path = ftp->path; 3821 struct WildcardData *wildcard = data->wildcard; 3822 CURLcode result = CURLE_OK; 3823 struct ftp_wc *ftpwc = NULL; 3824 3825 last_slash = strrchr(ftp->path, '/'); 3826 if(last_slash) { 3827 last_slash++; 3828 if(last_slash[0] == '\0') { 3829 wildcard->state = CURLWC_CLEAN; 3830 return ftp_parse_url_path(data, ftpc, ftp); 3831 } 3832 wildcard->pattern = strdup(last_slash); 3833 if(!wildcard->pattern) 3834 return CURLE_OUT_OF_MEMORY; 3835 last_slash[0] = '\0'; /* cut file from path */ 3836 } 3837 else { /* there is only 'wildcard pattern' or nothing */ 3838 if(path[0]) { 3839 wildcard->pattern = strdup(path); 3840 if(!wildcard->pattern) 3841 return CURLE_OUT_OF_MEMORY; 3842 path[0] = '\0'; 3843 } 3844 else { /* only list */ 3845 wildcard->state = CURLWC_CLEAN; 3846 return ftp_parse_url_path(data, ftpc, ftp); 3847 } 3848 } 3849 3850 /* program continues only if URL is not ending with slash, allocate needed 3851 resources for wildcard transfer */ 3852 3853 /* allocate ftp protocol specific wildcard data */ 3854 ftpwc = calloc(1, sizeof(struct ftp_wc)); 3855 if(!ftpwc) { 3856 result = CURLE_OUT_OF_MEMORY; 3857 goto fail; 3858 } 3859 3860 /* INITIALIZE parselist structure */ 3861 ftpwc->parser = Curl_ftp_parselist_data_alloc(); 3862 if(!ftpwc->parser) { 3863 result = CURLE_OUT_OF_MEMORY; 3864 goto fail; 3865 } 3866 3867 wildcard->ftpwc = ftpwc; /* put it to the WildcardData tmp pointer */ 3868 wildcard->dtor = wc_data_dtor; 3869 3870 /* wildcard does not support NOCWD option (assert it?) */ 3871 if(data->set.ftp_filemethod == FTPFILE_NOCWD) 3872 data->set.ftp_filemethod = FTPFILE_MULTICWD; 3873 3874 /* try to parse ftp URL */ 3875 result = ftp_parse_url_path(data, ftpc, ftp); 3876 if(result) { 3877 goto fail; 3878 } 3879 3880 wildcard->path = strdup(ftp->path); 3881 if(!wildcard->path) { 3882 result = CURLE_OUT_OF_MEMORY; 3883 goto fail; 3884 } 3885 3886 /* backup old write_function */ 3887 ftpwc->backup.write_function = data->set.fwrite_func; 3888 /* parsing write function */ 3889 data->set.fwrite_func = Curl_ftp_parselist; 3890 /* backup old file descriptor */ 3891 ftpwc->backup.file_descriptor = data->set.out; 3892 /* let the writefunc callback know the transfer */ 3893 data->set.out = data; 3894 3895 infof(data, "Wildcard - Parsing started"); 3896 return CURLE_OK; 3897 3898 fail: 3899 if(ftpwc) { 3900 Curl_ftp_parselist_data_free(&ftpwc->parser); 3901 free(ftpwc); 3902 } 3903 Curl_safefree(wildcard->pattern); 3904 wildcard->dtor = ZERO_NULL; 3905 wildcard->ftpwc = NULL; 3906 return result; 3907 } 3908 3909 static CURLcode wc_statemach(struct Curl_easy *data, 3910 struct ftp_conn *ftpc, 3911 struct FTP *ftp) 3912 { 3913 struct WildcardData * const wildcard = data->wildcard; 3914 CURLcode result = CURLE_OK; 3915 3916 for(;;) { 3917 switch(wildcard->state) { 3918 case CURLWC_INIT: 3919 result = init_wc_data(data, ftpc, ftp); 3920 if(wildcard->state == CURLWC_CLEAN) 3921 /* only listing! */ 3922 return result; 3923 wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING; 3924 return result; 3925 3926 case CURLWC_MATCHING: { 3927 /* In this state is LIST response successfully parsed, so lets restore 3928 previous WRITEFUNCTION callback and WRITEDATA pointer */ 3929 struct ftp_wc *ftpwc = wildcard->ftpwc; 3930 data->set.fwrite_func = ftpwc->backup.write_function; 3931 data->set.out = ftpwc->backup.file_descriptor; 3932 ftpwc->backup.write_function = ZERO_NULL; 3933 ftpwc->backup.file_descriptor = NULL; 3934 wildcard->state = CURLWC_DOWNLOADING; 3935 3936 if(Curl_ftp_parselist_geterror(ftpwc->parser)) { 3937 /* error found in LIST parsing */ 3938 wildcard->state = CURLWC_CLEAN; 3939 continue; 3940 } 3941 if(Curl_llist_count(&wildcard->filelist) == 0) { 3942 /* no corresponding file */ 3943 wildcard->state = CURLWC_CLEAN; 3944 return CURLE_REMOTE_FILE_NOT_FOUND; 3945 } 3946 continue; 3947 } 3948 3949 case CURLWC_DOWNLOADING: { 3950 /* filelist has at least one file, lets get first one */ 3951 struct Curl_llist_node *head = Curl_llist_head(&wildcard->filelist); 3952 struct curl_fileinfo *finfo = Curl_node_elem(head); 3953 3954 char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); 3955 if(!tmp_path) 3956 return CURLE_OUT_OF_MEMORY; 3957 3958 /* switch default ftp->path and tmp_path */ 3959 free(ftp->pathalloc); 3960 ftp->pathalloc = ftp->path = tmp_path; 3961 3962 infof(data, "Wildcard - START of \"%s\"", finfo->filename); 3963 if(data->set.chunk_bgn) { 3964 long userresponse; 3965 Curl_set_in_callback(data, TRUE); 3966 userresponse = data->set.chunk_bgn( 3967 finfo, data->set.wildcardptr, 3968 (int)Curl_llist_count(&wildcard->filelist)); 3969 Curl_set_in_callback(data, FALSE); 3970 switch(userresponse) { 3971 case CURL_CHUNK_BGN_FUNC_SKIP: 3972 infof(data, "Wildcard - \"%s\" skipped by user", 3973 finfo->filename); 3974 wildcard->state = CURLWC_SKIP; 3975 continue; 3976 case CURL_CHUNK_BGN_FUNC_FAIL: 3977 return CURLE_CHUNK_FAILED; 3978 } 3979 } 3980 3981 if(finfo->filetype != CURLFILETYPE_FILE) { 3982 wildcard->state = CURLWC_SKIP; 3983 continue; 3984 } 3985 3986 if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE) 3987 ftpc->known_filesize = finfo->size; 3988 3989 result = ftp_parse_url_path(data, ftpc, ftp); 3990 if(result) 3991 return result; 3992 3993 /* we do not need the Curl_fileinfo of first file anymore */ 3994 Curl_node_remove(Curl_llist_head(&wildcard->filelist)); 3995 3996 if(Curl_llist_count(&wildcard->filelist) == 0) { 3997 /* remains only one file to down. */ 3998 wildcard->state = CURLWC_CLEAN; 3999 /* after that will be ftp_do called once again and no transfer 4000 will be done because of CURLWC_CLEAN state */ 4001 return CURLE_OK; 4002 } 4003 return result; 4004 } 4005 4006 case CURLWC_SKIP: { 4007 if(data->set.chunk_end) { 4008 Curl_set_in_callback(data, TRUE); 4009 data->set.chunk_end(data->set.wildcardptr); 4010 Curl_set_in_callback(data, FALSE); 4011 } 4012 Curl_node_remove(Curl_llist_head(&wildcard->filelist)); 4013 wildcard->state = (Curl_llist_count(&wildcard->filelist) == 0) ? 4014 CURLWC_CLEAN : CURLWC_DOWNLOADING; 4015 continue; 4016 } 4017 4018 case CURLWC_CLEAN: { 4019 struct ftp_wc *ftpwc = wildcard->ftpwc; 4020 result = CURLE_OK; 4021 if(ftpwc) 4022 result = Curl_ftp_parselist_geterror(ftpwc->parser); 4023 4024 wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE; 4025 return result; 4026 } 4027 4028 case CURLWC_DONE: 4029 case CURLWC_ERROR: 4030 case CURLWC_CLEAR: 4031 if(wildcard->dtor) { 4032 wildcard->dtor(wildcard->ftpwc); 4033 wildcard->ftpwc = NULL; 4034 } 4035 return result; 4036 } 4037 } 4038 /* UNREACHABLE */ 4039 } 4040 4041 /*********************************************************************** 4042 * 4043 * ftp_do() 4044 * 4045 * This function is registered as 'curl_do' function. It decodes the path 4046 * parts etc as a wrapper to the actual DO function (ftp_perform). 4047 * 4048 * The input argument is already checked for validity. 4049 */ 4050 static CURLcode ftp_do(struct Curl_easy *data, bool *done) 4051 { 4052 CURLcode result = CURLE_OK; 4053 struct ftp_conn *ftpc = Curl_conn_meta_get(data->conn, CURL_META_FTP_CONN); 4054 struct FTP *ftp = Curl_meta_get(data, CURL_META_FTP_EASY); 4055 4056 *done = FALSE; /* default to false */ 4057 if(!ftpc || !ftp) 4058 return CURLE_FAILED_INIT; 4059 ftpc->wait_data_conn = FALSE; /* default to no such wait */ 4060 4061 #ifdef CURL_PREFER_LF_LINEENDS 4062 { 4063 /* FTP data may need conversion. */ 4064 struct Curl_cwriter *ftp_lc_writer; 4065 4066 result = Curl_cwriter_create(&ftp_lc_writer, data, &ftp_cw_lc, 4067 CURL_CW_CONTENT_DECODE); 4068 if(result) 4069 return result; 4070 4071 result = Curl_cwriter_add(data, ftp_lc_writer); 4072 if(result) { 4073 Curl_cwriter_free(data, ftp_lc_writer); 4074 return result; 4075 } 4076 } 4077 #endif /* CURL_PREFER_LF_LINEENDS */ 4078 4079 if(data->state.wildcardmatch) { 4080 result = wc_statemach(data, ftpc, ftp); 4081 if(data->wildcard->state == CURLWC_SKIP || 4082 data->wildcard->state == CURLWC_DONE) { 4083 /* do not call ftp_regular_transfer */ 4084 return CURLE_OK; 4085 } 4086 if(result) /* error, loop or skipping the file */ 4087 return result; 4088 } 4089 else { /* no wildcard FSM needed */ 4090 result = ftp_parse_url_path(data, ftpc, ftp); 4091 if(result) 4092 return result; 4093 } 4094 4095 result = ftp_regular_transfer(data, ftpc, ftp, done); 4096 4097 return result; 4098 } 4099 4100 /*********************************************************************** 4101 * 4102 * ftp_quit() 4103 * 4104 * This should be called before calling sclose() on an ftp control connection 4105 * (not data connections). We should then wait for the response from the 4106 * server before returning. The calling code should then try to close the 4107 * connection. 4108 * 4109 */ 4110 static CURLcode ftp_quit(struct Curl_easy *data, 4111 struct ftp_conn *ftpc) 4112 { 4113 CURLcode result = CURLE_OK; 4114 4115 if(ftpc->ctl_valid) { 4116 CURL_TRC_FTP(data, "sending QUIT to close session"); 4117 result = Curl_pp_sendf(data, &ftpc->pp, "%s", "QUIT"); 4118 if(result) { 4119 failf(data, "Failure sending QUIT command: %s", 4120 curl_easy_strerror(result)); 4121 ftpc->ctl_valid = FALSE; /* mark control connection as bad */ 4122 connclose(data->conn, "QUIT command failed"); /* mark for closure */ 4123 ftp_state(data, ftpc, FTP_STOP); 4124 return result; 4125 } 4126 4127 ftp_state(data, ftpc, FTP_QUIT); 4128 4129 result = ftp_block_statemach(data, ftpc); 4130 } 4131 4132 return result; 4133 } 4134 4135 /*********************************************************************** 4136 * 4137 * ftp_disconnect() 4138 * 4139 * Disconnect from an FTP server. Cleanup protocol-specific per-connection 4140 * resources. BLOCKING. 4141 */ 4142 static CURLcode ftp_disconnect(struct Curl_easy *data, 4143 struct connectdata *conn, 4144 bool dead_connection) 4145 { 4146 struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN); 4147 4148 if(!ftpc) 4149 return CURLE_FAILED_INIT; 4150 /* We cannot send quit unconditionally. If this connection is stale or 4151 bad in any way, sending quit and waiting around here will make the 4152 disconnect wait in vain and cause more problems than we need to. 4153 4154 ftp_quit() will check the state of ftp->ctl_valid. If it is ok it 4155 will try to send the QUIT command, otherwise it will just return. 4156 */ 4157 ftpc->shutdown = TRUE; 4158 if(dead_connection || Curl_pp_needs_flush(data, &ftpc->pp)) 4159 ftpc->ctl_valid = FALSE; 4160 4161 /* The FTP session may or may not have been allocated/setup at this point! */ 4162 (void)ftp_quit(data, ftpc); /* ignore errors on the QUIT */ 4163 return CURLE_OK; 4164 } 4165 4166 /*********************************************************************** 4167 * 4168 * ftp_parse_url_path() 4169 * 4170 * Parse the URL path into separate path components. 4171 * 4172 */ 4173 static 4174 CURLcode ftp_parse_url_path(struct Curl_easy *data, 4175 struct ftp_conn *ftpc, 4176 struct FTP *ftp) 4177 { 4178 const char *slashPos = NULL; 4179 const char *fileName = NULL; 4180 CURLcode result = CURLE_OK; 4181 char *rawPath = NULL; /* url-decoded "raw" path */ 4182 size_t pathLen = 0; 4183 4184 ftpc->ctl_valid = FALSE; 4185 ftpc->cwdfail = FALSE; 4186 4187 /* url-decode ftp path before further evaluation */ 4188 result = Curl_urldecode(ftp->path, 0, &rawPath, &pathLen, REJECT_CTRL); 4189 if(result) { 4190 failf(data, "path contains control characters"); 4191 return result; 4192 } 4193 4194 switch(data->set.ftp_filemethod) { 4195 case FTPFILE_NOCWD: /* fastest, but less standard-compliant */ 4196 4197 if((pathLen > 0) && (rawPath[pathLen - 1] != '/')) 4198 fileName = rawPath; /* this is a full file path */ 4199 /* 4200 else: ftpc->file is not used anywhere other than for operations on 4201 a file. In other words, never for directory operations. 4202 So we can safely leave filename as NULL here and use it as a 4203 argument in dir/file decisions. 4204 */ 4205 break; 4206 4207 case FTPFILE_SINGLECWD: 4208 slashPos = strrchr(rawPath, '/'); 4209 if(slashPos) { 4210 /* get path before last slash, except for / */ 4211 size_t dirlen = slashPos - rawPath; 4212 if(dirlen == 0) 4213 dirlen = 1; 4214 4215 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0])); 4216 if(!ftpc->dirs) { 4217 free(rawPath); 4218 return CURLE_OUT_OF_MEMORY; 4219 } 4220 4221 ftpc->dirs[0] = Curl_memdup0(rawPath, dirlen); 4222 if(!ftpc->dirs[0]) { 4223 free(rawPath); 4224 return CURLE_OUT_OF_MEMORY; 4225 } 4226 4227 ftpc->dirdepth = 1; /* we consider it to be a single dir */ 4228 fileName = slashPos + 1; /* rest is filename */ 4229 } 4230 else 4231 fileName = rawPath; /* filename only (or empty) */ 4232 break; 4233 4234 default: /* allow pretty much anything */ 4235 case FTPFILE_MULTICWD: { 4236 /* current position: begin of next path component */ 4237 const char *curPos = rawPath; 4238 4239 /* number of entries allocated for the 'dirs' array */ 4240 size_t dirAlloc = 0; 4241 const char *str = rawPath; 4242 for(; *str != 0; ++str) 4243 if(*str == '/') 4244 ++dirAlloc; 4245 4246 if(dirAlloc) { 4247 ftpc->dirs = calloc(dirAlloc, sizeof(ftpc->dirs[0])); 4248 if(!ftpc->dirs) { 4249 free(rawPath); 4250 return CURLE_OUT_OF_MEMORY; 4251 } 4252 4253 /* parse the URL path into separate path components */ 4254 /* !checksrc! disable EQUALSNULL 1 */ 4255 while((slashPos = strchr(curPos, '/')) != NULL) { 4256 size_t compLen = slashPos - curPos; 4257 4258 /* path starts with a slash: add that as a directory */ 4259 if((compLen == 0) && (ftpc->dirdepth == 0)) 4260 ++compLen; 4261 4262 /* we skip empty path components, like "x//y" since the FTP command 4263 CWD requires a parameter and a non-existent parameter a) does not 4264 work on many servers and b) has no effect on the others. */ 4265 if(compLen > 0) { 4266 char *comp = Curl_memdup0(curPos, compLen); 4267 if(!comp) { 4268 free(rawPath); 4269 return CURLE_OUT_OF_MEMORY; 4270 } 4271 ftpc->dirs[ftpc->dirdepth++] = comp; 4272 } 4273 curPos = slashPos + 1; 4274 } 4275 } 4276 DEBUGASSERT((size_t)ftpc->dirdepth <= dirAlloc); 4277 fileName = curPos; /* the rest is the filename (or empty) */ 4278 } 4279 break; 4280 } /* switch */ 4281 4282 if(fileName && *fileName) 4283 ftpc->file = strdup(fileName); 4284 else 4285 ftpc->file = NULL; /* instead of point to a zero byte, 4286 we make it a NULL pointer */ 4287 4288 if(data->state.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) { 4289 /* We need a filename when uploading. Return error! */ 4290 failf(data, "Uploading to a URL without a filename"); 4291 free(rawPath); 4292 return CURLE_URL_MALFORMAT; 4293 } 4294 4295 ftpc->cwddone = FALSE; /* default to not done */ 4296 4297 if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/')) 4298 ftpc->cwddone = TRUE; /* skip CWD for absolute paths */ 4299 else { /* newly created FTP connections are already in entry path */ 4300 const char *oldPath = data->conn->bits.reuse ? ftpc->prevpath : ""; 4301 if(oldPath) { 4302 size_t n = pathLen; 4303 if(data->set.ftp_filemethod == FTPFILE_NOCWD) 4304 n = 0; /* CWD to entry for relative paths */ 4305 else 4306 n -= ftpc->file ? strlen(ftpc->file) : 0; 4307 4308 if((strlen(oldPath) == n) && rawPath && !strncmp(rawPath, oldPath, n)) { 4309 infof(data, "Request has same path as previous transfer"); 4310 ftpc->cwddone = TRUE; 4311 } 4312 } 4313 } 4314 4315 free(rawPath); 4316 return CURLE_OK; 4317 } 4318 4319 /* call this when the DO phase has completed */ 4320 static CURLcode ftp_dophase_done(struct Curl_easy *data, 4321 struct ftp_conn *ftpc, 4322 struct FTP *ftp, 4323 bool connected) 4324 { 4325 if(connected) { 4326 int completed; 4327 CURLcode result = ftp_do_more(data, &completed); 4328 4329 if(result) { 4330 close_secondarysocket(data, ftpc); 4331 return result; 4332 } 4333 } 4334 4335 if(ftp->transfer != PPTRANSFER_BODY) 4336 /* no data to transfer */ 4337 Curl_xfer_setup_nop(data); 4338 else if(!connected) 4339 /* since we did not connect now, we want do_more to get called */ 4340 data->conn->bits.do_more = TRUE; 4341 4342 ftpc->ctl_valid = TRUE; /* seems good */ 4343 4344 return CURLE_OK; 4345 } 4346 4347 /* called from multi.c while DOing */ 4348 static CURLcode ftp_doing(struct Curl_easy *data, 4349 bool *dophase_done) 4350 { 4351 struct ftp_conn *ftpc = Curl_conn_meta_get(data->conn, CURL_META_FTP_CONN); 4352 struct FTP *ftp = Curl_meta_get(data, CURL_META_FTP_EASY); 4353 CURLcode result; 4354 4355 if(!ftpc || !ftp) 4356 return CURLE_FAILED_INIT; 4357 result = ftp_statemach(data, ftpc, dophase_done); 4358 4359 if(result) 4360 CURL_TRC_FTP(data, "[%s] DO phase failed", FTP_CSTATE(ftpc)); 4361 else if(*dophase_done) { 4362 result = ftp_dophase_done(data, ftpc, ftp, FALSE /* not connected */); 4363 4364 CURL_TRC_FTP(data, "[%s] DO phase is complete2", FTP_CSTATE(ftpc)); 4365 } 4366 return result; 4367 } 4368 4369 /*********************************************************************** 4370 * 4371 * ftp_regular_transfer() 4372 * 4373 * The input argument is already checked for validity. 4374 * 4375 * Performs all commands done before a regular transfer between a local and a 4376 * remote host. 4377 * 4378 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the 4379 * ftp_done() function without finding any major problem. 4380 */ 4381 static 4382 CURLcode ftp_regular_transfer(struct Curl_easy *data, 4383 struct ftp_conn *ftpc, 4384 struct FTP *ftp, 4385 bool *dophase_done) 4386 { 4387 CURLcode result = CURLE_OK; 4388 bool connected = FALSE; 4389 data->req.size = -1; /* make sure this is unknown at this point */ 4390 4391 Curl_pgrsSetUploadCounter(data, 0); 4392 Curl_pgrsSetDownloadCounter(data, 0); 4393 Curl_pgrsSetUploadSize(data, -1); 4394 Curl_pgrsSetDownloadSize(data, -1); 4395 4396 ftpc->ctl_valid = TRUE; /* starts good */ 4397 4398 result = ftp_perform(data, ftpc, ftp, 4399 &connected, /* have we connected after PASV/PORT */ 4400 dophase_done); /* all commands in the DO-phase done? */ 4401 4402 if(!result) { 4403 4404 if(!*dophase_done) 4405 /* the DO phase has not completed yet */ 4406 return CURLE_OK; 4407 4408 result = ftp_dophase_done(data, ftpc, ftp, connected); 4409 4410 if(result) 4411 return result; 4412 } 4413 else 4414 freedirs(ftpc); 4415 4416 return result; 4417 } 4418 4419 static void ftp_easy_dtor(void *key, size_t klen, void *entry) 4420 { 4421 struct FTP *ftp = entry; 4422 (void)key; 4423 (void)klen; 4424 Curl_safefree(ftp->pathalloc); 4425 free(ftp); 4426 } 4427 4428 static void ftp_conn_dtor(void *key, size_t klen, void *entry) 4429 { 4430 struct ftp_conn *ftpc = entry; 4431 (void)key; 4432 (void)klen; 4433 freedirs(ftpc); 4434 Curl_safefree(ftpc->account); 4435 Curl_safefree(ftpc->alternative_to_user); 4436 Curl_safefree(ftpc->entrypath); 4437 Curl_safefree(ftpc->prevpath); 4438 Curl_safefree(ftpc->server_os); 4439 Curl_pp_disconnect(&ftpc->pp); 4440 free(ftpc); 4441 } 4442 4443 static CURLcode ftp_setup_connection(struct Curl_easy *data, 4444 struct connectdata *conn) 4445 { 4446 char *type; 4447 struct FTP *ftp; 4448 CURLcode result = CURLE_OK; 4449 struct ftp_conn *ftpc; 4450 4451 ftp = calloc(1, sizeof(*ftp)); 4452 if(!ftp || 4453 Curl_meta_set(data, CURL_META_FTP_EASY, ftp, ftp_easy_dtor)) 4454 return CURLE_OUT_OF_MEMORY; 4455 4456 ftpc = calloc(1, sizeof(*ftpc)); 4457 if(!ftpc || 4458 Curl_conn_meta_set(conn, CURL_META_FTP_CONN, ftpc, ftp_conn_dtor)) 4459 return CURLE_OUT_OF_MEMORY; 4460 4461 /* clone connection related data that is FTP specific */ 4462 if(data->set.str[STRING_FTP_ACCOUNT]) { 4463 ftpc->account = strdup(data->set.str[STRING_FTP_ACCOUNT]); 4464 if(!ftpc->account) { 4465 Curl_conn_meta_remove(conn, CURL_META_FTP_CONN); 4466 return CURLE_OUT_OF_MEMORY; 4467 } 4468 } 4469 if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]) { 4470 ftpc->alternative_to_user = 4471 strdup(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); 4472 if(!ftpc->alternative_to_user) { 4473 Curl_safefree(ftpc->account); 4474 Curl_conn_meta_remove(conn, CURL_META_FTP_CONN); 4475 return CURLE_OUT_OF_MEMORY; 4476 } 4477 } 4478 4479 ftp->path = &data->state.up.path[1]; /* do not include the initial slash */ 4480 4481 /* FTP URLs support an extension like ";type=<typecode>" that 4482 * we will try to get now! */ 4483 type = strstr(ftp->path, ";type="); 4484 4485 if(!type) 4486 type = strstr(conn->host.rawalloc, ";type="); 4487 4488 if(type) { 4489 char command; 4490 *type = 0; /* it was in the middle of the hostname */ 4491 command = Curl_raw_toupper(type[6]); 4492 4493 switch(command) { 4494 case 'A': /* ASCII mode */ 4495 data->state.prefer_ascii = TRUE; 4496 break; 4497 4498 case 'D': /* directory mode */ 4499 data->state.list_only = TRUE; 4500 break; 4501 4502 case 'I': /* binary mode */ 4503 default: 4504 /* switch off ASCII */ 4505 data->state.prefer_ascii = FALSE; 4506 break; 4507 } 4508 } 4509 4510 /* get some initial data into the ftp struct */ 4511 ftp->transfer = PPTRANSFER_BODY; 4512 ftp->downloadsize = 0; 4513 ftpc->known_filesize = -1; /* unknown size for now */ 4514 ftpc->use_ssl = data->set.use_ssl; 4515 ftpc->ccc = data->set.ftp_ccc; 4516 4517 CURL_TRC_FTP(data, "[%s] setup connection -> %d", FTP_CSTATE(ftpc), result); 4518 return result; 4519 } 4520 4521 bool ftp_conns_match(struct connectdata *needle, struct connectdata *conn) 4522 { 4523 struct ftp_conn *nftpc = Curl_conn_meta_get(needle, CURL_META_FTP_CONN); 4524 struct ftp_conn *cftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN); 4525 /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */ 4526 if(!nftpc || !cftpc || 4527 Curl_timestrcmp(nftpc->account, cftpc->account) || 4528 Curl_timestrcmp(nftpc->alternative_to_user, 4529 cftpc->alternative_to_user) || 4530 (nftpc->use_ssl != cftpc->use_ssl) || 4531 (nftpc->ccc != cftpc->ccc)) 4532 return FALSE; 4533 return TRUE; 4534 } 4535 4536 #endif /* CURL_DISABLE_FTP */