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