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