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


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:09