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