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