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