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