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