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_ssl_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 if((ip_end = strchr(string_ftpport, ']')) != NULL)
1039 strncpy(addr, ip_start, ip_end - ip_start);
1040 }
1041 else
1042 #endif
1043 if(*string_ftpport == ':') {
1044 /* :port */
1045 ip_end = string_ftpport;
1046 }
1047 else if((ip_end = strchr(string_ftpport, ':')) != NULL) {
1048 /* either ipv6 or (ipv4|domain|interface):port(-range) */
1049 #ifdef ENABLE_IPV6
1050 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
1051 /* ipv6 */
1052 port_min = port_max = 0;
1053 strcpy(addr, string_ftpport);
1054 ip_end = NULL; /* this got no port ! */
1055 }
1056 else
1057 #endif
1058 /* (ipv4|domain|interface):port(-range) */
1059 strncpy(addr, string_ftpport, ip_end - ip_start);
1060 }
1061 else
1062 /* ipv4|interface */
1063 strcpy(addr, string_ftpport);
1064
1065 /* parse the port */
1066 if(ip_end != NULL) {
1067 if((port_start = strchr(ip_end, ':')) != NULL) {
1068 port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
1069 if((port_sep = strchr(port_start, '-')) != NULL) {
1070 port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
1071 }
1072 else
1073 port_max = port_min;
1074 }
1075 }
1076
1077 /* correct errors like:
1078 * :1234-1230
1079 * :-4711, in this case port_min is (unsigned)-1,
1080 * therefore port_min > port_max for all cases
1081 * but port_max = (unsigned)-1
1082 */
1083 if(port_min > port_max)
1084 port_min = port_max = 0;
1085
1086
1087 if(*addr != '\0') {
1088 /* attempt to get the address of the given interface name */
1089 switch(Curl_if2ip(conn->ip_addr->ai_family,
1090 Curl_ipv6_scope(conn->ip_addr->ai_addr),
1091 conn->scope_id, addr, hbuf, sizeof(hbuf))) {
1092 case IF2IP_NOT_FOUND:
1093 /* not an interface, use the given string as host name instead */
1094 host = addr;
1095 break;
1096 case IF2IP_AF_NOT_SUPPORTED:
1097 return CURLE_FTP_PORT_FAILED;
1098 case IF2IP_FOUND:
1099 host = hbuf; /* use the hbuf for host name */
1100 }
1101 }
1102 else
1103 /* there was only a port(-range) given, default the host */
1104 host = NULL;
1105 } /* data->set.ftpport */
1106
1107 if(!host) {
1108 /* not an interface and not a host name, get default by extracting
1109 the IP from the control connection */
1110
1111 sslen = sizeof(ss);
1112 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1113 failf(data, "getsockname() failed: %s",
1114 Curl_strerror(conn, SOCKERRNO) );
1115 free(addr);
1116 return CURLE_FTP_PORT_FAILED;
1117 }
1118 switch(sa->sa_family) {
1119 #ifdef ENABLE_IPV6
1120 case AF_INET6:
1121 Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
1122 break;
1123 #endif
1124 default:
1125 Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
1126 break;
1127 }
1128 host = hbuf; /* use this host name */
1129 possibly_non_local = FALSE; /* we know it is local now */
1130 }
1131
1132 /* resolv ip/host to ip */
1133 rc = Curl_resolv(conn, host, 0, &h);
1134 if(rc == CURLRESOLV_PENDING)
1135 (void)Curl_resolver_wait_resolv(conn, &h);
1136 if(h) {
1137 res = h->addr;
1138 /* when we return from this function, we can forget about this entry
1139 to we can unlock it now already */
1140 Curl_resolv_unlock(data, h);
1141 } /* (h) */
1142 else
1143 res = NULL; /* failure! */
1144
1145 if(res == NULL) {
1146 failf(data, "failed to resolve the address provided to PORT: %s", host);
1147 free(addr);
1148 return CURLE_FTP_PORT_FAILED;
1149 }
1150
1151 free(addr);
1152 host = NULL;
1153
1154 /* step 2, create a socket for the requested address */
1155
1156 portsock = CURL_SOCKET_BAD;
1157 error = 0;
1158 for(ai = res; ai; ai = ai->ai_next) {
1159 result = Curl_socket(conn, ai, NULL, &portsock);
1160 if(result) {
1161 error = SOCKERRNO;
1162 continue;
1163 }
1164 break;
1165 }
1166 if(!ai) {
1167 failf(data, "socket failure: %s", Curl_strerror(conn, error));
1168 return CURLE_FTP_PORT_FAILED;
1169 }
1170
1171 /* step 3, bind to a suitable local address */
1172
1173 memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1174 sslen = ai->ai_addrlen;
1175
1176 for(port = port_min; port <= port_max;) {
1177 if(sa->sa_family == AF_INET)
1178 sa4->sin_port = htons(port);
1179 #ifdef ENABLE_IPV6
1180 else
1181 sa6->sin6_port = htons(port);
1182 #endif
1183 /* Try binding the given address. */
1184 if(bind(portsock, sa, sslen) ) {
1185 /* It failed. */
1186 error = SOCKERRNO;
1187 if(possibly_non_local && (error == EADDRNOTAVAIL)) {
1188 /* The requested bind address is not local. Use the address used for
1189 * the control connection instead and restart the port loop
1190 */
1191
1192 infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
1193 Curl_strerror(conn, error) );
1194
1195 sslen = sizeof(ss);
1196 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1197 failf(data, "getsockname() failed: %s",
1198 Curl_strerror(conn, SOCKERRNO) );
1199 Curl_closesocket(conn, portsock);
1200 return CURLE_FTP_PORT_FAILED;
1201 }
1202 port = port_min;
1203 possibly_non_local = FALSE; /* don't try this again */
1204 continue;
1205 }
1206 else if(error != EADDRINUSE && error != EACCES) {
1207 failf(data, "bind(port=%hu) failed: %s", port,
1208 Curl_strerror(conn, error) );
1209 Curl_closesocket(conn, portsock);
1210 return CURLE_FTP_PORT_FAILED;
1211 }
1212 }
1213 else
1214 break;
1215
1216 port++;
1217 }
1218
1219 /* maybe all ports were in use already*/
1220 if(port > port_max) {
1221 failf(data, "bind() failed, we ran out of ports!");
1222 Curl_closesocket(conn, portsock);
1223 return CURLE_FTP_PORT_FAILED;
1224 }
1225
1226 /* get the name again after the bind() so that we can extract the
1227 port number it uses now */
1228 sslen = sizeof(ss);
1229 if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
1230 failf(data, "getsockname() failed: %s",
1231 Curl_strerror(conn, SOCKERRNO) );
1232 Curl_closesocket(conn, portsock);
1233 return CURLE_FTP_PORT_FAILED;
1234 }
1235
1236 /* step 4, listen on the socket */
1237
1238 if(listen(portsock, 1)) {
1239 failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
1240 Curl_closesocket(conn, portsock);
1241 return CURLE_FTP_PORT_FAILED;
1242 }
1243
1244 /* step 5, send the proper FTP command */
1245
1246 /* get a plain printable version of the numerical address to work with
1247 below */
1248 Curl_printable_address(ai, myhost, sizeof(myhost));
1249
1250 #ifdef ENABLE_IPV6
1251 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
1252 /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
1253 request and enable EPRT again! */
1254 conn->bits.ftp_use_eprt = TRUE;
1255 #endif
1256
1257 for(; fcmd != DONE; fcmd++) {
1258
1259 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1260 /* if disabled, goto next */
1261 continue;
1262
1263 if((PORT == fcmd) && sa->sa_family != AF_INET)
1264 /* PORT is IPv4 only */
1265 continue;
1266
1267 switch(sa->sa_family) {
1268 case AF_INET:
1269 port = ntohs(sa4->sin_port);
1270 break;
1271 #ifdef ENABLE_IPV6
1272 case AF_INET6:
1273 port = ntohs(sa6->sin6_port);
1274 break;
1275 #endif
1276 default:
1277 continue; /* might as well skip this */
1278 }
1279
1280 if(EPRT == fcmd) {
1281 /*
1282 * Two fine examples from RFC2428;
1283 *
1284 * EPRT |1|132.235.1.2|6275|
1285 *
1286 * EPRT |2|1080::8:800:200C:417A|5282|
1287 */
1288
1289 result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1290 sa->sa_family == AF_INET?1:2,
1291 myhost, port);
1292 if(result) {
1293 failf(data, "Failure sending EPRT command: %s",
1294 curl_easy_strerror(result));
1295 Curl_closesocket(conn, portsock);
1296 /* don't retry using PORT */
1297 ftpc->count1 = PORT;
1298 /* bail out */
1299 state(conn, FTP_STOP);
1300 return result;
1301 }
1302 break;
1303 }
1304 else if(PORT == fcmd) {
1305 char *source = myhost;
1306 char *dest = tmp;
1307
1308 /* translate x.x.x.x to x,x,x,x */
1309 while(source && *source) {
1310 if(*source == '.')
1311 *dest=',';
1312 else
1313 *dest = *source;
1314 dest++;
1315 source++;
1316 }
1317 *dest = 0;
1318 snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1319
1320 result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
1321 if(result) {
1322 failf(data, "Failure sending PORT command: %s",
1323 curl_easy_strerror(result));
1324 Curl_closesocket(conn, portsock);
1325 /* bail out */
1326 state(conn, FTP_STOP);
1327 return result;
1328 }
1329 break;
1330 }
1331 }
1332
1333 /* store which command was sent */
1334 ftpc->count1 = fcmd;
1335
1336 close_secondarysocket(conn);
1337
1338 /* we set the secondary socket variable to this for now, it is only so that
1339 the cleanup function will close it in case we fail before the true
1340 secondary stuff is made */
1341 conn->sock[SECONDARYSOCKET] = portsock;
1342
1343 /* this tcpconnect assignment below is a hackish work-around to make the
1344 multi interface with active FTP work - as it will not wait for a
1345 (passive) connect in Curl_is_connected().
1346
1347 The *proper* fix is to make sure that the active connection from the
1348 server is done in a non-blocking way. Currently, it is still BLOCKING.
1349 */
1350 conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
1351
1352 state(conn, FTP_PORT);
1353 return result;
1354 }
1355
ftp_state_use_pasv(struct connectdata * conn)1356 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1357 {
1358 struct ftp_conn *ftpc = &conn->proto.ftpc;
1359 CURLcode result = CURLE_OK;
1360 /*
1361 Here's the excecutive summary on what to do:
1362
1363 PASV is RFC959, expect:
1364 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1365
1366 LPSV is RFC1639, expect:
1367 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1368
1369 EPSV is RFC2428, expect:
1370 229 Entering Extended Passive Mode (|||port|)
1371
1372 */
1373
1374 static const char mode[][5] = { "EPSV", "PASV" };
1375 int modeoff;
1376
1377 #ifdef PF_INET6
1378 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1379 /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1380 request and enable EPSV again! */
1381 conn->bits.ftp_use_epsv = TRUE;
1382 #endif
1383
1384 modeoff = conn->bits.ftp_use_epsv?0:1;
1385
1386 PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
1387
1388 ftpc->count1 = modeoff;
1389 state(conn, FTP_PASV);
1390 infof(conn->data, "Connect data stream passively\n");
1391
1392 return result;
1393 }
1394
1395 /*
1396 * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
1397 *
1398 * REST is the last command in the chain of commands when a "head"-like
1399 * request is made. Thus, if an actual transfer is to be made this is where we
1400 * take off for real.
1401 */
ftp_state_prepare_transfer(struct connectdata * conn)1402 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
1403 {
1404 CURLcode result = CURLE_OK;
1405 struct FTP *ftp = conn->data->req.protop;
1406 struct Curl_easy *data = conn->data;
1407
1408 if(ftp->transfer != FTPTRANSFER_BODY) {
1409 /* doesn't transfer any data */
1410
1411 /* still possibly do PRE QUOTE jobs */
1412 state(conn, FTP_RETR_PREQUOTE);
1413 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1414 }
1415 else if(data->set.ftp_use_port) {
1416 /* We have chosen to use the PORT (or similar) command */
1417 result = ftp_state_use_port(conn, EPRT);
1418 }
1419 else {
1420 /* We have chosen (this is default) to use the PASV (or similar) command */
1421 if(data->set.ftp_use_pret) {
1422 /* The user has requested that we send a PRET command
1423 to prepare the server for the upcoming PASV */
1424 if(!conn->proto.ftpc.file) {
1425 PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
1426 data->set.str[STRING_CUSTOMREQUEST]?
1427 data->set.str[STRING_CUSTOMREQUEST]:
1428 (data->set.ftp_list_only?"NLST":"LIST"));
1429 }
1430 else if(data->set.upload) {
1431 PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
1432 }
1433 else {
1434 PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
1435 }
1436 state(conn, FTP_PRET);
1437 }
1438 else {
1439 result = ftp_state_use_pasv(conn);
1440 }
1441 }
1442 return result;
1443 }
1444
ftp_state_rest(struct connectdata * conn)1445 static CURLcode ftp_state_rest(struct connectdata *conn)
1446 {
1447 CURLcode result = CURLE_OK;
1448 struct FTP *ftp = conn->data->req.protop;
1449 struct ftp_conn *ftpc = &conn->proto.ftpc;
1450
1451 if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
1452 /* if a "head"-like request is being made (on a file) */
1453
1454 /* Determine if server can respond to REST command and therefore
1455 whether it supports range */
1456 PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
1457
1458 state(conn, FTP_REST);
1459 }
1460 else
1461 result = ftp_state_prepare_transfer(conn);
1462
1463 return result;
1464 }
1465
ftp_state_size(struct connectdata * conn)1466 static CURLcode ftp_state_size(struct connectdata *conn)
1467 {
1468 CURLcode result = CURLE_OK;
1469 struct FTP *ftp = conn->data->req.protop;
1470 struct ftp_conn *ftpc = &conn->proto.ftpc;
1471
1472 if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
1473 /* if a "head"-like request is being made (on a file) */
1474
1475 /* we know ftpc->file is a valid pointer to a file name */
1476 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1477
1478 state(conn, FTP_SIZE);
1479 }
1480 else
1481 result = ftp_state_rest(conn);
1482
1483 return result;
1484 }
1485
ftp_state_list(struct connectdata * conn)1486 static CURLcode ftp_state_list(struct connectdata *conn)
1487 {
1488 CURLcode result = CURLE_OK;
1489 struct Curl_easy *data = conn->data;
1490
1491 /* If this output is to be machine-parsed, the NLST command might be better
1492 to use, since the LIST command output is not specified or standard in any
1493 way. It has turned out that the NLST list output is not the same on all
1494 servers either... */
1495
1496 /*
1497 if FTPFILE_NOCWD was specified, we are currently in
1498 the user's home directory, so we should add the path
1499 as argument for the LIST / NLST / or custom command.
1500 Whether the server will support this, is uncertain.
1501
1502 The other ftp_filemethods will CWD into dir/dir/ first and
1503 then just do LIST (in that case: nothing to do here)
1504 */
1505 char *cmd, *lstArg, *slashPos;
1506
1507 lstArg = NULL;
1508 if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
1509 data->state.path &&
1510 data->state.path[0] &&
1511 strchr(data->state.path, '/')) {
1512
1513 lstArg = strdup(data->state.path);
1514 if(!lstArg)
1515 return CURLE_OUT_OF_MEMORY;
1516
1517 /* Check if path does not end with /, as then we cut off the file part */
1518 if(lstArg[strlen(lstArg) - 1] != '/') {
1519
1520 /* chop off the file part if format is dir/dir/file */
1521 slashPos = strrchr(lstArg, '/');
1522 if(slashPos)
1523 *(slashPos+1) = '\0';
1524 }
1525 }
1526
1527 cmd = aprintf("%s%s%s",
1528 data->set.str[STRING_CUSTOMREQUEST]?
1529 data->set.str[STRING_CUSTOMREQUEST]:
1530 (data->set.ftp_list_only?"NLST":"LIST"),
1531 lstArg? " ": "",
1532 lstArg? lstArg: "");
1533
1534 if(!cmd) {
1535 free(lstArg);
1536 return CURLE_OUT_OF_MEMORY;
1537 }
1538
1539 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
1540
1541 free(lstArg);
1542 free(cmd);
1543
1544 if(result)
1545 return result;
1546
1547 state(conn, FTP_LIST);
1548
1549 return result;
1550 }
1551
ftp_state_retr_prequote(struct connectdata * conn)1552 static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
1553 {
1554 CURLcode result = CURLE_OK;
1555
1556 /* We've sent the TYPE, now we must send the list of prequote strings */
1557
1558 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1559
1560 return result;
1561 }
1562
ftp_state_stor_prequote(struct connectdata * conn)1563 static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
1564 {
1565 CURLcode result = CURLE_OK;
1566
1567 /* We've sent the TYPE, now we must send the list of prequote strings */
1568
1569 result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
1570
1571 return result;
1572 }
1573
ftp_state_type(struct connectdata * conn)1574 static CURLcode ftp_state_type(struct connectdata *conn)
1575 {
1576 CURLcode result = CURLE_OK;
1577 struct FTP *ftp = conn->data->req.protop;
1578 struct Curl_easy *data = conn->data;
1579 struct ftp_conn *ftpc = &conn->proto.ftpc;
1580
1581 /* If we have selected NOBODY and HEADER, it means that we only want file
1582 information. Which in FTP can't be much more than the file size and
1583 date. */
1584 if(data->set.opt_no_body && ftpc->file &&
1585 ftp_need_type(conn, data->set.prefer_ascii)) {
1586 /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
1587 may not support it! It is however the only way we have to get a file's
1588 size! */
1589
1590 ftp->transfer = FTPTRANSFER_INFO;
1591 /* this means no actual transfer will be made */
1592
1593 /* Some servers return different sizes for different modes, and thus we
1594 must set the proper type before we check the size */
1595 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
1596 if(result)
1597 return result;
1598 }
1599 else
1600 result = ftp_state_size(conn);
1601
1602 return result;
1603 }
1604
1605 /* This is called after the CWD commands have been done in the beginning of
1606 the DO phase */
ftp_state_mdtm(struct connectdata * conn)1607 static CURLcode ftp_state_mdtm(struct connectdata *conn)
1608 {
1609 CURLcode result = CURLE_OK;
1610 struct Curl_easy *data = conn->data;
1611 struct ftp_conn *ftpc = &conn->proto.ftpc;
1612
1613 /* Requested time of file or time-depended transfer? */
1614 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1615
1616 /* we have requested to get the modified-time of the file, this is a white
1617 spot as the MDTM is not mentioned in RFC959 */
1618 PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
1619
1620 state(conn, FTP_MDTM);
1621 }
1622 else
1623 result = ftp_state_type(conn);
1624
1625 return result;
1626 }
1627
1628
1629 /* This is called after the TYPE and possible quote commands have been sent */
ftp_state_ul_setup(struct connectdata * conn,bool sizechecked)1630 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
1631 bool sizechecked)
1632 {
1633 CURLcode result = CURLE_OK;
1634 struct FTP *ftp = conn->data->req.protop;
1635 struct Curl_easy *data = conn->data;
1636 struct ftp_conn *ftpc = &conn->proto.ftpc;
1637 int seekerr = CURL_SEEKFUNC_OK;
1638
1639 if((data->state.resume_from && !sizechecked) ||
1640 ((data->state.resume_from > 0) && sizechecked)) {
1641 /* we're about to continue the uploading of a file */
1642 /* 1. get already existing file's size. We use the SIZE command for this
1643 which may not exist in the server! The SIZE command is not in
1644 RFC959. */
1645
1646 /* 2. This used to set REST. But since we can do append, we
1647 don't another ftp command. We just skip the source file
1648 offset and then we APPEND the rest on the file instead */
1649
1650 /* 3. pass file-size number of bytes in the source file */
1651 /* 4. lower the infilesize counter */
1652 /* => transfer as usual */
1653
1654 if(data->state.resume_from < 0) {
1655 /* Got no given size to start from, figure it out */
1656 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1657 state(conn, FTP_STOR_SIZE);
1658 return result;
1659 }
1660
1661 /* enable append */
1662 data->set.ftp_append = TRUE;
1663
1664 /* Let's read off the proper amount of bytes from the input. */
1665 if(conn->seek_func) {
1666 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1667 SEEK_SET);
1668 }
1669
1670 if(seekerr != CURL_SEEKFUNC_OK) {
1671 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1672 failf(data, "Could not seek stream");
1673 return CURLE_FTP_COULDNT_USE_REST;
1674 }
1675 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1676 else {
1677 curl_off_t passed=0;
1678 do {
1679 size_t readthisamountnow =
1680 (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
1681 BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
1682
1683 size_t actuallyread =
1684 data->state.fread_func(data->state.buffer, 1, readthisamountnow,
1685 data->state.in);
1686
1687 passed += actuallyread;
1688 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1689 /* this checks for greater-than only to make sure that the
1690 CURL_READFUNC_ABORT return code still aborts */
1691 failf(data, "Failed to read data");
1692 return CURLE_FTP_COULDNT_USE_REST;
1693 }
1694 } while(passed < data->state.resume_from);
1695 }
1696 }
1697 /* now, decrease the size of the read */
1698 if(data->state.infilesize>0) {
1699 data->state.infilesize -= data->state.resume_from;
1700
1701 if(data->state.infilesize <= 0) {
1702 infof(data, "File already completely uploaded\n");
1703
1704 /* no data to transfer */
1705 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1706
1707 /* Set ->transfer so that we won't get any error in
1708 * ftp_done() because we didn't transfer anything! */
1709 ftp->transfer = FTPTRANSFER_NONE;
1710
1711 state(conn, FTP_STOP);
1712 return CURLE_OK;
1713 }
1714 }
1715 /* we've passed, proceed as normal */
1716 } /* resume_from */
1717
1718 PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1719 ftpc->file);
1720
1721 state(conn, FTP_STOR);
1722
1723 return result;
1724 }
1725
ftp_state_quote(struct connectdata * conn,bool init,ftpstate instate)1726 static CURLcode ftp_state_quote(struct connectdata *conn,
1727 bool init,
1728 ftpstate instate)
1729 {
1730 CURLcode result = CURLE_OK;
1731 struct Curl_easy *data = conn->data;
1732 struct FTP *ftp = data->req.protop;
1733 struct ftp_conn *ftpc = &conn->proto.ftpc;
1734 bool quote=FALSE;
1735 struct curl_slist *item;
1736
1737 switch(instate) {
1738 case FTP_QUOTE:
1739 default:
1740 item = data->set.quote;
1741 break;
1742 case FTP_RETR_PREQUOTE:
1743 case FTP_STOR_PREQUOTE:
1744 item = data->set.prequote;
1745 break;
1746 case FTP_POSTQUOTE:
1747 item = data->set.postquote;
1748 break;
1749 }
1750
1751 /*
1752 * This state uses:
1753 * 'count1' to iterate over the commands to send
1754 * 'count2' to store wether to allow commands to fail
1755 */
1756
1757 if(init)
1758 ftpc->count1 = 0;
1759 else
1760 ftpc->count1++;
1761
1762 if(item) {
1763 int i = 0;
1764
1765 /* Skip count1 items in the linked list */
1766 while((i< ftpc->count1) && item) {
1767 item = item->next;
1768 i++;
1769 }
1770 if(item) {
1771 char *cmd = item->data;
1772 if(cmd[0] == '*') {
1773 cmd++;
1774 ftpc->count2 = 1; /* the sent command is allowed to fail */
1775 }
1776 else
1777 ftpc->count2 = 0; /* failure means cancel operation */
1778
1779 PPSENDF(&ftpc->pp, "%s", cmd);
1780 state(conn, instate);
1781 quote = TRUE;
1782 }
1783 }
1784
1785 if(!quote) {
1786 /* No more quote to send, continue to ... */
1787 switch(instate) {
1788 case FTP_QUOTE:
1789 default:
1790 result = ftp_state_cwd(conn);
1791 break;
1792 case FTP_RETR_PREQUOTE:
1793 if(ftp->transfer != FTPTRANSFER_BODY)
1794 state(conn, FTP_STOP);
1795 else {
1796 if(ftpc->known_filesize != -1) {
1797 Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1798 result = ftp_state_retr(conn, ftpc->known_filesize);
1799 }
1800 else {
1801 if(data->set.ignorecl) {
1802 /* This code is to support download of growing files. It prevents
1803 the state machine from requesting the file size from the
1804 server. With an unknown file size the download continues until
1805 the server terminates it, otherwise the client stops if the
1806 received byte count exceeds the reported file size. Set option
1807 CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/
1808 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
1809 state(conn, FTP_RETR);
1810 }
1811 else {
1812 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1813 state(conn, FTP_RETR_SIZE);
1814 }
1815 }
1816 }
1817 break;
1818 case FTP_STOR_PREQUOTE:
1819 result = ftp_state_ul_setup(conn, FALSE);
1820 break;
1821 case FTP_POSTQUOTE:
1822 break;
1823 }
1824 }
1825
1826 return result;
1827 }
1828
1829 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
1830 problems */
ftp_epsv_disable(struct connectdata * conn)1831 static CURLcode ftp_epsv_disable(struct connectdata *conn)
1832 {
1833 CURLcode result = CURLE_OK;
1834
1835 if(conn->bits.ipv6) {
1836 /* We can't disable EPSV when doing IPv6, so this is instead a fail */
1837 failf(conn->data, "Failed EPSV attempt, exiting\n");
1838 return CURLE_WEIRD_SERVER_REPLY;
1839 }
1840
1841 infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
1842 /* disable it for next transfer */
1843 conn->bits.ftp_use_epsv = FALSE;
1844 conn->data->state.errorbuf = FALSE; /* allow error message to get
1845 rewritten */
1846 PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
1847 conn->proto.ftpc.count1++;
1848 /* remain in/go to the FTP_PASV state */
1849 state(conn, FTP_PASV);
1850 return result;
1851 }
1852
1853
control_address(struct connectdata * conn)1854 static char *control_address(struct connectdata *conn)
1855 {
1856 /* Returns the control connection IP address.
1857 If a proxy tunnel is used, returns the original host name instead, because
1858 the effective control connection address is the proxy address,
1859 not the ftp host. */
1860 if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
1861 return conn->host.name;
1862
1863 return conn->ip_addr_str;
1864 }
1865
ftp_state_pasv_resp(struct connectdata * conn,int ftpcode)1866 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1867 int ftpcode)
1868 {
1869 struct ftp_conn *ftpc = &conn->proto.ftpc;
1870 CURLcode result;
1871 struct Curl_easy *data=conn->data;
1872 struct Curl_dns_entry *addr=NULL;
1873 int rc;
1874 unsigned short connectport; /* the local port connect() should use! */
1875 char *str=&data->state.buffer[4]; /* start on the first letter */
1876
1877 /* if we come here again, make sure the former name is cleared */
1878 Curl_safefree(ftpc->newhost);
1879
1880 if((ftpc->count1 == 0) &&
1881 (ftpcode == 229)) {
1882 /* positive EPSV response */
1883 char *ptr = strchr(str, '(');
1884 if(ptr) {
1885 unsigned int num;
1886 char separator[4];
1887 ptr++;
1888 if(5 == sscanf(ptr, "%c%c%c%u%c",
1889 &separator[0],
1890 &separator[1],
1891 &separator[2],
1892 &num,
1893 &separator[3])) {
1894 const char sep1 = separator[0];
1895 int i;
1896
1897 /* The four separators should be identical, or else this is an oddly
1898 formatted reply and we bail out immediately. */
1899 for(i=1; i<4; i++) {
1900 if(separator[i] != sep1) {
1901 ptr=NULL; /* set to NULL to signal error */
1902 break;
1903 }
1904 }
1905 if(num > 0xffff) {
1906 failf(data, "Illegal port number in EPSV reply");
1907 return CURLE_FTP_WEIRD_PASV_REPLY;
1908 }
1909 if(ptr) {
1910 ftpc->newport = (unsigned short)(num & 0xffff);
1911 ftpc->newhost = strdup(control_address(conn));
1912 if(!ftpc->newhost)
1913 return CURLE_OUT_OF_MEMORY;
1914 }
1915 }
1916 else
1917 ptr=NULL;
1918 }
1919 if(!ptr) {
1920 failf(data, "Weirdly formatted EPSV reply");
1921 return CURLE_FTP_WEIRD_PASV_REPLY;
1922 }
1923 }
1924 else if((ftpc->count1 == 1) &&
1925 (ftpcode == 227)) {
1926 /* positive PASV response */
1927 int ip[4];
1928 int port[2];
1929
1930 /*
1931 * Scan for a sequence of six comma-separated numbers and use them as
1932 * IP+port indicators.
1933 *
1934 * Found reply-strings include:
1935 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1936 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1937 * "227 Entering passive mode. 127,0,0,1,4,51"
1938 */
1939 while(*str) {
1940 if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1941 &ip[0], &ip[1], &ip[2], &ip[3],
1942 &port[0], &port[1]))
1943 break;
1944 str++;
1945 }
1946
1947 if(!*str) {
1948 failf(data, "Couldn't interpret the 227-response");
1949 return CURLE_FTP_WEIRD_227_FORMAT;
1950 }
1951
1952 /* we got OK from server */
1953 if(data->set.ftp_skip_ip) {
1954 /* told to ignore the remotely given IP but instead use the host we used
1955 for the control connection */
1956 infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n",
1957 ip[0], ip[1], ip[2], ip[3],
1958 conn->host.name);
1959 ftpc->newhost = strdup(control_address(conn));
1960 }
1961 else
1962 ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1963
1964 if(!ftpc->newhost)
1965 return CURLE_OUT_OF_MEMORY;
1966
1967 ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
1968 }
1969 else if(ftpc->count1 == 0) {
1970 /* EPSV failed, move on to PASV */
1971 return ftp_epsv_disable(conn);
1972 }
1973 else {
1974 failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
1975 return CURLE_FTP_WEIRD_PASV_REPLY;
1976 }
1977
1978 if(conn->bits.proxy) {
1979 /*
1980 * This connection uses a proxy and we need to connect to the proxy again
1981 * here. We don't want to rely on a former host lookup that might've
1982 * expired now, instead we remake the lookup here and now!
1983 */
1984 const char * const host_name = conn->bits.socksproxy ?
1985 conn->socks_proxy.host.name : conn->http_proxy.host.name;
1986 rc = Curl_resolv(conn, host_name, (int)conn->port, &addr);
1987 if(rc == CURLRESOLV_PENDING)
1988 /* BLOCKING, ignores the return code but 'addr' will be NULL in
1989 case of failure */
1990 (void)Curl_resolver_wait_resolv(conn, &addr);
1991
1992 connectport =
1993 (unsigned short)conn->port; /* we connect to the proxy's port */
1994
1995 if(!addr) {
1996 failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);
1997 return CURLE_FTP_CANT_GET_HOST;
1998 }
1999 }
2000 else {
2001 /* normal, direct, ftp connection */
2002 rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
2003 if(rc == CURLRESOLV_PENDING)
2004 /* BLOCKING */
2005 (void)Curl_resolver_wait_resolv(conn, &addr);
2006
2007 connectport = ftpc->newport; /* we connect to the remote port */
2008
2009 if(!addr) {
2010 failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
2011 return CURLE_FTP_CANT_GET_HOST;
2012 }
2013 }
2014
2015 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
2016 result = Curl_connecthost(conn, addr);
2017
2018 if(result) {
2019 Curl_resolv_unlock(data, addr); /* we're done using this address */
2020 if(ftpc->count1 == 0 && ftpcode == 229)
2021 return ftp_epsv_disable(conn);
2022
2023 return result;
2024 }
2025
2026
2027 /*
2028 * When this is used from the multi interface, this might've returned with
2029 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
2030 * connect to connect.
2031 */
2032
2033 if(data->set.verbose)
2034 /* this just dumps information about this second connection */
2035 ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport);
2036
2037 Curl_safefree(conn->secondaryhostname);
2038 conn->secondaryhostname = strdup(ftpc->newhost);
2039 conn->secondary_port = ftpc->newport;
2040
2041 Curl_resolv_unlock(data, addr); /* we're done using this address */
2042 conn->bits.do_more = TRUE;
2043 state(conn, FTP_STOP); /* this phase is completed */
2044
2045 return result;
2046 }
2047
ftp_state_port_resp(struct connectdata * conn,int ftpcode)2048 static CURLcode ftp_state_port_resp(struct connectdata *conn,
2049 int ftpcode)
2050 {
2051 struct Curl_easy *data = conn->data;
2052 struct ftp_conn *ftpc = &conn->proto.ftpc;
2053 ftpport fcmd = (ftpport)ftpc->count1;
2054 CURLcode result = CURLE_OK;
2055
2056 /* The FTP spec tells a positive response should have code 200.
2057 Be more permissive here to tolerate deviant servers. */
2058 if(ftpcode / 100 != 2) {
2059 /* the command failed */
2060
2061 if(EPRT == fcmd) {
2062 infof(data, "disabling EPRT usage\n");
2063 conn->bits.ftp_use_eprt = FALSE;
2064 }
2065 fcmd++;
2066
2067 if(fcmd == DONE) {
2068 failf(data, "Failed to do PORT");
2069 result = CURLE_FTP_PORT_FAILED;
2070 }
2071 else
2072 /* try next */
2073 result = ftp_state_use_port(conn, fcmd);
2074 }
2075 else {
2076 infof(data, "Connect data stream actively\n");
2077 state(conn, FTP_STOP); /* end of DO phase */
2078 result = ftp_dophase_done(conn, FALSE);
2079 }
2080
2081 return result;
2082 }
2083
ftp_state_mdtm_resp(struct connectdata * conn,int ftpcode)2084 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
2085 int ftpcode)
2086 {
2087 CURLcode result = CURLE_OK;
2088 struct Curl_easy *data=conn->data;
2089 struct FTP *ftp = data->req.protop;
2090 struct ftp_conn *ftpc = &conn->proto.ftpc;
2091
2092 switch(ftpcode) {
2093 case 213:
2094 {
2095 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
2096 last .sss part is optional and means fractions of a second */
2097 int year, month, day, hour, minute, second;
2098 char *buf = data->state.buffer;
2099 if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
2100 &year, &month, &day, &hour, &minute, &second)) {
2101 /* we have a time, reformat it */
2102 time_t secs=time(NULL);
2103 /* using the good old yacc/bison yuck */
2104 snprintf(buf, sizeof(conn->data->state.buffer),
2105 "%04d%02d%02d %02d:%02d:%02d GMT",
2106 year, month, day, hour, minute, second);
2107 /* now, convert this into a time() value: */
2108 data->info.filetime = (long)curl_getdate(buf, &secs);
2109 }
2110
2111 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2112 /* If we asked for a time of the file and we actually got one as well,
2113 we "emulate" a HTTP-style header in our output. */
2114
2115 if(data->set.opt_no_body &&
2116 ftpc->file &&
2117 data->set.get_filetime &&
2118 (data->info.filetime>=0) ) {
2119 time_t filetime = (time_t)data->info.filetime;
2120 struct tm buffer;
2121 const struct tm *tm = &buffer;
2122
2123 result = Curl_gmtime(filetime, &buffer);
2124 if(result)
2125 return result;
2126
2127 /* format: "Tue, 15 Nov 1994 12:45:26" */
2128 snprintf(buf, BUFSIZE-1,
2129 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2130 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2131 tm->tm_mday,
2132 Curl_month[tm->tm_mon],
2133 tm->tm_year + 1900,
2134 tm->tm_hour,
2135 tm->tm_min,
2136 tm->tm_sec);
2137 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2138 if(result)
2139 return result;
2140 } /* end of a ridiculous amount of conditionals */
2141 #endif
2142 }
2143 break;
2144 default:
2145 infof(data, "unsupported MDTM reply format\n");
2146 break;
2147 case 550: /* "No such file or directory" */
2148 failf(data, "Given file does not exist");
2149 result = CURLE_FTP_COULDNT_RETR_FILE;
2150 break;
2151 }
2152
2153 if(data->set.timecondition) {
2154 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2155 switch(data->set.timecondition) {
2156 case CURL_TIMECOND_IFMODSINCE:
2157 default:
2158 if(data->info.filetime <= data->set.timevalue) {
2159 infof(data, "The requested document is not new enough\n");
2160 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2161 data->info.timecond = TRUE;
2162 state(conn, FTP_STOP);
2163 return CURLE_OK;
2164 }
2165 break;
2166 case CURL_TIMECOND_IFUNMODSINCE:
2167 if(data->info.filetime > data->set.timevalue) {
2168 infof(data, "The requested document is not old enough\n");
2169 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2170 data->info.timecond = TRUE;
2171 state(conn, FTP_STOP);
2172 return CURLE_OK;
2173 }
2174 break;
2175 } /* switch */
2176 }
2177 else {
2178 infof(data, "Skipping time comparison\n");
2179 }
2180 }
2181
2182 if(!result)
2183 result = ftp_state_type(conn);
2184
2185 return result;
2186 }
2187
ftp_state_type_resp(struct connectdata * conn,int ftpcode,ftpstate instate)2188 static CURLcode ftp_state_type_resp(struct connectdata *conn,
2189 int ftpcode,
2190 ftpstate instate)
2191 {
2192 CURLcode result = CURLE_OK;
2193 struct Curl_easy *data=conn->data;
2194
2195 if(ftpcode/100 != 2) {
2196 /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
2197 successful 'TYPE I'. While that is not as RFC959 says, it is still a
2198 positive response code and we allow that. */
2199 failf(data, "Couldn't set desired mode");
2200 return CURLE_FTP_COULDNT_SET_TYPE;
2201 }
2202 if(ftpcode != 200)
2203 infof(data, "Got a %03d response code instead of the assumed 200\n",
2204 ftpcode);
2205
2206 if(instate == FTP_TYPE)
2207 result = ftp_state_size(conn);
2208 else if(instate == FTP_LIST_TYPE)
2209 result = ftp_state_list(conn);
2210 else if(instate == FTP_RETR_TYPE)
2211 result = ftp_state_retr_prequote(conn);
2212 else if(instate == FTP_STOR_TYPE)
2213 result = ftp_state_stor_prequote(conn);
2214
2215 return result;
2216 }
2217
ftp_state_retr(struct connectdata * conn,curl_off_t filesize)2218 static CURLcode ftp_state_retr(struct connectdata *conn,
2219 curl_off_t filesize)
2220 {
2221 CURLcode result = CURLE_OK;
2222 struct Curl_easy *data=conn->data;
2223 struct FTP *ftp = data->req.protop;
2224 struct ftp_conn *ftpc = &conn->proto.ftpc;
2225
2226 if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
2227 failf(data, "Maximum file size exceeded");
2228 return CURLE_FILESIZE_EXCEEDED;
2229 }
2230 ftp->downloadsize = filesize;
2231
2232 if(data->state.resume_from) {
2233 /* We always (attempt to) get the size of downloads, so it is done before
2234 this even when not doing resumes. */
2235 if(filesize == -1) {
2236 infof(data, "ftp server doesn't support SIZE\n");
2237 /* We couldn't get the size and therefore we can't know if there really
2238 is a part of the file left to get, although the server will just
2239 close the connection when we start the connection so it won't cause
2240 us any harm, just not make us exit as nicely. */
2241 }
2242 else {
2243 /* We got a file size report, so we check that there actually is a
2244 part of the file left to get, or else we go home. */
2245 if(data->state.resume_from< 0) {
2246 /* We're supposed to download the last abs(from) bytes */
2247 if(filesize < -data->state.resume_from) {
2248 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2249 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2250 data->state.resume_from, filesize);
2251 return CURLE_BAD_DOWNLOAD_RESUME;
2252 }
2253 /* convert to size to download */
2254 ftp->downloadsize = -data->state.resume_from;
2255 /* download from where? */
2256 data->state.resume_from = filesize - ftp->downloadsize;
2257 }
2258 else {
2259 if(filesize < data->state.resume_from) {
2260 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2261 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2262 data->state.resume_from, filesize);
2263 return CURLE_BAD_DOWNLOAD_RESUME;
2264 }
2265 /* Now store the number of bytes we are expected to download */
2266 ftp->downloadsize = filesize-data->state.resume_from;
2267 }
2268 }
2269
2270 if(ftp->downloadsize == 0) {
2271 /* no data to transfer */
2272 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2273 infof(data, "File already completely downloaded\n");
2274
2275 /* Set ->transfer so that we won't get any error in ftp_done()
2276 * because we didn't transfer the any file */
2277 ftp->transfer = FTPTRANSFER_NONE;
2278 state(conn, FTP_STOP);
2279 return CURLE_OK;
2280 }
2281
2282 /* Set resume file transfer offset */
2283 infof(data, "Instructs server to resume from offset %"
2284 CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
2285
2286 PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
2287 data->state.resume_from);
2288
2289 state(conn, FTP_RETR_REST);
2290 }
2291 else {
2292 /* no resume */
2293 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2294 state(conn, FTP_RETR);
2295 }
2296
2297 return result;
2298 }
2299
ftp_state_size_resp(struct connectdata * conn,int ftpcode,ftpstate instate)2300 static CURLcode ftp_state_size_resp(struct connectdata *conn,
2301 int ftpcode,
2302 ftpstate instate)
2303 {
2304 CURLcode result = CURLE_OK;
2305 struct Curl_easy *data=conn->data;
2306 curl_off_t filesize;
2307 char *buf = data->state.buffer;
2308
2309 /* get the size from the ascii string: */
2310 filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
2311
2312 if(instate == FTP_SIZE) {
2313 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2314 if(-1 != filesize) {
2315 snprintf(buf, sizeof(data->state.buffer),
2316 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
2317 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2318 if(result)
2319 return result;
2320 }
2321 #endif
2322 Curl_pgrsSetDownloadSize(data, filesize);
2323 result = ftp_state_rest(conn);
2324 }
2325 else if(instate == FTP_RETR_SIZE) {
2326 Curl_pgrsSetDownloadSize(data, filesize);
2327 result = ftp_state_retr(conn, filesize);
2328 }
2329 else if(instate == FTP_STOR_SIZE) {
2330 data->state.resume_from = filesize;
2331 result = ftp_state_ul_setup(conn, TRUE);
2332 }
2333
2334 return result;
2335 }
2336
ftp_state_rest_resp(struct connectdata * conn,int ftpcode,ftpstate instate)2337 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2338 int ftpcode,
2339 ftpstate instate)
2340 {
2341 CURLcode result = CURLE_OK;
2342 struct ftp_conn *ftpc = &conn->proto.ftpc;
2343
2344 switch(instate) {
2345 case FTP_REST:
2346 default:
2347 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2348 if(ftpcode == 350) {
2349 char buffer[24]= { "Accept-ranges: bytes\r\n" };
2350 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2351 if(result)
2352 return result;
2353 }
2354 #endif
2355 result = ftp_state_prepare_transfer(conn);
2356 break;
2357
2358 case FTP_RETR_REST:
2359 if(ftpcode != 350) {
2360 failf(conn->data, "Couldn't use REST");
2361 result = CURLE_FTP_COULDNT_USE_REST;
2362 }
2363 else {
2364 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2365 state(conn, FTP_RETR);
2366 }
2367 break;
2368 }
2369
2370 return result;
2371 }
2372
ftp_state_stor_resp(struct connectdata * conn,int ftpcode,ftpstate instate)2373 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
2374 int ftpcode, ftpstate instate)
2375 {
2376 CURLcode result = CURLE_OK;
2377 struct Curl_easy *data = conn->data;
2378
2379 if(ftpcode>=400) {
2380 failf(data, "Failed FTP upload: %0d", ftpcode);
2381 state(conn, FTP_STOP);
2382 /* oops, we never close the sockets! */
2383 return CURLE_UPLOAD_FAILED;
2384 }
2385
2386 conn->proto.ftpc.state_saved = instate;
2387
2388 /* PORT means we are now awaiting the server to connect to us. */
2389 if(data->set.ftp_use_port) {
2390 bool connected;
2391
2392 state(conn, FTP_STOP); /* no longer in STOR state */
2393
2394 result = AllowServerConnect(conn, &connected);
2395 if(result)
2396 return result;
2397
2398 if(!connected) {
2399 struct ftp_conn *ftpc = &conn->proto.ftpc;
2400 infof(data, "Data conn was not available immediately\n");
2401 ftpc->wait_data_conn = TRUE;
2402 }
2403
2404 return CURLE_OK;
2405 }
2406 else
2407 return InitiateTransfer(conn);
2408 }
2409
2410 /* for LIST and RETR responses */
ftp_state_get_resp(struct connectdata * conn,int ftpcode,ftpstate instate)2411 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2412 int ftpcode,
2413 ftpstate instate)
2414 {
2415 CURLcode result = CURLE_OK;
2416 struct Curl_easy *data = conn->data;
2417 struct FTP *ftp = data->req.protop;
2418 char *buf = data->state.buffer;
2419
2420 if((ftpcode == 150) || (ftpcode == 125)) {
2421
2422 /*
2423 A;
2424 150 Opening BINARY mode data connection for /etc/passwd (2241
2425 bytes). (ok, the file is being transferred)
2426
2427 B:
2428 150 Opening ASCII mode data connection for /bin/ls
2429
2430 C:
2431 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2432
2433 D:
2434 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
2435
2436 E:
2437 125 Data connection already open; Transfer starting. */
2438
2439 curl_off_t size=-1; /* default unknown size */
2440
2441
2442 /*
2443 * It appears that there are FTP-servers that return size 0 for files when
2444 * SIZE is used on the file while being in BINARY mode. To work around
2445 * that (stupid) behavior, we attempt to parse the RETR response even if
2446 * the SIZE returned size zero.
2447 *
2448 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2449 */
2450
2451 if((instate != FTP_LIST) &&
2452 !data->set.prefer_ascii &&
2453 (ftp->downloadsize < 1)) {
2454 /*
2455 * It seems directory listings either don't show the size or very
2456 * often uses size 0 anyway. ASCII transfers may very well turn out
2457 * that the transferred amount of data is not the same as this line
2458 * tells, why using this number in those cases only confuses us.
2459 *
2460 * Example D above makes this parsing a little tricky */
2461 char *bytes;
2462 bytes=strstr(buf, " bytes");
2463 if(bytes--) {
2464 long in=(long)(bytes-buf);
2465 /* this is a hint there is size information in there! ;-) */
2466 while(--in) {
2467 /* scan for the left parenthesis and break there */
2468 if('(' == *bytes)
2469 break;
2470 /* skip only digits */
2471 if(!ISDIGIT(*bytes)) {
2472 bytes=NULL;
2473 break;
2474 }
2475 /* one more estep backwards */
2476 bytes--;
2477 }
2478 /* if we have nothing but digits: */
2479 if(bytes++) {
2480 /* get the number! */
2481 size = curlx_strtoofft(bytes, NULL, 0);
2482 }
2483 }
2484 }
2485 else if(ftp->downloadsize > -1)
2486 size = ftp->downloadsize;
2487
2488 if(size > data->req.maxdownload && data->req.maxdownload > 0)
2489 size = data->req.size = data->req.maxdownload;
2490 else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2491 size = -1; /* kludge for servers that understate ASCII mode file size */
2492
2493 infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
2494 data->req.maxdownload);
2495
2496 if(instate != FTP_LIST)
2497 infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
2498 size);
2499
2500 /* FTP download: */
2501 conn->proto.ftpc.state_saved = instate;
2502 conn->proto.ftpc.retr_size_saved = size;
2503
2504 if(data->set.ftp_use_port) {
2505 bool connected;
2506
2507 result = AllowServerConnect(conn, &connected);
2508 if(result)
2509 return result;
2510
2511 if(!connected) {
2512 struct ftp_conn *ftpc = &conn->proto.ftpc;
2513 infof(data, "Data conn was not available immediately\n");
2514 state(conn, FTP_STOP);
2515 ftpc->wait_data_conn = TRUE;
2516 }
2517 }
2518 else
2519 return InitiateTransfer(conn);
2520 }
2521 else {
2522 if((instate == FTP_LIST) && (ftpcode == 450)) {
2523 /* simply no matching files in the dir listing */
2524 ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2525 state(conn, FTP_STOP); /* this phase is over */
2526 }
2527 else {
2528 failf(data, "RETR response: %03d", ftpcode);
2529 return instate == FTP_RETR && ftpcode == 550?
2530 CURLE_REMOTE_FILE_NOT_FOUND:
2531 CURLE_FTP_COULDNT_RETR_FILE;
2532 }
2533 }
2534
2535 return result;
2536 }
2537
2538 /* after USER, PASS and ACCT */
ftp_state_loggedin(struct connectdata * conn)2539 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2540 {
2541 CURLcode result = CURLE_OK;
2542
2543 if(conn->ssl[FIRSTSOCKET].use) {
2544 /* PBSZ = PROTECTION BUFFER SIZE.
2545
2546 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2547
2548 Specifically, the PROT command MUST be preceded by a PBSZ
2549 command and a PBSZ command MUST be preceded by a successful
2550 security data exchange (the TLS negotiation in this case)
2551
2552 ... (and on page 8):
2553
2554 Thus the PBSZ command must still be issued, but must have a
2555 parameter of '0' to indicate that no buffering is taking place
2556 and the data connection should not be encapsulated.
2557 */
2558 PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2559 state(conn, FTP_PBSZ);
2560 }
2561 else {
2562 result = ftp_state_pwd(conn);
2563 }
2564 return result;
2565 }
2566
2567 /* for USER and PASS responses */
ftp_state_user_resp(struct connectdata * conn,int ftpcode,ftpstate instate)2568 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2569 int ftpcode,
2570 ftpstate instate)
2571 {
2572 CURLcode result = CURLE_OK;
2573 struct Curl_easy *data = conn->data;
2574 struct FTP *ftp = data->req.protop;
2575 struct ftp_conn *ftpc = &conn->proto.ftpc;
2576 (void)instate; /* no use for this yet */
2577
2578 /* some need password anyway, and others just return 2xx ignored */
2579 if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2580 /* 331 Password required for ...
2581 (the server requires to send the user's password too) */
2582 PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2583 state(conn, FTP_PASS);
2584 }
2585 else if(ftpcode/100 == 2) {
2586 /* 230 User ... logged in.
2587 (the user logged in with or without password) */
2588 result = ftp_state_loggedin(conn);
2589 }
2590 else if(ftpcode == 332) {
2591 if(data->set.str[STRING_FTP_ACCOUNT]) {
2592 PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2593 state(conn, FTP_ACCT);
2594 }
2595 else {
2596 failf(data, "ACCT requested but none available");
2597 result = CURLE_LOGIN_DENIED;
2598 }
2599 }
2600 else {
2601 /* All other response codes, like:
2602
2603 530 User ... access denied
2604 (the server denies to log the specified user) */
2605
2606 if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2607 !conn->data->state.ftp_trying_alternative) {
2608 /* Ok, USER failed. Let's try the supplied command. */
2609 PPSENDF(&conn->proto.ftpc.pp, "%s",
2610 conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2611 conn->data->state.ftp_trying_alternative = TRUE;
2612 state(conn, FTP_USER);
2613 result = CURLE_OK;
2614 }
2615 else {
2616 failf(data, "Access denied: %03d", ftpcode);
2617 result = CURLE_LOGIN_DENIED;
2618 }
2619 }
2620 return result;
2621 }
2622
2623 /* for ACCT response */
ftp_state_acct_resp(struct connectdata * conn,int ftpcode)2624 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2625 int ftpcode)
2626 {
2627 CURLcode result = CURLE_OK;
2628 struct Curl_easy *data = conn->data;
2629 if(ftpcode != 230) {
2630 failf(data, "ACCT rejected by server: %03d", ftpcode);
2631 result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2632 }
2633 else
2634 result = ftp_state_loggedin(conn);
2635
2636 return result;
2637 }
2638
2639
ftp_statemach_act(struct connectdata * conn)2640 static CURLcode ftp_statemach_act(struct connectdata *conn)
2641 {
2642 CURLcode result;
2643 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2644 struct Curl_easy *data=conn->data;
2645 int ftpcode;
2646 struct ftp_conn *ftpc = &conn->proto.ftpc;
2647 struct pingpong *pp = &ftpc->pp;
2648 static const char ftpauth[][4] = { "SSL", "TLS" };
2649 size_t nread = 0;
2650
2651 if(pp->sendleft)
2652 return Curl_pp_flushsend(pp);
2653
2654 result = ftp_readresp(sock, pp, &ftpcode, &nread);
2655 if(result)
2656 return result;
2657
2658 if(ftpcode) {
2659 /* we have now received a full FTP server response */
2660 switch(ftpc->state) {
2661 case FTP_WAIT220:
2662 if(ftpcode == 230)
2663 /* 230 User logged in - already! */
2664 return ftp_state_user_resp(conn, ftpcode, ftpc->state);
2665 else if(ftpcode != 220) {
2666 failf(data, "Got a %03d ftp-server response when 220 was expected",
2667 ftpcode);
2668 return CURLE_WEIRD_SERVER_REPLY;
2669 }
2670
2671 /* We have received a 220 response fine, now we proceed. */
2672 #ifdef HAVE_GSSAPI
2673 if(data->set.krb) {
2674 /* If not anonymous login, try a secure login. Note that this
2675 procedure is still BLOCKING. */
2676
2677 Curl_sec_request_prot(conn, "private");
2678 /* We set private first as default, in case the line below fails to
2679 set a valid level */
2680 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2681
2682 if(Curl_sec_login(conn))
2683 infof(data, "Logging in with password in cleartext!\n");
2684 else
2685 infof(data, "Authentication successful\n");
2686 }
2687 #endif
2688
2689 if(data->set.use_ssl &&
2690 (!conn->ssl[FIRSTSOCKET].use ||
2691 (conn->bits.proxy_ssl_connected[FIRSTSOCKET] &&
2692 !conn->proxy_ssl[FIRSTSOCKET].use))) {
2693 /* We don't have a SSL/TLS connection yet, but FTPS is
2694 requested. Try a FTPS connection now */
2695
2696 ftpc->count3=0;
2697 switch(data->set.ftpsslauth) {
2698 case CURLFTPAUTH_DEFAULT:
2699 case CURLFTPAUTH_SSL:
2700 ftpc->count2 = 1; /* add one to get next */
2701 ftpc->count1 = 0;
2702 break;
2703 case CURLFTPAUTH_TLS:
2704 ftpc->count2 = -1; /* subtract one to get next */
2705 ftpc->count1 = 1;
2706 break;
2707 default:
2708 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2709 (int)data->set.ftpsslauth);
2710 return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2711 }
2712 PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2713 state(conn, FTP_AUTH);
2714 }
2715 else {
2716 result = ftp_state_user(conn);
2717 if(result)
2718 return result;
2719 }
2720
2721 break;
2722
2723 case FTP_AUTH:
2724 /* we have gotten the response to a previous AUTH command */
2725
2726 /* RFC2228 (page 5) says:
2727 *
2728 * If the server is willing to accept the named security mechanism,
2729 * and does not require any security data, it must respond with
2730 * reply code 234/334.
2731 */
2732
2733 if((ftpcode == 234) || (ftpcode == 334)) {
2734 /* Curl_ssl_connect is BLOCKING */
2735 result = Curl_ssl_connect(conn, FIRSTSOCKET);
2736 if(!result) {
2737 conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */
2738 result = ftp_state_user(conn);
2739 }
2740 }
2741 else if(ftpc->count3 < 1) {
2742 ftpc->count3++;
2743 ftpc->count1 += ftpc->count2; /* get next attempt */
2744 result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2745 /* remain in this same state */
2746 }
2747 else {
2748 if(data->set.use_ssl > CURLUSESSL_TRY)
2749 /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2750 result = CURLE_USE_SSL_FAILED;
2751 else
2752 /* ignore the failure and continue */
2753 result = ftp_state_user(conn);
2754 }
2755
2756 if(result)
2757 return result;
2758 break;
2759
2760 case FTP_USER:
2761 case FTP_PASS:
2762 result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2763 break;
2764
2765 case FTP_ACCT:
2766 result = ftp_state_acct_resp(conn, ftpcode);
2767 break;
2768
2769 case FTP_PBSZ:
2770 PPSENDF(&ftpc->pp, "PROT %c",
2771 data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2772 state(conn, FTP_PROT);
2773
2774 break;
2775
2776 case FTP_PROT:
2777 if(ftpcode/100 == 2)
2778 /* We have enabled SSL for the data connection! */
2779 conn->bits.ftp_use_data_ssl =
2780 (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
2781 /* FTP servers typically responds with 500 if they decide to reject
2782 our 'P' request */
2783 else if(data->set.use_ssl > CURLUSESSL_CONTROL)
2784 /* we failed and bails out */
2785 return CURLE_USE_SSL_FAILED;
2786
2787 if(data->set.ftp_ccc) {
2788 /* CCC - Clear Command Channel
2789 */
2790 PPSENDF(&ftpc->pp, "%s", "CCC");
2791 state(conn, FTP_CCC);
2792 }
2793 else {
2794 result = ftp_state_pwd(conn);
2795 if(result)
2796 return result;
2797 }
2798 break;
2799
2800 case FTP_CCC:
2801 if(ftpcode < 500) {
2802 /* First shut down the SSL layer (note: this call will block) */
2803 result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2804
2805 if(result) {
2806 failf(conn->data, "Failed to clear the command channel (CCC)");
2807 return result;
2808 }
2809 }
2810
2811 /* Then continue as normal */
2812 result = ftp_state_pwd(conn);
2813 if(result)
2814 return result;
2815 break;
2816
2817 case FTP_PWD:
2818 if(ftpcode == 257) {
2819 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2820 char *dir;
2821 char *store;
2822
2823 dir = malloc(nread + 1);
2824 if(!dir)
2825 return CURLE_OUT_OF_MEMORY;
2826
2827 /* Reply format is like
2828 257<space>[rubbish]"<directory-name>"<space><commentary> and the
2829 RFC959 says
2830
2831 The directory name can contain any character; embedded
2832 double-quotes should be escaped by double-quotes (the
2833 "quote-doubling" convention).
2834 */
2835
2836 /* scan for the first double-quote for non-standard responses */
2837 while(ptr < &data->state.buffer[sizeof(data->state.buffer)]
2838 && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
2839 ptr++;
2840
2841 if('\"' == *ptr) {
2842 /* it started good */
2843 ptr++;
2844 for(store = dir; *ptr;) {
2845 if('\"' == *ptr) {
2846 if('\"' == ptr[1]) {
2847 /* "quote-doubling" */
2848 *store = ptr[1];
2849 ptr++;
2850 }
2851 else {
2852 /* end of path */
2853 *store = '\0'; /* zero terminate */
2854 break; /* get out of this loop */
2855 }
2856 }
2857 else
2858 *store = *ptr;
2859 store++;
2860 ptr++;
2861 }
2862
2863 /* If the path name does not look like an absolute path (i.e.: it
2864 does not start with a '/'), we probably need some server-dependent
2865 adjustments. For example, this is the case when connecting to
2866 an OS400 FTP server: this server supports two name syntaxes,
2867 the default one being incompatible with standard pathes. In
2868 addition, this server switches automatically to the regular path
2869 syntax when one is encountered in a command: this results in
2870 having an entrypath in the wrong syntax when later used in CWD.
2871 The method used here is to check the server OS: we do it only
2872 if the path name looks strange to minimize overhead on other
2873 systems. */
2874
2875 if(!ftpc->server_os && dir[0] != '/') {
2876
2877 result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
2878 if(result) {
2879 free(dir);
2880 return result;
2881 }
2882 Curl_safefree(ftpc->entrypath);
2883 ftpc->entrypath = dir; /* remember this */
2884 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2885 /* also save it where getinfo can access it: */
2886 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2887 state(conn, FTP_SYST);
2888 break;
2889 }
2890
2891 Curl_safefree(ftpc->entrypath);
2892 ftpc->entrypath = dir; /* remember this */
2893 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2894 /* also save it where getinfo can access it: */
2895 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2896 }
2897 else {
2898 /* couldn't get the path */
2899 free(dir);
2900 infof(data, "Failed to figure out path\n");
2901 }
2902 }
2903 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2904 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2905 break;
2906
2907 case FTP_SYST:
2908 if(ftpcode == 215) {
2909 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2910 char *os;
2911 char *store;
2912
2913 os = malloc(nread + 1);
2914 if(!os)
2915 return CURLE_OUT_OF_MEMORY;
2916
2917 /* Reply format is like
2918 215<space><OS-name><space><commentary>
2919 */
2920 while(*ptr == ' ')
2921 ptr++;
2922 for(store = os; *ptr && *ptr != ' ';)
2923 *store++ = *ptr++;
2924 *store = '\0'; /* zero terminate */
2925
2926 /* Check for special servers here. */
2927
2928 if(strcasecompare(os, "OS/400")) {
2929 /* Force OS400 name format 1. */
2930 result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
2931 if(result) {
2932 free(os);
2933 return result;
2934 }
2935 /* remember target server OS */
2936 Curl_safefree(ftpc->server_os);
2937 ftpc->server_os = os;
2938 state(conn, FTP_NAMEFMT);
2939 break;
2940 }
2941 else {
2942 /* Nothing special for the target server. */
2943 /* remember target server OS */
2944 Curl_safefree(ftpc->server_os);
2945 ftpc->server_os = os;
2946 }
2947 }
2948 else {
2949 /* Cannot identify server OS. Continue anyway and cross fingers. */
2950 }
2951
2952 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2953 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2954 break;
2955
2956 case FTP_NAMEFMT:
2957 if(ftpcode == 250) {
2958 /* Name format change successful: reload initial path. */
2959 ftp_state_pwd(conn);
2960 break;
2961 }
2962
2963 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2964 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2965 break;
2966
2967 case FTP_QUOTE:
2968 case FTP_POSTQUOTE:
2969 case FTP_RETR_PREQUOTE:
2970 case FTP_STOR_PREQUOTE:
2971 if((ftpcode >= 400) && !ftpc->count2) {
2972 /* failure response code, and not allowed to fail */
2973 failf(conn->data, "QUOT command failed with %03d", ftpcode);
2974 return CURLE_QUOTE_ERROR;
2975 }
2976 result = ftp_state_quote(conn, FALSE, ftpc->state);
2977 if(result)
2978 return result;
2979
2980 break;
2981
2982 case FTP_CWD:
2983 if(ftpcode/100 != 2) {
2984 /* failure to CWD there */
2985 if(conn->data->set.ftp_create_missing_dirs &&
2986 ftpc->count1 && !ftpc->count2) {
2987 /* try making it */
2988 ftpc->count2++; /* counter to prevent CWD-MKD loops */
2989 PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
2990 state(conn, FTP_MKD);
2991 }
2992 else {
2993 /* return failure */
2994 failf(data, "Server denied you to change to the given directory");
2995 ftpc->cwdfail = TRUE; /* don't remember this path as we failed
2996 to enter it */
2997 return CURLE_REMOTE_ACCESS_DENIED;
2998 }
2999 }
3000 else {
3001 /* success */
3002 ftpc->count2=0;
3003 if(++ftpc->count1 <= ftpc->dirdepth) {
3004 /* send next CWD */
3005 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3006 }
3007 else {
3008 result = ftp_state_mdtm(conn);
3009 if(result)
3010 return result;
3011 }
3012 }
3013 break;
3014
3015 case FTP_MKD:
3016 if((ftpcode/100 != 2) && !ftpc->count3--) {
3017 /* failure to MKD the dir */
3018 failf(data, "Failed to MKD dir: %03d", ftpcode);
3019 return CURLE_REMOTE_ACCESS_DENIED;
3020 }
3021 state(conn, FTP_CWD);
3022 /* send CWD */
3023 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3024 break;
3025
3026 case FTP_MDTM:
3027 result = ftp_state_mdtm_resp(conn, ftpcode);
3028 break;
3029
3030 case FTP_TYPE:
3031 case FTP_LIST_TYPE:
3032 case FTP_RETR_TYPE:
3033 case FTP_STOR_TYPE:
3034 result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
3035 break;
3036
3037 case FTP_SIZE:
3038 case FTP_RETR_SIZE:
3039 case FTP_STOR_SIZE:
3040 result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
3041 break;
3042
3043 case FTP_REST:
3044 case FTP_RETR_REST:
3045 result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
3046 break;
3047
3048 case FTP_PRET:
3049 if(ftpcode != 200) {
3050 /* there only is this one standard OK return code. */
3051 failf(data, "PRET command not accepted: %03d", ftpcode);
3052 return CURLE_FTP_PRET_FAILED;
3053 }
3054 result = ftp_state_use_pasv(conn);
3055 break;
3056
3057 case FTP_PASV:
3058 result = ftp_state_pasv_resp(conn, ftpcode);
3059 break;
3060
3061 case FTP_PORT:
3062 result = ftp_state_port_resp(conn, ftpcode);
3063 break;
3064
3065 case FTP_LIST:
3066 case FTP_RETR:
3067 result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
3068 break;
3069
3070 case FTP_STOR:
3071 result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
3072 break;
3073
3074 case FTP_QUIT:
3075 /* fallthrough, just stop! */
3076 default:
3077 /* internal error */
3078 state(conn, FTP_STOP);
3079 break;
3080 }
3081 } /* if(ftpcode) */
3082
3083 return result;
3084 }
3085
3086
3087 /* called repeatedly until done from multi.c */
ftp_multi_statemach(struct connectdata * conn,bool * done)3088 static CURLcode ftp_multi_statemach(struct connectdata *conn,
3089 bool *done)
3090 {
3091 struct ftp_conn *ftpc = &conn->proto.ftpc;
3092 CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
3093
3094 /* Check for the state outside of the Curl_socket_check() return code checks
3095 since at times we are in fact already in this state when this function
3096 gets called. */
3097 *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
3098
3099 return result;
3100 }
3101
ftp_block_statemach(struct connectdata * conn)3102 static CURLcode ftp_block_statemach(struct connectdata *conn)
3103 {
3104 struct ftp_conn *ftpc = &conn->proto.ftpc;
3105 struct pingpong *pp = &ftpc->pp;
3106 CURLcode result = CURLE_OK;
3107
3108 while(ftpc->state != FTP_STOP) {
3109 result = Curl_pp_statemach(pp, TRUE);
3110 if(result)
3111 break;
3112 }
3113
3114 return result;
3115 }
3116
3117 /*
3118 * ftp_connect() should do everything that is to be considered a part of
3119 * the connection phase.
3120 *
3121 * The variable 'done' points to will be TRUE if the protocol-layer connect
3122 * phase is done when this function returns, or FALSE if not.
3123 *
3124 */
ftp_connect(struct connectdata * conn,bool * done)3125 static CURLcode ftp_connect(struct connectdata *conn,
3126 bool *done) /* see description above */
3127 {
3128 CURLcode result;
3129 struct ftp_conn *ftpc = &conn->proto.ftpc;
3130 struct pingpong *pp = &ftpc->pp;
3131
3132 *done = FALSE; /* default to not done yet */
3133
3134 /* We always support persistent connections on ftp */
3135 connkeep(conn, "FTP default");
3136
3137 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
3138 pp->statemach_act = ftp_statemach_act;
3139 pp->endofresp = ftp_endofresp;
3140 pp->conn = conn;
3141
3142 if(conn->handler->flags & PROTOPT_SSL) {
3143 /* BLOCKING */
3144 result = Curl_ssl_connect(conn, FIRSTSOCKET);
3145 if(result)
3146 return result;
3147 }
3148
3149 Curl_pp_init(pp); /* init the generic pingpong data */
3150
3151 /* When we connect, we start in the state where we await the 220
3152 response */
3153 state(conn, FTP_WAIT220);
3154
3155 result = ftp_multi_statemach(conn, done);
3156
3157 return result;
3158 }
3159
3160 /***********************************************************************
3161 *
3162 * ftp_done()
3163 *
3164 * The DONE function. This does what needs to be done after a single DO has
3165 * performed.
3166 *
3167 * Input argument is already checked for validity.
3168 */
ftp_done(struct connectdata * conn,CURLcode status,bool premature)3169 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
3170 bool premature)
3171 {
3172 struct Curl_easy *data = conn->data;
3173 struct FTP *ftp = data->req.protop;
3174 struct ftp_conn *ftpc = &conn->proto.ftpc;
3175 struct pingpong *pp = &ftpc->pp;
3176 ssize_t nread;
3177 int ftpcode;
3178 CURLcode result = CURLE_OK;
3179 char *path = NULL;
3180 const char *path_to_use = data->state.path;
3181
3182 if(!ftp)
3183 return CURLE_OK;
3184
3185 switch(status) {
3186 case CURLE_BAD_DOWNLOAD_RESUME:
3187 case CURLE_FTP_WEIRD_PASV_REPLY:
3188 case CURLE_FTP_PORT_FAILED:
3189 case CURLE_FTP_ACCEPT_FAILED:
3190 case CURLE_FTP_ACCEPT_TIMEOUT:
3191 case CURLE_FTP_COULDNT_SET_TYPE:
3192 case CURLE_FTP_COULDNT_RETR_FILE:
3193 case CURLE_PARTIAL_FILE:
3194 case CURLE_UPLOAD_FAILED:
3195 case CURLE_REMOTE_ACCESS_DENIED:
3196 case CURLE_FILESIZE_EXCEEDED:
3197 case CURLE_REMOTE_FILE_NOT_FOUND:
3198 case CURLE_WRITE_ERROR:
3199 /* the connection stays alive fine even though this happened */
3200 /* fall-through */
3201 case CURLE_OK: /* doesn't affect the control connection's status */
3202 if(!premature)
3203 break;
3204
3205 /* until we cope better with prematurely ended requests, let them
3206 * fallback as if in complete failure */
3207 default: /* by default, an error means the control connection is
3208 wedged and should not be used anymore */
3209 ftpc->ctl_valid = FALSE;
3210 ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3211 current path, as this connection is going */
3212 connclose(conn, "FTP ended with bad error code");
3213 result = status; /* use the already set error code */
3214 break;
3215 }
3216
3217 /* now store a copy of the directory we are in */
3218 free(ftpc->prevpath);
3219
3220 if(data->set.wildcardmatch) {
3221 if(data->set.chunk_end && ftpc->file) {
3222 data->set.chunk_end(data->wildcard.customptr);
3223 }
3224 ftpc->known_filesize = -1;
3225 }
3226
3227 if(!result)
3228 /* get the "raw" path */
3229 result = Curl_urldecode(data, path_to_use, 0, &path, NULL, FALSE);
3230 if(result) {
3231 /* We can limp along anyway (and should try to since we may already be in
3232 * the error path) */
3233 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3234 connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
3235 ftpc->prevpath = NULL; /* no path remembering */
3236 }
3237 else {
3238 size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3239 size_t dlen = strlen(path)-flen;
3240 if(!ftpc->cwdfail) {
3241 if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3242 ftpc->prevpath = path;
3243 if(flen)
3244 /* if 'path' is not the whole string */
3245 ftpc->prevpath[dlen]=0; /* terminate */
3246 }
3247 else {
3248 /* we never changed dir */
3249 ftpc->prevpath=strdup("");
3250 free(path);
3251 }
3252 if(ftpc->prevpath)
3253 infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3254 }
3255 else {
3256 ftpc->prevpath = NULL; /* no path */
3257 free(path);
3258 }
3259 }
3260 /* free the dir tree and file parts */
3261 freedirs(ftpc);
3262
3263 /* shut down the socket to inform the server we're done */
3264
3265 #ifdef _WIN32_WCE
3266 shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */
3267 #endif
3268
3269 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3270 if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
3271 /* partial download completed */
3272 result = Curl_pp_sendf(pp, "%s", "ABOR");
3273 if(result) {
3274 failf(data, "Failure sending ABOR command: %s",
3275 curl_easy_strerror(result));
3276 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3277 connclose(conn, "ABOR command failed"); /* connection closure */
3278 }
3279 }
3280
3281 if(conn->ssl[SECONDARYSOCKET].use) {
3282 /* The secondary socket is using SSL so we must close down that part
3283 first before we close the socket for real */
3284 Curl_ssl_close(conn, SECONDARYSOCKET);
3285
3286 /* Note that we keep "use" set to TRUE since that (next) connection is
3287 still requested to use SSL */
3288 }
3289 close_secondarysocket(conn);
3290 }
3291
3292 if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3293 pp->pending_resp && !premature) {
3294 /*
3295 * Let's see what the server says about the transfer we just performed,
3296 * but lower the timeout as sometimes this connection has died while the
3297 * data has been transferred. This happens when doing through NATs etc that
3298 * abandon old silent connections.
3299 */
3300 long old_time = pp->response_time;
3301
3302 pp->response_time = 60*1000; /* give it only a minute for now */
3303 pp->response = Curl_tvnow(); /* timeout relative now */
3304
3305 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3306
3307 pp->response_time = old_time; /* set this back to previous value */
3308
3309 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3310 failf(data, "control connection looks dead");
3311 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3312 connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
3313 }
3314
3315 if(result)
3316 return result;
3317
3318 if(ftpc->dont_check && data->req.maxdownload > 0) {
3319 /* we have just sent ABOR and there is no reliable way to check if it was
3320 * successful or not; we have to close the connection now */
3321 infof(data, "partial download completed, closing connection\n");
3322 connclose(conn, "Partial download with no ability to check");
3323 return result;
3324 }
3325
3326 if(!ftpc->dont_check) {
3327 /* 226 Transfer complete, 250 Requested file action okay, completed. */
3328 if((ftpcode != 226) && (ftpcode != 250)) {
3329 failf(data, "server did not report OK, got %d", ftpcode);
3330 result = CURLE_PARTIAL_FILE;
3331 }
3332 }
3333 }
3334
3335 if(result || premature)
3336 /* the response code from the transfer showed an error already so no
3337 use checking further */
3338 ;
3339 else if(data->set.upload) {
3340 if((-1 != data->state.infilesize) &&
3341 (data->state.infilesize != *ftp->bytecountp) &&
3342 !data->set.crlf &&
3343 (ftp->transfer == FTPTRANSFER_BODY)) {
3344 failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
3345 " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
3346 *ftp->bytecountp, data->state.infilesize);
3347 result = CURLE_PARTIAL_FILE;
3348 }
3349 }
3350 else {
3351 if((-1 != data->req.size) &&
3352 (data->req.size != *ftp->bytecountp) &&
3353 #ifdef CURL_DO_LINEEND_CONV
3354 /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3355 * we'll check to see if the discrepancy can be explained by the number
3356 * of CRLFs we've changed to LFs.
3357 */
3358 ((data->req.size + data->state.crlf_conversions) !=
3359 *ftp->bytecountp) &&
3360 #endif /* CURL_DO_LINEEND_CONV */
3361 (data->req.maxdownload != *ftp->bytecountp)) {
3362 failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
3363 " bytes", *ftp->bytecountp);
3364 result = CURLE_PARTIAL_FILE;
3365 }
3366 else if(!ftpc->dont_check &&
3367 !*ftp->bytecountp &&
3368 (data->req.size>0)) {
3369 failf(data, "No data was received!");
3370 result = CURLE_FTP_COULDNT_RETR_FILE;
3371 }
3372 }
3373
3374 /* clear these for next connection */
3375 ftp->transfer = FTPTRANSFER_BODY;
3376 ftpc->dont_check = FALSE;
3377
3378 /* Send any post-transfer QUOTE strings? */
3379 if(!status && !result && !premature && data->set.postquote)
3380 result = ftp_sendquote(conn, data->set.postquote);
3381
3382 return result;
3383 }
3384
3385 /***********************************************************************
3386 *
3387 * ftp_sendquote()
3388 *
3389 * Where a 'quote' means a list of custom commands to send to the server.
3390 * The quote list is passed as an argument.
3391 *
3392 * BLOCKING
3393 */
3394
3395 static
ftp_sendquote(struct connectdata * conn,struct curl_slist * quote)3396 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3397 {
3398 struct curl_slist *item;
3399 ssize_t nread;
3400 int ftpcode;
3401 CURLcode result;
3402 struct ftp_conn *ftpc = &conn->proto.ftpc;
3403 struct pingpong *pp = &ftpc->pp;
3404
3405 item = quote;
3406 while(item) {
3407 if(item->data) {
3408 char *cmd = item->data;
3409 bool acceptfail = FALSE;
3410
3411 /* if a command starts with an asterisk, which a legal FTP command never
3412 can, the command will be allowed to fail without it causing any
3413 aborts or cancels etc. It will cause libcurl to act as if the command
3414 is successful, whatever the server reponds. */
3415
3416 if(cmd[0] == '*') {
3417 cmd++;
3418 acceptfail = TRUE;
3419 }
3420
3421 PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
3422
3423 pp->response = Curl_tvnow(); /* timeout relative now */
3424
3425 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3426 if(result)
3427 return result;
3428
3429 if(!acceptfail && (ftpcode >= 400)) {
3430 failf(conn->data, "QUOT string not accepted: %s", cmd);
3431 return CURLE_QUOTE_ERROR;
3432 }
3433 }
3434
3435 item = item->next;
3436 }
3437
3438 return CURLE_OK;
3439 }
3440
3441 /***********************************************************************
3442 *
3443 * ftp_need_type()
3444 *
3445 * Returns TRUE if we in the current situation should send TYPE
3446 */
ftp_need_type(struct connectdata * conn,bool ascii_wanted)3447 static int ftp_need_type(struct connectdata *conn,
3448 bool ascii_wanted)
3449 {
3450 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3451 }
3452
3453 /***********************************************************************
3454 *
3455 * ftp_nb_type()
3456 *
3457 * Set TYPE. We only deal with ASCII or BINARY so this function
3458 * sets one of them.
3459 * If the transfer type is not sent, simulate on OK response in newstate
3460 */
ftp_nb_type(struct connectdata * conn,bool ascii,ftpstate newstate)3461 static CURLcode ftp_nb_type(struct connectdata *conn,
3462 bool ascii, ftpstate newstate)
3463 {
3464 struct ftp_conn *ftpc = &conn->proto.ftpc;
3465 CURLcode result;
3466 char want = (char)(ascii?'A':'I');
3467
3468 if(ftpc->transfertype == want) {
3469 state(conn, newstate);
3470 return ftp_state_type_resp(conn, 200, newstate);
3471 }
3472
3473 PPSENDF(&ftpc->pp, "TYPE %c", want);
3474 state(conn, newstate);
3475
3476 /* keep track of our current transfer type */
3477 ftpc->transfertype = want;
3478 return CURLE_OK;
3479 }
3480
3481 /***************************************************************************
3482 *
3483 * ftp_pasv_verbose()
3484 *
3485 * This function only outputs some informationals about this second connection
3486 * when we've issued a PASV command before and thus we have connected to a
3487 * possibly new IP address.
3488 *
3489 */
3490 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3491 static void
ftp_pasv_verbose(struct connectdata * conn,Curl_addrinfo * ai,char * newhost,int port)3492 ftp_pasv_verbose(struct connectdata *conn,
3493 Curl_addrinfo *ai,
3494 char *newhost, /* ascii version */
3495 int port)
3496 {
3497 char buf[256];
3498 Curl_printable_address(ai, buf, sizeof(buf));
3499 infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3500 }
3501 #endif
3502
3503 /*
3504 Check if this is a range download, and if so, set the internal variables
3505 properly.
3506 */
3507
ftp_range(struct connectdata * conn)3508 static CURLcode ftp_range(struct connectdata *conn)
3509 {
3510 curl_off_t from, to;
3511 char *ptr;
3512 char *ptr2;
3513 struct Curl_easy *data = conn->data;
3514 struct ftp_conn *ftpc = &conn->proto.ftpc;
3515
3516 if(data->state.use_range && data->state.range) {
3517 from=curlx_strtoofft(data->state.range, &ptr, 0);
3518 while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3519 ptr++;
3520 to=curlx_strtoofft(ptr, &ptr2, 0);
3521 if(ptr == ptr2) {
3522 /* we didn't get any digit */
3523 to=-1;
3524 }
3525 if((-1 == to) && (from>=0)) {
3526 /* X - */
3527 data->state.resume_from = from;
3528 DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
3529 " to end of file\n", from));
3530 }
3531 else if(from < 0) {
3532 /* -Y */
3533 data->req.maxdownload = -from;
3534 data->state.resume_from = from;
3535 DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
3536 " bytes\n", -from));
3537 }
3538 else {
3539 /* X-Y */
3540 data->req.maxdownload = (to-from)+1; /* include last byte */
3541 data->state.resume_from = from;
3542 DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
3543 " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
3544 from, data->req.maxdownload));
3545 }
3546 DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T
3547 " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
3548 CURL_FORMAT_CURL_OFF_T " bytes\n",
3549 from, to, data->req.maxdownload));
3550 ftpc->dont_check = TRUE; /* dont check for successful transfer */
3551 }
3552 else
3553 data->req.maxdownload = -1;
3554 return CURLE_OK;
3555 }
3556
3557
3558 /*
3559 * ftp_do_more()
3560 *
3561 * This function shall be called when the second FTP (data) connection is
3562 * connected.
3563 *
3564 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
3565 * (which basically is only for when PASV is being sent to retry a failed
3566 * EPSV).
3567 */
3568
ftp_do_more(struct connectdata * conn,int * completep)3569 static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
3570 {
3571 struct Curl_easy *data=conn->data;
3572 struct ftp_conn *ftpc = &conn->proto.ftpc;
3573 CURLcode result = CURLE_OK;
3574 bool connected = FALSE;
3575 bool complete = FALSE;
3576
3577 /* the ftp struct is inited in ftp_connect() */
3578 struct FTP *ftp = data->req.protop;
3579
3580 /* if the second connection isn't done yet, wait for it */
3581 if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
3582 if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
3583 /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
3584 aren't used so we blank their arguments. TODO: make this nicer */
3585 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0, FALSE);
3586
3587 return result;
3588 }
3589
3590 result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
3591
3592 /* Ready to do more? */
3593 if(connected) {
3594 DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
3595 }
3596 else {
3597 if(result && (ftpc->count1 == 0)) {
3598 *completep = -1; /* go back to DOING please */
3599 /* this is a EPSV connect failing, try PASV instead */
3600 return ftp_epsv_disable(conn);
3601 }
3602 return result;
3603 }
3604 }
3605
3606 result = Curl_proxy_connect(conn, SECONDARYSOCKET);
3607 if(result)
3608 return result;
3609
3610 if(CONNECT_SECONDARYSOCKET_PROXY_SSL())
3611 return result;
3612
3613 if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
3614 conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE)
3615 return result;
3616
3617
3618 if(ftpc->state) {
3619 /* already in a state so skip the intial commands.
3620 They are only done to kickstart the do_more state */
3621 result = ftp_multi_statemach(conn, &complete);
3622
3623 *completep = (int)complete;
3624
3625 /* if we got an error or if we don't wait for a data connection return
3626 immediately */
3627 if(result || (ftpc->wait_data_conn != TRUE))
3628 return result;
3629
3630 if(ftpc->wait_data_conn)
3631 /* if we reach the end of the FTP state machine here, *complete will be
3632 TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3633 the data connection and therefore we're not actually complete */
3634 *completep = 0;
3635 }
3636
3637 if(ftp->transfer <= FTPTRANSFER_INFO) {
3638 /* a transfer is about to take place, or if not a file name was given
3639 so we'll do a SIZE on it later and then we need the right TYPE first */
3640
3641 if(ftpc->wait_data_conn == TRUE) {
3642 bool serv_conned;
3643
3644 result = ReceivedServerConnect(conn, &serv_conned);
3645 if(result)
3646 return result; /* Failed to accept data connection */
3647
3648 if(serv_conned) {
3649 /* It looks data connection is established */
3650 result = AcceptServerConnect(conn);
3651 ftpc->wait_data_conn = FALSE;
3652 if(!result)
3653 result = InitiateTransfer(conn);
3654
3655 if(result)
3656 return result;
3657
3658 *completep = 1; /* this state is now complete when the server has
3659 connected back to us */
3660 }
3661 }
3662 else if(data->set.upload) {
3663 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3664 if(result)
3665 return result;
3666
3667 result = ftp_multi_statemach(conn, &complete);
3668 if(ftpc->wait_data_conn)
3669 /* if we reach the end of the FTP state machine here, *complete will be
3670 TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3671 the data connection and therefore we're not actually complete */
3672 *completep = 0;
3673 else
3674 *completep = (int)complete;
3675 }
3676 else {
3677 /* download */
3678 ftp->downloadsize = -1; /* unknown as of yet */
3679
3680 result = ftp_range(conn);
3681 if(result)
3682 ;
3683 else if(data->set.ftp_list_only || !ftpc->file) {
3684 /* The specified path ends with a slash, and therefore we think this
3685 is a directory that is requested, use LIST. But before that we
3686 need to set ASCII transfer mode. */
3687
3688 /* But only if a body transfer was requested. */
3689 if(ftp->transfer == FTPTRANSFER_BODY) {
3690 result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3691 if(result)
3692 return result;
3693 }
3694 /* otherwise just fall through */
3695 }
3696 else {
3697 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3698 if(result)
3699 return result;
3700 }
3701
3702 result = ftp_multi_statemach(conn, &complete);
3703 *completep = (int)complete;
3704 }
3705 return result;
3706 }
3707
3708 if(!result && (ftp->transfer != FTPTRANSFER_BODY))
3709 /* no data to transfer. FIX: it feels like a kludge to have this here
3710 too! */
3711 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3712
3713 if(!ftpc->wait_data_conn) {
3714 /* no waiting for the data connection so this is now complete */
3715 *completep = 1;
3716 DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3717 }
3718
3719 return result;
3720 }
3721
3722
3723
3724 /***********************************************************************
3725 *
3726 * ftp_perform()
3727 *
3728 * This is the actual DO function for FTP. Get a file/directory according to
3729 * the options previously setup.
3730 */
3731
3732 static
ftp_perform(struct connectdata * conn,bool * connected,bool * dophase_done)3733 CURLcode ftp_perform(struct connectdata *conn,
3734 bool *connected, /* connect status after PASV / PORT */
3735 bool *dophase_done)
3736 {
3737 /* this is FTP and no proxy */
3738 CURLcode result=CURLE_OK;
3739
3740 DEBUGF(infof(conn->data, "DO phase starts\n"));
3741
3742 if(conn->data->set.opt_no_body) {
3743 /* requested no body means no transfer... */
3744 struct FTP *ftp = conn->data->req.protop;
3745 ftp->transfer = FTPTRANSFER_INFO;
3746 }
3747
3748 *dophase_done = FALSE; /* not done yet */
3749
3750 /* start the first command in the DO phase */
3751 result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3752 if(result)
3753 return result;
3754
3755 /* run the state-machine */
3756 result = ftp_multi_statemach(conn, dophase_done);
3757
3758 *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
3759
3760 infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
3761
3762 if(*dophase_done)
3763 DEBUGF(infof(conn->data, "DO phase is complete1\n"));
3764
3765 return result;
3766 }
3767
wc_data_dtor(void * ptr)3768 static void wc_data_dtor(void *ptr)
3769 {
3770 struct ftp_wc_tmpdata *tmp = ptr;
3771 if(tmp)
3772 Curl_ftp_parselist_data_free(&tmp->parser);
3773 free(tmp);
3774 }
3775
init_wc_data(struct connectdata * conn)3776 static CURLcode init_wc_data(struct connectdata *conn)
3777 {
3778 char *last_slash;
3779 char *path = conn->data->state.path;
3780 struct WildcardData *wildcard = &(conn->data->wildcard);
3781 CURLcode result = CURLE_OK;
3782 struct ftp_wc_tmpdata *ftp_tmp;
3783
3784 last_slash = strrchr(conn->data->state.path, '/');
3785 if(last_slash) {
3786 last_slash++;
3787 if(last_slash[0] == '\0') {
3788 wildcard->state = CURLWC_CLEAN;
3789 result = ftp_parse_url_path(conn);
3790 return result;
3791 }
3792 else {
3793 wildcard->pattern = strdup(last_slash);
3794 if(!wildcard->pattern)
3795 return CURLE_OUT_OF_MEMORY;
3796 last_slash[0] = '\0'; /* cut file from path */
3797 }
3798 }
3799 else { /* there is only 'wildcard pattern' or nothing */
3800 if(path[0]) {
3801 wildcard->pattern = strdup(path);
3802 if(!wildcard->pattern)
3803 return CURLE_OUT_OF_MEMORY;
3804 path[0] = '\0';
3805 }
3806 else { /* only list */
3807 wildcard->state = CURLWC_CLEAN;
3808 result = ftp_parse_url_path(conn);
3809 return result;
3810 }
3811 }
3812
3813 /* program continues only if URL is not ending with slash, allocate needed
3814 resources for wildcard transfer */
3815
3816 /* allocate ftp protocol specific temporary wildcard data */
3817 ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
3818 if(!ftp_tmp) {
3819 Curl_safefree(wildcard->pattern);
3820 return CURLE_OUT_OF_MEMORY;
3821 }
3822
3823 /* INITIALIZE parselist structure */
3824 ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
3825 if(!ftp_tmp->parser) {
3826 Curl_safefree(wildcard->pattern);
3827 free(ftp_tmp);
3828 return CURLE_OUT_OF_MEMORY;
3829 }
3830
3831 wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
3832 wildcard->tmp_dtor = wc_data_dtor;
3833
3834 /* wildcard does not support NOCWD option (assert it?) */
3835 if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3836 conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3837
3838 /* try to parse ftp url */
3839 result = ftp_parse_url_path(conn);
3840 if(result) {
3841 Curl_safefree(wildcard->pattern);
3842 wildcard->tmp_dtor(wildcard->tmp);
3843 wildcard->tmp_dtor = ZERO_NULL;
3844 wildcard->tmp = NULL;
3845 return result;
3846 }
3847
3848 wildcard->path = strdup(conn->data->state.path);
3849 if(!wildcard->path) {
3850 Curl_safefree(wildcard->pattern);
3851 wildcard->tmp_dtor(wildcard->tmp);
3852 wildcard->tmp_dtor = ZERO_NULL;
3853 wildcard->tmp = NULL;
3854 return CURLE_OUT_OF_MEMORY;
3855 }
3856
3857 /* backup old write_function */
3858 ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
3859 /* parsing write function */
3860 conn->data->set.fwrite_func = Curl_ftp_parselist;
3861 /* backup old file descriptor */
3862 ftp_tmp->backup.file_descriptor = conn->data->set.out;
3863 /* let the writefunc callback know what curl pointer is working with */
3864 conn->data->set.out = conn;
3865
3866 infof(conn->data, "Wildcard - Parsing started\n");
3867 return CURLE_OK;
3868 }
3869
3870 /* This is called recursively */
wc_statemach(struct connectdata * conn)3871 static CURLcode wc_statemach(struct connectdata *conn)
3872 {
3873 struct WildcardData * const wildcard = &(conn->data->wildcard);
3874 CURLcode result = CURLE_OK;
3875
3876 switch (wildcard->state) {
3877 case CURLWC_INIT:
3878 result = init_wc_data(conn);
3879 if(wildcard->state == CURLWC_CLEAN)
3880 /* only listing! */
3881 break;
3882 else
3883 wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
3884 break;
3885
3886 case CURLWC_MATCHING: {
3887 /* In this state is LIST response successfully parsed, so lets restore
3888 previous WRITEFUNCTION callback and WRITEDATA pointer */
3889 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3890 conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
3891 conn->data->set.out = ftp_tmp->backup.file_descriptor;
3892 ftp_tmp->backup.write_function = ZERO_NULL;
3893 ftp_tmp->backup.file_descriptor = NULL;
3894 wildcard->state = CURLWC_DOWNLOADING;
3895
3896 if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
3897 /* error found in LIST parsing */
3898 wildcard->state = CURLWC_CLEAN;
3899 return wc_statemach(conn);
3900 }
3901 else if(wildcard->filelist->size == 0) {
3902 /* no corresponding file */
3903 wildcard->state = CURLWC_CLEAN;
3904 return CURLE_REMOTE_FILE_NOT_FOUND;
3905 }
3906 return wc_statemach(conn);
3907 }
3908
3909 case CURLWC_DOWNLOADING: {
3910 /* filelist has at least one file, lets get first one */
3911 struct ftp_conn *ftpc = &conn->proto.ftpc;
3912 struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
3913
3914 char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
3915 if(!tmp_path)
3916 return CURLE_OUT_OF_MEMORY;
3917
3918 /* switch default "state.pathbuffer" and tmp_path, good to see
3919 ftp_parse_url_path function to understand this trick */
3920 Curl_safefree(conn->data->state.pathbuffer);
3921 conn->data->state.pathbuffer = tmp_path;
3922 conn->data->state.path = tmp_path;
3923
3924 infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3925 if(conn->data->set.chunk_bgn) {
3926 long userresponse = conn->data->set.chunk_bgn(
3927 finfo, wildcard->customptr, (int)wildcard->filelist->size);
3928 switch(userresponse) {
3929 case CURL_CHUNK_BGN_FUNC_SKIP:
3930 infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
3931 finfo->filename);
3932 wildcard->state = CURLWC_SKIP;
3933 return wc_statemach(conn);
3934 case CURL_CHUNK_BGN_FUNC_FAIL:
3935 return CURLE_CHUNK_FAILED;
3936 }
3937 }
3938
3939 if(finfo->filetype != CURLFILETYPE_FILE) {
3940 wildcard->state = CURLWC_SKIP;
3941 return wc_statemach(conn);
3942 }
3943
3944 if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
3945 ftpc->known_filesize = finfo->size;
3946
3947 result = ftp_parse_url_path(conn);
3948 if(result)
3949 return result;
3950
3951 /* we don't need the Curl_fileinfo of first file anymore */
3952 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
3953
3954 if(wildcard->filelist->size == 0) { /* remains only one file to down. */
3955 wildcard->state = CURLWC_CLEAN;
3956 /* after that will be ftp_do called once again and no transfer
3957 will be done because of CURLWC_CLEAN state */
3958 return CURLE_OK;
3959 }
3960 } break;
3961
3962 case CURLWC_SKIP: {
3963 if(conn->data->set.chunk_end)
3964 conn->data->set.chunk_end(conn->data->wildcard.customptr);
3965 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
3966 wildcard->state = (wildcard->filelist->size == 0) ?
3967 CURLWC_CLEAN : CURLWC_DOWNLOADING;
3968 return wc_statemach(conn);
3969 }
3970
3971 case CURLWC_CLEAN: {
3972 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3973 result = CURLE_OK;
3974 if(ftp_tmp)
3975 result = Curl_ftp_parselist_geterror(ftp_tmp->parser);
3976
3977 wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
3978 } break;
3979
3980 case CURLWC_DONE:
3981 case CURLWC_ERROR:
3982 break;
3983 }
3984
3985 return result;
3986 }
3987
3988 /***********************************************************************
3989 *
3990 * ftp_do()
3991 *
3992 * This function is registered as 'curl_do' function. It decodes the path
3993 * parts etc as a wrapper to the actual DO function (ftp_perform).
3994 *
3995 * The input argument is already checked for validity.
3996 */
ftp_do(struct connectdata * conn,bool * done)3997 static CURLcode ftp_do(struct connectdata *conn, bool *done)
3998 {
3999 CURLcode result = CURLE_OK;
4000 struct ftp_conn *ftpc = &conn->proto.ftpc;
4001
4002 *done = FALSE; /* default to false */
4003 ftpc->wait_data_conn = FALSE; /* default to no such wait */
4004
4005 if(conn->data->set.wildcardmatch) {
4006 result = wc_statemach(conn);
4007 if(conn->data->wildcard.state == CURLWC_SKIP ||
4008 conn->data->wildcard.state == CURLWC_DONE) {
4009 /* do not call ftp_regular_transfer */
4010 return CURLE_OK;
4011 }
4012 if(result) /* error, loop or skipping the file */
4013 return result;
4014 }
4015 else { /* no wildcard FSM needed */
4016 result = ftp_parse_url_path(conn);
4017 if(result)
4018 return result;
4019 }
4020
4021 result = ftp_regular_transfer(conn, done);
4022
4023 return result;
4024 }
4025
4026
Curl_ftpsend(struct connectdata * conn,const char * cmd)4027 CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
4028 {
4029 ssize_t bytes_written;
4030 #define SBUF_SIZE 1024
4031 char s[SBUF_SIZE];
4032 size_t write_len;
4033 char *sptr=s;
4034 CURLcode result = CURLE_OK;
4035 #ifdef HAVE_GSSAPI
4036 enum protection_level data_sec = conn->data_prot;
4037 #endif
4038
4039 write_len = strlen(cmd);
4040 if(write_len > (sizeof(s) -3))
4041 return CURLE_BAD_FUNCTION_ARGUMENT;
4042
4043 strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
4044 write_len +=2;
4045
4046 bytes_written=0;
4047
4048 result = Curl_convert_to_network(conn->data, s, write_len);
4049 /* Curl_convert_to_network calls failf if unsuccessful */
4050 if(result)
4051 return result;
4052
4053 for(;;) {
4054 #ifdef HAVE_GSSAPI
4055 conn->data_prot = PROT_CMD;
4056 #endif
4057 result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
4058 &bytes_written);
4059 #ifdef HAVE_GSSAPI
4060 DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
4061 conn->data_prot = data_sec;
4062 #endif
4063
4064 if(result)
4065 break;
4066
4067 if(conn->data->set.verbose)
4068 Curl_debug(conn->data, CURLINFO_HEADER_OUT,
4069 sptr, (size_t)bytes_written, conn);
4070
4071 if(bytes_written != (ssize_t)write_len) {
4072 write_len -= bytes_written;
4073 sptr += bytes_written;
4074 }
4075 else
4076 break;
4077 }
4078
4079 return result;
4080 }
4081
4082 /***********************************************************************
4083 *
4084 * ftp_quit()
4085 *
4086 * This should be called before calling sclose() on an ftp control connection
4087 * (not data connections). We should then wait for the response from the
4088 * server before returning. The calling code should then try to close the
4089 * connection.
4090 *
4091 */
ftp_quit(struct connectdata * conn)4092 static CURLcode ftp_quit(struct connectdata *conn)
4093 {
4094 CURLcode result = CURLE_OK;
4095
4096 if(conn->proto.ftpc.ctl_valid) {
4097 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
4098 if(result) {
4099 failf(conn->data, "Failure sending QUIT command: %s",
4100 curl_easy_strerror(result));
4101 conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
4102 connclose(conn, "QUIT command failed"); /* mark for connection closure */
4103 state(conn, FTP_STOP);
4104 return result;
4105 }
4106
4107 state(conn, FTP_QUIT);
4108
4109 result = ftp_block_statemach(conn);
4110 }
4111
4112 return result;
4113 }
4114
4115 /***********************************************************************
4116 *
4117 * ftp_disconnect()
4118 *
4119 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4120 * resources. BLOCKING.
4121 */
ftp_disconnect(struct connectdata * conn,bool dead_connection)4122 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
4123 {
4124 struct ftp_conn *ftpc= &conn->proto.ftpc;
4125 struct pingpong *pp = &ftpc->pp;
4126
4127 /* We cannot send quit unconditionally. If this connection is stale or
4128 bad in any way, sending quit and waiting around here will make the
4129 disconnect wait in vain and cause more problems than we need to.
4130
4131 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4132 will try to send the QUIT command, otherwise it will just return.
4133 */
4134 if(dead_connection)
4135 ftpc->ctl_valid = FALSE;
4136
4137 /* The FTP session may or may not have been allocated/setup at this point! */
4138 (void)ftp_quit(conn); /* ignore errors on the QUIT */
4139
4140 if(ftpc->entrypath) {
4141 struct Curl_easy *data = conn->data;
4142 if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4143 data->state.most_recent_ftp_entrypath = NULL;
4144 }
4145 free(ftpc->entrypath);
4146 ftpc->entrypath = NULL;
4147 }
4148
4149 freedirs(ftpc);
4150 free(ftpc->prevpath);
4151 ftpc->prevpath = NULL;
4152 free(ftpc->server_os);
4153 ftpc->server_os = NULL;
4154
4155 Curl_pp_disconnect(pp);
4156
4157 #ifdef HAVE_GSSAPI
4158 Curl_sec_end(conn);
4159 #endif
4160
4161 return CURLE_OK;
4162 }
4163
4164 /***********************************************************************
4165 *
4166 * ftp_parse_url_path()
4167 *
4168 * Parse the URL path into separate path components.
4169 *
4170 */
4171 static
ftp_parse_url_path(struct connectdata * conn)4172 CURLcode ftp_parse_url_path(struct connectdata *conn)
4173 {
4174 struct Curl_easy *data = conn->data;
4175 /* the ftp struct is already inited in ftp_connect() */
4176 struct FTP *ftp = data->req.protop;
4177 struct ftp_conn *ftpc = &conn->proto.ftpc;
4178 const char *slash_pos; /* position of the first '/' char in curpos */
4179 const char *path_to_use = data->state.path;
4180 const char *cur_pos;
4181 const char *filename = NULL;
4182
4183 cur_pos = path_to_use; /* current position in path. point at the begin of
4184 next path component */
4185
4186 ftpc->ctl_valid = FALSE;
4187 ftpc->cwdfail = FALSE;
4188
4189 switch(data->set.ftp_filemethod) {
4190 case FTPFILE_NOCWD:
4191 /* fastest, but less standard-compliant */
4192
4193 /*
4194 The best time to check whether the path is a file or directory is right
4195 here. so:
4196
4197 the first condition in the if() right here, is there just in case
4198 someone decides to set path to NULL one day
4199 */
4200 if(path_to_use[0] &&
4201 (path_to_use[strlen(path_to_use) - 1] != '/') )
4202 filename = path_to_use; /* this is a full file path */
4203 /*
4204 else {
4205 ftpc->file is not used anywhere other than for operations on a file.
4206 In other words, never for directory operations.
4207 So we can safely leave filename as NULL here and use it as a
4208 argument in dir/file decisions.
4209 }
4210 */
4211 break;
4212
4213 case FTPFILE_SINGLECWD:
4214 /* get the last slash */
4215 if(!path_to_use[0]) {
4216 /* no dir, no file */
4217 ftpc->dirdepth = 0;
4218 break;
4219 }
4220 slash_pos=strrchr(cur_pos, '/');
4221 if(slash_pos || !*cur_pos) {
4222 size_t dirlen = slash_pos-cur_pos;
4223 CURLcode result;
4224
4225 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4226 if(!ftpc->dirs)
4227 return CURLE_OUT_OF_MEMORY;
4228
4229 if(!dirlen)
4230 dirlen++;
4231
4232 result = Curl_urldecode(conn->data, slash_pos ? cur_pos : "/",
4233 slash_pos ? dirlen : 1,
4234 &ftpc->dirs[0], NULL,
4235 FALSE);
4236 if(result) {
4237 freedirs(ftpc);
4238 return result;
4239 }
4240 ftpc->dirdepth = 1; /* we consider it to be a single dir */
4241 filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
4242 }
4243 else
4244 filename = cur_pos; /* this is a file name only */
4245 break;
4246
4247 default: /* allow pretty much anything */
4248 case FTPFILE_MULTICWD:
4249 ftpc->dirdepth = 0;
4250 ftpc->diralloc = 5; /* default dir depth to allocate */
4251 ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
4252 if(!ftpc->dirs)
4253 return CURLE_OUT_OF_MEMORY;
4254
4255 /* we have a special case for listing the root dir only */
4256 if(!strcmp(path_to_use, "/")) {
4257 cur_pos++; /* make it point to the zero byte */
4258 ftpc->dirs[0] = strdup("/");
4259 ftpc->dirdepth++;
4260 }
4261 else {
4262 /* parse the URL path into separate path components */
4263 while((slash_pos = strchr(cur_pos, '/')) != NULL) {
4264 /* 1 or 0 pointer offset to indicate absolute directory */
4265 ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
4266 (ftpc->dirdepth == 0))?1:0;
4267
4268 /* seek out the next path component */
4269 if(slash_pos-cur_pos) {
4270 /* we skip empty path components, like "x//y" since the FTP command
4271 CWD requires a parameter and a non-existent parameter a) doesn't
4272 work on many servers and b) has no effect on the others. */
4273 size_t len = slash_pos - cur_pos + absolute_dir;
4274 CURLcode result =
4275 Curl_urldecode(conn->data, cur_pos - absolute_dir, len,
4276 &ftpc->dirs[ftpc->dirdepth], NULL,
4277 TRUE);
4278 if(result) {
4279 free(ftpc->dirs[ftpc->dirdepth]);
4280 freedirs(ftpc);
4281 return result;
4282 }
4283 }
4284 else {
4285 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4286 if(!ftpc->dirdepth) {
4287 /* path starts with a slash, add that as a directory */
4288 ftpc->dirs[ftpc->dirdepth] = strdup("/");
4289 if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */
4290 failf(data, "no memory");
4291 freedirs(ftpc);
4292 return CURLE_OUT_OF_MEMORY;
4293 }
4294 }
4295 continue;
4296 }
4297
4298 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4299 if(++ftpc->dirdepth >= ftpc->diralloc) {
4300 /* enlarge array */
4301 char **bigger;
4302 ftpc->diralloc *= 2; /* double the size each time */
4303 bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
4304 if(!bigger) {
4305 freedirs(ftpc);
4306 return CURLE_OUT_OF_MEMORY;
4307 }
4308 ftpc->dirs = bigger;
4309 }
4310 }
4311 }
4312 filename = cur_pos; /* the rest is the file name */
4313 break;
4314 } /* switch */
4315
4316 if(filename && *filename) {
4317 CURLcode result =
4318 Curl_urldecode(conn->data, filename, 0, &ftpc->file, NULL, TRUE);
4319
4320 if(result) {
4321 freedirs(ftpc);
4322 return result;
4323 }
4324 }
4325 else
4326 ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
4327 pointer */
4328
4329 if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
4330 /* We need a file name when uploading. Return error! */
4331 failf(data, "Uploading to a URL without a file name!");
4332 return CURLE_URL_MALFORMAT;
4333 }
4334
4335 ftpc->cwddone = FALSE; /* default to not done */
4336
4337 if(ftpc->prevpath) {
4338 /* prevpath is "raw" so we convert the input path before we compare the
4339 strings */
4340 size_t dlen;
4341 char *path;
4342 CURLcode result =
4343 Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, FALSE);
4344 if(result) {
4345 freedirs(ftpc);
4346 return result;
4347 }
4348
4349 dlen -= ftpc->file?strlen(ftpc->file):0;
4350 if((dlen == strlen(ftpc->prevpath)) &&
4351 !strncmp(path, ftpc->prevpath, dlen)) {
4352 infof(data, "Request has same path as previous transfer\n");
4353 ftpc->cwddone = TRUE;
4354 }
4355 free(path);
4356 }
4357
4358 return CURLE_OK;
4359 }
4360
4361 /* call this when the DO phase has completed */
ftp_dophase_done(struct connectdata * conn,bool connected)4362 static CURLcode ftp_dophase_done(struct connectdata *conn,
4363 bool connected)
4364 {
4365 struct FTP *ftp = conn->data->req.protop;
4366 struct ftp_conn *ftpc = &conn->proto.ftpc;
4367
4368 if(connected) {
4369 int completed;
4370 CURLcode result = ftp_do_more(conn, &completed);
4371
4372 if(result) {
4373 close_secondarysocket(conn);
4374 return result;
4375 }
4376 }
4377
4378 if(ftp->transfer != FTPTRANSFER_BODY)
4379 /* no data to transfer */
4380 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
4381 else if(!connected)
4382 /* since we didn't connect now, we want do_more to get called */
4383 conn->bits.do_more = TRUE;
4384
4385 ftpc->ctl_valid = TRUE; /* seems good */
4386
4387 return CURLE_OK;
4388 }
4389
4390 /* called from multi.c while DOing */
ftp_doing(struct connectdata * conn,bool * dophase_done)4391 static CURLcode ftp_doing(struct connectdata *conn,
4392 bool *dophase_done)
4393 {
4394 CURLcode result = ftp_multi_statemach(conn, dophase_done);
4395
4396 if(result)
4397 DEBUGF(infof(conn->data, "DO phase failed\n"));
4398 else if(*dophase_done) {
4399 result = ftp_dophase_done(conn, FALSE /* not connected */);
4400
4401 DEBUGF(infof(conn->data, "DO phase is complete2\n"));
4402 }
4403 return result;
4404 }
4405
4406 /***********************************************************************
4407 *
4408 * ftp_regular_transfer()
4409 *
4410 * The input argument is already checked for validity.
4411 *
4412 * Performs all commands done before a regular transfer between a local and a
4413 * remote host.
4414 *
4415 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4416 * ftp_done() function without finding any major problem.
4417 */
4418 static
ftp_regular_transfer(struct connectdata * conn,bool * dophase_done)4419 CURLcode ftp_regular_transfer(struct connectdata *conn,
4420 bool *dophase_done)
4421 {
4422 CURLcode result=CURLE_OK;
4423 bool connected=FALSE;
4424 struct Curl_easy *data = conn->data;
4425 struct ftp_conn *ftpc = &conn->proto.ftpc;
4426 data->req.size = -1; /* make sure this is unknown at this point */
4427
4428 Curl_pgrsSetUploadCounter(data, 0);
4429 Curl_pgrsSetDownloadCounter(data, 0);
4430 Curl_pgrsSetUploadSize(data, -1);
4431 Curl_pgrsSetDownloadSize(data, -1);
4432
4433 ftpc->ctl_valid = TRUE; /* starts good */
4434
4435 result = ftp_perform(conn,
4436 &connected, /* have we connected after PASV/PORT */
4437 dophase_done); /* all commands in the DO-phase done? */
4438
4439 if(!result) {
4440
4441 if(!*dophase_done)
4442 /* the DO phase has not completed yet */
4443 return CURLE_OK;
4444
4445 result = ftp_dophase_done(conn, connected);
4446
4447 if(result)
4448 return result;
4449 }
4450 else
4451 freedirs(ftpc);
4452
4453 return result;
4454 }
4455
ftp_setup_connection(struct connectdata * conn)4456 static CURLcode ftp_setup_connection(struct connectdata *conn)
4457 {
4458 struct Curl_easy *data = conn->data;
4459 char *type;
4460 char command;
4461 struct FTP *ftp;
4462
4463 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
4464 /* Unless we have asked to tunnel ftp operations through the proxy, we
4465 switch and use HTTP operations only */
4466 #ifndef CURL_DISABLE_HTTP
4467 if(conn->handler == &Curl_handler_ftp)
4468 conn->handler = &Curl_handler_ftp_proxy;
4469 else {
4470 #ifdef USE_SSL
4471 conn->handler = &Curl_handler_ftps_proxy;
4472 #else
4473 failf(data, "FTPS not supported!");
4474 return CURLE_UNSUPPORTED_PROTOCOL;
4475 #endif
4476 }
4477 /* set it up as a HTTP connection instead */
4478 return conn->handler->setup_connection(conn);
4479 #else
4480 failf(data, "FTP over http proxy requires HTTP support built-in!");
4481 return CURLE_UNSUPPORTED_PROTOCOL;
4482 #endif
4483 }
4484
4485 conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
4486 if(NULL == ftp)
4487 return CURLE_OUT_OF_MEMORY;
4488
4489 data->state.path++; /* don't include the initial slash */
4490 data->state.slash_removed = TRUE; /* we've skipped the slash */
4491
4492 /* FTP URLs support an extension like ";type=<typecode>" that
4493 * we'll try to get now! */
4494 type = strstr(data->state.path, ";type=");
4495
4496 if(!type)
4497 type = strstr(conn->host.rawalloc, ";type=");
4498
4499 if(type) {
4500 *type = 0; /* it was in the middle of the hostname */
4501 command = Curl_raw_toupper(type[6]);
4502 conn->bits.type_set = TRUE;
4503
4504 switch (command) {
4505 case 'A': /* ASCII mode */
4506 data->set.prefer_ascii = TRUE;
4507 break;
4508
4509 case 'D': /* directory mode */
4510 data->set.ftp_list_only = TRUE;
4511 break;
4512
4513 case 'I': /* binary mode */
4514 default:
4515 /* switch off ASCII */
4516 data->set.prefer_ascii = FALSE;
4517 break;
4518 }
4519 }
4520
4521 /* get some initial data into the ftp struct */
4522 ftp->bytecountp = &conn->data->req.bytecount;
4523 ftp->transfer = FTPTRANSFER_BODY;
4524 ftp->downloadsize = 0;
4525
4526 /* No need to duplicate user+password, the connectdata struct won't change
4527 during a session, but we re-init them here since on subsequent inits
4528 since the conn struct may have changed or been replaced.
4529 */
4530 ftp->user = conn->user;
4531 ftp->passwd = conn->passwd;
4532 if(isBadFtpString(ftp->user))
4533 return CURLE_URL_MALFORMAT;
4534 if(isBadFtpString(ftp->passwd))
4535 return CURLE_URL_MALFORMAT;
4536
4537 conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
4538
4539 return CURLE_OK;
4540 }
4541
4542 #endif /* CURL_DISABLE_FTP */
4543