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