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