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