Don't free too much in freedirs() if realloc() fails.
[platform/upstream/curl.git] / lib / ftp.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2005, 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  * $Id$
22  ***************************************************************************/
23
24 #include "setup.h"
25
26 #ifndef CURL_DISABLE_FTP
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <ctype.h>
32 #include <errno.h>
33
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
39
40 #else /* probably some kind of unix */
41 #ifdef HAVE_SYS_SOCKET_H
42 #include <sys/socket.h>
43 #endif
44 #include <sys/types.h>
45 #ifdef HAVE_NETINET_IN_H
46 #include <netinet/in.h>
47 #endif
48 #ifdef HAVE_ARPA_INET_H
49 #include <arpa/inet.h>
50 #endif
51 #ifdef HAVE_UTSNAME_H
52 #include <sys/utsname.h>
53 #endif
54 #ifdef HAVE_NETDB_H
55 #include <netdb.h>
56 #endif
57 #ifdef  VMS
58 #include <in.h>
59 #include <inet.h>
60 #endif
61 #endif
62
63 #if defined(WIN32) && defined(__GNUC__) || defined(__MINGW32__)
64 #include <errno.h>
65 #endif
66
67 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
68 #undef in_addr_t
69 #define in_addr_t unsigned long
70 #endif
71
72 #include <curl/curl.h>
73 #include "urldata.h"
74 #include "sendf.h"
75
76 #include "if2ip.h"
77 #include "hostip.h"
78 #include "progress.h"
79 #include "transfer.h"
80 #include "escape.h"
81 #include "http.h" /* for HTTP proxy tunnel stuff */
82 #include "ftp.h"
83
84 #ifdef HAVE_KRB4
85 #include "security.h"
86 #include "krb4.h"
87 #endif
88
89 #include "strtoofft.h"
90 #include "strequal.h"
91 #include "ssluse.h"
92 #include "connect.h"
93 #include "strerror.h"
94 #include "memory.h"
95 #include "inet_ntop.h"
96 #include "select.h"
97
98 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
99 #include "inet_ntoa_r.h"
100 #endif
101
102 #define _MPRINTF_REPLACE /* use our functions only */
103 #include <curl/mprintf.h>
104
105 /* The last #include file should be: */
106 #ifdef CURLDEBUG
107 #include "memdebug.h"
108 #endif
109
110 #ifdef HAVE_NI_WITHSCOPEID
111 #define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID
112 #else
113 #define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV
114 #endif
115
116 /* Local API functions */
117 static CURLcode ftp_sendquote(struct connectdata *conn,
118                               struct curl_slist *quote);
119 static CURLcode ftp_cwd(struct connectdata *conn, char *path);
120 static CURLcode ftp_mkd(struct connectdata *conn, char *path);
121 static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path);
122 static CURLcode ftp_quit(struct connectdata *conn);
123 static CURLcode ftp_3rdparty_pretransfer(struct connectdata *conn);
124 static CURLcode ftp_3rdparty_transfer(struct connectdata *conn);
125 static CURLcode ftp_parse_url_path(struct connectdata *conn);
126 static CURLcode ftp_cwd_and_create_path(struct connectdata *conn);
127 static CURLcode ftp_regular_transfer(struct connectdata *conn);
128 static CURLcode ftp_3rdparty(struct connectdata *conn);
129
130 /* easy-to-use macro: */
131 #define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z))) return result
132
133 static void freedirs(struct FTP *ftp)
134 {
135   int i;
136   if(ftp->dirs) {
137     for (i=0; i < ftp->dirdepth; i++){
138       if(ftp->dirs[i]) {
139         free(ftp->dirs[i]);
140         ftp->dirs[i]=NULL;
141       }
142     }
143     free(ftp->dirs);
144     ftp->dirs = NULL;
145   }
146   if(ftp->file) {
147     free(ftp->file);
148     ftp->file = NULL;
149   }
150 }
151
152 /* Returns non-zero iff the given string contains CR (0x0D) or LF (0x0A), which
153    are not allowed within RFC 959 <string>.
154  */
155 static bool isBadFtpString(const char *string)
156 {
157   return strchr(string, 0x0D) != NULL || strchr(string, 0x0A) != NULL;
158 }
159
160 /***********************************************************************
161  *
162  * AllowServerConnect()
163  *
164  * When we've issue the PORT command, we have told the server to connect
165  * to us. This function will sit and wait here until the server has
166  * connected.
167  *
168  */
169 static CURLcode AllowServerConnect(struct connectdata *conn)
170 {
171   int timeout_ms;
172   struct SessionHandle *data = conn->data;
173   curl_socket_t sock = conn->sock[SECONDARYSOCKET];
174   struct timeval now = Curl_tvnow();
175   long timespent = Curl_tvdiff(Curl_tvnow(), now)/1000;
176   long timeout = data->set.connecttimeout?data->set.connecttimeout:
177     (data->set.timeout?data->set.timeout: 0);
178
179   if(timeout) {
180     timeout -= timespent;
181     if(timeout<=0) {
182       failf(data, "Timed out before server could connect to us");
183       return CURLE_OPERATION_TIMEDOUT;
184     }
185   }
186
187   /* We allow the server 60 seconds to connect to us, or a custom timeout.
188      Note the typecast here. */
189   timeout_ms = (timeout?(int)timeout:60) * 1000;
190
191   switch (Curl_select(sock, CURL_SOCKET_BAD, timeout_ms)) {
192   case -1: /* error */
193     /* let's die here */
194     failf(data, "Error while waiting for server connect");
195     return CURLE_FTP_PORT_FAILED;
196   case 0:  /* timeout */
197     /* let's die here */
198     failf(data, "Timeout while waiting for server connect");
199     return CURLE_FTP_PORT_FAILED;
200   default:
201     /* we have received data here */
202     {
203       curl_socket_t s;
204       size_t size = sizeof(struct sockaddr_in);
205       struct sockaddr_in add;
206
207       getsockname(sock, (struct sockaddr *) &add, (socklen_t *)&size);
208       s=accept(sock, (struct sockaddr *) &add, (socklen_t *)&size);
209
210       sclose(sock); /* close the first socket */
211
212       if (CURL_SOCKET_BAD == s) {
213         /* DIE! */
214         failf(data, "Error accept()ing server connect");
215         return CURLE_FTP_PORT_FAILED;
216       }
217       infof(data, "Connection accepted from server\n");
218
219       conn->sock[SECONDARYSOCKET] = s;
220       Curl_nonblock(s, TRUE); /* enable non-blocking */
221     }
222     break;
223   }
224
225   return CURLE_OK;
226 }
227
228
229 /* --- parse FTP server responses --- */
230
231 /*
232  * Curl_GetFTPResponse() is supposed to be invoked after each command sent to
233  * a remote FTP server. This function will wait and read all lines of the
234  * response and extract the relevant return code for the invoking function.
235  */
236
237 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
238                              struct connectdata *conn,
239                              int *ftpcode) /* return the ftp-code */
240 {
241   /* Brand new implementation.
242    * We cannot read just one byte per read() and then go back to select()
243    * as it seems that the OpenSSL read() stuff doesn't grok that properly.
244    *
245    * Alas, read as much as possible, split up into lines, use the ending
246    * line in a response or continue reading.  */
247
248   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
249   int perline; /* count bytes per line */
250   bool keepon=TRUE;
251   ssize_t gotbytes;
252   char *ptr;
253   long timeout;              /* timeout in seconds */
254   int interval_ms;
255   struct SessionHandle *data = conn->data;
256   char *line_start;
257   int code=0; /* default ftp "error code" to return */
258   char *buf = data->state.buffer;
259   CURLcode result = CURLE_OK;
260   struct FTP *ftp = conn->proto.ftp;
261   struct timeval now = Curl_tvnow();
262
263   if (ftpcode)
264     *ftpcode = 0; /* 0 for errors */
265
266   ptr=buf;
267   line_start = buf;
268
269   *nreadp=0;
270   perline=0;
271   keepon=TRUE;
272
273   while((*nreadp<BUFSIZE) && (keepon && !result)) {
274     /* check and reset timeout value every lap */
275     if(data->set.ftp_response_timeout )
276       /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine
277          remaining time.  Also, use "now" as opposed to "conn->now"
278          because ftp_response_timeout is only supposed to govern
279          the response for any given ftp response, not for the time
280          from connect to the given ftp response. */
281       timeout = data->set.ftp_response_timeout - /* timeout time */
282         Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
283     else if(data->set.timeout)
284       /* if timeout is requested, find out how much remaining time we have */
285       timeout = data->set.timeout - /* timeout time */
286         Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
287     else
288       /* Even without a requested timeout, we only wait response_time
289          seconds for the full response to arrive before we bail out */
290       timeout = ftp->response_time -
291         Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
292
293     if(timeout <=0 ) {
294       failf(data, "FTP response timeout");
295       return CURLE_OPERATION_TIMEDOUT; /* already too little time */
296     }
297
298     if(!ftp->cache) {
299       interval_ms = 1 * 1000;  /* use 1 second timeout intervals */
300
301       switch (Curl_select(sockfd, CURL_SOCKET_BAD, interval_ms)) {
302       case -1: /* select() error, stop reading */
303         result = CURLE_RECV_ERROR;
304         failf(data, "FTP response aborted due to select() error: %d", errno);
305         break;
306       case 0: /* timeout */
307         if(Curl_pgrsUpdate(conn))
308           return CURLE_ABORTED_BY_CALLBACK;
309         continue; /* just continue in our loop for the timeout duration */
310
311       default:
312         break;
313       }
314     }
315     if(CURLE_OK == result) {
316       /*
317        * This code previously didn't use the kerberos sec_read() code
318        * to read, but when we use Curl_read() it may do so. Do confirm
319        * that this is still ok and then remove this comment!
320        */
321       if(ftp->cache) {
322         /* we had data in the "cache", copy that instead of doing an actual
323          * read
324          *
325          * Dave Meyer, December 2003:
326          * ftp->cache_size is cast to int here.  This should be safe,
327          * because it would have been populated with something of size
328          * int to begin with, even though its datatype may be larger
329          * than an int.
330          */
331         memcpy(ptr, ftp->cache, (int)ftp->cache_size);
332         gotbytes = (int)ftp->cache_size;
333         free(ftp->cache);    /* free the cache */
334         ftp->cache = NULL;   /* clear the pointer */
335         ftp->cache_size = 0; /* zero the size just in case */
336       }
337       else {
338         int res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp, &gotbytes);
339         if(res < 0)
340           /* EWOULDBLOCK */
341           continue; /* go looping again */
342
343         if(CURLE_OK != res)
344           keepon = FALSE;
345       }
346
347       if(!keepon)
348         ;
349       else if(gotbytes <= 0) {
350         keepon = FALSE;
351         result = CURLE_RECV_ERROR;
352         failf(data, "FTP response reading failed");
353       }
354       else {
355         /* we got a whole chunk of data, which can be anything from one
356          * byte to a set of lines and possible just a piece of the last
357          * line */
358         int i;
359
360         conn->headerbytecount += gotbytes;
361
362         *nreadp += gotbytes;
363         for(i = 0; i < gotbytes; ptr++, i++) {
364           perline++;
365           if(*ptr=='\n') {
366             /* a newline is CRLF in ftp-talk, so the CR is ignored as
367                the line isn't really terminated until the LF comes */
368
369             /* output debug output if that is requested */
370             if(data->set.verbose)
371               Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline, conn);
372
373             /*
374              * We pass all response-lines to the callback function registered
375              * for "headers". The response lines can be seen as a kind of
376              * headers.
377              */
378             result = Curl_client_write(data, CLIENTWRITE_HEADER,
379                                        line_start, perline);
380             if(result)
381               return result;
382
383 #define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
384                         isdigit((int)line[2]) && (' ' == line[3]))
385
386             if(perline>3 && lastline(line_start)) {
387               /* This is the end of the last line, copy the last
388                * line to the start of the buffer and zero terminate,
389                * for old times sake (and krb4)! */
390               char *meow;
391               int n;
392               for(meow=line_start, n=0; meow<ptr; meow++, n++)
393                 buf[n] = *meow;
394               *meow=0; /* zero terminate */
395               keepon=FALSE;
396               line_start = ptr+1; /* advance pointer */
397               i++; /* skip this before getting out */
398               break;
399             }
400             perline=0; /* line starts over here */
401             line_start = ptr+1;
402           }
403         }
404         if(!keepon && (i != gotbytes)) {
405           /* We found the end of the response lines, but we didn't parse the
406              full chunk of data we have read from the server. We therefore
407              need to store the rest of the data to be checked on the next
408              invoke as it may actually contain another end of response
409              already!  Cleverly figured out by Eric Lavigne in December
410              2001. */
411           ftp->cache_size = gotbytes - i;
412           ftp->cache = (char *)malloc((int)ftp->cache_size);
413           if(ftp->cache)
414             memcpy(ftp->cache, line_start, (int)ftp->cache_size);
415           else
416             return CURLE_OUT_OF_MEMORY; /**BANG**/
417         }
418       } /* there was data */
419     } /* if(no error) */
420   } /* while there's buffer left and loop is requested */
421
422   if(!result)
423     code = atoi(buf);
424
425 #ifdef HAVE_KRB4
426   /* handle the security-oriented responses 6xx ***/
427   /* FIXME: some errorchecking perhaps... ***/
428   switch(code) {
429   case 631:
430     Curl_sec_read_msg(conn, buf, prot_safe);
431     break;
432   case 632:
433     Curl_sec_read_msg(conn, buf, prot_private);
434     break;
435   case 633:
436     Curl_sec_read_msg(conn, buf, prot_confidential);
437     break;
438   default:
439     /* normal ftp stuff we pass through! */
440     break;
441   }
442 #endif
443
444   if(ftpcode)
445     *ftpcode=code; /* return the initial number like this */
446
447   /* store the latest code for later retrieval */
448   conn->data->info.httpcode=code;
449
450   return result;
451 }
452
453 /*
454  * Curl_ftp_connect() should do everything that is to be considered a part of
455  * the connection phase.
456  */
457 CURLcode Curl_ftp_connect(struct connectdata *conn)
458 {
459   /* this is FTP and no proxy */
460   ssize_t nread;
461   struct SessionHandle *data=conn->data;
462   char *buf = data->state.buffer; /* this is our buffer */
463   struct FTP *ftp;
464   CURLcode result;
465   int ftpcode, trynum;
466   static const char * const ftpauth[]  = {
467     "SSL", "TLS", NULL
468   };
469
470   ftp = (struct FTP *)calloc(sizeof(struct FTP), 1);
471   if(!ftp)
472     return CURLE_OUT_OF_MEMORY;
473
474   conn->proto.ftp = ftp;
475
476   /* We always support persistant connections on ftp */
477   conn->bits.close = FALSE;
478
479   /* get some initial data into the ftp struct */
480   ftp->bytecountp = &conn->bytecount;
481
482   /* no need to duplicate them, this connectdata struct won't change */
483   ftp->user = conn->user;
484   ftp->passwd = conn->passwd;
485   if (isBadFtpString(ftp->user) || isBadFtpString(ftp->passwd)) {
486     return CURLE_URL_MALFORMAT;
487   }
488   ftp->response_time = 3600; /* set default response time-out */
489
490 #ifndef CURL_DISABLE_HTTP
491   if (conn->bits.tunnel_proxy) {
492     /* We want "seamless" FTP operations through HTTP proxy tunnel */
493     result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET,
494                                          conn->host.name, conn->remote_port);
495     if(CURLE_OK != result)
496       return result;
497   }
498 #endif   /* CURL_DISABLE_HTTP */
499
500   if(conn->protocol & PROT_FTPS) {
501     /* FTPS is simply ftp with SSL for the control channel */
502     /* now, perform the SSL initialization for this socket */
503     result = Curl_SSLConnect(conn, FIRSTSOCKET);
504     if(result)
505       return result;
506   }
507
508   /* The first thing we do is wait for the "220*" line: */
509   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
510   if(result)
511     return result;
512
513   if(ftpcode != 220) {
514     failf(data, "This doesn't seem like a nice ftp-server response");
515     return CURLE_FTP_WEIRD_SERVER_REPLY;
516   }
517
518 #ifdef HAVE_KRB4
519   /* if not anonymous login, try a secure login */
520   if(data->set.krb4) {
521
522     /* request data protection level (default is 'clear') */
523     Curl_sec_request_prot(conn, "private");
524
525     /* We set private first as default, in case the line below fails to
526        set a valid level */
527     Curl_sec_request_prot(conn, data->set.krb4_level);
528
529     if(Curl_sec_login(conn) != 0)
530       infof(data, "Logging in with password in cleartext!\n");
531     else
532       infof(data, "Authentication successful\n");
533   }
534 #endif
535
536   if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
537     /* we don't have a SSL/TLS connection, try a FTPS connection now */
538     int start;
539     int trynext;
540     int count=0;
541
542     switch(data->set.ftpsslauth) {
543     case CURLFTPAUTH_DEFAULT:
544     case CURLFTPAUTH_SSL:
545       start = 0;
546       trynext = 1;
547       break;
548     case CURLFTPAUTH_TLS:
549       start = 1;
550       trynext = 0;
551       break;
552     default:
553       failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d\n",
554             data->set.ftpsslauth);
555       return CURLE_FAILED_INIT; /* we don't know what to do */
556     }
557
558     for (trynum = start; ftpauth[count]; trynum=trynext, count++) {
559
560       FTPSENDF(conn, "AUTH %s", ftpauth[trynum]);
561
562       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
563
564       if(result)
565         return result;
566
567       /* RFC2228 (page 5) says:
568        *
569        * If the server is willing to accept the named security mechanism, and
570        * does not require any security data, it must respond with reply code
571        * 234/334.
572        */
573
574       if((ftpcode == 234) || (ftpcode == 334)) {
575         result = Curl_SSLConnect(conn, FIRSTSOCKET);
576         if(result)
577           return result;
578         conn->protocol |= PROT_FTPS;
579         conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
580         break;
581       }
582     }
583   }
584
585   /* send USER */
586   FTPSENDF(conn, "USER %s", ftp->user?ftp->user:"");
587
588   /* wait for feedback */
589   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
590   if(result)
591     return result;
592
593   if(ftpcode == 530) {
594     /* 530 User ... access denied
595        (the server denies to log the specified user) */
596     failf(data, "Access denied: %03d", ftpcode);
597     return CURLE_FTP_ACCESS_DENIED;
598   }
599   else if(ftpcode == 331) {
600     /* 331 Password required for ...
601        (the server requires to send the user's password too) */
602     FTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:"");
603     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
604     if(result)
605       return result;
606
607     if(ftpcode == 530) {
608       /* 530 Login incorrect.
609          (the username and/or the password are incorrect)
610       or
611          530 Sorry, the maximum number of allowed users are already connected
612       */
613       failf(data, "not logged in: %03d", ftpcode);
614       return CURLE_FTP_USER_PASSWORD_INCORRECT;
615     }
616     else if(ftpcode/100 == 2) {
617       /* 230 User ... logged in.
618          (user successfully logged in)
619
620          Apparently, proftpd with SSL returns 232 here at times. */
621
622       infof(data, "We have successfully logged in\n");
623     }
624     else if(ftpcode == 332) {
625       /* 332 Please provide account info */
626       if(data->set.ftp_account) {
627         FTPSENDF(conn, "ACCT %s", data->set.ftp_account);
628         result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
629         if(!result && (ftpcode != 230)) {
630           failf(data, "ACCT rejected by server: %03d", ftpcode);
631           result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
632         }
633       }
634       else {
635         failf(data, "ACCT requested by none available");
636         result = CURLE_FTP_WEIRD_PASS_REPLY;
637       }
638       if(result)
639         return result;
640     }
641     else {
642       failf(data, "Odd return code after PASS");
643       return CURLE_FTP_WEIRD_PASS_REPLY;
644     }
645   }
646   else if(buf[0] == '2') {
647     /* 230 User ... logged in.
648        (the user logged in without password) */
649     infof(data, "We have successfully logged in\n");
650     if (conn->ssl[FIRSTSOCKET].use) {
651 #ifdef HAVE_KRB4
652       /* We are logged in with Kerberos, now set the requested protection
653        * level
654        */
655       if(conn->sec_complete)
656         Curl_sec_set_protection_level(conn);
657
658       /* We may need to issue a KAUTH here to have access to the files
659        * do it if user supplied a password
660        */
661       if(conn->passwd && *conn->passwd) {
662         result = Curl_krb_kauth(conn);
663         if(result)
664           return result;
665       }
666 #endif
667     }
668   }
669   else {
670     failf(data, "Odd return code after USER");
671     return CURLE_FTP_WEIRD_USER_REPLY;
672   }
673
674   if(conn->ssl[FIRSTSOCKET].use) {
675     /* PBSZ = PROTECTION BUFFER SIZE.
676
677        The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
678
679        Specifically, the PROT command MUST be preceded by a PBSZ command
680        and a PBSZ command MUST be preceded by a successful security data
681        exchange (the TLS negotiation in this case)
682
683        ... (and on page 8):
684
685        Thus the PBSZ command must still be issued, but must have a parameter
686        of '0' to indicate that no buffering is taking place and the data
687        connection should not be encapsulated.
688     */
689     FTPSENDF(conn, "PBSZ %d", 0);
690     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
691     if(result)
692       return result;
693
694     /* For TLS, the data connection can have one of two security levels.
695
696        1)Clear (requested by 'PROT C')
697
698        2)Private (requested by 'PROT P')
699     */
700     if(!conn->ssl[SECONDARYSOCKET].use) {
701       FTPSENDF(conn, "PROT %c", 'P');
702       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
703       if(result)
704         return result;
705
706       if(ftpcode/100 == 2)
707         /* We have enabled SSL for the data connection! */
708         conn->ssl[SECONDARYSOCKET].use = TRUE;
709       /* FTP servers typically responds with 500 if they decide to reject
710          our 'P' request */
711       else if(data->set.ftp_ssl> CURLFTPSSL_CONTROL)
712         /* we failed and bails out */
713         return CURLE_FTP_SSL_FAILED;
714     }
715   }
716
717   /* send PWD to discover our entry point */
718   FTPSENDF(conn, "PWD", NULL);
719
720   /* wait for feedback */
721   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
722   if(result)
723     return result;
724
725   if(ftpcode == 257) {
726     char *dir = (char *)malloc(nread+1);
727     char *store=dir;
728     char *ptr=&buf[4]; /* start on the first letter */
729
730     if(!dir)
731       return CURLE_OUT_OF_MEMORY;
732
733     /* Reply format is like
734        257<space>"<directory-name>"<space><commentary> and the RFC959 says
735
736        The directory name can contain any character; embedded double-quotes
737        should be escaped by double-quotes (the "quote-doubling" convention).
738     */
739     if('\"' == *ptr) {
740       /* it started good */
741       ptr++;
742       while(ptr && *ptr) {
743         if('\"' == *ptr) {
744           if('\"' == ptr[1]) {
745             /* "quote-doubling" */
746             *store = ptr[1];
747             ptr++;
748           }
749           else {
750             /* end of path */
751             *store = '\0'; /* zero terminate */
752             break; /* get out of this loop */
753           }
754         }
755         else
756           *store = *ptr;
757         store++;
758         ptr++;
759       }
760       ftp->entrypath =dir; /* remember this */
761       infof(data, "Entry path is '%s'\n", ftp->entrypath);
762     }
763     else {
764       /* couldn't get the path */
765       free(dir);
766       infof(data, "Failed to figure out path\n");
767     }
768
769   }
770   else {
771     /* We couldn't read the PWD response! */
772   }
773
774   return CURLE_OK;
775 }
776
777 /***********************************************************************
778  *
779  * Curl_ftp_done()
780  *
781  * The DONE function. This does what needs to be done after a single DO has
782  * performed.
783  *
784  * Input argument is already checked for validity.
785  */
786 CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
787 {
788   struct SessionHandle *data = conn->data;
789   struct FTP *ftp = conn->proto.ftp;
790   ssize_t nread;
791   int ftpcode;
792   CURLcode result=CURLE_OK;
793   bool was_ctl_valid = ftp->ctl_valid;
794   size_t flen;
795   size_t dlen;
796   char *path;
797
798   /* now store a copy of the directory we are in */
799   if(ftp->prevpath)
800     free(ftp->prevpath);
801
802   path = curl_unescape(conn->path, 0); /* get the "raw" path */
803   if(!path)
804     return CURLE_OUT_OF_MEMORY;
805
806   flen = ftp->file?strlen(ftp->file):0; /* file is "raw" already */
807   dlen = strlen(path)-flen;
808   if(dlen) {
809     ftp->prevpath = path;
810     if(flen)
811       /* if 'path' is not the whole string */
812       ftp->prevpath[dlen]=0; /* terminate */
813     infof(data, "Remembering we are in dir %s\n", ftp->prevpath);
814   }
815   else {
816     ftp->prevpath = NULL; /* no path */
817     free(path);
818   }
819   /* free the dir tree and file parts */
820   freedirs(ftp);
821
822   ftp->ctl_valid = FALSE;
823
824   if(data->set.upload) {
825     if((-1 != data->set.infilesize) &&
826        (data->set.infilesize != *ftp->bytecountp) &&
827        !data->set.crlf) {
828       failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
829             " out of %" FORMAT_OFF_T " bytes)",
830             *ftp->bytecountp, data->set.infilesize);
831       conn->bits.close = TRUE; /* close this connection since we don't
832                                   know what state this error leaves us in */
833       return CURLE_PARTIAL_FILE;
834     }
835   }
836   else {
837     if((-1 != conn->size) && (conn->size != *ftp->bytecountp) &&
838        (conn->maxdownload != *ftp->bytecountp)) {
839       failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
840             *ftp->bytecountp);
841       conn->bits.close = TRUE; /* close this connection since we don't
842                                   know what state this error leaves us in */
843       return CURLE_PARTIAL_FILE;
844     }
845     else if(!ftp->dont_check &&
846             !*ftp->bytecountp &&
847             (conn->size>0)) {
848       /* We consider this an error, but there's no true FTP error received
849          why we need to continue to "read out" the server response too.
850          We don't want to leave a "waiting" server reply if we'll get told
851          to make a second request on this same connection! */
852       failf(data, "No data was received!");
853       result = CURLE_FTP_COULDNT_RETR_FILE;
854     }
855   }
856
857   switch(status) {
858   case CURLE_BAD_DOWNLOAD_RESUME:
859   case CURLE_FTP_WEIRD_PASV_REPLY:
860   case CURLE_FTP_PORT_FAILED:
861   case CURLE_FTP_COULDNT_SET_BINARY:
862   case CURLE_FTP_COULDNT_RETR_FILE:
863   case CURLE_FTP_ACCESS_DENIED:
864     /* the connection stays alive fine even though this happened */
865     /* fall-through */
866   case CURLE_OK: /* doesn't affect the control connection's status */
867     ftp->ctl_valid = was_ctl_valid;
868     break;
869   default:       /* by default, an error means the control connection is
870                     wedged and should not be used anymore */
871     ftp->ctl_valid = FALSE;
872     break;
873   }
874
875 #ifdef HAVE_KRB4
876   Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]);
877 #endif
878
879   /* shut down the socket to inform the server we're done */
880
881 #ifdef _WIN32_WCE
882   shutdown(conn->sock[SECONDARYSOCKET],2);  /* SD_BOTH */
883 #endif
884
885   sclose(conn->sock[SECONDARYSOCKET]);
886
887   conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
888
889   if(!ftp->no_transfer && !status) {
890     /* Let's see what the server says about the transfer we just performed,
891      * but lower the timeout as sometimes this connection has died while the
892      * data has been transfered. This happens when doing through NATs etc that
893      * abandon old silent connections.
894      */
895     ftp->response_time = 60; /* give it only a minute for now */
896
897     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
898
899     ftp->response_time = 3600; /* set this back to one hour waits */
900
901     if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
902       failf(data, "control connection looks dead");
903       return result;
904     }
905
906     if(result)
907       return result;
908
909     if(!ftp->dont_check) {
910       /* 226 Transfer complete, 250 Requested file action okay, completed. */
911       if((ftpcode != 226) && (ftpcode != 250)) {
912         failf(data, "server did not report OK, got %d", ftpcode);
913         return CURLE_FTP_WRITE_ERROR;
914       }
915     }
916   }
917
918   /* clear these for next connection */
919   ftp->no_transfer = FALSE;
920   ftp->dont_check = FALSE;
921
922   if (!result && conn->sec_conn) {   /* 3rd party transfer */
923     /* "done" with the secondary connection */
924     result = Curl_ftp_done(conn->sec_conn, status);
925   }
926
927   /* Send any post-transfer QUOTE strings? */
928   if(!status && !result && data->set.postquote)
929     result = ftp_sendquote(conn, data->set.postquote);
930
931   return result;
932 }
933
934 /***********************************************************************
935  *
936  * ftp_sendquote()
937  *
938  * Where a 'quote' means a list of custom commands to send to the server.
939  * The quote list is passed as an argument.
940  */
941
942 static
943 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
944 {
945   struct curl_slist *item;
946   ssize_t nread;
947   int ftpcode;
948   CURLcode result;
949
950   item = quote;
951   while (item) {
952     if (item->data) {
953       FTPSENDF(conn, "%s", item->data);
954
955       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
956       if (result)
957         return result;
958
959       if (ftpcode >= 400) {
960         failf(conn->data, "QUOT string not accepted: %s", item->data);
961         return CURLE_FTP_QUOTE_ERROR;
962       }
963     }
964
965     item = item->next;
966   }
967
968   return CURLE_OK;
969 }
970
971 /***********************************************************************
972  *
973  * ftp_getfiletime()
974  *
975  * Get the timestamp of the given file.
976  */
977 static
978 CURLcode ftp_getfiletime(struct connectdata *conn, char *file)
979 {
980   CURLcode result=CURLE_OK;
981   int ftpcode; /* for ftp status */
982   ssize_t nread;
983   char *buf = conn->data->state.buffer;
984
985   /* we have requested to get the modified-time of the file, this is yet
986      again a grey area as the MDTM is not kosher RFC959 */
987   FTPSENDF(conn, "MDTM %s", file);
988
989   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
990   if(result)
991     return result;
992
993   switch(ftpcode) {
994   case 213:
995     {
996       /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
997          last .sss part is optional and means fractions of a second */
998       int year, month, day, hour, minute, second;
999       if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
1000                      &year, &month, &day, &hour, &minute, &second)) {
1001         /* we have a time, reformat it */
1002         time_t secs=time(NULL);
1003         /* using the good old yacc/bison yuck */
1004         snprintf(buf, sizeof(conn->data->state.buffer),
1005                  "%04d%02d%02d %02d:%02d:%02d GMT",
1006                  year, month, day, hour, minute, second);
1007         /* now, convert this into a time() value: */
1008         conn->data->info.filetime = curl_getdate(buf, &secs);
1009       }
1010     }
1011     break;
1012   default:
1013     infof(conn->data, "unsupported MDTM reply format\n");
1014     break;
1015   case 550: /* "No such file or directory" */
1016     failf(conn->data, "Given file does not exist");
1017     result = CURLE_FTP_COULDNT_RETR_FILE;
1018     break;
1019   }
1020   return  result;
1021 }
1022
1023 /***********************************************************************
1024  *
1025  * ftp_transfertype()
1026  *
1027  * Set transfer type. We only deal with ASCII or BINARY so this function
1028  * sets one of them.
1029  */
1030 static CURLcode ftp_transfertype(struct connectdata *conn,
1031                                   bool ascii)
1032 {
1033   struct SessionHandle *data = conn->data;
1034   int ftpcode;
1035   ssize_t nread;
1036   CURLcode result;
1037
1038   FTPSENDF(conn, "TYPE %s", ascii?"A":"I");
1039
1040   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1041   if(result)
1042     return result;
1043
1044   if(ftpcode != 200) {
1045     failf(data, "Couldn't set %s mode",
1046           ascii?"ASCII":"binary");
1047     return ascii? CURLE_FTP_COULDNT_SET_ASCII:CURLE_FTP_COULDNT_SET_BINARY;
1048   }
1049
1050   return CURLE_OK;
1051 }
1052
1053 /***********************************************************************
1054  *
1055  * ftp_getsize()
1056  *
1057  * Returns the file size (in bytes) of the given remote file.
1058  */
1059
1060 static
1061 CURLcode ftp_getsize(struct connectdata *conn, char *file,
1062                      curl_off_t *size)
1063 {
1064   struct SessionHandle *data = conn->data;
1065   int ftpcode;
1066   ssize_t nread;
1067   char *buf=data->state.buffer;
1068   CURLcode result;
1069
1070   FTPSENDF(conn, "SIZE %s", file);
1071   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1072   if(result)
1073     return result;
1074
1075   if(ftpcode == 213) {
1076     /* get the size from the ascii string: */
1077     *size = curlx_strtoofft(buf+4, NULL, 0);
1078   }
1079   else
1080     return CURLE_FTP_COULDNT_GET_SIZE;
1081
1082   return CURLE_OK;
1083 }
1084
1085 /***************************************************************************
1086  *
1087  * ftp_pasv_verbose()
1088  *
1089  * This function only outputs some informationals about this second connection
1090  * when we've issued a PASV command before and thus we have connected to a
1091  * possibly new IP address.
1092  *
1093  */
1094 static void
1095 ftp_pasv_verbose(struct connectdata *conn,
1096                  Curl_addrinfo *ai,
1097                  char *newhost, /* ascii version */
1098                  int port)
1099 {
1100   char buf[256];
1101   Curl_printable_address(ai, buf, sizeof(buf));
1102   infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
1103 }
1104
1105 /***********************************************************************
1106  *
1107  * ftp_use_port()
1108  *
1109  * Send the proper PORT command. PORT is the ftp client's way of telling the
1110  * server that *WE* open a port that we listen on an awaits the server to
1111  * connect to. This is the opposite of PASV.
1112  */
1113
1114 static
1115 CURLcode ftp_use_port(struct connectdata *conn)
1116 {
1117   struct SessionHandle *data=conn->data;
1118   curl_socket_t portsock= CURL_SOCKET_BAD;
1119   ssize_t nread;
1120   int ftpcode; /* receive FTP response codes in this */
1121   CURLcode result;
1122
1123 #ifdef ENABLE_IPV6
1124   /******************************************************************
1125    *
1126    * Here's a piece of IPv6-specific code coming up
1127    *
1128    */
1129
1130   struct addrinfo *res, *ai;
1131   struct sockaddr_storage ss;
1132   socklen_t sslen;
1133   char hbuf[NI_MAXHOST]="";
1134   struct sockaddr *sa=(struct sockaddr *)&ss;
1135   unsigned char *ap;
1136   unsigned char *pp;
1137   char portmsgbuf[1024], tmp[1024];
1138   enum ftpcommand { EPRT, LPRT, PORT, DONE } fcmd;
1139   const char *mode[] = { "EPRT", "LPRT", "PORT", NULL };
1140   int rc;
1141   int error;
1142   char *host=NULL;
1143   struct Curl_dns_entry *h=NULL;
1144
1145   if(data->set.ftpport && (strlen(data->set.ftpport) > 1)) {
1146     /* attempt to get the address of the given interface name */
1147     if(!Curl_if2ip(data->set.ftpport, hbuf, sizeof(hbuf)))
1148       /* not an interface, use the given string as host name instead */
1149       host = data->set.ftpport;
1150     else
1151       host = hbuf; /* use the hbuf for host name */
1152   } /* data->set.ftpport */
1153
1154   if(!host) {
1155     /* not an interface and not a host name, get default by extracting
1156        the IP from the control connection */
1157
1158     sslen = sizeof(ss);
1159     rc = getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&ss, &sslen);
1160     if(rc < 0) {
1161       failf(data, "getsockname() returned %d\n", rc);
1162       return CURLE_FTP_PORT_FAILED;
1163     }
1164
1165     rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL,
1166                      0, NIFLAGS);
1167     if(rc) {
1168       failf(data, "getnameinfo() returned %d\n", rc);
1169       return CURLE_FTP_PORT_FAILED;
1170     }
1171     host = hbuf; /* use this host name */
1172   }
1173
1174   rc = Curl_resolv(conn, host, 0, &h);
1175   if(rc == CURLRESOLV_PENDING)
1176     rc = Curl_wait_for_resolv(conn, &h);
1177   if(h) {
1178     res = h->addr;
1179     /* when we return from this function, we can forget about this entry
1180        to we can unlock it now already */
1181     Curl_resolv_unlock(data, h);
1182   } /* (h) */
1183   else
1184     res = NULL; /* failure! */
1185
1186   portsock = CURL_SOCKET_BAD;
1187   error = 0;
1188   for (ai = res; ai; ai = ai->ai_next) {
1189     /*
1190      * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
1191      */
1192     if (ai->ai_socktype == 0)
1193       ai->ai_socktype = SOCK_STREAM;
1194
1195     portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1196     if (portsock == CURL_SOCKET_BAD) {
1197       error = Curl_ourerrno();
1198       continue;
1199     }
1200     if (bind(portsock, ai->ai_addr, ai->ai_addrlen) < 0) {
1201       error = Curl_ourerrno();
1202       sclose(portsock);
1203       portsock = CURL_SOCKET_BAD;
1204       continue;
1205     }
1206
1207     if (listen(portsock, 1) < 0) {
1208       error = Curl_ourerrno();
1209       sclose(portsock);
1210       portsock = CURL_SOCKET_BAD;
1211       continue;
1212     }
1213
1214     break;
1215   }
1216
1217   if (portsock == CURL_SOCKET_BAD) {
1218     failf(data, "%s", Curl_strerror(conn,error));
1219     return CURLE_FTP_PORT_FAILED;
1220   }
1221
1222   sslen = sizeof(ss);
1223   if (getsockname(portsock, sa, &sslen) < 0) {
1224     failf(data, "%s", Curl_strerror(conn,Curl_ourerrno()));
1225     return CURLE_FTP_PORT_FAILED;
1226   }
1227
1228 #ifdef PF_INET6
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 = EPRT; fcmd != DONE; fcmd++) {
1236     int lprtaf, eprtaf;
1237     int alen=0, plen=0;
1238
1239     if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1240       /* if disabled, goto next */
1241       continue;
1242
1243     if(!conn->bits.ftp_use_lprt && (LPRT == fcmd))
1244       /* if disabled, goto next */
1245       continue;
1246
1247     switch (sa->sa_family) {
1248     case AF_INET:
1249       ap = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_addr;
1250       alen = sizeof(((struct sockaddr_in *)&ss)->sin_addr);
1251       pp = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_port;
1252       plen = sizeof(((struct sockaddr_in *)&ss)->sin_port);
1253       lprtaf = 4;
1254       eprtaf = 1;
1255       break;
1256     case AF_INET6:
1257       ap = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_addr;
1258       alen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_addr);
1259       pp = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_port;
1260       plen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_port);
1261       lprtaf = 6;
1262       eprtaf = 2;
1263       break;
1264     default:
1265       ap = pp = NULL;
1266       lprtaf = eprtaf = -1;
1267       break;
1268     }
1269
1270     if (EPRT == fcmd) {
1271       if (eprtaf < 0)
1272         continue;
1273       if (getnameinfo((struct sockaddr *)&ss, sslen,
1274                       portmsgbuf, sizeof(portmsgbuf), tmp, sizeof(tmp),
1275                       NIFLAGS))
1276         continue;
1277
1278       /* do not transmit IPv6 scope identifier to the wire */
1279       if (sa->sa_family == AF_INET6) {
1280         char *q = strchr(portmsgbuf, '%');
1281         if (q)
1282           *q = '\0';
1283       }
1284
1285       result = Curl_ftpsendf(conn, "%s |%d|%s|%s|", mode[fcmd], eprtaf,
1286                              portmsgbuf, tmp);
1287       if(result)
1288         return result;
1289     }
1290     else if ((LPRT == fcmd) || (PORT == fcmd)) {
1291       int i;
1292
1293       if ((LPRT == fcmd) && lprtaf < 0)
1294         continue;
1295       if ((PORT == fcmd) && sa->sa_family != AF_INET)
1296         continue;
1297
1298       portmsgbuf[0] = '\0';
1299       if (LPRT == fcmd) {
1300         snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen);
1301         if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1302             sizeof(portmsgbuf)) {
1303           continue;
1304         }
1305       }
1306
1307       for (i = 0; i < alen; i++) {
1308         if (portmsgbuf[0])
1309           snprintf(tmp, sizeof(tmp), ",%u", ap[i]);
1310         else
1311           snprintf(tmp, sizeof(tmp), "%u", ap[i]);
1312
1313         if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1314             sizeof(portmsgbuf)) {
1315           continue;
1316         }
1317       }
1318
1319       if (LPRT == fcmd) {
1320         snprintf(tmp, sizeof(tmp), ",%d", plen);
1321
1322         if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf))
1323           continue;
1324       }
1325
1326       for (i = 0; i < plen; i++) {
1327         snprintf(tmp, sizeof(tmp), ",%u", pp[i]);
1328
1329         if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1330             sizeof(portmsgbuf)) {
1331           continue;
1332         }
1333       }
1334
1335       result = Curl_ftpsendf(conn, "%s %s", mode[fcmd], portmsgbuf);
1336       if(result)
1337         return result;
1338     }
1339
1340     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1341     if(result)
1342       return result;
1343
1344     if (ftpcode != 200) {
1345       if (EPRT == fcmd) {
1346         infof(data, "disabling EPRT usage\n");
1347         conn->bits.ftp_use_eprt = FALSE;
1348       }
1349       else if (LPRT == fcmd) {
1350         infof(data, "disabling LPRT usage\n");
1351         conn->bits.ftp_use_lprt = FALSE;
1352       }
1353       continue;
1354     }
1355     else
1356       break;
1357   }
1358
1359   if (fcmd == DONE) {
1360     sclose(portsock);
1361     failf(data, "PORT command attempts failed");
1362     return CURLE_FTP_PORT_FAILED;
1363   }
1364   /* we set the secondary socket variable to this for now, it
1365      is only so that the cleanup function will close it in case
1366      we fail before the true secondary stuff is made */
1367   conn->sock[SECONDARYSOCKET] = portsock;
1368
1369 #else
1370   /******************************************************************
1371    *
1372    * Here's a piece of IPv4-specific code coming up
1373    *
1374    */
1375   struct sockaddr_in sa;
1376   unsigned short porttouse;
1377   char myhost[256] = "";
1378   bool sa_filled_in = FALSE;
1379   Curl_addrinfo *addr = NULL;
1380   unsigned short ip[4];
1381
1382   if(data->set.ftpport) {
1383     in_addr_t in;
1384
1385     /* First check if the given name is an IP address */
1386     in=inet_addr(data->set.ftpport);
1387
1388     if(in != CURL_INADDR_NONE)
1389       /* this is an IPv4 address */
1390       addr = Curl_ip2addr(in, data->set.ftpport, 0);
1391     else {
1392       if(Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
1393         /* The interface to IP conversion provided a dotted address */
1394         in=inet_addr(myhost);
1395         addr = Curl_ip2addr(in, myhost, 0);
1396       }
1397       else if(strlen(data->set.ftpport)> 1) {
1398         /* might be a host name! */
1399         struct Curl_dns_entry *h=NULL;
1400         int rc = Curl_resolv(conn, myhost, 0, &h);
1401         if(rc == CURLRESOLV_PENDING)
1402           rc = Curl_wait_for_resolv(conn, &h);
1403         if(h) {
1404           addr = h->addr;
1405           /* when we return from this function, we can forget about this entry
1406              to we can unlock it now already */
1407           Curl_resolv_unlock(data, h);
1408         } /* (h) */
1409       } /* strlen */
1410     } /* CURL_INADDR_NONE */
1411   } /* data->set.ftpport */
1412
1413   if(!addr) {
1414     /* pick a suitable default here */
1415
1416     socklen_t sslen;
1417
1418     sslen = sizeof(sa);
1419     if (getsockname(conn->sock[FIRSTSOCKET],
1420                     (struct sockaddr *)&sa, &sslen) < 0) {
1421       failf(data, "getsockname() failed");
1422       return CURLE_FTP_PORT_FAILED;
1423     }
1424
1425     sa_filled_in = TRUE; /* the sa struct is filled in */
1426   }
1427
1428   if (addr || sa_filled_in) {
1429     portsock = socket(AF_INET, SOCK_STREAM, 0);
1430     if(CURL_SOCKET_BAD != portsock) {
1431       socklen_t size;
1432
1433       /* we set the secondary socket variable to this for now, it
1434          is only so that the cleanup function will close it in case
1435          we fail before the true secondary stuff is made */
1436       conn->sock[SECONDARYSOCKET] = portsock;
1437
1438       if(!sa_filled_in) {
1439         memcpy(&sa, addr->ai_addr, sizeof(sa));
1440         sa.sin_addr.s_addr = INADDR_ANY;
1441       }
1442
1443       sa.sin_port = 0;
1444       size = sizeof(sa);
1445
1446       if(bind(portsock, (struct sockaddr *)&sa, size) >= 0) {
1447         /* we succeeded to bind */
1448         struct sockaddr_in add;
1449         socklen_t socksize = sizeof(add);
1450
1451         if(getsockname(portsock, (struct sockaddr *) &add,
1452                        &socksize)<0) {
1453           failf(data, "getsockname() failed");
1454           return CURLE_FTP_PORT_FAILED;
1455         }
1456         porttouse = ntohs(add.sin_port);
1457
1458         if ( listen(portsock, 1) < 0 ) {
1459           failf(data, "listen(2) failed on socket");
1460           return CURLE_FTP_PORT_FAILED;
1461         }
1462       }
1463       else {
1464         failf(data, "bind(2) failed on socket");
1465         return CURLE_FTP_PORT_FAILED;
1466       }
1467     }
1468     else {
1469       failf(data, "socket(2) failed (%s)");
1470       return CURLE_FTP_PORT_FAILED;
1471     }
1472   }
1473   else {
1474     failf(data, "could't find IP address to use");
1475     return CURLE_FTP_PORT_FAILED;
1476   }
1477
1478   if(sa_filled_in)
1479     Curl_inet_ntop(AF_INET, &((struct sockaddr_in *)&sa)->sin_addr,
1480                    myhost, sizeof(myhost));
1481   else
1482     Curl_printable_address(addr, myhost, sizeof(myhost));
1483
1484   if(4 == sscanf(myhost, "%hu.%hu.%hu.%hu",
1485                  &ip[0], &ip[1], &ip[2], &ip[3])) {
1486
1487     infof(data, "Telling server to connect to %d.%d.%d.%d:%d\n",
1488           ip[0], ip[1], ip[2], ip[3], porttouse);
1489
1490     result=Curl_ftpsendf(conn, "PORT %d,%d,%d,%d,%d,%d",
1491                          ip[0], ip[1], ip[2], ip[3],
1492                          porttouse >> 8,
1493                          porttouse & 255);
1494     if(result)
1495       return result;
1496
1497   }
1498   else
1499     return CURLE_FTP_PORT_FAILED;
1500
1501   Curl_freeaddrinfo(addr);
1502
1503   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1504   if(result)
1505     return result;
1506
1507   if(ftpcode != 200) {
1508     failf(data, "Server does not grok PORT, try without it!");
1509     return CURLE_FTP_PORT_FAILED;
1510   }
1511 #endif /* end of ipv4-specific code */
1512
1513   return CURLE_OK;
1514 }
1515
1516 /***********************************************************************
1517  *
1518  * ftp_use_pasv()
1519  *
1520  * Send the PASV command. PASV is the ftp client's way of asking the server to
1521  * open a second port that we can connect to (for the data transfer). This is
1522  * the opposite of PORT.
1523  */
1524
1525 static
1526 CURLcode ftp_use_pasv(struct connectdata *conn,
1527                       bool *connected)
1528 {
1529   struct SessionHandle *data = conn->data;
1530   ssize_t nread;
1531   char *buf = data->state.buffer; /* this is our buffer */
1532   int ftpcode; /* receive FTP response codes in this */
1533   CURLcode result;
1534   struct Curl_dns_entry *addr=NULL;
1535   Curl_addrinfo *conninfo;
1536   int rc;
1537
1538   /*
1539     Here's the excecutive summary on what to do:
1540
1541     PASV is RFC959, expect:
1542     227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1543
1544     LPSV is RFC1639, expect:
1545     228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1546
1547     EPSV is RFC2428, expect:
1548     229 Entering Extended Passive Mode (|||port|)
1549
1550   */
1551
1552   const char *mode[] = { "EPSV", "PASV", NULL };
1553   int results[] = { 229, 227, 0 };
1554   int modeoff;
1555   unsigned short connectport; /* the local port connect() should use! */
1556   unsigned short newport=0; /* remote port, not necessary the local one */
1557
1558   /* newhost must be able to hold a full IP-style address in ASCII, which
1559      in the IPv6 case means 5*8-1 = 39 letters */
1560 #define NEWHOST_BUFSIZE 48
1561   char newhost[NEWHOST_BUFSIZE];
1562
1563 #ifdef PF_INET6
1564   if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1565     /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1566        request and enable EPSV again! */
1567     conn->bits.ftp_use_epsv = TRUE;
1568 #endif
1569
1570   for (modeoff = (conn->bits.ftp_use_epsv?0:1);
1571        mode[modeoff]; modeoff++) {
1572     result = Curl_ftpsendf(conn, "%s", mode[modeoff]);
1573     if(result)
1574       return result;
1575     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1576     if(result)
1577       return result;
1578     if (ftpcode == results[modeoff])
1579       break;
1580
1581     if(modeoff == 0) {
1582       /* EPSV is not supported, disable it for next transfer */
1583       conn->bits.ftp_use_epsv = FALSE;
1584       infof(data, "disabling EPSV usage\n");
1585     }
1586   }
1587
1588   if (!mode[modeoff]) {
1589     failf(data, "Odd return code after PASV");
1590     return CURLE_FTP_WEIRD_PASV_REPLY;
1591   }
1592   else if (227 == results[modeoff]) {
1593     int ip[4];
1594     int port[2];
1595     char *str=buf;
1596
1597     /*
1598      * New 227-parser June 3rd 1999.
1599      * It now scans for a sequence of six comma-separated numbers and
1600      * will take them as IP+port indicators.
1601      *
1602      * Found reply-strings include:
1603      * "227 Entering Passive Mode (127,0,0,1,4,51)"
1604      * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1605      * "227 Entering passive mode. 127,0,0,1,4,51"
1606      */
1607
1608     while(*str) {
1609       if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1610                       &ip[0], &ip[1], &ip[2], &ip[3],
1611                       &port[0], &port[1]))
1612         break;
1613       str++;
1614     }
1615
1616     if(!*str) {
1617       failf(data, "Couldn't interpret the 227-reply");
1618       return CURLE_FTP_WEIRD_227_FORMAT;
1619     }
1620
1621     snprintf(newhost, sizeof(newhost),
1622              "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1623     newport = (port[0]<<8) + port[1];
1624   }
1625   else if (229 == results[modeoff]) {
1626     char *ptr = strchr(buf, '(');
1627     if(ptr) {
1628       unsigned int num;
1629       char separator[4];
1630       ptr++;
1631       if(5  == sscanf(ptr, "%c%c%c%u%c",
1632                       &separator[0],
1633                       &separator[1],
1634                       &separator[2],
1635                       &num,
1636                       &separator[3])) {
1637         char sep1 = separator[0];
1638         int i;
1639
1640         /* The four separators should be identical, or else this is an oddly
1641            formatted reply and we bail out immediately. */
1642         for(i=1; i<4; i++) {
1643           if(separator[i] != sep1) {
1644             ptr=NULL; /* set to NULL to signal error */
1645             break;
1646           }
1647         }
1648         if(ptr) {
1649           newport = num;
1650
1651           /* We must use the same IP we are already connected to */
1652           snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
1653         }
1654       }
1655       else
1656         ptr=NULL;
1657     }
1658     if(!ptr) {
1659       failf(data, "Weirdly formatted EPSV reply");
1660       return CURLE_FTP_WEIRD_PASV_REPLY;
1661     }
1662   }
1663   else
1664     return CURLE_FTP_CANT_RECONNECT;
1665
1666   if(data->change.proxy && *data->change.proxy) {
1667     /*
1668      * This is a tunnel through a http proxy and we need to connect to the
1669      * proxy again here.
1670      *
1671      * We don't want to rely on a former host lookup that might've expired
1672      * now, instead we remake the lookup here and now!
1673      */
1674     rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
1675     if(rc == CURLRESOLV_PENDING)
1676       rc = Curl_wait_for_resolv(conn, &addr);
1677
1678     connectport =
1679       (unsigned short)conn->port; /* we connect to the proxy's port */
1680
1681   }
1682   else {
1683     /* normal, direct, ftp connection */
1684     rc = Curl_resolv(conn, newhost, newport, &addr);
1685     if(rc == CURLRESOLV_PENDING)
1686       rc = Curl_wait_for_resolv(conn, &addr);
1687
1688     if(!addr) {
1689       failf(data, "Can't resolve new host %s:%d", newhost, newport);
1690       return CURLE_FTP_CANT_GET_HOST;
1691     }
1692     connectport = newport; /* we connect to the remote port */
1693   }
1694
1695   result = Curl_connecthost(conn,
1696                             addr,
1697                             &conn->sock[SECONDARYSOCKET],
1698                             &conninfo,
1699                             connected);
1700
1701   Curl_resolv_unlock(data, addr); /* we're done using this address */
1702
1703   if(result)
1704     return result;
1705
1706   /*
1707    * When this is used from the multi interface, this might've returned with
1708    * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
1709    * connect to connect and we should not be "hanging" here waiting.
1710    */
1711
1712   if(data->set.verbose)
1713     /* this just dumps information about this second connection */
1714     ftp_pasv_verbose(conn, conninfo, newhost, connectport);
1715
1716 #ifndef CURL_DISABLE_HTTP
1717   if(conn->bits.tunnel_proxy) {
1718     /* We want "seamless" FTP operations through HTTP proxy tunnel */
1719     result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET,
1720                                          newhost, newport);
1721     if(CURLE_OK != result)
1722       return result;
1723   }
1724 #endif   /* CURL_DISABLE_HTTP */
1725
1726   return CURLE_OK;
1727 }
1728
1729 /*
1730  * Curl_ftp_nextconnect()
1731  *
1732  * This function shall be called when the second FTP connection has been
1733  * established and is confirmed connected.
1734  */
1735
1736 CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
1737 {
1738   struct SessionHandle *data=conn->data;
1739   char *buf = data->state.buffer; /* this is our buffer */
1740   CURLcode result;
1741   ssize_t nread;
1742   int ftpcode; /* for ftp status */
1743
1744   /* the ftp struct is already inited in Curl_ftp_connect() */
1745   struct FTP *ftp = conn->proto.ftp;
1746   curl_off_t *bytecountp = ftp->bytecountp;
1747
1748   if(data->set.upload) {
1749
1750     /* Set type to binary (unless specified ASCII) */
1751     result = ftp_transfertype(conn, data->set.ftp_ascii);
1752     if(result)
1753       return result;
1754
1755     /* Send any PREQUOTE strings after transfer type is set? (Wesley Laxton)*/
1756     if(data->set.prequote) {
1757       if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
1758         return result;
1759     }
1760
1761     if(conn->resume_from) {
1762       /* we're about to continue the uploading of a file */
1763       /* 1. get already existing file's size. We use the SIZE
1764          command for this which may not exist in the server!
1765          The SIZE command is not in RFC959. */
1766
1767       /* 2. This used to set REST. But since we can do append, we
1768          don't another ftp command. We just skip the source file
1769          offset and then we APPEND the rest on the file instead */
1770
1771       /* 3. pass file-size number of bytes in the source file */
1772       /* 4. lower the infilesize counter */
1773       /* => transfer as usual */
1774
1775       if(conn->resume_from < 0 ) {
1776         /* we could've got a specified offset from the command line,
1777            but now we know we didn't */
1778         curl_off_t gottensize;
1779
1780         if(CURLE_OK != ftp_getsize(conn, ftp->file, &gottensize)) {
1781           failf(data, "Couldn't get remote file size");
1782           return CURLE_FTP_COULDNT_GET_SIZE;
1783         }
1784         conn->resume_from = gottensize;
1785       }
1786
1787       if(conn->resume_from) {
1788         /* do we still game? */
1789         curl_off_t passed=0;
1790         /* enable append instead */
1791         data->set.ftp_append = 1;
1792
1793         /* Now, let's read off the proper amount of bytes from the
1794            input. If we knew it was a proper file we could've just
1795            fseek()ed but we only have a stream here */
1796         do {
1797           curl_off_t readthisamountnow = (conn->resume_from - passed);
1798           curl_off_t actuallyread;
1799
1800           if(readthisamountnow > BUFSIZE)
1801             readthisamountnow = BUFSIZE;
1802
1803           actuallyread = (curl_off_t)
1804             conn->fread(data->state.buffer, 1, (size_t)readthisamountnow,
1805                         conn->fread_in);
1806
1807           passed += actuallyread;
1808           if(actuallyread != readthisamountnow) {
1809             failf(data, "Could only read %" FORMAT_OFF_T
1810                   " bytes from the input", passed);
1811             return CURLE_FTP_COULDNT_USE_REST;
1812           }
1813         }
1814         while(passed != conn->resume_from);
1815
1816         /* now, decrease the size of the read */
1817         if(data->set.infilesize>0) {
1818           data->set.infilesize -= conn->resume_from;
1819
1820           if(data->set.infilesize <= 0) {
1821             infof(data, "File already completely uploaded\n");
1822
1823             /* no data to transfer */
1824             result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1825
1826             /* Set no_transfer so that we won't get any error in
1827              * Curl_ftp_done() because we didn't transfer anything! */
1828             ftp->no_transfer = TRUE;
1829
1830             return CURLE_OK;
1831           }
1832         }
1833         /* we've passed, proceed as normal */
1834       }
1835     }
1836
1837     /* Send everything on data->state.in to the socket */
1838     if(data->set.ftp_append) {
1839       /* we append onto the file instead of rewriting it */
1840       FTPSENDF(conn, "APPE %s", ftp->file);
1841     }
1842     else {
1843       FTPSENDF(conn, "STOR %s", ftp->file);
1844     }
1845
1846     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1847     if(result)
1848       return result;
1849
1850     if(ftpcode>=400) {
1851       failf(data, "Failed FTP upload: %03d", ftpcode);
1852       /* oops, we never close the sockets! */
1853       return CURLE_FTP_COULDNT_STOR_FILE;
1854     }
1855
1856     if(data->set.ftp_use_port) {
1857       /* PORT means we are now awaiting the server to connect to us. */
1858       result = AllowServerConnect(conn);
1859       if( result )
1860         return result;
1861     }
1862
1863     if(conn->ssl[SECONDARYSOCKET].use) {
1864       /* since we only have a plaintext TCP connection here, we must now
1865          do the TLS stuff */
1866       infof(data, "Doing the SSL/TLS handshake on the data stream\n");
1867       result = Curl_SSLConnect(conn, SECONDARYSOCKET);
1868       if(result)
1869         return result;
1870     }
1871
1872     *bytecountp=0;
1873
1874     /* When we know we're uploading a specified file, we can get the file
1875        size prior to the actual upload. */
1876
1877     Curl_pgrsSetUploadSize(data, data->set.infilesize);
1878
1879     result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
1880                            SECONDARYSOCKET, bytecountp);
1881     if(result)
1882       return result;
1883
1884   }
1885   else if(!conn->bits.no_body) {
1886     /* Retrieve file or directory */
1887     bool dirlist=FALSE;
1888     curl_off_t downloadsize=-1;
1889
1890     if(conn->bits.use_range && conn->range) {
1891       curl_off_t from, to;
1892       curl_off_t totalsize=-1;
1893       char *ptr;
1894       char *ptr2;
1895
1896       from=curlx_strtoofft(conn->range, &ptr, 0);
1897       while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
1898         ptr++;
1899       to=curlx_strtoofft(ptr, &ptr2, 0);
1900       if(ptr == ptr2) {
1901         /* we didn't get any digit */
1902         to=-1;
1903       }
1904       if((-1 == to) && (from>=0)) {
1905         /* X - */
1906         conn->resume_from = from;
1907         infof(data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n", from);
1908       }
1909       else if(from < 0) {
1910         /* -Y */
1911         totalsize = -from;
1912         conn->maxdownload = -from;
1913         conn->resume_from = from;
1914         infof(data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n", totalsize);
1915       }
1916       else {
1917         /* X-Y */
1918         totalsize = to-from;
1919         conn->maxdownload = totalsize+1; /* include the last mentioned byte */
1920         conn->resume_from = from;
1921         infof(data, "FTP RANGE from %" FORMAT_OFF_T
1922               " getting %" FORMAT_OFF_T " bytes\n", from, conn->maxdownload);
1923       }
1924       infof(data, "range-download from %" FORMAT_OFF_T
1925             " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
1926             from, to, conn->maxdownload);
1927       ftp->dont_check = TRUE; /* dont check for successful transfer */
1928     }
1929
1930     if((data->set.ftp_list_only) || !ftp->file) {
1931       /* The specified path ends with a slash, and therefore we think this
1932          is a directory that is requested, use LIST. But before that we
1933          need to set ASCII transfer mode. */
1934       dirlist = TRUE;
1935
1936       /* Set type to ASCII */
1937       result = ftp_transfertype(conn, TRUE /* ASCII enforced */);
1938       if(result)
1939         return result;
1940
1941       /* if this output is to be machine-parsed, the NLST command will be
1942          better used since the LIST command output is not specified or
1943          standard in any way */
1944
1945       FTPSENDF(conn, "%s",
1946             data->set.customrequest?data->set.customrequest:
1947             (data->set.ftp_list_only?"NLST":"LIST"));
1948     }
1949     else {
1950       curl_off_t foundsize;
1951
1952       /* Set type to binary (unless specified ASCII) */
1953       result = ftp_transfertype(conn, data->set.ftp_ascii);
1954       if(result)
1955         return result;
1956
1957       /* Send any PREQUOTE strings after transfer type is set? */
1958       if(data->set.prequote) {
1959         if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
1960           return result;
1961       }
1962
1963       /* Attempt to get the size, it'll be useful in some cases: for resumed
1964          downloads and when talking to servers that don't give away the size
1965          in the RETR response line. */
1966       result = ftp_getsize(conn, ftp->file, &foundsize);
1967       if(CURLE_OK == result) {
1968         if (data->set.max_filesize && foundsize > data->set.max_filesize) {
1969           failf(data, "Maximum file size exceeded");
1970           return CURLE_FILESIZE_EXCEEDED;
1971         }
1972         downloadsize = foundsize;
1973       }
1974
1975       if(conn->resume_from) {
1976
1977         /* Daniel: (August 4, 1999)
1978          *
1979          * We start with trying to use the SIZE command to figure out the size
1980          * of the file we're gonna get. If we can get the size, this is by far
1981          * the best way to know if we're trying to resume beyond the EOF.
1982          *
1983          * Daniel, November 28, 2001. We *always* get the size on downloads
1984          * now, so it is done before this even when not doing resumes. I saved
1985          * the comment above for nostalgical reasons! ;-)
1986          */
1987         if(CURLE_OK != result) {
1988           infof(data, "ftp server doesn't support SIZE\n");
1989           /* We couldn't get the size and therefore we can't know if there
1990              really is a part of the file left to get, although the server
1991              will just close the connection when we start the connection so it
1992              won't cause us any harm, just not make us exit as nicely. */
1993         }
1994         else {
1995           /* We got a file size report, so we check that there actually is a
1996              part of the file left to get, or else we go home.  */
1997           if(conn->resume_from< 0) {
1998             /* We're supposed to download the last abs(from) bytes */
1999             if(foundsize < -conn->resume_from) {
2000               failf(data, "Offset (%" FORMAT_OFF_T
2001                     ") was beyond file size (%" FORMAT_OFF_T ")",
2002                     conn->resume_from, foundsize);
2003               return CURLE_BAD_DOWNLOAD_RESUME;
2004             }
2005             /* convert to size to download */
2006             downloadsize = -conn->resume_from;
2007             /* download from where? */
2008             conn->resume_from = foundsize - downloadsize;
2009           }
2010           else {
2011             if(foundsize < conn->resume_from) {
2012               failf(data, "Offset (%" FORMAT_OFF_T
2013                     ") was beyond file size (%" FORMAT_OFF_T ")",
2014                     conn->resume_from, foundsize);
2015               return CURLE_BAD_DOWNLOAD_RESUME;
2016             }
2017             /* Now store the number of bytes we are expected to download */
2018             downloadsize = foundsize-conn->resume_from;
2019           }
2020         }
2021
2022         if (downloadsize == 0) {
2023           /* no data to transfer */
2024           result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2025           infof(data, "File already completely downloaded\n");
2026
2027           /* Set no_transfer so that we won't get any error in Curl_ftp_done()
2028            * because we didn't transfer the any file */
2029           ftp->no_transfer = TRUE;
2030           return CURLE_OK;
2031         }
2032
2033         /* Set resume file transfer offset */
2034         infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
2035               "\n",
2036               conn->resume_from);
2037
2038         FTPSENDF(conn, "REST %" FORMAT_OFF_T, conn->resume_from);
2039
2040         result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2041         if(result)
2042           return result;
2043
2044         if(ftpcode != 350) {
2045           failf(data, "Couldn't use REST: %03d", ftpcode);
2046           return CURLE_FTP_COULDNT_USE_REST;
2047         }
2048       }
2049
2050       FTPSENDF(conn, "RETR %s", ftp->file);
2051     }
2052
2053     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2054     if(result)
2055       return result;
2056
2057     if((ftpcode == 150) || (ftpcode == 125)) {
2058
2059       /*
2060         A;
2061         150 Opening BINARY mode data connection for /etc/passwd (2241
2062         bytes).  (ok, the file is being transfered)
2063
2064         B:
2065         150 Opening ASCII mode data connection for /bin/ls
2066
2067         C:
2068         150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2069
2070         D:
2071         150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
2072
2073         E:
2074         125 Data connection already open; Transfer starting. */
2075
2076       curl_off_t size=-1; /* default unknown size */
2077
2078
2079       /*
2080        * It appears that there are FTP-servers that return size 0 for files
2081        * when SIZE is used on the file while being in BINARY mode. To work
2082        * around that (stupid) behavior, we attempt to parse the RETR response
2083        * even if the SIZE returned size zero.
2084        *
2085        * Debugging help from Salvatore Sorrentino on February 26, 2003.
2086        */
2087
2088       if(!dirlist &&
2089          !data->set.ftp_ascii &&
2090          (downloadsize < 1)) {
2091         /*
2092          * It seems directory listings either don't show the size or very
2093          * often uses size 0 anyway. ASCII transfers may very well turn out
2094          * that the transfered amount of data is not the same as this line
2095          * tells, why using this number in those cases only confuses us.
2096          *
2097          * Example D above makes this parsing a little tricky */
2098         char *bytes;
2099         bytes=strstr(buf, " bytes");
2100         if(bytes--) {
2101           long in=bytes-buf;
2102           /* this is a hint there is size information in there! ;-) */
2103           while(--in) {
2104             /* scan for the parenthesis and break there */
2105             if('(' == *bytes)
2106               break;
2107             /* if only skip digits, or else we're in deep trouble */
2108             if(!isdigit((int)*bytes)) {
2109               bytes=NULL;
2110               break;
2111             }
2112             /* one more estep backwards */
2113             bytes--;
2114           }
2115           /* only if we have nothing but digits: */
2116           if(bytes++) {
2117             /* get the number! */
2118             size = curlx_strtoofft(bytes, NULL, 0);
2119           }
2120
2121         }
2122       }
2123       else if(downloadsize > -1)
2124         size = downloadsize;
2125
2126       if(data->set.ftp_use_port) {
2127         result = AllowServerConnect(conn);
2128         if( result )
2129           return result;
2130       }
2131
2132       if(conn->ssl[SECONDARYSOCKET].use) {
2133         /* since we only have a plaintext TCP connection here, we must now
2134            do the TLS stuff */
2135         infof(data, "Doing the SSL/TLS handshake on the data stream\n");
2136         result = Curl_SSLConnect(conn, SECONDARYSOCKET);
2137         if(result)
2138           return result;
2139       }
2140
2141       if(size > conn->maxdownload && conn->maxdownload > 0)
2142         size = conn->size = conn->maxdownload;
2143
2144       infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2145
2146       /* FTP download: */
2147       result=Curl_Transfer(conn, SECONDARYSOCKET, size, FALSE,
2148                            bytecountp,
2149                            -1, NULL); /* no upload here */
2150       if(result)
2151         return result;
2152     }
2153     else {
2154       if(dirlist && (ftpcode == 450)) {
2155         /* simply no matching files */
2156         ftp->no_transfer = TRUE; /* don't think we should download anything */
2157       }
2158       else {
2159         failf(data, "RETR failed: %03d", ftpcode);
2160         return CURLE_FTP_COULDNT_RETR_FILE;
2161       }
2162     }
2163
2164   }
2165   /* end of transfer */
2166
2167   return CURLE_OK;
2168 }
2169
2170 /***********************************************************************
2171  *
2172  * ftp_perform()
2173  *
2174  * This is the actual DO function for FTP. Get a file/directory according to
2175  * the options previously setup.
2176  */
2177
2178 static
2179 CURLcode ftp_perform(struct connectdata *conn,
2180                      bool *connected)  /* for the TCP connect status after
2181                                           PASV / PORT */
2182 {
2183   /* this is FTP and no proxy */
2184   CURLcode result=CURLE_OK;
2185   struct SessionHandle *data=conn->data;
2186   char *buf = data->state.buffer; /* this is our buffer */
2187
2188   /* the ftp struct is already inited in Curl_ftp_connect() */
2189   struct FTP *ftp = conn->proto.ftp;
2190
2191   /* Send any QUOTE strings? */
2192   if(data->set.quote) {
2193     if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK)
2194       return result;
2195   }
2196
2197   result = ftp_cwd_and_create_path(conn);
2198   if (result)
2199     return result;
2200
2201   /* Requested time of file or time-depended transfer? */
2202   if((data->set.get_filetime || data->set.timecondition) &&
2203      ftp->file) {
2204     result = ftp_getfiletime(conn, ftp->file);
2205     switch( result )
2206       {
2207       case CURLE_FTP_COULDNT_RETR_FILE:
2208       case CURLE_OK:
2209         if(data->set.timecondition) {
2210           if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2211             switch(data->set.timecondition) {
2212             case CURL_TIMECOND_IFMODSINCE:
2213             default:
2214               if(data->info.filetime < data->set.timevalue) {
2215                 infof(data, "The requested document is not new enough\n");
2216                 ftp->no_transfer = TRUE; /* mark this to not transfer data */
2217                 return CURLE_OK;
2218               }
2219               break;
2220             case CURL_TIMECOND_IFUNMODSINCE:
2221               if(data->info.filetime > data->set.timevalue) {
2222                 infof(data, "The requested document is not old enough\n");
2223                 ftp->no_transfer = TRUE; /* mark this to not transfer data */
2224                 return CURLE_OK;
2225               }
2226               break;
2227             } /* switch */
2228           }
2229           else {
2230             infof(data, "Skipping time comparison\n");
2231           }
2232         }
2233         break;
2234       default:
2235         return result;
2236       } /* switch */
2237   }
2238
2239   /* If we have selected NOBODY and HEADER, it means that we only want file
2240      information. Which in FTP can't be much more than the file size and
2241      date. */
2242   if(conn->bits.no_body && data->set.include_header && ftp->file) {
2243     /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
2244        may not support it! It is however the only way we have to get a file's
2245        size! */
2246     curl_off_t filesize;
2247     ssize_t nread;
2248     int ftpcode;
2249
2250     ftp->no_transfer = TRUE; /* this means no actual transfer is made */
2251
2252     /* Some servers return different sizes for different modes, and thus we
2253        must set the proper type before we check the size */
2254     result = ftp_transfertype(conn, data->set.ftp_ascii);
2255     if(result)
2256       return result;
2257
2258     /* failing to get size is not a serious error */
2259     result = ftp_getsize(conn, ftp->file, &filesize);
2260
2261     if(CURLE_OK == result) {
2262       snprintf(buf, sizeof(data->state.buffer),
2263                "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
2264       result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
2265       if(result)
2266         return result;
2267     }
2268
2269     /* Determine if server can respond to REST command and therefore
2270        whether it can do a range */
2271     FTPSENDF(conn, "REST 0", NULL);
2272     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2273
2274     if ((CURLE_OK == result) && (ftpcode == 350)) {
2275       result = Curl_client_write(data, CLIENTWRITE_BOTH,
2276                                  (char *)"Accept-ranges: bytes\r\n", 0);
2277       if(result)
2278         return result;
2279     }
2280
2281     /* If we asked for a time of the file and we actually got one as
2282        well, we "emulate" a HTTP-style header in our output. */
2283
2284 #ifdef HAVE_STRFTIME
2285     if(data->set.get_filetime && (data->info.filetime>=0) ) {
2286       struct tm *tm;
2287       time_t clock = (time_t)data->info.filetime;
2288 #ifdef HAVE_GMTIME_R
2289       struct tm buffer;
2290       tm = (struct tm *)gmtime_r(&clock, &buffer);
2291 #else
2292       tm = gmtime(&clock);
2293 #endif
2294       /* format: "Tue, 15 Nov 1994 12:45:26" */
2295       strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT\r\n",
2296                tm);
2297       result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
2298       if(result)
2299         return result;
2300     }
2301 #endif
2302
2303     return CURLE_OK;
2304   }
2305
2306   if(conn->bits.no_body)
2307     /* doesn't really transfer any data */
2308     ftp->no_transfer = TRUE;
2309   /* Get us a second connection up and connected */
2310   else if(data->set.ftp_use_port) {
2311     /* We have chosen to use the PORT command */
2312     result = ftp_use_port(conn);
2313     if(CURLE_OK == result) {
2314       /* we have the data connection ready */
2315       infof(data, "Ordered connect of the data stream with PORT!\n");
2316       *connected = TRUE; /* mark us "still connected" */
2317     }
2318   }
2319   else {
2320     /* We have chosen (this is default) to use the PASV command */
2321     result = ftp_use_pasv(conn, connected);
2322     if(CURLE_OK == result && *connected)
2323       infof(data, "Connected the data stream with PASV!\n");
2324   }
2325
2326   return result;
2327 }
2328
2329 /***********************************************************************
2330  *
2331  * Curl_ftp()
2332  *
2333  * This function is registered as 'curl_do' function. It decodes the path
2334  * parts etc as a wrapper to the actual DO function (ftp_perform).
2335  *
2336  * The input argument is already checked for validity.
2337  */
2338 CURLcode Curl_ftp(struct connectdata *conn)
2339 {
2340   CURLcode retcode = CURLE_OK;
2341
2342   retcode = ftp_parse_url_path(conn);
2343   if (retcode)
2344     return retcode;
2345
2346   if (conn->sec_conn) /* 3rd party transfer */
2347     retcode = ftp_3rdparty(conn);
2348   else
2349     retcode = ftp_regular_transfer(conn);
2350
2351   return retcode;
2352 }
2353
2354 /***********************************************************************
2355  *
2356  * Curl_ftpsendf()
2357  *
2358  * Sends the formated string as a ftp command to a ftp server
2359  *
2360  * NOTE: we build the command in a fixed-length buffer, which sets length
2361  * restrictions on the command!
2362  */
2363 CURLcode Curl_ftpsendf(struct connectdata *conn,
2364                        const char *fmt, ...)
2365 {
2366   ssize_t bytes_written;
2367   char s[256];
2368   size_t write_len;
2369   char *sptr=s;
2370   CURLcode res = CURLE_OK;
2371
2372   va_list ap;
2373   va_start(ap, fmt);
2374   vsnprintf(s, 250, fmt, ap);
2375   va_end(ap);
2376
2377   strcat(s, "\r\n"); /* append a trailing CRLF */
2378
2379   bytes_written=0;
2380   write_len = strlen(s);
2381
2382   while(1) {
2383     res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
2384                      &bytes_written);
2385
2386     if(CURLE_OK != res)
2387       break;
2388
2389     if(conn->data->set.verbose)
2390       Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written, conn);
2391
2392     if(bytes_written != (ssize_t)write_len) {
2393       write_len -= bytes_written;
2394       sptr += bytes_written;
2395     }
2396     else
2397       break;
2398   }
2399
2400   return res;
2401 }
2402
2403 /***********************************************************************
2404  *
2405  * ftp_quit()
2406  *
2407  * This should be called before calling sclose() on an ftp control connection
2408  * (not data connections). We should then wait for the response from the
2409  * server before returning. The calling code should then try to close the
2410  * connection.
2411  *
2412  */
2413 static CURLcode ftp_quit(struct connectdata *conn)
2414 {
2415   ssize_t nread;
2416   int ftpcode;
2417   CURLcode ret = CURLE_OK;
2418
2419   if(conn->proto.ftp->ctl_valid) {
2420     ret = Curl_ftpsendf(conn, "%s", "QUIT");
2421     if(CURLE_OK == ret)
2422       ret = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2423   }
2424
2425   return ret;
2426 }
2427
2428 /***********************************************************************
2429  *
2430  * Curl_ftp_disconnect()
2431  *
2432  * Disconnect from an FTP server. Cleanup protocol-specific per-connection
2433  * resources
2434  */
2435 CURLcode Curl_ftp_disconnect(struct connectdata *conn)
2436 {
2437   struct FTP *ftp= conn->proto.ftp;
2438
2439   /* We cannot send quit unconditionally. If this connection is stale or
2440      bad in any way, sending quit and waiting around here will make the
2441      disconnect wait in vain and cause more problems than we need to.
2442
2443      ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
2444      will try to send the QUIT command, otherwise it will just return.
2445   */
2446
2447   /* The FTP session may or may not have been allocated/setup at this point! */
2448   if(ftp) {
2449     (void)ftp_quit(conn); /* ignore errors on the QUIT */
2450
2451     if(ftp->entrypath)
2452       free(ftp->entrypath);
2453     if(ftp->cache) {
2454       free(ftp->cache);
2455       ftp->cache = NULL;
2456     }
2457     freedirs(ftp);
2458     if(ftp->prevpath) {
2459       free(ftp->prevpath);
2460       ftp->prevpath = NULL;
2461     }
2462   }
2463   return CURLE_OK;
2464 }
2465
2466 /***********************************************************************
2467  *
2468  * ftp_mkd()
2469  *
2470  * Makes a directory on the FTP server.
2471  *
2472  * Calls failf()
2473  */
2474 static CURLcode ftp_mkd(struct connectdata *conn, char *path)
2475 {
2476   CURLcode result=CURLE_OK;
2477   int ftpcode; /* for ftp status */
2478   ssize_t nread;
2479
2480   /* Create a directory on the remote server */
2481   FTPSENDF(conn, "MKD %s", path);
2482
2483   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2484   if(result)
2485     return result;
2486
2487   switch(ftpcode) {
2488   case 257:
2489     /* success! */
2490     infof( conn->data , "Created remote directory %s\n" , path );
2491     break;
2492   case 550:
2493     failf(conn->data, "Permission denied to make directory %s", path);
2494     result = CURLE_FTP_ACCESS_DENIED;
2495     break;
2496   default:
2497     failf(conn->data, "unrecognized MKD response: %d", ftpcode );
2498     result = CURLE_FTP_ACCESS_DENIED;
2499     break;
2500   }
2501   return  result;
2502 }
2503
2504 /***********************************************************************
2505  *
2506  * ftp_cwd()
2507  *
2508  * Send 'CWD' to the remote server to Change Working Directory.  It is the ftp
2509  * version of the unix 'cd' command. This function is only called from the
2510  * ftp_cwd_and_mkd() function these days.
2511  *
2512  * This function does NOT call failf().
2513  */
2514 static
2515 CURLcode ftp_cwd(struct connectdata *conn, char *path)
2516 {
2517   ssize_t nread;
2518   int     ftpcode;
2519   CURLcode result;
2520
2521   FTPSENDF(conn, "CWD %s", path);
2522   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2523   if (!result) {
2524     /* According to RFC959, CWD is supposed to return 250 on success, but
2525        there seem to be non-compliant FTP servers out there that return 200,
2526        so we accept any '2xy' code here. */
2527     if (ftpcode/100 != 2)
2528       result = CURLE_FTP_ACCESS_DENIED;
2529   }
2530
2531   return result;
2532 }
2533
2534 /***********************************************************************
2535  *
2536  * ftp_cwd_and_mkd()
2537  *
2538  * Change to the given directory.  If the directory is not present, and we
2539  * have been told to allow it, then create the directory and cd to it.
2540  *
2541  */
2542 static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
2543 {
2544   CURLcode result;
2545
2546   result = ftp_cwd(conn, path);
2547   if (result) {
2548     if(conn->data->set.ftp_create_missing_dirs) {
2549       result = ftp_mkd(conn, path);
2550       if (result)
2551         /* ftp_mkd() calls failf() itself */
2552         return result;
2553       result = ftp_cwd(conn, path);
2554     }
2555     if(result)
2556       failf(conn->data, "Couldn't CWD to %s", path);
2557   }
2558   return result;
2559 }
2560
2561
2562
2563 /***********************************************************************
2564  *
2565  * ftp_3rdparty_pretransfer()
2566  *
2567  * Preparation for 3rd party transfer.
2568  *
2569  */
2570 static CURLcode ftp_3rdparty_pretransfer(struct connectdata *conn)
2571 {
2572   CURLcode result = CURLE_OK;
2573   struct SessionHandle *data = conn->data;
2574   struct connectdata *sec_conn = conn->sec_conn;
2575
2576   conn->xfertype = TARGET3RD;
2577   sec_conn->xfertype = SOURCE3RD;
2578
2579   /* sets transfer type */
2580   result = ftp_transfertype(conn, data->set.ftp_ascii);
2581   if (result)
2582     return result;
2583
2584   result = ftp_transfertype(sec_conn, data->set.ftp_ascii);
2585   if (result)
2586     return result;
2587
2588   /* Send any PREQUOTE strings after transfer type is set? */
2589   if (data->set.source_prequote) {
2590     /* sends command(s) to source server before file transfer */
2591     result = ftp_sendquote(sec_conn, data->set.source_prequote);
2592   }
2593   if (!result && data->set.prequote)
2594     result = ftp_sendquote(conn, data->set.prequote);
2595
2596   return result;
2597 }
2598
2599
2600
2601 /***********************************************************************
2602  *
2603  * ftp_3rdparty_transfer()
2604  *
2605  * Performs 3rd party transfer.
2606  *
2607  */
2608 static CURLcode ftp_3rdparty_transfer(struct connectdata *conn)
2609 {
2610   CURLcode result = CURLE_OK;
2611   ssize_t nread;
2612   int ftpcode, ip[4], port[2];
2613   struct SessionHandle *data = conn->data;
2614   struct connectdata *sec_conn = conn->sec_conn;
2615   char *buf = data->state.buffer;   /* this is our buffer */
2616   char *str = buf;
2617   char pasv_port[50];
2618   const char *stor_cmd;
2619   struct connectdata *pasv_conn;
2620   struct connectdata *port_conn;
2621
2622   if (data->set.ftpport == NULL) {
2623     pasv_conn = conn;
2624     port_conn = sec_conn;
2625   }
2626   else {
2627     pasv_conn = sec_conn;
2628     port_conn = conn;
2629   }
2630
2631   result = ftp_cwd_and_create_path(conn);
2632   if (result)
2633     return result;
2634
2635   /* sets the passive mode */
2636   FTPSENDF(pasv_conn, "%s", "PASV");
2637   result = Curl_GetFTPResponse(&nread, pasv_conn, &ftpcode);
2638   if (result)
2639     return result;
2640
2641   if (ftpcode != 227) {
2642     failf(data, "Odd return code after PASV: %03d", ftpcode);
2643     return CURLE_FTP_WEIRD_PASV_REPLY;
2644   }
2645
2646   while (*str) {
2647     if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
2648                     &ip[0], &ip[1], &ip[2], &ip[3], &port[0], &port[1]))
2649       break;
2650     str++;
2651   }
2652
2653   if (!*str) {
2654     failf(pasv_conn->data, "Couldn't interpret the 227-reply");
2655     return CURLE_FTP_WEIRD_227_FORMAT;
2656   }
2657
2658   snprintf(pasv_port, sizeof(pasv_port), "%d,%d,%d,%d,%d,%d", ip[0], ip[1],
2659            ip[2], ip[3], port[0], port[1]);
2660
2661   /* sets data connection between remote hosts */
2662   FTPSENDF(port_conn, "PORT %s", pasv_port);
2663   result = Curl_GetFTPResponse(&nread, port_conn, &ftpcode);
2664   if (result)
2665     return result;
2666
2667   if (ftpcode != 200) {
2668     failf(data, "PORT command attempts failed: %03d", ftpcode);
2669     return CURLE_FTP_PORT_FAILED;
2670   }
2671
2672   /* we might append onto the file instead of overwriting it */
2673   stor_cmd = data->set.ftp_append?"APPE":"STOR";
2674
2675   /* transfers file between remote hosts */
2676   /* FIX: this should send a series of CWD commands and then RETR only the
2677      ftp->file file. The conn->path "full path" is not unescaped. Test case
2678      230 tests this. */
2679   FTPSENDF(sec_conn, "RETR %s", sec_conn->path);
2680
2681   if(!data->set.ftpport) {
2682
2683     result = Curl_GetFTPResponse(&nread, sec_conn, &ftpcode);
2684     if (result)
2685       return result;
2686
2687     if((ftpcode != 150) && (ftpcode != 125)) {
2688       failf(data, "Failed RETR: %03d", ftpcode);
2689       return CURLE_FTP_COULDNT_RETR_FILE;
2690     }
2691
2692     result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->proto.ftp->file);
2693     if(CURLE_OK == result)
2694       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2695     if (result)
2696       return result;
2697
2698     if (ftpcode >= 400) {
2699       failf(data, "Failed FTP upload: %03d", ftpcode);
2700       return CURLE_FTP_COULDNT_STOR_FILE;
2701     }
2702
2703   }
2704   else {
2705
2706     result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->proto.ftp->file);
2707     if(CURLE_OK == result)
2708       result = Curl_GetFTPResponse(&nread, sec_conn, &ftpcode);
2709     if (result)
2710       return result;
2711
2712     if (ftpcode >= 400) {
2713       failf(data, "Failed FTP upload: %03d", ftpcode);
2714       return CURLE_FTP_COULDNT_STOR_FILE;
2715     }
2716
2717     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2718     if (result)
2719       return result;
2720
2721     if((ftpcode != 150) && (ftpcode != 125)) {
2722       failf(data, "Failed FTP upload: %03d", ftpcode);
2723       return CURLE_FTP_COULDNT_STOR_FILE;
2724     }
2725   }
2726
2727   return CURLE_OK;
2728 }
2729
2730
2731
2732 /***********************************************************************
2733  *
2734  * ftp_parse_url_path()
2735  *
2736  * Parse the URL path into separate path components.
2737  *
2738  */
2739 static
2740 CURLcode ftp_parse_url_path(struct connectdata *conn)
2741 {
2742   CURLcode retcode = CURLE_OK;
2743   struct SessionHandle *data = conn->data;
2744   struct FTP *ftp;
2745   size_t dlen;
2746
2747   char *slash_pos;  /* position of the first '/' char in curpos */
2748   char *cur_pos = conn->path; /* current position in path. point at the begin
2749                                  of next path component */
2750
2751   /* the ftp struct is already inited in ftp_connect() */
2752   ftp = conn->proto.ftp;
2753   ftp->ctl_valid = FALSE;
2754
2755   ftp->dirdepth = 0;
2756   ftp->diralloc = 5; /* default dir depth to allocate */
2757   ftp->dirs = (char **)calloc(ftp->diralloc, sizeof(ftp->dirs[0]));
2758   if(!ftp->dirs)
2759     return CURLE_OUT_OF_MEMORY;
2760
2761   /* parse the URL path into separate path components */
2762   while((slash_pos=strchr(cur_pos, '/'))) {
2763     /* 1 or 0 to indicate absolute directory */
2764     bool absolute_dir = (cur_pos - conn->path > 0) && (ftp->dirdepth == 0);
2765
2766     /* seek out the next path component */
2767     if (slash_pos-cur_pos) {
2768       /* we skip empty path components, like "x//y" since the FTP command CWD
2769          requires a parameter and a non-existant parameter a) doesn't work on
2770          many servers and b) has no effect on the others. */
2771       int len = (int)(slash_pos - cur_pos + absolute_dir);
2772       ftp->dirs[ftp->dirdepth] = curl_unescape(cur_pos - absolute_dir, len);
2773
2774       if (!ftp->dirs[ftp->dirdepth]) { /* run out of memory ... */
2775         failf(data, "no memory");
2776         freedirs(ftp);
2777         return CURLE_OUT_OF_MEMORY;
2778       }
2779       if (isBadFtpString(ftp->dirs[ftp->dirdepth])) {
2780         freedirs(ftp);
2781         return CURLE_URL_MALFORMAT;
2782       }
2783     }
2784     else {
2785       cur_pos = slash_pos + 1; /* jump to the rest of the string */
2786       continue;
2787     }
2788
2789     if(!retcode) {
2790       cur_pos = slash_pos + 1; /* jump to the rest of the string */
2791       if(++ftp->dirdepth >= ftp->diralloc) {
2792         /* enlarge array */
2793         char *bigger;
2794         ftp->diralloc *= 2; /* double the size each time */
2795         bigger = realloc(ftp->dirs, ftp->diralloc * sizeof(ftp->dirs[0]));
2796         if(!bigger) {
2797           ftp->dirdepth--;
2798           freedirs(ftp);
2799           return CURLE_OUT_OF_MEMORY;
2800         }
2801         ftp->dirs = (char **)bigger;
2802       }
2803     }
2804   }
2805
2806   ftp->file = cur_pos;  /* the rest is the file name */
2807
2808   if(*ftp->file) {
2809     ftp->file = curl_unescape(ftp->file, 0);
2810     if(NULL == ftp->file) {
2811       freedirs(ftp);
2812       failf(data, "no memory");
2813       return CURLE_OUT_OF_MEMORY;
2814     }
2815     if (isBadFtpString(ftp->file)) {
2816       freedirs(ftp);
2817       return CURLE_URL_MALFORMAT;
2818     }
2819   }
2820   else
2821     ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
2822                        pointer */
2823
2824   ftp->cwddone = FALSE; /* default to not done */
2825
2826   if(ftp->prevpath) {
2827     /* prevpath is "raw" so we convert the input path before we compare the
2828        strings */
2829     char *path = curl_unescape(conn->path, 0);
2830     if(!path)
2831       return CURLE_OUT_OF_MEMORY;
2832
2833     dlen = strlen(path) - (ftp->file?strlen(ftp->file):0);
2834     if((dlen == strlen(ftp->prevpath)) &&
2835        curl_strnequal(path, ftp->prevpath, dlen)) {
2836       infof(data, "Request has same path as previous transfer\n");
2837       ftp->cwddone = TRUE;
2838     }
2839     free(path);
2840   }
2841
2842   return retcode;
2843 }
2844
2845
2846
2847 /***********************************************************************
2848  *
2849  * ftp_cwd_and_create_path()
2850  *
2851  * Creates full path on remote target host.
2852  *
2853  */
2854 static
2855 CURLcode ftp_cwd_and_create_path(struct connectdata *conn)
2856 {
2857   CURLcode result = CURLE_OK;
2858   /* the ftp struct is already inited in Curl_ftp_connect() */
2859   struct FTP *ftp = conn->proto.ftp;
2860   int i;
2861
2862   if(ftp->cwddone)
2863     /* already done and fine */
2864     return CURLE_OK;
2865
2866   /* This is a re-used connection. Since we change directory to where the
2867      transfer is taking place, we must now get back to the original dir
2868      where we ended up after login: */
2869   if (conn->bits.reuse && ftp->entrypath) {
2870     if ((result = ftp_cwd_and_mkd(conn, ftp->entrypath)) != CURLE_OK)
2871       return result;
2872   }
2873
2874   for (i=0; i < ftp->dirdepth; i++) {
2875     /* RFC 1738 says empty components should be respected too, but
2876        that is plain stupid since CWD can't be used with an empty argument */
2877     if ((result = ftp_cwd_and_mkd(conn, ftp->dirs[i])) != CURLE_OK)
2878       return result;
2879   }
2880
2881   return result;
2882 }
2883
2884
2885 /***********************************************************************
2886  *
2887  * ftp_regular_transfer()
2888  *
2889  * The input argument is already checked for validity.
2890  * Performs a regular transfer between local and remote hosts.
2891  *
2892  * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
2893  * Curl_ftp_done() function without finding any major problem.
2894  */
2895 static
2896 CURLcode ftp_regular_transfer(struct connectdata *conn)
2897 {
2898   CURLcode retcode=CURLE_OK;
2899   bool connected=0;
2900   struct SessionHandle *data = conn->data;
2901   struct FTP *ftp;
2902
2903   /* the ftp struct is already inited in ftp_connect() */
2904   ftp = conn->proto.ftp;
2905   conn->size = -1; /* make sure this is unknown at this point */
2906
2907   Curl_pgrsSetUploadCounter(data, 0);
2908   Curl_pgrsSetDownloadCounter(data, 0);
2909   Curl_pgrsSetUploadSize(data, 0);
2910   Curl_pgrsSetDownloadSize(data, 0);
2911
2912   retcode = ftp_perform(conn, &connected);
2913
2914   if(CURLE_OK == retcode) {
2915     if(connected)
2916       retcode = Curl_ftp_nextconnect(conn);
2917
2918     if(retcode && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
2919       /* Failure detected, close the second socket if it was created already */
2920       sclose(conn->sock[SECONDARYSOCKET]);
2921       conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
2922     }
2923
2924     if(ftp->no_transfer)
2925       /* no data to transfer */
2926       retcode=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2927     else if(!connected)
2928       /* since we didn't connect now, we want do_more to get called */
2929       conn->bits.do_more = TRUE;
2930   }
2931   else
2932     freedirs(ftp);
2933
2934   ftp->ctl_valid = TRUE; /* seems good */
2935
2936   return retcode;
2937 }
2938
2939
2940
2941 /***********************************************************************
2942  *
2943  * ftp_3rdparty()
2944  *
2945  * The input argument is already checked for validity.
2946  * Performs a 3rd party transfer between two remote hosts.
2947  */
2948 static CURLcode ftp_3rdparty(struct connectdata *conn)
2949 {
2950   CURLcode retcode = CURLE_OK;
2951
2952   conn->proto.ftp->ctl_valid = conn->sec_conn->proto.ftp->ctl_valid = TRUE;
2953   conn->size = conn->sec_conn->size = -1;
2954
2955   retcode = ftp_3rdparty_pretransfer(conn);
2956   if (!retcode)
2957     retcode = ftp_3rdparty_transfer(conn);
2958
2959   return retcode;
2960 }
2961
2962 #endif /* CURL_DISABLE_FTP */