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