Revert "Imported Upstream version 7.44.0"
[platform/upstream/curl.git] / lib / ftp.c
index fade092..2f4351e 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -77,7 +77,9 @@
 #include "warnless.h"
 #include "http_proxy.h"
 #include "non-ascii.h"
-#include "curl_printf.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
 
 #include "curl_memory.h"
 /* The last #include file should be: */
@@ -283,17 +285,19 @@ static void freedirs(struct ftp_conn *ftpc)
   int i;
   if(ftpc->dirs) {
     for(i=0; i < ftpc->dirdepth; i++) {
-      free(ftpc->dirs[i]);
-      ftpc->dirs[i]=NULL;
+      if(ftpc->dirs[i]) {
+        free(ftpc->dirs[i]);
+        ftpc->dirs[i]=NULL;
+      }
     }
     free(ftpc->dirs);
     ftpc->dirs = NULL;
     ftpc->dirdepth = 0;
   }
-  Curl_safefree(ftpc->file);
-
-  /* no longer of any use */
-  Curl_safefree(ftpc->newhost);
+  if(ftpc->file) {
+    free(ftpc->file);
+    ftpc->file = NULL;
+  }
 }
 
 /* Returns non-zero if the given string contains CR (\r) or LF (\n),
@@ -1101,7 +1105,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
     if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
       failf(data, "getsockname() failed: %s",
           Curl_strerror(conn, SOCKERRNO) );
-      free(addr);
+      Curl_safefree(addr);
       return CURLE_FTP_PORT_FAILED;
     }
     switch(sa->sa_family) {
@@ -1133,11 +1137,11 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
 
   if(res == NULL) {
     failf(data, "failed to resolve the address provided to PORT: %s", host);
-    free(addr);
+    Curl_safefree(addr);
     return CURLE_FTP_PORT_FAILED;
   }
 
-  free(addr);
+  Curl_safefree(addr);
   host = NULL;
 
   /* step 2, create a socket for the requested address */
@@ -1491,13 +1495,13 @@ static CURLcode ftp_state_list(struct connectdata *conn)
      The other ftp_filemethods will CWD into dir/dir/ first and
      then just do LIST (in that case: nothing to do here)
   */
-  char *cmd, *lstArg, *slashPos;
+  char *cmd,*lstArg,*slashPos;
 
   lstArg = NULL;
   if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
      data->state.path &&
      data->state.path[0] &&
-     strchr(data->state.path, '/')) {
+     strchr(data->state.path,'/')) {
 
     lstArg = strdup(data->state.path);
     if(!lstArg)
@@ -1507,7 +1511,7 @@ static CURLcode ftp_state_list(struct connectdata *conn)
     if(lstArg[strlen(lstArg) - 1] != '/')  {
 
       /* chop off the file part if format is dir/dir/file */
-      slashPos = strrchr(lstArg, '/');
+      slashPos = strrchr(lstArg,'/');
       if(slashPos)
         *(slashPos+1) = '\0';
     }
@@ -1521,13 +1525,16 @@ static CURLcode ftp_state_list(struct connectdata *conn)
                  lstArg? lstArg: "" );
 
   if(!cmd) {
-    free(lstArg);
+    if(lstArg)
+      free(lstArg);
     return CURLE_OUT_OF_MEMORY;
   }
 
   result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
 
-  free(lstArg);
+  if(lstArg)
+    free(lstArg);
+
   free(cmd);
 
   if(result)
@@ -1670,8 +1677,8 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
             BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
 
           size_t actuallyread =
-            data->set.fread_func(data->state.buffer, 1, readthisamountnow,
-                                 data->set.in);
+            conn->fread_func(data->state.buffer, 1, readthisamountnow,
+                             conn->fread_in);
 
           passed += actuallyread;
           if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
