source: UsbWattMeter/trunk/curl-7.47.1/lib/ftp.c@ 164

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

TOPPERS/ECNLサンプルアプリ「USB充電器電力計」を追加

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