~ubuntu-branches/ubuntu/lucid/curl/lucid-security

« back to all changes in this revision

Viewing changes to lib/ftp.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Vogt
  • Date: 2009-04-29 11:10:29 UTC
  • mfrom: (3.2.3 sid)
  • Revision ID: james.westby@ubuntu.com-20090429111029-2j5eiyokfw2bw049
Tags: 7.19.4-1ubuntu1
* Merge from debian unstable, remaining changes:
  - Drop build dependencies: stunnel, libdb4.6-dev, libssh2-1-dev
  - Add build-dependency on openssh-server
  - Drop libssh2-1-dev from libcurl4-openssl-dev's Depends.
  - Call automake-1.9 with --add-missing --copy --force
* drop debian/patches/security_CVE-2009-0037.patch 
  - this patch is part of 7.19.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 *                            | (__| |_| |  _ <| |___
6
6
 *                             \___|\___/|_| \_\_____|
7
7
 *
8
 
 * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
 
8
 * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
9
9
 *
10
10
 * This software is licensed as described in the file COPYING, which
11
11
 * you should have received as part of this distribution. The terms
18
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
 * KIND, either express or implied.
20
20
 *
21
 
 * $Id: ftp.c,v 1.471 2008-05-07 21:02:21 bagder Exp $
 
21
 * $Id: ftp.c,v 1.502 2009-02-20 08:16:03 bagder Exp $
22
22
 ***************************************************************************/
23
23
 
24
24
#include "setup.h"
34
34
#include <unistd.h>
35
35
#endif
36
36
 
37
 
#ifndef WIN32
38
37
#ifdef HAVE_SYS_SOCKET_H
39
38
#include <sys/socket.h>
40
39
#endif
54
53
#include <in.h>
55
54
#include <inet.h>
56
55
#endif
57
 
#endif  /* !WIN32 */
58
56
 
59
57
#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
60
58
#undef in_addr_t
84
82
#include "sslgen.h"
85
83
#include "connect.h"
86
84
#include "strerror.h"
87
 
#include "memory.h"
88
85
#include "inet_ntop.h"
 
86
#include "inet_pton.h"
89
87
#include "select.h"
90
88
#include "parsedate.h" /* for the week day and month names */
91
89
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
92
90
#include "multiif.h"
93
91
#include "url.h"
94
 
 
95
 
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
96
 
#include "inet_ntoa_r.h"
97
 
#endif
 
92
#include "rawstr.h"
98
93
 
99
94
#define _MPRINTF_REPLACE /* use our functions only */
100
95
#include <curl/mprintf.h>
101
96
 
 
97
#include "memory.h"
102
98
/* The last #include file should be: */
103
 
#ifdef CURLDEBUG
104
99
#include "memdebug.h"
105
 
#endif
106
100
 
107
101
#ifdef HAVE_NI_WITHSCOPEID
108
102
#define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID
155
149
static CURLcode ftp_doing(struct connectdata *conn,
156
150
                               bool *dophase_done);
157
151
static CURLcode ftp_setup_connection(struct connectdata * conn);
158
 
#ifdef USE_SSL
159
 
static CURLcode ftps_setup_connection(struct connectdata * conn);
160
 
#endif
161
152
 
162
153
/* easy-to-use macro: */
163
154
#define FTPSENDF(x,y,z)    if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
181
172
  ftp_doing,                       /* doing */
182
173
  ftp_getsock,                     /* proto_getsock */
183
174
  ftp_getsock,                     /* doing_getsock */
 
175
  ZERO_NULL,                       /* perform_getsock */
184
176
  ftp_disconnect,                  /* disconnect */
185
 
  PORT_FTP,                             /* defport */
186
 
  PROT_FTP                              /* protocol */
 
177
  PORT_FTP,                        /* defport */
 
178
  PROT_FTP                         /* protocol */
187
179
};
188
180
 
189
181
 
194
186
 
195
187
const struct Curl_handler Curl_handler_ftps = {
196
188
  "FTPS",                               /* scheme */
197
 
  ftps_setup_connection,           /* setup_connection */
 
189
  ftp_setup_connection,            /* setup_connection */
198
190
  ftp_do,                          /* do_it */
199
191
  ftp_done,                        /* done */
200
192
  ftp_nextconnect,                 /* do_more */
203
195
  ftp_doing,                       /* doing */
204
196
  ftp_getsock,                     /* proto_getsock */
205
197
  ftp_getsock,                     /* doing_getsock */
 
198
  ZERO_NULL,                       /* perform_getsock */
206
199
  ftp_disconnect,                  /* disconnect */
207
 
  PORT_FTPS,                            /* defport */
208
 
  PROT_FTP | PROT_FTPS | PROT_SSL       /* protocol */
 
200
  PORT_FTPS,                       /* defport */
 
201
  PROT_FTP | PROT_FTPS | PROT_SSL  /* protocol */
209
202
};
210
203
#endif
211
204
 
225
218
  ZERO_NULL,                            /* doing */
226
219
  ZERO_NULL,                            /* proto_getsock */
227
220
  ZERO_NULL,                            /* doing_getsock */
 
221
  ZERO_NULL,                            /* perform_getsock */
228
222
  ZERO_NULL,                            /* disconnect */
229
223
  PORT_FTP,                             /* defport */
230
224
  PROT_HTTP                             /* protocol */
247
241
  ZERO_NULL,                            /* doing */
248
242
  ZERO_NULL,                            /* proto_getsock */
249
243
  ZERO_NULL,                            /* doing_getsock */
 
244
  ZERO_NULL,                            /* perform_getsock */
250
245
  ZERO_NULL,                            /* disconnect */
251
246
  PORT_FTPS,                            /* defport */
252
247
  PROT_HTTP                             /* protocol */
279
274
    }
280
275
    free(ftpc->dirs);
281
276
    ftpc->dirs = NULL;
 
277
    ftpc->dirdepth = 0;
282
278
  }
283
279
  if(ftpc->file) {
284
280
    free(ftpc->file);
367
363
  struct ftp_conn *ftpc = &conn->proto.ftpc;
368
364
  ftpc->nread_resp = 0;
369
365
  ftpc->linestart_resp = conn->data->state.buffer;
 
366
  ftpc->pending_resp = TRUE;
370
367
}
371
368
 
372
369
/* macro to check for a three-digit ftp status code at the start of the
387
384
  ssize_t gotbytes;
388
385
  char *ptr;
389
386
  struct SessionHandle *data = conn->data;
390
 
  char *buf = data->state.buffer;
 
387
  char * const buf = data->state.buffer;
391
388
  CURLcode result = CURLE_OK;
392
389
  struct ftp_conn *ftpc = &conn->proto.ftpc;
393
390
  int code = 0;
413
410
       * int to begin with, even though its datatype may be larger
414
411
       * than an int.
415
412
       */
 
413
      DEBUGASSERT((ptr+ftpc->cache_size) <= (buf+BUFSIZE+1));
416
414
      memcpy(ptr, ftpc->cache, (int)ftpc->cache_size);
417
415
      gotbytes = (int)ftpc->cache_size;
418
416
      free(ftpc->cache);    /* free the cache */
426
424
 
427
425
      conn->data_prot = 0;
428
426
#endif
 
427
      DEBUGASSERT((ptr+BUFSIZE-ftpc->nread_resp) <= (buf+BUFSIZE+1));
429
428
      res = Curl_read(conn, sockfd, ptr, BUFSIZE-ftpc->nread_resp,
430
429
                      &gotbytes);
431
430
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
534
533
               dash or a space and it is significant */
535
534
            clipamount = 4;
536
535
        }
537
 
        else if(perline && (ftpc->nread_resp > BUFSIZE/2)) {
538
 
          /* We got a large chunk of data and there's still trailing data to
539
 
             take care of, so we put that part in the "cache" and restart */
 
536
        else if(ftpc->nread_resp > BUFSIZE/2) {
 
537
          /* We got a large chunk of data and there's potentially still trailing
 
538
             data to take care of, so we put any such part in the "cache", clear
 
539
             the buffer to make space and restart. */
540
540
          clipamount = perline;
541
541
          restart = TRUE;
542
542
        }
546
546
 
547
547
      if(clipamount) {
548
548
        ftpc->cache_size = clipamount;
549
 
        ftpc->cache = (char *)malloc((int)ftpc->cache_size);
 
549
        ftpc->cache = malloc((int)ftpc->cache_size);
550
550
        if(ftpc->cache)
551
551
          memcpy(ftpc->cache, ftpc->linestart_resp, (int)ftpc->cache_size);
552
552
        else
591
591
  /* store the latest code for later retrieval */
592
592
  conn->data->info.httpcode=code;
593
593
 
 
594
  ftpc->pending_resp = FALSE;
 
595
 
594
596
  return result;
595
597
}
596
598
 
716
718
 
717
719
  } /* while there's buffer left and loop is requested */
718
720
 
 
721
  ftpc->pending_resp = FALSE;
 
722
 
719
723
  return result;
720
724
}
721
725
 
816
820
 
817
821
/* This is called after the FTP_QUOTE state is passed.
818
822
 
819
 
   ftp_state_cwd() sends the range of PWD commands to the server to change to
 
823
   ftp_state_cwd() sends the range of CWD commands to the server to change to
820
824
   the correct directory. It may also need to send MKD commands to create
821
825
   missing ones, if that option is enabled.
822
826
*/
829
833
    /* already done and fine */
830
834
    result = ftp_state_post_cwd(conn);
831
835
  else {
832
 
    ftpc->count2 = 0;
 
836
    ftpc->count2 = 0; /* count2 counts failed CWDs */
 
837
 
 
838
    /* count3 is set to allow a MKD to fail once. In the case when first CWD
 
839
       fails and then MKD fails (due to another session raced it to create the
 
840
       dir) this then allows for a second try to CWD to it */
 
841
    ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
 
842
 
833
843
    if(conn->bits.reuse && ftpc->entrypath) {
834
844
      /* This is a re-used connection. Since we change directory to where the
835
845
         transfer is taking place, we must first get back to the original dir
877
887
   * IPv6-specific section
878
888
   */
879
889
  struct Curl_sockaddr_storage ss;
880
 
  struct addrinfo *res, *ai;
 
890
  Curl_addrinfo *res, *ai;
881
891
  socklen_t sslen;
882
892
  char hbuf[NI_MAXHOST];
883
893
  struct sockaddr *sa=(struct sockaddr *)&ss;
 
894
  struct sockaddr_in * const sa4 = (void *)sa;
 
895
  struct sockaddr_in6 * const sa6 = (void *)sa;
884
896
  char tmp[1024];
885
 
  static const char * const mode[] = { "EPRT", "PORT", NULL };
 
897
  static const char mode[][5] = { "EPRT", "PORT" };
886
898
  int rc;
887
899
  int error;
888
900
  char *host=NULL;
894
906
  if(data->set.str[STRING_FTPPORT] &&
895
907
     (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
896
908
    /* attempt to get the address of the given interface name */
897
 
    if(!Curl_if2ip(data->set.str[STRING_FTPPORT], hbuf, sizeof(hbuf)))
 
909
    if(!Curl_if2ip(conn->ip_addr->ai_family, data->set.str[STRING_FTPPORT],
 
910
                   hbuf, sizeof(hbuf)))
898
911
      /* not an interface, use the given string as host name instead */
899
912
      host = data->set.str[STRING_FTPPORT];
900
913
    else
966
979
 
967
980
    /* It failed. Bind the address used for the control connection instead */
968
981
    sslen = sizeof(ss);
969
 
    if(getsockname(conn->sock[FIRSTSOCKET],
970
 
                    (struct sockaddr *)sa, &sslen)) {
 
982
    if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
971
983
      failf(data, "getsockname() failed: %s",
972
984
          Curl_strerror(conn, SOCKERRNO) );
973
985
      sclose(portsock);
975
987
    }
976
988
 
977
989
    /* set port number to zero to make bind() pick "any" */
978
 
    if(((struct sockaddr *)sa)->sa_family == AF_INET)
979
 
      ((struct sockaddr_in *)sa)->sin_port=0;
 
990
    if(sa->sa_family == AF_INET)
 
991
      sa4->sin_port = 0;
980
992
    else
981
 
      ((struct sockaddr_in6 *)sa)->sin6_port =0;
 
993
      sa6->sin6_port = 0;
982
994
 
983
995
    if(sslen > (socklen_t)sizeof(ss))
984
996
      sslen = sizeof(ss);
985
997
 
986
 
    if(bind(portsock, (struct sockaddr *)sa, sslen)) {
 
998
    if(bind(portsock, sa, sslen)) {
987
999
      failf(data, "bind failed: %s", Curl_strerror(conn, SOCKERRNO));
988
1000
      sclose(portsock);
989
1001
      return CURLE_FTP_PORT_FAILED;
1029
1041
 
1030
1042
    switch (sa->sa_family) {
1031
1043
    case AF_INET:
1032
 
      port = ntohs(((struct sockaddr_in *)sa)->sin_port);
 
1044
      port = ntohs(sa4->sin_port);
1033
1045
      break;
1034
1046
    case AF_INET6:
1035
 
      port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
 
1047
      port = ntohs(sa6->sin6_port);
1036
1048
      break;
1037
1049
    default:
1038
1050
      break;
1105
1117
 
1106
1118
  (void)fcmd; /* not used in the IPv4 code */
1107
1119
  if(ftpportstr) {
1108
 
    in_addr_t in;
1109
 
 
1110
 
    /* First check if the given name is an IP address */
1111
 
    in=inet_addr(ftpportstr);
1112
 
 
1113
 
    if(in != CURL_INADDR_NONE)
 
1120
    struct in_addr in;
 
1121
 
 
1122
    /* First check if the given string is an IP address */
 
1123
    if(Curl_inet_pton(AF_INET, ftpportstr, &in) > 0) {
1114
1124
      /* this is an IPv4 address */
1115
 
      addr = Curl_ip2addr(in, ftpportstr, 0);
1116
 
    else {
1117
 
      if(Curl_if2ip(ftpportstr, myhost, sizeof(myhost))) {
1118
 
        /* The interface to IP conversion provided a dotted address */
1119
 
        in=inet_addr(myhost);
1120
 
        addr = Curl_ip2addr(in, myhost, 0);
 
1125
      addr = Curl_ip2addr(AF_INET, &in, ftpportstr, 0);
 
1126
    }
 
1127
    /* otherwise check if the given string is an interface */
 
1128
    else if(Curl_if2ip(AF_INET, ftpportstr, myhost, sizeof(myhost))) {
 
1129
      /* The interface to IP conversion provided a dotted address */
 
1130
      if(Curl_inet_pton(AF_INET, myhost, &in) > 0)
 
1131
        addr = Curl_ip2addr(AF_INET, &in, myhost, 0);
 
1132
    }
 
1133
    else if(strlen(ftpportstr)> 1) {
 
1134
      /* might be a host name! */
 
1135
      struct Curl_dns_entry *h=NULL;
 
1136
      int rc = Curl_resolv(conn, ftpportstr, 0, &h);
 
1137
      if(rc == CURLRESOLV_PENDING)
 
1138
        /* BLOCKING */
 
1139
        rc = Curl_wait_for_resolv(conn, &h);
 
1140
      if(h) {
 
1141
        addr = h->addr;
 
1142
        /* when we return from this function, we can forget about this entry
 
1143
           so we can unlock it now already */
 
1144
        Curl_resolv_unlock(data, h);
 
1145
 
 
1146
        freeaddr = FALSE; /* make sure we don't free 'addr' in this function
 
1147
                             since it points to a DNS cache entry! */
 
1148
      } /* (h) */
 
1149
      else {
 
1150
        infof(data, "Failed to resolve host name %s\n", ftpportstr);
1121
1151
      }
1122
 
      else if(strlen(ftpportstr)> 1) {
1123
 
        /* might be a host name! */
1124
 
        struct Curl_dns_entry *h=NULL;
1125
 
        int rc = Curl_resolv(conn, ftpportstr, 0, &h);
1126
 
        if(rc == CURLRESOLV_PENDING)
1127
 
          /* BLOCKING */
1128
 
          rc = Curl_wait_for_resolv(conn, &h);
1129
 
        if(h) {
1130
 
          addr = h->addr;
1131
 
          /* when we return from this function, we can forget about this entry
1132
 
             so we can unlock it now already */
1133
 
          Curl_resolv_unlock(data, h);
1134
 
 
1135
 
          freeaddr = FALSE; /* make sure we don't free 'addr' in this function
1136
 
                               since it points to a DNS cache entry! */
1137
 
        } /* (h) */
1138
 
        else {
1139
 
          infof(data, "Failed to resolve host name %s\n", ftpportstr);
1140
 
        }
1141
 
      } /* strlen */
1142
 
    } /* CURL_INADDR_NONE */
 
1152
    } /* strlen */
1143
1153
  } /* ftpportstr */
1144
1154
 
1145
1155
  if(!addr) {
1268
1278
 
1269
1279
  */
1270
1280
 
1271
 
  static const char * const mode[] = { "EPSV", "PASV", NULL };
 
1281
  static const char mode[][5] = { "EPSV", "PASV" };
1272
1282
  int modeoff;
1273
1283
 
1274
1284
#ifdef PF_INET6
1395
1405
 
1396
1406
      /* chop off the file part if format is dir/dir/file */
1397
1407
      slashPos = strrchr(lstArg,'/');
1398
 
      *(slashPos+1) = '\0';
 
1408
      if(slashPos)
 
1409
        *(slashPos+1) = '\0';
1399
1410
    }
1400
1411
  }
1401
1412
 
1540
1551
      curl_off_t readthisamountnow = data->state.resume_from;
1541
1552
 
1542
1553
      if(conn->seek_func(conn->seek_client,
1543
 
                         readthisamountnow, SEEK_SET) != 0) {
 
1554
                         readthisamountnow, SEEK_SET) != 0) {
1544
1555
        failf(data, "Could not seek stream");
1545
1556
        return CURLE_FTP_COULDNT_USE_REST;
1546
1557
      }
1821
1832
    connectport =
1822
1833
      (unsigned short)conn->port; /* we connect to the proxy's port */
1823
1834
 
 
1835
    if(!addr) {
 
1836
      failf(data, "Can't resolve proxy host %s:%d",
 
1837
            conn->proxy.name, connectport);
 
1838
      return CURLE_FTP_CANT_GET_HOST;
 
1839
    }
1824
1840
  }
1825
1841
  else {
1826
1842
    /* normal, direct, ftp connection */
1829
1845
      /* BLOCKING */
1830
1846
      rc = Curl_wait_for_resolv(conn, &addr);
1831
1847
 
1832
 
    if(!addr) {
1833
 
      failf(data, "Can't resolve new host %s:%d", newhost, newport);
1834
 
      return CURLE_FTP_CANT_GET_HOST;
1835
 
    }
1836
1848
    connectport = newport; /* we connect to the remote port */
 
1849
 
 
1850
    if(!addr) {
 
1851
      failf(data, "Can't resolve new host %s:%d", newhost, connectport);
 
1852
      return CURLE_FTP_CANT_GET_HOST;
 
1853
    }
1837
1854
  }
1838
1855
 
1839
1856
  result = Curl_connecthost(conn,
1872
1889
    ftp_pasv_verbose(conn, conninfo, newhost, connectport);
1873
1890
 
1874
1891
  switch(data->set.proxytype) {
 
1892
#ifndef CURL_DISABLE_PROXY
1875
1893
  case CURLPROXY_SOCKS5:
1876
1894
  case CURLPROXY_SOCKS5_HOSTNAME:
1877
1895
    result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, newport,
1878
1896
                         SECONDARYSOCKET, conn);
1879
1897
    break;
1880
 
  case CURLPROXY_HTTP:
1881
 
    /* do nothing here. handled later. */
1882
 
    break;
1883
1898
  case CURLPROXY_SOCKS4:
1884
1899
    result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1885
1900
                         SECONDARYSOCKET, conn, FALSE);
1888
1903
    result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1889
1904
                         SECONDARYSOCKET, conn, TRUE);
1890
1905
    break;
 
1906
#endif /* CURL_DISABLE_PROXY */
 
1907
  case CURLPROXY_HTTP:
 
1908
  case CURLPROXY_HTTP_1_0:
 
1909
    /* do nothing here. handled later. */
 
1910
    break;
1891
1911
  default:
1892
1912
    failf(data, "unknown proxytype option given");
1893
1913
    result = CURLE_COULDNT_CONNECT;
1894
1914
    break;
1895
1915
  }
1896
 
#ifndef CURL_DISABLE_HTTP
 
1916
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
1897
1917
  if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
1898
1918
    /* FIX: this MUST wait for a proper connect first if 'connected' is
1899
1919
     * FALSE */
1919
1939
    if(CURLE_OK != result)
1920
1940
      return result;
1921
1941
  }
1922
 
#endif   /* CURL_DISABLE_HTTP */
 
1942
#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
1923
1943
 
1924
1944
  state(conn, FTP_STOP); /* this phase is completed */
1925
1945
 
2036
2056
        if(data->info.filetime <= data->set.timevalue) {
2037
2057
          infof(data, "The requested document is not new enough\n");
2038
2058
          ftp->transfer = FTPTRANSFER_NONE; /* mark this to not transfer data */
 
2059
          data->info.timecond = TRUE;
2039
2060
          state(conn, FTP_STOP);
2040
2061
          return CURLE_OK;
2041
2062
        }
2044
2065
        if(data->info.filetime > data->set.timevalue) {
2045
2066
          infof(data, "The requested document is not old enough\n");
2046
2067
          ftp->transfer = FTPTRANSFER_NONE; /* mark this to not transfer data */
 
2068
          data->info.timecond = TRUE;
2047
2069
          state(conn, FTP_STOP);
2048
2070
          return CURLE_OK;
2049
2071
        }
2288
2310
                               SECONDARYSOCKET, ftp->bytecountp);
2289
2311
  state(conn, FTP_STOP);
2290
2312
 
 
2313
  conn->proto.ftpc.pending_resp = TRUE; /* we expect a server response more */
 
2314
 
2291
2315
  return result;
2292
2316
}
2293
2317
 