@@ -1808,13 +1815,6 @@ static CURLcode ftp_state_quote(struct connectdata *conn,
 static CURLcode ftp_epsv_disable(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-
-  if(conn->bits.ipv6) {
-    /* We can't disable EPSV when doing IPv6, so this is instead a fail */
-    failf(conn->data, "Failed EPSV attempt, exiting\n");
-    return CURLE_FTP_WEIRD_SERVER_REPLY;
-  }
-
   infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
   /* disable it for next transfer */
   conn->bits.ftp_use_epsv = FALSE;
@@ -1887,7 +1887,7 @@ static CURLcode proxy_magic(struct connectdata *conn,
     memset(&http_proxy, 0, sizeof(http_proxy));
     data->req.protop = &http_proxy;
 
-    result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport, TRUE);
+    result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
 
     data->req.protop = ftp_save;
 
@@ -1906,22 +1906,6 @@ static CURLcode proxy_magic(struct connectdata *conn,
   return result;
 }
 
-static char *control_address(struct connectdata *conn)
-{
-  /* Returns the control connection IP address.
-     If a proxy tunnel is used, returns the original host name instead, because
-     the effective control connection address is the proxy address,
-     not the ftp host. */
-  if(conn->bits.tunnel_proxy ||
-     conn->proxytype == CURLPROXY_SOCKS5 ||
-     conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
-     conn->proxytype == CURLPROXY_SOCKS4 ||
-     conn->proxytype == CURLPROXY_SOCKS4A)
-    return conn->host.name;
-
-  return conn->ip_addr_str;
-}
-
 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
                                     int ftpcode)
 {
@@ -1933,9 +1917,6 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
   unsigned short connectport; /* the local port connect() should use! */
   char *str=&data->state.buffer[4];  /* start on the first letter */
 
-  /* if we come here again, make sure the former name is cleared */
-  Curl_safefree(ftpc->newhost);
-
   if((ftpc->count1 == 0) &&
      (ftpcode == 229)) {
     /* positive EPSV response */
@@ -1944,12 +1925,12 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
       unsigned int num;
       char separator[4];
       ptr++;
-      if(5 == sscanf(ptr, "%c%c%c%u%c",
-                     &separator[0],
-                     &separator[1],
-                     &separator[2],
-                     &num,
-                     &separator[3])) {
+      if(5  == sscanf(ptr, "%c%c%c%u%c",
+                      &separator[0],
+                      &separator[1],
+                      &separator[2],
+                      &num,
+                      &separator[3])) {
         const char sep1 = separator[0];
         int i;
 
@@ -1967,9 +1948,19 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
         }
         if(ptr) {
           ftpc->newport = (unsigned short)(num & 0xffff);
-          ftpc->newhost = strdup(control_address(conn));
-          if(!ftpc->newhost)
-            return CURLE_OUT_OF_MEMORY;
+
+          if(conn->bits.tunnel_proxy ||
+             conn->proxytype == CURLPROXY_SOCKS5 ||
+             conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
+             conn->proxytype == CURLPROXY_SOCKS4 ||
+             conn->proxytype == CURLPROXY_SOCKS4A)
+            /* proxy tunnel -> use other host info because ip_addr_str is the
+               proxy address not the ftp host */
+            snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s",
+                     conn->host.name);
+          else
+            /* use the same IP we are already connected to */
+            snprintf(ftpc->newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
         }
       }
       else
@@ -1997,8 +1988,8 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
      */
     while(*str) {
       if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
-                     &ip[0], &ip[1], &ip[2], &ip[3],
-                     &port[0], &port[1]))
+                      &ip[0], &ip[1], &ip[2], &ip[3],
+                      &port[0], &port[1]))
         break;
       str++;
     }
@@ -2010,19 +2001,26 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
 
     /* we got OK from server */
     if(data->set.ftp_skip_ip) {
-      /* told to ignore the remotely given IP but instead use the host we used
+      /* told to ignore the remotely given IP but instead use the one we used
          for the control connection */
-      infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n",
+      infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
             ip[0], ip[1], ip[2], ip[3],
-            conn->host.name);
-      ftpc->newhost = strdup(control_address(conn));
+            conn->ip_addr_str);
+      if(conn->bits.tunnel_proxy ||
+         conn->proxytype == CURLPROXY_SOCKS5 ||
+         conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
+         conn->proxytype == CURLPROXY_SOCKS4 ||
+         conn->proxytype == CURLPROXY_SOCKS4A)
+        /* proxy tunnel -> use other host info because ip_addr_str is the
+           proxy address not the ftp host */
+        snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s", conn->host.name);
+      else
+        snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s",
+                 conn->ip_addr_str);
     }
     else
-      ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
-
-    if(!ftpc->newhost)
-      return CURLE_OUT_OF_MEMORY;
-
+      snprintf(ftpc->newhost, sizeof(ftpc->newhost),
+               "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
     ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
   }
   else if(ftpc->count1 == 0) {
@@ -2073,8 +2071,9 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
   conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
   result = Curl_connecthost(conn, addr);
 
+  Curl_resolv_unlock(data, addr); /* we're done using this address */
+
   if(result) {
-    Curl_resolv_unlock(data, addr); /* we're done using this address */
     if(ftpc->count1 == 0 && ftpcode == 229)
       return ftp_epsv_disable(conn);
 
@@ -2090,9 +2089,8 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
 
   if(data->set.verbose)
     /* this just dumps information about this second connection */
-    ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport);
+    ftp_pasv_verbose(conn, conn->ip_addr, ftpc->newhost, connectport);
 
-  Curl_resolv_unlock(data, addr); /* we're done using this address */
   conn->bits.do_more = TRUE;
   state(conn, FTP_STOP); /* this phase is completed */
 
@@ -2107,9 +2105,7 @@ static CURLcode ftp_state_port_resp(struct connectdata *conn,
   ftpport fcmd = (ftpport)ftpc->count1;
   CURLcode result = CURLE_OK;
 
-  /* The FTP spec tells a positive response should have code 200.
-     Be more permissive here to tolerate deviant servers. */
-  if(ftpcode / 100 != 2) {
+  if(ftpcode != 200) {
     /* the command failed */
 
     if(EPRT == fcmd) {
@@ -3273,7 +3269,8 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
   }
 
   /* now store a copy of the directory we are in */
-  free(ftpc->prevpath);
+  if(ftpc->prevpath)
+    free(ftpc->prevpath);
 
   if(data->set.wildcardmatch) {
     if(data->set.chunk_end && ftpc->file) {
@@ -3322,7 +3319,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
   /* shut down the socket to inform the server we're done */
 
 #ifdef _WIN32_WCE
-  shutdown(conn->sock[SECONDARYSOCKET], 2);  /* SD_BOTH */
+  shutdown(conn->sock[SECONDARYSOCKET],2);  /* SD_BOTH */
 #endif
 
   if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
@@ -3645,7 +3642,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
     if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
       /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
          aren't used so we blank their arguments. TODO: make this nicer */
-      result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0, FALSE);
+      result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
 
       return result;
     }
@@ -3819,7 +3816,7 @@ static void wc_data_dtor(void *ptr)
   struct ftp_wc_tmpdata *tmp = ptr;
   if(tmp)
     Curl_ftp_parselist_data_free(&tmp->parser);
-  free(tmp);
+  Curl_safefree(tmp);
 }
 
 static CURLcode init_wc_data(struct connectdata *conn)
@@ -3873,7 +3870,7 @@ static CURLcode init_wc_data(struct connectdata *conn)
   ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
   if(!ftp_tmp->parser) {
     Curl_safefree(wildcard->pattern);
-    free(ftp_tmp);
+    Curl_safefree(ftp_tmp);
     return CURLE_OUT_OF_MEMORY;
   }
 
@@ -4099,7 +4096,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
   result = Curl_convert_to_network(conn->data, s, write_len);
   /* Curl_convert_to_network calls failf if unsuccessful */
   if(result)
-    return result;
+    return(result);
 
   for(;;) {
 #ifdef HAVE_GSSAPI
@@ -4198,10 +4195,14 @@ static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
   }
 
   freedirs(ftpc);
-  free(ftpc->prevpath);
-  ftpc->prevpath = NULL;
-  free(ftpc->server_os);
-  ftpc->server_os = NULL;
+  if(ftpc->prevpath) {
+    free(ftpc->prevpath);
+    ftpc->prevpath = NULL;
+  }
+  if(ftpc->server_os) {
+    free(ftpc->server_os);
+    ftpc->server_os = NULL;
+  }
 
   Curl_pp_disconnect(pp);