X-Git-Url: http://sjero.net/git/?p=wget;a=blobdiff_plain;f=src%2Fftp-basic.c;h=7a512c6ed607478ea39373c88196ba773aa07a29;hp=e6a2345f9de672c07a4d8ae1232c3bcc6c6c13bb;hb=HEAD;hpb=0967c21094580317353f0742c4836c5bbea34059
diff --git a/src/ftp-basic.c b/src/ftp-basic.c
index e6a2345f..7a512c6e 100644
--- a/src/ftp-basic.c
+++ b/src/ftp-basic.c
@@ -1,11 +1,13 @@
/* Basic FTP routines.
- Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+ 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
+ Inc.
This file is part of GNU Wget.
GNU Wget is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
GNU Wget is distributed in the hope that it will be useful,
@@ -14,37 +16,28 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Wget; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+along with Wget. If not, see .
-In addition, as a special exception, the Free Software Foundation
-gives permission to link the code of its release of Wget with the
-OpenSSL project's "OpenSSL" library (or with modified versions of it
-that use the same license as the "OpenSSL" library), and distribute
-the linked executables. You must obey the GNU General Public License
-in all respects for all of the code used other than "OpenSSL". If you
-modify this file, you may extend this exception to your version of the
-file, but you are not obligated to do so. If you do not wish to do
-so, delete this exception statement from your version. */
+Additional permission under GNU GPL version 3 section 7
-#include
+If you modify this program, or any covered work, by linking or
+combining it with the OpenSSL project's OpenSSL library (or a
+modified version of that library), containing parts covered by the
+terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
+grants you additional permission to convey the resulting work.
+Corresponding Source for a non-source form of such a combination
+shall include the source code for the parts of OpenSSL used as well
+as that of the covered work. */
+
+#include "wget.h"
#include
#include
#include
#include
-#ifdef HAVE_STRING_H
-# include
-#else
-# include
-#endif
-#ifdef HAVE_UNISTD_H
-# include
-#endif
-#include
-
-#include "wget.h"
+#include
+#include
#include "utils.h"
#include "connect.h"
#include "host.h"
@@ -57,32 +50,45 @@ char ftp_last_respline[128];
/* Get the response of FTP server and allocate enough room to handle
it. and characters are stripped from the line, and the
line is 0-terminated. All the response lines but the last one are
- skipped. The last line is determined as described in RFC959. */
+ skipped. The last line is determined as described in RFC959.
+
+ If the line is successfully read, FTPOK is returned, and *ret_line
+ is assigned a freshly allocated line. Otherwise, FTPRERR is
+ returned, and the value of *ret_line should be ignored. */
+
uerr_t
ftp_response (int fd, char **ret_line)
{
while (1)
{
+ char *p;
char *line = fd_read_line (fd);
if (!line)
- return FTPRERR;
+ return FTPRERR;
+
+ /* Strip trailing CRLF before printing the line, so that
+ quotting doesn't include bogus \012 and \015. */
+ p = strchr (line, '\0');
+ if (p > line && p[-1] == '\n')
+ *--p = '\0';
+ if (p > line && p[-1] == '\r')
+ *--p = '\0';
+
if (opt.server_response)
- logputs (LOG_NOTQUIET, escnonprint (line));
+ logprintf (LOG_NOTQUIET, "%s\n",
+ quotearg_style (escape_quoting_style, line));
else
- DEBUGP (("%s", escnonprint (line)));
- if (ISDIGIT (line[0]) && ISDIGIT (line[1]) && ISDIGIT (line[2])
- && line[3] == ' ')
- {
- char *p = line + strlen (line);
- if (p > line && p[-1] == '\n')
- *--p = '\0';
- if (p > line && p[-1] == '\r')
- *--p = '\0';
- strncpy (ftp_last_respline, line, sizeof (ftp_last_respline));
- ftp_last_respline[sizeof (ftp_last_respline) - 1] = '\0';
- *ret_line = line;
- return FTPOK;
- }
+ DEBUGP (("%s\n", quotearg_style (escape_quoting_style, line)));
+
+ /* The last line of output is the one that begins with "ddd ". */
+ if (c_isdigit (line[0]) && c_isdigit (line[1]) && c_isdigit (line[2])
+ && line[3] == ' ')
+ {
+ strncpy (ftp_last_respline, line, sizeof (ftp_last_respline));
+ ftp_last_respline[sizeof (ftp_last_respline) - 1] = '\0';
+ *ret_line = line;
+ return FTPOK;
+ }
xfree (line);
}
}
@@ -95,7 +101,28 @@ ftp_request (const char *command, const char *value)
{
char *res;
if (value)
- res = concat_strings (command, " ", value, "\r\n", (char *) 0);
+ {
+ /* Check for newlines in VALUE (possibly injected by the %0A URL
+ escape) making the callers inadvertently send multiple FTP
+ commands at once. Without this check an attacker could
+ intentionally redirect to ftp://server/fakedir%0Acommand.../
+ and execute arbitrary FTP command on a remote FTP server. */
+ if (strpbrk (value, "\r\n"))
+ {
+ /* Copy VALUE to the stack and modify CR/LF to space. */
+ char *defanged, *p;
+ STRDUP_ALLOCA (defanged, value);
+ for (p = defanged; *p; p++)
+ if (*p == '\r' || *p == '\n')
+ *p = ' ';
+ DEBUGP (("\nDetected newlines in %s \"%s\"; changing to %s \"%s\"\n",
+ command, quotearg_style (escape_quoting_style, value),
+ command, quotearg_style (escape_quoting_style, defanged)));
+ /* Make VALUE point to the defanged copy of the string. */
+ value = defanged;
+ }
+ res = concat_strings (command, " ", value, "\r\n", (char *) 0);
+ }
else
res = concat_strings (command, "\r\n", (char *) 0);
if (opt.server_response)
@@ -132,7 +159,7 @@ ftp_login (int csock, const char *acc, const char *pass)
xfree (respline);
/* Send USER username. */
request = ftp_request ("USER", acc);
- nwritten = fd_write (csock, request, strlen (request), -1.0);
+ nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
@@ -142,10 +169,7 @@ ftp_login (int csock, const char *acc, const char *pass)
/* Get appropriate response. */
err = ftp_response (csock, &respline);
if (err != FTPOK)
- {
- xfree (respline);
- return err;
- }
+ return err;
/* An unprobable possibility of logging without a password. */
if (*respline == '2')
{
@@ -164,34 +188,34 @@ ftp_login (int csock, const char *acc, const char *pass)
"331 s/key ",
"331 opiekey "
};
- int i;
+ size_t i;
const char *seed = NULL;
for (i = 0; i < countof (skey_head); i++)
{
- int l = strlen (skey_head[i]);
+ int l = strlen (skey_head[i]);
if (0 == strncasecmp (skey_head[i], respline, l))
- {
- seed = respline + l;
- break;
- }
+ {
+ seed = respline + l;
+ break;
+ }
}
if (seed)
{
int skey_sequence = 0;
- /* Extract the sequence from SEED. */
- for (; ISDIGIT (*seed); seed++)
- skey_sequence = 10 * skey_sequence + *seed - '0';
- if (*seed == ' ')
- ++seed;
+ /* Extract the sequence from SEED. */
+ for (; c_isdigit (*seed); seed++)
+ skey_sequence = 10 * skey_sequence + *seed - '0';
+ if (*seed == ' ')
+ ++seed;
else
{
xfree (respline);
return FTPLOGREFUSED;
}
- /* Replace the password with the SKEY response to the
- challenge. */
+ /* Replace the password with the SKEY response to the
+ challenge. */
pass = skey_response (skey_sequence, seed, pass);
}
}
@@ -199,7 +223,7 @@ ftp_login (int csock, const char *acc, const char *pass)
xfree (respline);
/* Send PASS password. */
request = ftp_request ("PASS", pass);
- nwritten = fd_write (csock, request, strlen (request), -1.0);
+ nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
@@ -209,10 +233,7 @@ ftp_login (int csock, const char *acc, const char *pass)
/* Get appropriate response. */
err = ftp_response (csock, &respline);
if (err != FTPOK)
- {
- xfree (respline);
- return err;
- }
+ return err;
if (*respline != '2')
{
xfree (respline);
@@ -224,18 +245,16 @@ ftp_login (int csock, const char *acc, const char *pass)
}
static void
-ip_address_to_port_repr (const ip_address *addr, int port, char *buf,
+ip_address_to_port_repr (const ip_address *addr, int port, char *buf,
size_t buflen)
{
unsigned char *ptr;
- assert (addr != NULL);
- assert (addr->type == IPV4_ADDRESS);
- assert (buf != NULL);
+ assert (addr->family == AF_INET);
/* buf must contain the argument of PORT (of the form a,b,c,d,e,f). */
assert (buflen >= 6 * 4);
- ptr = ADDRESS_IPV4_DATA (addr);
+ ptr = IP_INADDR_DATA (addr);
snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1],
ptr[2], ptr[3], (port & 0xff00) >> 8, port & 0xff);
buf[buflen - 1] = '\0';
@@ -259,7 +278,7 @@ ftp_port (int csock, int *local_sock)
if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
return FTPSYSERR;
- assert (addr.type == IPV4_ADDRESS);
+ assert (addr.family == AF_INET);
/* Setting port to 0 lets the system choose a free port. */
port = 0;
@@ -274,7 +293,7 @@ ftp_port (int csock, int *local_sock)
/* Send PORT request. */
request = ftp_request ("PORT", bytes);
- nwritten = fd_write (csock, request, strlen (request), -1.0);
+ nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
@@ -287,7 +306,6 @@ ftp_port (int csock, int *local_sock)
err = ftp_response (csock, &respline);
if (err != FTPOK)
{
- xfree (respline);
fd_close (*local_sock);
return err;
}
@@ -303,35 +321,32 @@ ftp_port (int csock, int *local_sock)
#ifdef ENABLE_IPV6
static void
-ip_address_to_lprt_repr (const ip_address *addr, int port, char *buf,
+ip_address_to_lprt_repr (const ip_address *addr, int port, char *buf,
size_t buflen)
{
- unsigned char *ptr;
+ unsigned char *ptr = IP_INADDR_DATA (addr);
- assert (addr != NULL);
- assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
- assert (buf != NULL);
/* buf must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
assert (buflen >= 21 * 4);
/* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
- switch (addr->type)
- {
- case IPV4_ADDRESS:
- ptr = ADDRESS_IPV4_DATA (addr);
- snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4,
- ptr[0], ptr[1], ptr[2], ptr[3], 2,
- (port & 0xff00) >> 8, port & 0xff);
- buf[buflen - 1] = '\0';
- break;
- case IPV6_ADDRESS:
- ptr = ADDRESS_IPV6_DATA (addr);
- snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
- 6, 16, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
- ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], 2,
- (port & 0xff00) >> 8, port & 0xff);
- buf[buflen - 1] = '\0';
- break;
+ switch (addr->family)
+ {
+ case AF_INET:
+ snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4,
+ ptr[0], ptr[1], ptr[2], ptr[3], 2,
+ (port & 0xff00) >> 8, port & 0xff);
+ break;
+ case AF_INET6:
+ snprintf (buf, buflen,
+ "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+ 6, 16,
+ ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
+ ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15],
+ 2, (port & 0xff00) >> 8, port & 0xff);
+ break;
+ default:
+ abort ();
}
}
@@ -353,7 +368,7 @@ ftp_lprt (int csock, int *local_sock)
if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
return FTPSYSERR;
- assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
+ assert (addr.family == AF_INET || addr.family == AF_INET6);
/* Setting port to 0 lets the system choose a free port. */
port = 0;
@@ -368,7 +383,7 @@ ftp_lprt (int csock, int *local_sock)
/* Send PORT request. */
request = ftp_request ("LPRT", bytes);
- nwritten = fd_write (csock, request, strlen (request), -1.0);
+ nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
@@ -380,7 +395,6 @@ ftp_lprt (int csock, int *local_sock)
err = ftp_response (csock, &respline);
if (err != FTPOK)
{
- xfree (respline);
fd_close (*local_sock);
return err;
}
@@ -395,22 +409,19 @@ ftp_lprt (int csock, int *local_sock)
}
static void
-ip_address_to_eprt_repr (const ip_address *addr, int port, char *buf,
+ip_address_to_eprt_repr (const ip_address *addr, int port, char *buf,
size_t buflen)
{
int afnum;
- assert (addr != NULL);
- assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
- assert (buf != NULL);
- /* buf must contain the argument of EPRT (of the form |af|addr|port|).
- * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr
+ /* buf must contain the argument of EPRT (of the form |af|addr|port|).
+ * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr
* 1 char for af (1-2) and 5 chars for port (0-65535) */
- assert (buflen >= 4 + INET6_ADDRSTRLEN + 1 + 5);
+ assert (buflen >= 4 + INET6_ADDRSTRLEN + 1 + 5);
/* Construct the argument of EPRT (of the form |af|addr|port|). */
- afnum = (addr->type == IPV4_ADDRESS ? 1 : 2);
- snprintf (buf, buflen, "|%d|%s|%d|", afnum, pretty_print_address (addr), port);
+ afnum = (addr->family == AF_INET ? 1 : 2);
+ snprintf (buf, buflen, "|%d|%s|%d|", afnum, print_address (addr), port);
buf[buflen - 1] = '\0';
}
@@ -425,8 +436,8 @@ ftp_eprt (int csock, int *local_sock)
ip_address addr;
int nwritten;
int port;
- /* Must contain the argument of EPRT (of the form |af|addr|port|).
- * 4 chars for the | separators, ENABLE_IPV6_ADDRSTRLEN chars for addr
+ /* Must contain the argument of EPRT (of the form |af|addr|port|).
+ * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr
* 1 char for af (1-2) and 5 chars for port (0-65535) */
char bytes[4 + INET6_ADDRSTRLEN + 1 + 5 + 1];
@@ -434,8 +445,6 @@ ftp_eprt (int csock, int *local_sock)
if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
return FTPSYSERR;
- assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
-
/* Setting port to 0 lets the system choose a free port. */
port = 0;
@@ -444,12 +453,12 @@ ftp_eprt (int csock, int *local_sock)
if (*local_sock < 0)
return FTPSYSERR;
- /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
+ /* Construct the argument of EPRT (of the form |af|addr|port|). */
ip_address_to_eprt_repr (&addr, port, bytes, sizeof (bytes));
/* Send PORT request. */
request = ftp_request ("EPRT", bytes);
- nwritten = fd_write (csock, request, strlen (request), -1.0);
+ nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
@@ -461,7 +470,6 @@ ftp_eprt (int csock, int *local_sock)
err = ftp_response (csock, &respline);
if (err != FTPOK)
{
- xfree (respline);
fd_close (*local_sock);
return err;
}
@@ -495,7 +503,7 @@ ftp_pasv (int csock, ip_address *addr, int *port)
/* Form the request. */
request = ftp_request ("PASV", NULL);
/* And send it. */
- nwritten = fd_write (csock, request, strlen (request), -1.0);
+ nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
@@ -505,10 +513,7 @@ ftp_pasv (int csock, ip_address *addr, int *port)
/* Get the server response. */
err = ftp_response (csock, &respline);
if (err != FTPOK)
- {
- xfree (respline);
- return err;
- }
+ return err;
if (*respline != '2')
{
xfree (respline);
@@ -516,13 +521,17 @@ ftp_pasv (int csock, ip_address *addr, int *port)
}
/* Parse the request. */
s = respline;
- for (s += 4; *s && !ISDIGIT (*s); s++);
+ for (s += 4; *s && !c_isdigit (*s); s++)
+ ;
if (!*s)
- return FTPINVPASV;
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
for (i = 0; i < 6; i++)
{
tmp[i] = 0;
- for (; ISDIGIT (*s); s++)
+ for (; c_isdigit (*s); s++)
tmp[i] = (*s - '0') + 10 * tmp[i];
if (*s == ',')
s++;
@@ -535,8 +544,8 @@ ftp_pasv (int csock, ip_address *addr, int *port)
}
xfree (respline);
- addr->type = IPV4_ADDRESS;
- memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
+ addr->family = AF_INET;
+ memcpy (IP_INADDR_DATA (addr), tmp, 4);
*port = ((tmp[4] << 8) & 0xff00) + tmp[5];
return FTPOK;
@@ -564,7 +573,7 @@ ftp_lpsv (int csock, ip_address *addr, int *port)
request = ftp_request ("LPSV", NULL);
/* And send it. */
- nwritten = fd_write (csock, request, strlen (request), -1.0);
+ nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
@@ -575,25 +584,26 @@ ftp_lpsv (int csock, ip_address *addr, int *port)
/* Get the server response. */
err = ftp_response (csock, &respline);
if (err != FTPOK)
- {
- xfree (respline);
- return err;
- }
+ return err;
if (*respline != '2')
{
xfree (respline);
return FTPNOPASV;
- }
+ }
/* Parse the response. */
s = respline;
- for (s += 4; *s && !ISDIGIT (*s); s++);
+ for (s += 4; *s && !c_isdigit (*s); s++)
+ ;
if (!*s)
- return FTPINVPASV;
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
/* First, get the address family */
af = 0;
- for (; ISDIGIT (*s); s++)
+ for (; c_isdigit (*s); s++)
af = (*s - '0') + 10 * af;
if (af != 4 && af != 6)
@@ -610,7 +620,7 @@ ftp_lpsv (int csock, ip_address *addr, int *port)
/* Then, get the address length */
addrlen = 0;
- for (; ISDIGIT (*s); s++)
+ for (; c_isdigit (*s); s++)
addrlen = (*s - '0') + 10 * addrlen;
if (!*s || *s++ != ',')
@@ -636,7 +646,7 @@ ftp_lpsv (int csock, ip_address *addr, int *port)
for (i = 0; i < addrlen; i++)
{
tmp[i] = 0;
- for (; ISDIGIT (*s); s++)
+ for (; c_isdigit (*s); s++)
tmp[i] = (*s - '0') + 10 * tmp[i];
if (*s == ',')
s++;
@@ -649,7 +659,7 @@ ftp_lpsv (int csock, ip_address *addr, int *port)
/* Now, get the port length */
portlen = 0;
- for (; ISDIGIT (*s); s++)
+ for (; c_isdigit (*s); s++)
portlen = (*s - '0') + 10 * portlen;
if (!*s || *s++ != ',')
@@ -666,7 +676,7 @@ ftp_lpsv (int csock, ip_address *addr, int *port)
/* Finally, we get the port number */
tmpprt[0] = 0;
- for (; ISDIGIT (*s); s++)
+ for (; c_isdigit (*s); s++)
tmpprt[0] = (*s - '0') + 10 * tmpprt[0];
if (!*s || *s++ != ',')
@@ -676,17 +686,17 @@ ftp_lpsv (int csock, ip_address *addr, int *port)
}
tmpprt[1] = 0;
- for (; ISDIGIT (*s); s++)
+ for (; c_isdigit (*s); s++)
tmpprt[1] = (*s - '0') + 10 * tmpprt[1];
assert (s != NULL);
if (af == 4)
{
- addr->type = IPV4_ADDRESS;
- memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
+ addr->family = AF_INET;
+ memcpy (IP_INADDR_DATA (addr), tmp, 4);
*port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
- DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
+ DEBUGP (("lpsv addr is: %s\n", print_address(addr)));
DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
DEBUGP (("*port is: %d\n", *port));
@@ -694,10 +704,10 @@ ftp_lpsv (int csock, ip_address *addr, int *port)
else
{
assert (af == 6);
- addr->type = IPV6_ADDRESS;
- memcpy (ADDRESS_IPV6_DATA (addr), tmp, 16);
+ addr->family = AF_INET6;
+ memcpy (IP_INADDR_DATA (addr), tmp, 16);
*port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
- DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
+ DEBUGP (("lpsv addr is: %s\n", print_address(addr)));
DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
DEBUGP (("*port is: %d\n", *port));
@@ -726,10 +736,10 @@ ftp_epsv (int csock, ip_address *ip, int *port)
/* Form the request. */
/* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */
- request = ftp_request ("EPSV", (ip->type == IPV4_ADDRESS ? "1" : "2"));
+ request = ftp_request ("EPSV", (ip->family == AF_INET ? "1" : "2"));
/* And send it. */
- nwritten = fd_write (csock, request, strlen (request), -1.0);
+ nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
@@ -740,30 +750,24 @@ ftp_epsv (int csock, ip_address *ip, int *port)
/* Get the server response. */
err = ftp_response (csock, &respline);
if (err != FTPOK)
- {
- xfree (respline);
- return err;
- }
+ return err;
if (*respline != '2')
{
xfree (respline);
return FTPNOPASV;
- }
+ }
assert (respline != NULL);
DEBUGP(("respline is %s\n", respline));
- /* Parse the response. */
- s = respline;
-
/* Skip the useless stuff and get what's inside the parentheses */
start = strchr (respline, '(');
if (start == NULL)
{
xfree (respline);
return FTPINVPASV;
- }
+ }
/* Skip the first two void fields */
s = start + 1;
@@ -772,26 +776,26 @@ ftp_epsv (int csock, ip_address *ip, int *port)
{
xfree (respline);
return FTPINVPASV;
- }
+ }
for (i = 0; i < 2; i++)
{
- if (*s++ != delim)
+ if (*s++ != delim)
{
xfree (respline);
return FTPINVPASV;
- }
+ }
}
/* Finally, get the port number */
- tport = 0;
- for (i = 1; ISDIGIT (*s); s++)
+ tport = 0;
+ for (i = 1; c_isdigit (*s); s++)
{
if (i > 5)
{
xfree (respline);
return FTPINVPASV;
- }
+ }
tport = (*s - '0') + 10 * tport;
}
@@ -800,13 +804,13 @@ ftp_epsv (int csock, ip_address *ip, int *port)
{
xfree (respline);
return FTPINVPASV;
- }
+ }
- if (*s++ != ')')
+ if (*s != ')')
{
xfree (respline);
return FTPINVPASV;
- }
+ }
*port = tport;
@@ -829,7 +833,7 @@ ftp_type (int csock, int type)
stype[1] = 0;
/* Send TYPE request. */
request = ftp_request ("TYPE", stype);
- nwritten = fd_write (csock, request, strlen (request), -1.0);
+ nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
@@ -839,10 +843,7 @@ ftp_type (int csock, int type)
/* Get appropriate response. */
err = ftp_response (csock, &respline);
if (err != FTPOK)
- {
- xfree (respline);
- return err;
- }
+ return err;
if (*respline != '2')
{
xfree (respline);
@@ -864,7 +865,7 @@ ftp_cwd (int csock, const char *dir)
/* Send CWD request. */
request = ftp_request ("CWD", dir);
- nwritten = fd_write (csock, request, strlen (request), -1.0);
+ nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
@@ -874,10 +875,7 @@ ftp_cwd (int csock, const char *dir)
/* Get appropriate response. */
err = ftp_response (csock, &respline);
if (err != FTPOK)
- {
- xfree (respline);
- return err;
- }
+ return err;
if (*respline == '5')
{
xfree (respline);
@@ -902,7 +900,7 @@ ftp_rest (int csock, wgint offset)
uerr_t err;
request = ftp_request ("REST", number_to_static_string (offset));
- nwritten = fd_write (csock, request, strlen (request), -1.0);
+ nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
@@ -912,10 +910,7 @@ ftp_rest (int csock, wgint offset)
/* Get appropriate response. */
err = ftp_response (csock, &respline);
if (err != FTPOK)
- {
- xfree (respline);
- return err;
- }
+ return err;
if (*respline != '3')
{
xfree (respline);
@@ -936,7 +931,7 @@ ftp_retr (int csock, const char *file)
/* Send RETR request. */
request = ftp_request ("RETR", file);
- nwritten = fd_write (csock, request, strlen (request), -1.0);
+ nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
@@ -946,10 +941,7 @@ ftp_retr (int csock, const char *file)
/* Get appropriate response. */
err = ftp_response (csock, &respline);
if (err != FTPOK)
- {
- xfree (respline);
- return err;
- }
+ return err;
if (*respline == '5')
{
xfree (respline);
@@ -968,46 +960,79 @@ ftp_retr (int csock, const char *file)
/* Sends the LIST command to the server. If FILE is NULL, send just
`LIST' (no space). */
uerr_t
-ftp_list (int csock, const char *file)
+ftp_list (int csock, const char *file, bool avoid_list_a, bool avoid_list,
+ bool *list_a_used)
{
char *request, *respline;
int nwritten;
uerr_t err;
+ bool ok = false;
+ size_t i = 0;
- /* Send LIST request. */
- request = ftp_request ("LIST", file);
- nwritten = fd_write (csock, request, strlen (request), -1.0);
- if (nwritten < 0)
- {
- xfree (request);
- return WRITEFAILED;
- }
- xfree (request);
- /* Get appropriate respone. */
- err = ftp_response (csock, &respline);
- if (err != FTPOK)
- {
- xfree (respline);
- return err;
- }
- if (*respline == '5')
- {
- xfree (respline);
- return FTPNSFOD;
- }
- if (*respline != '1')
+ *list_a_used = false;
+
+ /* 2013-10-12 Andrea Urbani (matfanjol)
+ For more information about LIST and "LIST -a" please look at ftp.c,
+ function getftp, text "__LIST_A_EXPLANATION__".
+
+ If somebody changes the following commands, please, checks also the
+ later "i" variable. */
+ const char *list_commands[] = { "LIST -a",
+ "LIST" };
+
+ if (avoid_list_a)
{
- xfree (respline);
- return FTPRERR;
+ i = countof (list_commands)- 1;
+ DEBUGP (("(skipping \"LIST -a\")"));
}
- xfree (respline);
- /* All OK. */
- return FTPOK;
+
+
+ do {
+ /* Send request. */
+ request = ftp_request (list_commands[i], file);
+ nwritten = fd_write (csock, request, strlen (request), -1);
+ if (nwritten < 0)
+ {
+ xfree (request);
+ return WRITEFAILED;
+ }
+ xfree (request);
+ /* Get appropriate response. */
+ err = ftp_response (csock, &respline);
+ if (err == FTPOK)
+ {
+ if (*respline == '5')
+ {
+ err = FTPNSFOD;
+ }
+ else if (*respline == '1')
+ {
+ err = FTPOK;
+ ok = true;
+ /* Which list command was used? */
+ *list_a_used = (i == 0);
+ }
+ else
+ {
+ err = FTPRERR;
+ }
+ xfree (respline);
+ }
+ ++i;
+ if ((avoid_list) && (i == 1))
+ {
+ /* I skip LIST */
+ ++i;
+ DEBUGP (("(skipping \"LIST\")"));
+ }
+ } while (i < countof (list_commands) && !ok);
+
+ return err;
}
/* Sends the SYST command to the server. */
uerr_t
-ftp_syst (int csock, enum stype *server_type)
+ftp_syst (int csock, enum stype *server_type, enum ustype *unix_type)
{
char *request, *respline;
int nwritten;
@@ -1015,7 +1040,7 @@ ftp_syst (int csock, enum stype *server_type)
/* Send SYST request. */
request = ftp_request ("SYST", NULL);
- nwritten = fd_write (csock, request, strlen (request), -1.0);
+ nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
@@ -1026,10 +1051,7 @@ ftp_syst (int csock, enum stype *server_type)
/* Get appropriate response. */
err = ftp_response (csock, &respline);
if (err != FTPOK)
- {
- xfree (respline);
- return err;
- }
+ return err;
if (*respline == '5')
{
xfree (respline);
@@ -1043,12 +1065,25 @@ ftp_syst (int csock, enum stype *server_type)
first word of the server response)? */
request = strtok (NULL, " ");
- if (!strcasecmp (request, "VMS"))
+ *unix_type = UST_OTHER;
+
+ if (request == NULL)
+ *server_type = ST_OTHER;
+ else if (!strcasecmp (request, "VMS"))
*server_type = ST_VMS;
else if (!strcasecmp (request, "UNIX"))
- *server_type = ST_UNIX;
+ {
+ *server_type = ST_UNIX;
+ /* 2013-10-17 Andrea Urbani (matfanjol)
+ I check more in depth the system type */
+ if (!strncasecmp (ftp_last_respline, "215 UNIX Type: L8", 17))
+ *unix_type = UST_TYPE_L8;
+ else if (!strncasecmp (ftp_last_respline,
+ "215 UNIX MultiNet Unix Emulation V5.3(93)", 41))
+ *unix_type = UST_MULTINET;
+ }
else if (!strcasecmp (request, "WINDOWS_NT")
- || !strcasecmp (request, "WINDOWS2000"))
+ || !strcasecmp (request, "WINDOWS2000"))
*server_type = ST_WINNT;
else if (!strcasecmp (request, "MACOS"))
*server_type = ST_MACOS;
@@ -1072,7 +1107,7 @@ ftp_pwd (int csock, char **pwd)
/* Send PWD request. */
request = ftp_request ("PWD", NULL);
- nwritten = fd_write (csock, request, strlen (request), -1.0);
+ nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
@@ -1082,12 +1117,10 @@ ftp_pwd (int csock, char **pwd)
/* Get appropriate response. */
err = ftp_response (csock, &respline);
if (err != FTPOK)
- {
- xfree (respline);
- return err;
- }
+ return err;
if (*respline == '5')
{
+ err:
xfree (respline);
return FTPSRVERR;
}
@@ -1096,6 +1129,10 @@ ftp_pwd (int csock, char **pwd)
and everything following it. */
strtok (respline, "\"");
request = strtok (NULL, "\"");
+ if (!request)
+ /* Treat the malformed response as an error, which the caller has
+ to handle gracefully anyway. */
+ goto err;
/* Has the `pwd' been already allocated? Free! */
xfree_null (*pwd);
@@ -1118,7 +1155,7 @@ ftp_size (int csock, const char *file, wgint *size)
/* Send PWD request. */
request = ftp_request ("SIZE", file);
- nwritten = fd_write (csock, request, strlen (request), -1.0);
+ nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
@@ -1130,15 +1167,14 @@ ftp_size (int csock, const char *file, wgint *size)
err = ftp_response (csock, &respline);
if (err != FTPOK)
{
- xfree (respline);
*size = 0;
return err;
}
if (*respline == '5')
{
- /*
+ /*
* Probably means SIZE isn't supported on this server.
- * Error is nonfatal since SIZE isn't in RFC 959
+ * Error is nonfatal since SIZE isn't in RFC 959
*/
xfree (respline);
*size = 0;
@@ -1149,7 +1185,7 @@ ftp_size (int csock, const char *file, wgint *size)
*size = str_to_wgint (respline + 4, NULL, 10);
if (errno)
{
- /*
+ /*
* Couldn't parse the response for some reason. On the (few)
* tests I've done, the response is 213 with nothing else -
* maybe something a bit more resilient is necessary. It's not a
@@ -1173,7 +1209,7 @@ ftp_process_type (const char *params)
if (params
&& 0 == strncasecmp (params, "type=", 5)
&& params[5] != '\0')
- return TOUPPER (params[5]);
+ return c_toupper (params[5]);
else
return 'I';
}