VirtualBox

source: vbox/trunk/src/libs/curl-7.64.0/lib/ftp.c@ 90406

Last change on this file since 90406 was 85671, checked in by vboxsync, 5 years ago

Export out internal curl copy to make it a lot simpler to build VBox (OSE) on Windows. bugref:9814

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette