source: azure_iot_hub/trunk/curl-7.57.0/lib/ftp.c@ 388

Last change on this file since 388 was 388, checked in by coas-nagasima, 5 years ago

Azure IoT Hub Device C SDK を使ったサンプルの追加

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