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