2400
2424
    if(result)
2401
2425
      return result;
2402
2426
 
 
2427
    conn->proto.ftpc.pending_resp = TRUE; /* we expect a server response more */
2403
2428
    state(conn, FTP_STOP);
2404
2429
  }
2405
2430
  else {
2410
2435
    }
2411
2436
    else {
2412
2437
      failf(data, "RETR response: %03d", ftpcode);
2413
 
      return CURLE_FTP_COULDNT_RETR_FILE;
 
2438
      return instate == FTP_RETR && ftpcode == 550? CURLE_REMOTE_FILE_NOT_FOUND:
 
2439
                                                    CURLE_FTP_COULDNT_RETR_FILE;
2414
2440
    }
2415
2441
  }
2416
2442
 
2539
2565
  struct SessionHandle *data=conn->data;
2540
2566
  int ftpcode;
2541
2567
  struct ftp_conn *ftpc = &conn->proto.ftpc;
2542
 
  static const char * const ftpauth[]  = {
2543
 
    "SSL", "TLS"
2544
 
  };
 
2568
  static const char ftpauth[][4]  = { "SSL", "TLS" };
2545
2569
  size_t nread = 0;
2546
2570
 
2547
2571
  if(ftpc->sendleft) {
2677
2701
      break;
2678
2702
 
2679
2703
    case FTP_PBSZ:
2680
 
      /* FIX: check response code */
2681
 
 
2682
 
      /* For TLS, the data connection can have one of two security levels.
2683
 
 
2684
 
      1) Clear (requested by 'PROT C')
2685
 
 
2686
 
      2)Private (requested by 'PROT P')
2687
 
      */
2688
 
      if(!conn->ssl[SECONDARYSOCKET].use) {
2689
 
        NBFTPSENDF(conn, "PROT %c",
2690
 
                   data->set.ftp_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2691
 
        state(conn, FTP_PROT);
2692
 
      }
2693
 
      else {
2694
 
        result = ftp_state_pwd(conn);
2695
 
        if(result)
2696
 
          return result;
2697
 
      }
 
2704
      NBFTPSENDF(conn, "PROT %c",
 
2705
                 data->set.ftp_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
 
2706
      state(conn, FTP_PROT);
2698
2707
 
2699
2708
      break;
2700
2709
 
2741
2750
 
2742
2751
    case FTP_PWD:
2743
2752
      if(ftpcode == 257) {
2744
 
        char *dir = (char *)malloc(nread+1);
 
2753
        char *dir = malloc(nread+1);
2745
2754
        char *store=dir;
2746
2755
        char *ptr=&data->state.buffer[4];  /* start on the first letter */
2747
2756
 
2840
2849
      break;
2841
2850
 
2842
2851
    case FTP_MKD:
2843
 
      if(ftpcode/100 != 2) {
 
2852
      if((ftpcode/100 != 2) && !ftpc->count3--) {
2844
2853
        /* failure to MKD the dir */
2845
2854
        failf(data, "Failed to MKD dir: %03d", ftpcode);
2846
2855
        return CURLE_REMOTE_ACCESS_DENIED;
3012
3021
  struct SessionHandle *data = conn->data;
3013
3022
  struct FTP *ftp = data->state.proto.ftp;
3014
3023
  if(!ftp) {
3015
 
    ftp = (struct FTP *)calloc(sizeof(struct FTP), 1);
 
3024
    ftp = calloc(sizeof(struct FTP), 1);
3016
3025
    if(!ftp)
3017
3026
      return CURLE_OUT_OF_MEMORY;
3018
3027
 
3069
3078
 
3070
3079
  ftpc->response_time = RESP_TIMEOUT; /* set default response time-out */
3071
3080
 
3072
 
#ifndef CURL_DISABLE_HTTP
 
3081
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
3073
3082
  if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
3074
3083
    /* BLOCKING */
3075
3084
    /* We want "seamless" FTP operations through HTTP proxy tunnel */
3092
3101
    if(CURLE_OK != result)
3093
3102
      return result;
3094
3103
  }
3095
 
#endif   /* CURL_DISABLE_HTTP */
 
3104
#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
3096
3105
 
3097
3106
  if(conn->protocol & PROT_FTPS) {
3098
3107
    /* BLOCKING */
3140
3149
  CURLcode result=CURLE_OK;
3141
3150
  bool was_ctl_valid = ftpc->ctl_valid;
3142
3151
  char *path;
3143
 
  char *path_to_use = data->state.path;
 
3152
  const char *path_to_use = data->state.path;
3144
3153
 
3145
3154
  if(!ftp)
3146
3155
    /* When the easy handle is removed from the multi while libcurl is still
3159
3168
  case CURLE_UPLOAD_FAILED:
3160
3169
  case CURLE_REMOTE_ACCESS_DENIED:
3161
3170
  case CURLE_FILESIZE_EXCEEDED:
 
3171
  case CURLE_REMOTE_FILE_NOT_FOUND:
 
3172
  case CURLE_WRITE_ERROR:
3162
3173
    /* the connection stays alive fine even though this happened */
3163
3174
    /* fall-through */
3164
3175
  case CURLE_OK: /* doesn't affect the control connection's status */
3223
3234
  shutdown(conn->sock[SECONDARYSOCKET],2);  /* SD_BOTH */
3224
3235
#endif
3225
3236
 
3226
 
  if(conn->ssl[SECONDARYSOCKET].use) {
3227
 
    /* The secondary socket is using SSL so we must close down that part first
3228
 
       before we close the socket for real */
3229
 
    Curl_ssl_close(conn, SECONDARYSOCKET);
3230
 
 
3231
 
    /* Note that we keep "use" set to TRUE since that (next) connection is
3232
 
       still requested to use SSL */
 
3237
  if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
 
3238
    if(conn->ssl[SECONDARYSOCKET].use) {
 
3239
      /* The secondary socket is using SSL so we must close down that part first
 
3240
         before we close the socket for real */
 
3241
      Curl_ssl_close(conn, SECONDARYSOCKET);
 
3242
 
 
3243
      /* Note that we keep "use" set to TRUE since that (next) connection is
 
3244
         still requested to use SSL */
 
3245
    }
 
3246
    sclose(conn->sock[SECONDARYSOCKET]);
 
3247
 
 
3248
    conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3233
3249
  }
3234
 
  sclose(conn->sock[SECONDARYSOCKET]);
3235
 
 
3236
 
  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3237
 
 
3238
 
  if((ftp->transfer == FTPTRANSFER_BODY) && !status && !premature) {
 
3250
 
 
3251
  if((ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
 
3252
     ftpc->pending_resp && !premature) {
3239
3253
    /*
3240
3254
     * Let's see what the server says about the transfer we just performed,
3241
3255
     * but lower the timeout as sometimes this connection has died while the
3847
3861
  /* the ftp struct is already inited in ftp_connect() */
3848
3862
  struct FTP *ftp = data->state.proto.ftp;
3849
3863
  struct ftp_conn *ftpc = &conn->proto.ftpc;
3850
 
  size_t dlen;
3851
 
  char *slash_pos;  /* position of the first '/' char in curpos */
3852
 
  char *path_to_use = data->state.path;
3853
 
  char *cur_pos;
 
3864
  const char *slash_pos;  /* position of the first '/' char in curpos */
 
3865
  const char *path_to_use = data->state.path;
 
3866
  const char *cur_pos;
 
3867
  const char *filename = NULL;
3854
3868
 
3855
3869
  cur_pos = path_to_use; /* current position in path. point at the begin
3856
3870
                            of next path component */
3872
3886
    if(data->state.path &&
3873
3887
       data->state.path[0] &&
3874
3888
       (data->state.path[strlen(data->state.path) - 1] != '/') )
3875
 
      ftpc->file = data->state.path;  /* this is a full file path */
3876
 
    else
3877
 
      ftpc->file = NULL;
 
3889
      filename = data->state.path;  /* this is a full file path */
3878
3890
      /*
3879
3891
        ftpc->file is not used anywhere other than for operations on a file.
3880
3892
        In other words, never for directory operations.
3881
 
        So we can safely set it to NULL here and use it as a
 
3893
        So we can safely leave filename as NULL here and use it as a
3882
3894
        argument in dir/file decisions.
3883
3895
      */
3884
3896
    break;
3888
3900
    if(!path_to_use[0]) {
3889
3901
      /* no dir, no file */
3890
3902
      ftpc->dirdepth = 0;
3891
 
      ftpc->file = NULL;
3892
3903
      break;
3893
3904
    }
3894
3905
    slash_pos=strrchr(cur_pos, '/');
3895
3906
    if(slash_pos || !*cur_pos) {
3896
 
      ftpc->dirs = (char **)calloc(1, sizeof(ftpc->dirs[0]));
 
3907
      ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
3897
3908
      if(!ftpc->dirs)
3898
3909
        return CURLE_OUT_OF_MEMORY;
3899
3910
 
3905
3916
        return CURLE_OUT_OF_MEMORY;
3906
3917
      }
3907
3918
      ftpc->dirdepth = 1; /* we consider it to be a single dir */
3908
 
      ftpc->file = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
 
3919
      filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
3909
3920
    }
3910
3921
    else
3911
 
      ftpc->file = cur_pos;  /* this is a file name only */
 
3922
      filename = cur_pos;  /* this is a file name only */
3912
3923
    break;
3913
3924
 
3914
3925
  default: /* allow pretty much anything */
3915
3926
  case FTPFILE_MULTICWD:
3916
3927
    ftpc->dirdepth = 0;
3917
3928
    ftpc->diralloc = 5; /* default dir depth to allocate */
3918
 
    ftpc->dirs = (char **)calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
 
3929
    ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
3919
3930
    if(!ftpc->dirs)
3920
3931
      return CURLE_OUT_OF_MEMORY;
3921
3932
 
3970
3981
        }
3971
3982
      }
3972
3983
    }
3973
 
    ftpc->file = cur_pos;  /* the rest is the file name */
3974
 
  }
 
3984
    filename = cur_pos;  /* the rest is the file name */
 
3985
    break;
 
3986
  } /* switch */
3975
3987
 
3976
 
  if(ftpc->file && *ftpc->file) {
3977
 
    ftpc->file = curl_easy_unescape(conn->data, ftpc->file, 0, NULL);
 
3988
  if(filename && *filename) {
 
3989
    ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
3978
3990
    if(NULL == ftpc->file) {
3979
3991
      freedirs(ftpc);
3980
3992
      failf(data, "no memory");
4000
4012
  if(ftpc->prevpath) {
4001
4013
    /* prevpath is "raw" so we convert the input path before we compare the
4002
4014
       strings */
4003
 
    char *path = curl_easy_unescape(conn->data, data->state.path, 0, NULL);
 
4015
    int dlen;
 
4016
    char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
4004
4017
    if(!path) {
4005
4018
      freedirs(ftpc);
4006
4019
      return CURLE_OUT_OF_MEMORY;
4007
4020
    }
4008
4021
 
4009
 
    dlen = strlen(path) - (ftpc->file?strlen(ftpc->file):0);
4010
 
    if((dlen == strlen(ftpc->prevpath)) &&
4011
 
       curl_strnequal(path, ftpc->prevpath, dlen)) {
 
4022
    dlen -= ftpc->file?strlen(ftpc->file):0;
 
4023
    if((dlen == (int)strlen(ftpc->prevpath)) &&
 
4024
       strnequal(path, ftpc->prevpath, dlen)) {
4012
4025
      infof(data, "Request has same path as previous transfer\n");
4013
4026
      ftpc->cwddone = TRUE;
4014
4027
    }
4150
4163
 
4151
4164
  if(type) {
4152
4165
    *type = 0;                     /* it was in the middle of the hostname */
4153
 
    command = (char) toupper((int) type[6]);
 
4166
    command = Curl_raw_toupper(type[6]);
4154
4167
 
4155
4168
    switch (command) {
4156
4169
    case 'A': /* ASCII mode */
4172
4185
  return CURLE_OK;
4173
4186
}
4174
4187
 
4175
 
#ifdef USE_SSL
4176
 
static CURLcode ftps_setup_connection(struct connectdata * conn)
4177
 
{
4178
 
  struct SessionHandle *data = conn->data;
4179
 
 
4180
 
  conn->ssl[SECONDARYSOCKET].use = data->set.ftp_ssl != CURLUSESSL_CONTROL;
4181
 
  return ftp_setup_connection(conn);
4182
 
}
4183
 
#endif
4184
 
 
4185
4188
#endif /* CURL_DISABLE_FTP */