1999-12-02 02:42:23 -05:00
|
|
|
/* Basic FTP routines.
|
2009-09-04 03:13:47 -04:00
|
|
|
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
2015-03-09 11:32:01 -04:00
|
|
|
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014, 2015 Free Software
|
|
|
|
Foundation, Inc.
|
1999-12-02 02:42:23 -05:00
|
|
|
|
2001-05-27 15:35:15 -04:00
|
|
|
This file is part of GNU Wget.
|
1999-12-02 02:42:23 -05:00
|
|
|
|
2001-05-27 15:35:15 -04:00
|
|
|
GNU Wget is free software; you can redistribute it and/or modify
|
1999-12-02 02:42:23 -05:00
|
|
|
it under the terms of the GNU General Public License as published by
|
2007-07-10 01:53:22 -04:00
|
|
|
the Free Software Foundation; either version 3 of the License, or
|
2003-11-20 20:48:11 -05:00
|
|
|
(at your option) any later version.
|
1999-12-02 02:42:23 -05:00
|
|
|
|
2001-05-27 15:35:15 -04:00
|
|
|
GNU Wget is distributed in the hope that it will be useful,
|
1999-12-02 02:42:23 -05:00
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
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
|
2007-07-10 01:53:22 -04:00
|
|
|
along with Wget. If not, see <http://www.gnu.org/licenses/>.
|
2002-05-17 22:16:36 -04:00
|
|
|
|
2007-11-28 03:05:33 -05:00
|
|
|
Additional permission under GNU GPL version 3 section 7
|
|
|
|
|
|
|
|
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. */
|
1999-12-02 02:42:23 -05:00
|
|
|
|
2007-10-18 23:50:40 -04:00
|
|
|
#include "wget.h"
|
1999-12-02 02:42:23 -05:00
|
|
|
|
2003-10-29 13:23:56 -05:00
|
|
|
#include <assert.h>
|
1999-12-02 02:42:23 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2001-11-20 16:01:27 -05:00
|
|
|
#include <errno.h>
|
|
|
|
|
2005-06-19 18:34:58 -04:00
|
|
|
#include <string.h>
|
2010-12-01 07:15:13 -05:00
|
|
|
#include <unistd.h>
|
1999-12-02 02:42:23 -05:00
|
|
|
#include "utils.h"
|
|
|
|
#include "connect.h"
|
|
|
|
#include "host.h"
|
2000-11-21 11:48:39 -05:00
|
|
|
#include "ftp.h"
|
2003-11-20 20:48:11 -05:00
|
|
|
#include "retr.h"
|
2014-11-20 04:52:25 -05:00
|
|
|
#include "c-strcase.h"
|
1999-12-02 02:42:23 -05:00
|
|
|
|
2014-11-20 10:35:34 -05:00
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
/* Get the response of FTP server and allocate enough room to handle
|
|
|
|
it. <CR> and <LF> characters are stripped from the line, and the
|
|
|
|
line is 0-terminated. All the response lines but the last one are
|
2005-05-16 11:19:12 -04:00
|
|
|
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. */
|
2005-05-05 06:10:51 -04:00
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
uerr_t
|
2003-11-20 20:48:11 -05:00
|
|
|
ftp_response (int fd, char **ret_line)
|
1999-12-02 02:42:23 -05:00
|
|
|
{
|
2003-11-20 20:48:11 -05:00
|
|
|
while (1)
|
1999-12-02 02:42:23 -05:00
|
|
|
{
|
2005-05-05 06:10:51 -04:00
|
|
|
char *p;
|
2003-11-20 20:48:11 -05:00
|
|
|
char *line = fd_read_line (fd);
|
|
|
|
if (!line)
|
2007-08-02 23:38:21 -04:00
|
|
|
return FTPRERR;
|
2005-05-05 06:10:51 -04:00
|
|
|
|
|
|
|
/* Strip trailing CRLF before printing the line, so that
|
2008-06-30 14:03:01 -04:00
|
|
|
quotting doesn't include bogus \012 and \015. */
|
2005-05-05 06:10:51 -04:00
|
|
|
p = strchr (line, '\0');
|
|
|
|
if (p > line && p[-1] == '\n')
|
2007-08-02 23:38:21 -04:00
|
|
|
*--p = '\0';
|
2005-05-05 06:10:51 -04:00
|
|
|
if (p > line && p[-1] == '\r')
|
2007-08-02 23:38:21 -04:00
|
|
|
*--p = '\0';
|
2005-05-05 06:10:51 -04:00
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
if (opt.server_response)
|
2009-09-21 23:39:44 -04:00
|
|
|
logprintf (LOG_NOTQUIET, "%s\n",
|
2008-04-25 16:38:51 -04:00
|
|
|
quotearg_style (escape_quoting_style, line));
|
1999-12-02 02:42:23 -05:00
|
|
|
else
|
2008-04-25 16:38:51 -04:00
|
|
|
DEBUGP (("%s\n", quotearg_style (escape_quoting_style, line)));
|
2005-05-05 06:10:51 -04:00
|
|
|
|
|
|
|
/* The last line of output is the one that begins with "ddd ". */
|
2007-10-14 17:46:24 -04:00
|
|
|
if (c_isdigit (line[0]) && c_isdigit (line[1]) && c_isdigit (line[2])
|
2007-08-02 23:38:21 -04:00
|
|
|
&& line[3] == ' ')
|
|
|
|
{
|
|
|
|
*ret_line = line;
|
|
|
|
return FTPOK;
|
|
|
|
}
|
2003-11-20 20:48:11 -05:00
|
|
|
xfree (line);
|
1999-12-02 02:42:23 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns the malloc-ed FTP request, ending with <CR><LF>, printing
|
|
|
|
it if printing is required. If VALUE is NULL, just use
|
|
|
|
command<CR><LF>. */
|
|
|
|
static char *
|
|
|
|
ftp_request (const char *command, const char *value)
|
|
|
|
{
|
2005-03-19 12:23:32 -05:00
|
|
|
char *res;
|
|
|
|
if (value)
|
2005-05-06 21:06:26 -04:00
|
|
|
{
|
|
|
|
/* Check for newlines in VALUE (possibly injected by the %0A URL
|
2007-08-02 23:38:21 -04:00
|
|
|
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. */
|
2005-05-06 21:06:26 -04:00
|
|
|
if (strpbrk (value, "\r\n"))
|
2007-08-02 23:38:21 -04:00
|
|
|
{
|
|
|
|
/* 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",
|
2009-09-21 23:39:44 -04:00
|
|
|
command, quotearg_style (escape_quoting_style, value),
|
2008-04-25 16:38:51 -04:00
|
|
|
command, quotearg_style (escape_quoting_style, defanged)));
|
2007-08-02 23:38:21 -04:00
|
|
|
/* Make VALUE point to the defanged copy of the string. */
|
|
|
|
value = defanged;
|
|
|
|
}
|
2005-05-06 21:06:26 -04:00
|
|
|
res = concat_strings (command, " ", value, "\r\n", (char *) 0);
|
|
|
|
}
|
2005-03-19 12:23:32 -05:00
|
|
|
else
|
|
|
|
res = concat_strings (command, "\r\n", (char *) 0);
|
1999-12-02 02:42:23 -05:00
|
|
|
if (opt.server_response)
|
|
|
|
{
|
|
|
|
/* Hack: don't print out password. */
|
|
|
|
if (strncmp (res, "PASS", 4) != 0)
|
2001-02-13 02:44:59 -05:00
|
|
|
logprintf (LOG_ALWAYS, "--> %s\n", res);
|
1999-12-02 02:42:23 -05:00
|
|
|
else
|
2003-10-29 13:23:56 -05:00
|
|
|
logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n\n");
|
1999-12-02 02:42:23 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
DEBUGP (("\n--> %s\n", res));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2015-08-27 10:32:36 -04:00
|
|
|
uerr_t
|
|
|
|
ftp_greeting (int csock)
|
|
|
|
{
|
|
|
|
uerr_t err = FTPOK;
|
|
|
|
char *response = NULL;
|
|
|
|
|
|
|
|
err = ftp_response (csock, &response);
|
|
|
|
if (err != FTPOK)
|
|
|
|
goto bail;
|
|
|
|
if (*response != '2')
|
|
|
|
err = FTPSRVERR;
|
|
|
|
|
|
|
|
bail:
|
|
|
|
if (response)
|
|
|
|
xfree (response);
|
|
|
|
return err;
|
|
|
|
}
|
1999-12-02 02:42:23 -05:00
|
|
|
/* Sends the USER and PASS commands to the server, to control
|
|
|
|
connection socket csock. */
|
|
|
|
uerr_t
|
2003-11-20 20:48:11 -05:00
|
|
|
ftp_login (int csock, const char *acc, const char *pass)
|
1999-12-02 02:42:23 -05:00
|
|
|
{
|
|
|
|
uerr_t err;
|
|
|
|
char *request, *respline;
|
|
|
|
int nwritten;
|
|
|
|
|
|
|
|
/* Send USER username. */
|
|
|
|
request = ftp_request ("USER", acc);
|
2005-06-19 18:34:58 -04:00
|
|
|
nwritten = fd_write (csock, request, strlen (request), -1);
|
1999-12-02 02:42:23 -05:00
|
|
|
if (nwritten < 0)
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
1999-12-02 02:42:23 -05:00
|
|
|
return WRITEFAILED;
|
|
|
|
}
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
1999-12-02 02:42:23 -05:00
|
|
|
/* Get appropriate response. */
|
2003-11-20 20:48:11 -05:00
|
|
|
err = ftp_response (csock, &respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
if (err != FTPOK)
|
2005-05-16 11:19:12 -04:00
|
|
|
return err;
|
1999-12-02 02:42:23 -05:00
|
|
|
/* An unprobable possibility of logging without a password. */
|
|
|
|
if (*respline == '2')
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
return FTPOK;
|
|
|
|
}
|
|
|
|
/* Else, only response 3 is appropriate. */
|
|
|
|
if (*respline != '3')
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
return FTPLOGREFUSED;
|
|
|
|
}
|
2005-04-06 16:42:22 -04:00
|
|
|
#ifdef ENABLE_OPIE
|
1999-12-02 02:42:23 -05:00
|
|
|
{
|
|
|
|
static const char *skey_head[] = {
|
|
|
|
"331 s/key ",
|
|
|
|
"331 opiekey "
|
|
|
|
};
|
2008-05-31 01:42:36 -04:00
|
|
|
size_t i;
|
2003-11-01 11:36:43 -05:00
|
|
|
const char *seed = NULL;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
2003-09-19 10:08:37 -04:00
|
|
|
for (i = 0; i < countof (skey_head); i++)
|
1999-12-02 02:42:23 -05:00
|
|
|
{
|
2007-08-02 23:38:21 -04:00
|
|
|
int l = strlen (skey_head[i]);
|
2014-11-20 04:52:25 -05:00
|
|
|
if (0 == c_strncasecmp (skey_head[i], respline, l))
|
2007-08-02 23:38:21 -04:00
|
|
|
{
|
|
|
|
seed = respline + l;
|
|
|
|
break;
|
|
|
|
}
|
1999-12-02 02:42:23 -05:00
|
|
|
}
|
2003-11-01 11:36:43 -05:00
|
|
|
if (seed)
|
1999-12-02 02:42:23 -05:00
|
|
|
{
|
2001-02-13 02:44:59 -05:00
|
|
|
int skey_sequence = 0;
|
|
|
|
|
2007-08-02 23:38:21 -04:00
|
|
|
/* Extract the sequence from SEED. */
|
2007-10-14 17:46:24 -04:00
|
|
|
for (; c_isdigit (*seed); seed++)
|
2007-08-02 23:38:21 -04:00
|
|
|
skey_sequence = 10 * skey_sequence + *seed - '0';
|
|
|
|
if (*seed == ' ')
|
|
|
|
++seed;
|
2001-02-13 02:44:59 -05:00
|
|
|
else
|
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPLOGREFUSED;
|
|
|
|
}
|
2007-08-02 23:38:21 -04:00
|
|
|
/* Replace the password with the SKEY response to the
|
|
|
|
challenge. */
|
2003-11-01 11:36:43 -05:00
|
|
|
pass = skey_response (skey_sequence, seed, pass);
|
1999-12-02 02:42:23 -05:00
|
|
|
}
|
|
|
|
}
|
2005-04-06 16:42:22 -04:00
|
|
|
#endif /* ENABLE_OPIE */
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
/* Send PASS password. */
|
|
|
|
request = ftp_request ("PASS", pass);
|
2005-06-19 18:34:58 -04:00
|
|
|
nwritten = fd_write (csock, request, strlen (request), -1);
|
1999-12-02 02:42:23 -05:00
|
|
|
if (nwritten < 0)
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
1999-12-02 02:42:23 -05:00
|
|
|
return WRITEFAILED;
|
|
|
|
}
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
1999-12-02 02:42:23 -05:00
|
|
|
/* Get appropriate response. */
|
2003-11-20 20:48:11 -05:00
|
|
|
err = ftp_response (csock, &respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
if (err != FTPOK)
|
2005-05-16 11:19:12 -04:00
|
|
|
return err;
|
1999-12-02 02:42:23 -05:00
|
|
|
if (*respline != '2')
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
return FTPLOGINC;
|
|
|
|
}
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
/* All OK. */
|
|
|
|
return FTPOK;
|
|
|
|
}
|
|
|
|
|
2003-10-29 13:23:56 -05:00
|
|
|
static void
|
2009-09-21 23:39:44 -04:00
|
|
|
ip_address_to_port_repr (const ip_address *addr, int port, char *buf,
|
2003-10-29 13:23:56 -05:00
|
|
|
size_t buflen)
|
|
|
|
{
|
|
|
|
unsigned char *ptr;
|
|
|
|
|
2005-08-10 09:50:08 -04:00
|
|
|
assert (addr->family == AF_INET);
|
2003-10-29 13:23:56 -05:00
|
|
|
/* buf must contain the argument of PORT (of the form a,b,c,d,e,f). */
|
|
|
|
assert (buflen >= 6 * 4);
|
|
|
|
|
2005-08-10 09:50:08 -04:00
|
|
|
ptr = IP_INADDR_DATA (addr);
|
2003-10-29 13:23:56 -05:00
|
|
|
snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1],
|
2003-10-30 19:18:08 -05:00
|
|
|
ptr[2], ptr[3], (port & 0xff00) >> 8, port & 0xff);
|
2003-10-29 13:23:56 -05:00
|
|
|
buf[buflen - 1] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Bind a port and send the appropriate PORT command to the FTP
|
|
|
|
server. Use acceptport after RETR, to get the socket of data
|
|
|
|
connection. */
|
2002-01-24 00:45:54 -05:00
|
|
|
uerr_t
|
2003-11-20 20:48:11 -05:00
|
|
|
ftp_port (int csock, int *local_sock)
|
2002-01-24 00:45:54 -05:00
|
|
|
{
|
|
|
|
uerr_t err;
|
|
|
|
char *request, *respline;
|
2003-10-29 13:23:56 -05:00
|
|
|
ip_address addr;
|
|
|
|
int nwritten;
|
2003-10-30 19:18:08 -05:00
|
|
|
int port;
|
2003-10-29 13:23:56 -05:00
|
|
|
/* Must contain the argument of PORT (of the form a,b,c,d,e,f). */
|
|
|
|
char bytes[6 * 4 + 1];
|
2002-01-24 00:45:54 -05:00
|
|
|
|
2003-10-29 13:23:56 -05:00
|
|
|
/* Get the address of this side of the connection. */
|
2003-11-20 20:48:11 -05:00
|
|
|
if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
|
2003-11-13 12:05:06 -05:00
|
|
|
return FTPSYSERR;
|
2003-10-29 13:23:56 -05:00
|
|
|
|
2005-08-10 09:50:08 -04:00
|
|
|
assert (addr.family == AF_INET);
|
2002-01-24 00:45:54 -05:00
|
|
|
|
|
|
|
/* Setting port to 0 lets the system choose a free port. */
|
|
|
|
port = 0;
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
/* Bind the port. */
|
2003-11-13 12:05:06 -05:00
|
|
|
*local_sock = bind_local (&addr, &port);
|
|
|
|
if (*local_sock < 0)
|
|
|
|
return FTPSYSERR;
|
2002-01-24 00:45:54 -05:00
|
|
|
|
2003-10-29 13:23:56 -05:00
|
|
|
/* Construct the argument of PORT (of the form a,b,c,d,e,f). */
|
|
|
|
ip_address_to_port_repr (&addr, port, bytes, sizeof (bytes));
|
2002-01-24 00:45:54 -05:00
|
|
|
|
|
|
|
/* Send PORT request. */
|
2003-10-29 13:23:56 -05:00
|
|
|
request = ftp_request ("PORT", bytes);
|
2005-06-19 18:34:58 -04:00
|
|
|
nwritten = fd_write (csock, request, strlen (request), -1);
|
2003-10-29 13:23:56 -05:00
|
|
|
if (nwritten < 0)
|
2002-01-24 00:45:54 -05:00
|
|
|
{
|
|
|
|
xfree (request);
|
2003-11-20 10:19:59 -05:00
|
|
|
fd_close (*local_sock);
|
2002-01-24 00:45:54 -05:00
|
|
|
return WRITEFAILED;
|
|
|
|
}
|
|
|
|
xfree (request);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
2002-01-24 00:45:54 -05:00
|
|
|
/* Get appropriate response. */
|
2003-11-20 20:48:11 -05:00
|
|
|
err = ftp_response (csock, &respline);
|
2002-01-24 00:45:54 -05:00
|
|
|
if (err != FTPOK)
|
|
|
|
{
|
2003-11-20 10:19:59 -05:00
|
|
|
fd_close (*local_sock);
|
2002-01-24 00:45:54 -05:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
if (*respline != '2')
|
|
|
|
{
|
|
|
|
xfree (respline);
|
2003-11-20 10:19:59 -05:00
|
|
|
fd_close (*local_sock);
|
2002-01-24 00:45:54 -05:00
|
|
|
return FTPPORTERR;
|
|
|
|
}
|
|
|
|
xfree (respline);
|
|
|
|
return FTPOK;
|
|
|
|
}
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
#ifdef ENABLE_IPV6
|
|
|
|
static void
|
2009-09-21 23:39:44 -04:00
|
|
|
ip_address_to_lprt_repr (const ip_address *addr, int port, char *buf,
|
2003-10-29 13:23:56 -05:00
|
|
|
size_t buflen)
|
|
|
|
{
|
2005-08-10 09:50:08 -04:00
|
|
|
unsigned char *ptr = IP_INADDR_DATA (addr);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
/* 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). */
|
2009-09-21 23:39:44 -04:00
|
|
|
switch (addr->family)
|
2005-08-10 09:50:08 -04:00
|
|
|
{
|
2009-09-21 23:39:44 -04:00
|
|
|
case AF_INET:
|
|
|
|
snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4,
|
2007-08-02 23:38:21 -04:00
|
|
|
ptr[0], ptr[1], ptr[2], ptr[3], 2,
|
|
|
|
(port & 0xff00) >> 8, port & 0xff);
|
2005-08-10 09:50:08 -04:00
|
|
|
break;
|
2009-09-21 23:39:44 -04:00
|
|
|
case AF_INET6:
|
2005-08-10 09:50:08 -04:00
|
|
|
snprintf (buf, buflen,
|
2007-08-02 23:38:21 -04:00
|
|
|
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
|
|
|
|
6, 16,
|
2009-09-21 23:39:44 -04:00
|
|
|
ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
|
2007-08-02 23:38:21 -04:00
|
|
|
ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15],
|
|
|
|
2, (port & 0xff00) >> 8, port & 0xff);
|
2005-08-10 09:50:08 -04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
abort ();
|
2003-10-29 13:23:56 -05:00
|
|
|
}
|
|
|
|
}
|
2002-01-24 00:45:54 -05:00
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
/* Bind a port and send the appropriate PORT command to the FTP
|
|
|
|
server. Use acceptport after RETR, to get the socket of data
|
|
|
|
connection. */
|
|
|
|
uerr_t
|
2003-11-20 20:48:11 -05:00
|
|
|
ftp_lprt (int csock, int *local_sock)
|
1999-12-02 02:42:23 -05:00
|
|
|
{
|
|
|
|
uerr_t err;
|
2002-01-24 00:45:54 -05:00
|
|
|
char *request, *respline;
|
2003-10-29 13:23:56 -05:00
|
|
|
ip_address addr;
|
1999-12-02 02:42:23 -05:00
|
|
|
int nwritten;
|
2003-10-30 19:18:08 -05:00
|
|
|
int port;
|
2003-10-29 13:23:56 -05:00
|
|
|
/* Must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
|
|
|
|
char bytes[21 * 4 + 1];
|
|
|
|
|
|
|
|
/* Get the address of this side of the connection. */
|
2003-11-20 20:48:11 -05:00
|
|
|
if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
|
2003-11-13 12:05:06 -05:00
|
|
|
return FTPSYSERR;
|
2003-10-29 13:23:56 -05:00
|
|
|
|
2005-08-10 09:50:08 -04:00
|
|
|
assert (addr.family == AF_INET || addr.family == AF_INET6);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
/* Setting port to 0 lets the system choose a free port. */
|
|
|
|
port = 0;
|
|
|
|
|
|
|
|
/* Bind the port. */
|
2003-11-13 12:05:06 -05:00
|
|
|
*local_sock = bind_local (&addr, &port);
|
|
|
|
if (*local_sock < 0)
|
|
|
|
return FTPSYSERR;
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
/* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
|
|
|
|
ip_address_to_lprt_repr (&addr, port, bytes, sizeof (bytes));
|
|
|
|
|
|
|
|
/* Send PORT request. */
|
|
|
|
request = ftp_request ("LPRT", bytes);
|
2005-06-19 18:34:58 -04:00
|
|
|
nwritten = fd_write (csock, request, strlen (request), -1);
|
2003-10-29 13:23:56 -05:00
|
|
|
if (nwritten < 0)
|
2002-01-24 00:45:54 -05:00
|
|
|
{
|
2003-10-29 13:23:56 -05:00
|
|
|
xfree (request);
|
2003-11-20 10:19:59 -05:00
|
|
|
fd_close (*local_sock);
|
2003-10-29 13:23:56 -05:00
|
|
|
return WRITEFAILED;
|
2002-01-24 00:45:54 -05:00
|
|
|
}
|
2003-10-29 13:23:56 -05:00
|
|
|
xfree (request);
|
|
|
|
/* Get appropriate response. */
|
2003-11-20 20:48:11 -05:00
|
|
|
err = ftp_response (csock, &respline);
|
2003-10-29 13:23:56 -05:00
|
|
|
if (err != FTPOK)
|
|
|
|
{
|
2003-11-20 10:19:59 -05:00
|
|
|
fd_close (*local_sock);
|
2003-10-29 13:23:56 -05:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
if (*respline != '2')
|
|
|
|
{
|
|
|
|
xfree (respline);
|
2003-11-20 10:19:59 -05:00
|
|
|
fd_close (*local_sock);
|
2003-10-29 13:23:56 -05:00
|
|
|
return FTPPORTERR;
|
|
|
|
}
|
|
|
|
xfree (respline);
|
|
|
|
return FTPOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-09-21 23:39:44 -04:00
|
|
|
ip_address_to_eprt_repr (const ip_address *addr, int port, char *buf,
|
2003-10-29 13:23:56 -05:00
|
|
|
size_t buflen)
|
|
|
|
{
|
|
|
|
int afnum;
|
|
|
|
|
2009-09-21 23:39:44 -04:00
|
|
|
/* buf must contain the argument of EPRT (of the form |af|addr|port|).
|
|
|
|
* 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr
|
2003-10-29 13:23:56 -05:00
|
|
|
* 1 char for af (1-2) and 5 chars for port (0-65535) */
|
2009-09-21 23:39:44 -04:00
|
|
|
assert (buflen >= 4 + INET6_ADDRSTRLEN + 1 + 5);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
/* Construct the argument of EPRT (of the form |af|addr|port|). */
|
2005-08-10 09:50:08 -04:00
|
|
|
afnum = (addr->family == AF_INET ? 1 : 2);
|
2005-06-30 16:03:18 -04:00
|
|
|
snprintf (buf, buflen, "|%d|%s|%d|", afnum, print_address (addr), port);
|
2003-10-29 13:23:56 -05:00
|
|
|
buf[buflen - 1] = '\0';
|
|
|
|
}
|
|
|
|
|
2015-11-16 18:16:25 -05:00
|
|
|
/* Bind a port and send the appropriate PORT command to the FTP
|
|
|
|
server. Use acceptport after RETR, to get the socket of data
|
|
|
|
connection. */
|
|
|
|
uerr_t
|
|
|
|
ftp_eprt (int csock, int *local_sock)
|
|
|
|
{
|
|
|
|
uerr_t err;
|
|
|
|
char *request, *respline;
|
|
|
|
ip_address addr;
|
|
|
|
int nwritten;
|
|
|
|
int port;
|
|
|
|
/* 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];
|
|
|
|
|
|
|
|
/* Get the address of this side of the connection. */
|
|
|
|
if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
|
|
|
|
return FTPSYSERR;
|
|
|
|
|
|
|
|
/* Setting port to 0 lets the system choose a free port. */
|
|
|
|
port = 0;
|
|
|
|
|
|
|
|
/* Bind the port. */
|
|
|
|
*local_sock = bind_local (&addr, &port);
|
|
|
|
if (*local_sock < 0)
|
|
|
|
return FTPSYSERR;
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
if (nwritten < 0)
|
|
|
|
{
|
|
|
|
xfree (request);
|
|
|
|
fd_close (*local_sock);
|
|
|
|
return WRITEFAILED;
|
|
|
|
}
|
|
|
|
xfree (request);
|
|
|
|
/* Get appropriate response. */
|
|
|
|
err = ftp_response (csock, &respline);
|
|
|
|
if (err != FTPOK)
|
|
|
|
{
|
|
|
|
fd_close (*local_sock);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
if (*respline != '2')
|
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
fd_close (*local_sock);
|
|
|
|
return FTPPORTERR;
|
|
|
|
}
|
|
|
|
xfree (respline);
|
|
|
|
return FTPOK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-08-27 10:32:36 -04:00
|
|
|
#ifdef HAVE_SSL
|
|
|
|
/*
|
|
|
|
* The following three functions defined into this #ifdef block
|
|
|
|
* wrap the extended FTP commands defined in RFC 2228 (FTP Security Extensions).
|
|
|
|
* Currently, only FTPS is supported, so these functions are only compiled when SSL
|
|
|
|
* support is available, because there's no point in using FTPS when there's no SSL.
|
|
|
|
* Shall someone add new secure FTP protocols in the future, feel free to remove this
|
|
|
|
* #ifdef, or add new constants to it.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sends an AUTH command as defined by RFC 2228,
|
|
|
|
* deriving its argument from the scheme. For example, if the provided scheme
|
|
|
|
* is SCHEME_FTPS, the command sent will be "AUTH TLS". Currently, this is the only
|
|
|
|
* scheme supported, so this function will return FTPNOAUTH when supplied a different
|
|
|
|
* one. It will also return FTPNOAUTH if the target server does not support FTPS.
|
|
|
|
*/
|
|
|
|
uerr_t
|
|
|
|
ftp_auth (int csock, enum url_scheme scheme)
|
|
|
|
{
|
|
|
|
uerr_t err = 0;
|
|
|
|
int written = 0;
|
|
|
|
char *request = NULL, *response = NULL;
|
|
|
|
|
|
|
|
if (scheme == SCHEME_FTPS)
|
|
|
|
{
|
|
|
|
request = ftp_request ("AUTH", "TLS");
|
|
|
|
written = fd_write (csock, request, strlen (request), -1);
|
|
|
|
if (written < 0)
|
|
|
|
{
|
|
|
|
err = WRITEFAILED;
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
err = ftp_response (csock, &response);
|
|
|
|
if (err != FTPOK)
|
|
|
|
goto bail;
|
|
|
|
if (*response != '2')
|
|
|
|
err = FTPNOAUTH;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
err = FTPNOAUTH;
|
|
|
|
|
|
|
|
bail:
|
|
|
|
xfree (request);
|
|
|
|
xfree (response);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
uerr_t
|
|
|
|
ftp_pbsz (int csock, int pbsz)
|
|
|
|
{
|
|
|
|
uerr_t err = 0;
|
|
|
|
int written = 0;
|
|
|
|
char spbsz[5];
|
|
|
|
char *request = NULL, *response = NULL;
|
|
|
|
|
|
|
|
snprintf (spbsz, 5, "%d", pbsz);
|
|
|
|
request = ftp_request ("PBSZ", spbsz);
|
|
|
|
written = fd_write (csock, request, strlen (request), -1);
|
|
|
|
if (written < 0)
|
|
|
|
{
|
|
|
|
err = WRITEFAILED;
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = ftp_response (csock, &response);
|
|
|
|
if (err != FTPOK)
|
|
|
|
goto bail;
|
|
|
|
if (*response != '2')
|
|
|
|
err = FTPNOPBSZ;
|
|
|
|
|
|
|
|
bail:
|
|
|
|
xfree (request);
|
|
|
|
xfree (response);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
uerr_t
|
|
|
|
ftp_prot (int csock, enum prot_level prot)
|
|
|
|
{
|
|
|
|
uerr_t err = 0;
|
|
|
|
int written = 0;
|
|
|
|
char *request = NULL, *response = NULL;
|
|
|
|
/* value must be a single character value */
|
|
|
|
char value[2];
|
|
|
|
|
|
|
|
value[0] = prot;
|
|
|
|
value[1] = '\0';
|
|
|
|
|
|
|
|
request = ftp_request ("PROT", value);
|
|
|
|
written = fd_write (csock, request, strlen (request), -1);
|
|
|
|
if (written < 0)
|
|
|
|
{
|
|
|
|
err = WRITEFAILED;
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = ftp_response (csock, &response);
|
|
|
|
if (err != FTPOK)
|
|
|
|
goto bail;
|
|
|
|
if (*response != '2')
|
|
|
|
err = FTPNOPROT;
|
|
|
|
|
|
|
|
bail:
|
|
|
|
xfree (request);
|
|
|
|
xfree (response);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
#endif /* HAVE_SSL */
|
|
|
|
|
2003-10-29 13:23:56 -05:00
|
|
|
/* Similar to ftp_port, but uses `PASV' to initiate the passive FTP
|
|
|
|
transfer. Reads the response from server and parses it. Reads the
|
|
|
|
host and port addresses and returns them. */
|
2002-01-24 00:45:54 -05:00
|
|
|
uerr_t
|
2003-11-20 20:48:11 -05:00
|
|
|
ftp_pasv (int csock, ip_address *addr, int *port)
|
2002-01-24 00:45:54 -05:00
|
|
|
{
|
2003-10-29 13:23:56 -05:00
|
|
|
char *request, *respline, *s;
|
|
|
|
int nwritten, i;
|
|
|
|
uerr_t err;
|
|
|
|
unsigned char tmp[6];
|
|
|
|
|
|
|
|
assert (addr != NULL);
|
|
|
|
assert (port != NULL);
|
|
|
|
|
2005-04-01 19:41:04 -05:00
|
|
|
xzero (*addr);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
/* Form the request. */
|
|
|
|
request = ftp_request ("PASV", NULL);
|
|
|
|
/* And send it. */
|
2005-06-19 18:34:58 -04:00
|
|
|
nwritten = fd_write (csock, request, strlen (request), -1);
|
2003-10-29 13:23:56 -05:00
|
|
|
if (nwritten < 0)
|
2002-01-24 00:45:54 -05:00
|
|
|
{
|
|
|
|
xfree (request);
|
|
|
|
return WRITEFAILED;
|
|
|
|
}
|
2003-10-29 13:23:56 -05:00
|
|
|
xfree (request);
|
2002-01-24 00:45:54 -05:00
|
|
|
/* Get the server response. */
|
2003-11-20 20:48:11 -05:00
|
|
|
err = ftp_response (csock, &respline);
|
2002-01-24 00:45:54 -05:00
|
|
|
if (err != FTPOK)
|
2005-05-16 11:19:12 -04:00
|
|
|
return err;
|
2002-01-24 00:45:54 -05:00
|
|
|
if (*respline != '2')
|
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPNOPASV;
|
|
|
|
}
|
|
|
|
/* Parse the request. */
|
|
|
|
s = respline;
|
2007-10-14 17:46:24 -04:00
|
|
|
for (s += 4; *s && !c_isdigit (*s); s++)
|
2005-07-06 21:08:52 -04:00
|
|
|
;
|
2002-01-24 00:45:54 -05:00
|
|
|
if (!*s)
|
2012-04-21 06:08:45 -04:00
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
|
|
|
}
|
2003-10-29 13:23:56 -05:00
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
{
|
|
|
|
tmp[i] = 0;
|
2007-10-14 17:46:24 -04:00
|
|
|
for (; c_isdigit (*s); s++)
|
2003-10-29 13:23:56 -05:00
|
|
|
tmp[i] = (*s - '0') + 10 * tmp[i];
|
|
|
|
if (*s == ',')
|
|
|
|
s++;
|
|
|
|
else if (i < 5)
|
|
|
|
{
|
|
|
|
/* When on the last number, anything can be a terminator. */
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
|
|
|
}
|
|
|
|
}
|
2002-01-24 00:45:54 -05:00
|
|
|
xfree (respline);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
2005-08-10 09:50:08 -04:00
|
|
|
addr->family = AF_INET;
|
|
|
|
memcpy (IP_INADDR_DATA (addr), tmp, 4);
|
2003-10-29 13:23:56 -05:00
|
|
|
*port = ((tmp[4] << 8) & 0xff00) + tmp[5];
|
|
|
|
|
2002-01-24 00:45:54 -05:00
|
|
|
return FTPOK;
|
|
|
|
}
|
|
|
|
|
2003-10-29 13:23:56 -05:00
|
|
|
#ifdef ENABLE_IPV6
|
|
|
|
/* Similar to ftp_lprt, but uses `LPSV' to initiate the passive FTP
|
1999-12-02 02:42:23 -05:00
|
|
|
transfer. Reads the response from server and parses it. Reads the
|
|
|
|
host and port addresses and returns them. */
|
|
|
|
uerr_t
|
2003-11-20 20:48:11 -05:00
|
|
|
ftp_lpsv (int csock, ip_address *addr, int *port)
|
1999-12-02 02:42:23 -05:00
|
|
|
{
|
|
|
|
char *request, *respline, *s;
|
2003-10-29 13:23:56 -05:00
|
|
|
int nwritten, i, af, addrlen, portlen;
|
1999-12-02 02:42:23 -05:00
|
|
|
uerr_t err;
|
2003-10-29 13:23:56 -05:00
|
|
|
unsigned char tmp[16];
|
|
|
|
unsigned char tmpprt[2];
|
|
|
|
|
|
|
|
assert (addr != NULL);
|
|
|
|
assert (port != NULL);
|
|
|
|
|
2005-04-01 19:41:04 -05:00
|
|
|
xzero (*addr);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
|
|
/* Form the request. */
|
2003-10-29 13:23:56 -05:00
|
|
|
request = ftp_request ("LPSV", NULL);
|
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
/* And send it. */
|
2005-06-19 18:34:58 -04:00
|
|
|
nwritten = fd_write (csock, request, strlen (request), -1);
|
1999-12-02 02:42:23 -05:00
|
|
|
if (nwritten < 0)
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
1999-12-02 02:42:23 -05:00
|
|
|
return WRITEFAILED;
|
|
|
|
}
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
/* Get the server response. */
|
2003-11-20 20:48:11 -05:00
|
|
|
err = ftp_response (csock, &respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
if (err != FTPOK)
|
2005-05-16 11:19:12 -04:00
|
|
|
return err;
|
1999-12-02 02:42:23 -05:00
|
|
|
if (*respline != '2')
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
return FTPNOPASV;
|
2009-09-21 23:39:44 -04:00
|
|
|
}
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
/* Parse the response. */
|
1999-12-02 02:42:23 -05:00
|
|
|
s = respline;
|
2007-10-14 17:46:24 -04:00
|
|
|
for (s += 4; *s && !c_isdigit (*s); s++)
|
2005-07-06 21:08:52 -04:00
|
|
|
;
|
1999-12-02 02:42:23 -05:00
|
|
|
if (!*s)
|
2012-04-21 06:08:45 -04:00
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
|
|
|
}
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
/* First, get the address family */
|
|
|
|
af = 0;
|
2007-10-14 17:46:24 -04:00
|
|
|
for (; c_isdigit (*s); s++)
|
2003-10-29 13:23:56 -05:00
|
|
|
af = (*s - '0') + 10 * af;
|
|
|
|
|
|
|
|
if (af != 4 && af != 6)
|
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!*s || *s++ != ',')
|
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then, get the address length */
|
|
|
|
addrlen = 0;
|
2007-10-14 17:46:24 -04:00
|
|
|
for (; c_isdigit (*s); s++)
|
2003-10-29 13:23:56 -05:00
|
|
|
addrlen = (*s - '0') + 10 * addrlen;
|
|
|
|
|
|
|
|
if (!*s || *s++ != ',')
|
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addrlen > 16)
|
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((af == 4 && addrlen != 4)
|
|
|
|
|| (af == 6 && addrlen != 16))
|
1999-12-02 02:42:23 -05:00
|
|
|
{
|
2003-10-29 13:23:56 -05:00
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now, we get the actual address */
|
|
|
|
for (i = 0; i < addrlen; i++)
|
|
|
|
{
|
|
|
|
tmp[i] = 0;
|
2007-10-14 17:46:24 -04:00
|
|
|
for (; c_isdigit (*s); s++)
|
2003-10-29 13:23:56 -05:00
|
|
|
tmp[i] = (*s - '0') + 10 * tmp[i];
|
1999-12-02 02:42:23 -05:00
|
|
|
if (*s == ',')
|
2001-02-13 02:44:59 -05:00
|
|
|
s++;
|
2002-01-24 00:45:54 -05:00
|
|
|
else
|
2001-02-13 02:44:59 -05:00
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
|
|
|
}
|
1999-12-02 02:42:23 -05:00
|
|
|
}
|
2002-01-24 00:45:54 -05:00
|
|
|
|
2003-10-29 13:23:56 -05:00
|
|
|
/* Now, get the port length */
|
|
|
|
portlen = 0;
|
2007-10-14 17:46:24 -04:00
|
|
|
for (; c_isdigit (*s); s++)
|
2003-10-29 13:23:56 -05:00
|
|
|
portlen = (*s - '0') + 10 * portlen;
|
|
|
|
|
|
|
|
if (!*s || *s++ != ',')
|
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (portlen > 2)
|
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finally, we get the port number */
|
|
|
|
tmpprt[0] = 0;
|
2007-10-14 17:46:24 -04:00
|
|
|
for (; c_isdigit (*s); s++)
|
2003-10-29 13:23:56 -05:00
|
|
|
tmpprt[0] = (*s - '0') + 10 * tmpprt[0];
|
2002-01-24 00:45:54 -05:00
|
|
|
|
2003-10-29 13:23:56 -05:00
|
|
|
if (!*s || *s++ != ',')
|
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmpprt[1] = 0;
|
2007-10-14 17:46:24 -04:00
|
|
|
for (; c_isdigit (*s); s++)
|
2003-10-29 13:23:56 -05:00
|
|
|
tmpprt[1] = (*s - '0') + 10 * tmpprt[1];
|
|
|
|
|
|
|
|
assert (s != NULL);
|
|
|
|
|
|
|
|
if (af == 4)
|
|
|
|
{
|
2005-08-10 09:50:08 -04:00
|
|
|
addr->family = AF_INET;
|
|
|
|
memcpy (IP_INADDR_DATA (addr), tmp, 4);
|
2003-10-29 13:23:56 -05:00
|
|
|
*port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
|
2005-06-30 16:03:18 -04:00
|
|
|
DEBUGP (("lpsv addr is: %s\n", print_address(addr)));
|
2003-10-29 13:23:56 -05:00
|
|
|
DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
|
|
|
|
DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
|
|
|
|
DEBUGP (("*port is: %d\n", *port));
|
|
|
|
}
|
2002-01-24 00:45:54 -05:00
|
|
|
else
|
2003-10-29 13:23:56 -05:00
|
|
|
{
|
|
|
|
assert (af == 6);
|
2005-08-10 09:50:08 -04:00
|
|
|
addr->family = AF_INET6;
|
|
|
|
memcpy (IP_INADDR_DATA (addr), tmp, 16);
|
2003-10-29 13:23:56 -05:00
|
|
|
*port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
|
2005-06-30 16:03:18 -04:00
|
|
|
DEBUGP (("lpsv addr is: %s\n", print_address(addr)));
|
2003-10-29 13:23:56 -05:00
|
|
|
DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
|
|
|
|
DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
|
|
|
|
DEBUGP (("*port is: %d\n", *port));
|
|
|
|
}
|
|
|
|
|
|
|
|
xfree (respline);
|
|
|
|
return FTPOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Similar to ftp_eprt, but uses `EPSV' to initiate the passive FTP
|
|
|
|
transfer. Reads the response from server and parses it. Reads the
|
|
|
|
host and port addresses and returns them. */
|
|
|
|
uerr_t
|
2003-11-20 20:48:11 -05:00
|
|
|
ftp_epsv (int csock, ip_address *ip, int *port)
|
2003-10-29 13:23:56 -05:00
|
|
|
{
|
|
|
|
char *request, *respline, *start, delim, *s;
|
|
|
|
int nwritten, i;
|
|
|
|
uerr_t err;
|
2003-10-30 19:18:08 -05:00
|
|
|
int tport;
|
2003-10-29 13:23:56 -05:00
|
|
|
|
2003-10-30 19:18:08 -05:00
|
|
|
assert (ip != NULL);
|
2003-10-29 13:23:56 -05:00
|
|
|
assert (port != NULL);
|
|
|
|
|
2003-11-07 21:57:51 -05:00
|
|
|
/* IP already contains the IP address of the control connection's
|
|
|
|
peer, so we don't need to call socket_ip_address here. */
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
/* Form the request. */
|
|
|
|
/* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */
|
2005-08-10 09:50:08 -04:00
|
|
|
request = ftp_request ("EPSV", (ip->family == AF_INET ? "1" : "2"));
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
/* And send it. */
|
2005-06-19 18:34:58 -04:00
|
|
|
nwritten = fd_write (csock, request, strlen (request), -1);
|
2003-10-29 13:23:56 -05:00
|
|
|
if (nwritten < 0)
|
|
|
|
{
|
|
|
|
xfree (request);
|
|
|
|
return WRITEFAILED;
|
|
|
|
}
|
|
|
|
xfree (request);
|
|
|
|
|
|
|
|
/* Get the server response. */
|
2003-11-20 20:48:11 -05:00
|
|
|
err = ftp_response (csock, &respline);
|
2003-10-29 13:23:56 -05:00
|
|
|
if (err != FTPOK)
|
2005-05-16 11:19:12 -04:00
|
|
|
return err;
|
2003-10-29 13:23:56 -05:00
|
|
|
if (*respline != '2')
|
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPNOPASV;
|
2009-09-21 23:39:44 -04:00
|
|
|
}
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
assert (respline != NULL);
|
|
|
|
|
|
|
|
DEBUGP(("respline is %s\n", respline));
|
|
|
|
|
|
|
|
/* Skip the useless stuff and get what's inside the parentheses */
|
|
|
|
start = strchr (respline, '(');
|
|
|
|
if (start == NULL)
|
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
2009-09-21 23:39:44 -04:00
|
|
|
}
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
/* Skip the first two void fields */
|
|
|
|
s = start + 1;
|
|
|
|
delim = *s++;
|
|
|
|
if (delim < 33 || delim > 126)
|
2002-01-24 00:45:54 -05:00
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
2009-09-21 23:39:44 -04:00
|
|
|
}
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
for (i = 0; i < 2; i++)
|
|
|
|
{
|
2009-09-21 23:39:44 -04:00
|
|
|
if (*s++ != delim)
|
2003-10-29 13:23:56 -05:00
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
2009-09-21 23:39:44 -04:00
|
|
|
}
|
2002-01-24 00:45:54 -05:00
|
|
|
}
|
|
|
|
|
2003-10-29 13:23:56 -05:00
|
|
|
/* Finally, get the port number */
|
2014-11-19 08:35:40 -05:00
|
|
|
for (tport = 0, i = 0; i < 5 && c_isdigit (*s); i++, s++)
|
2003-10-29 13:23:56 -05:00
|
|
|
tport = (*s - '0') + 10 * tport;
|
2014-11-19 08:35:40 -05:00
|
|
|
|
2003-10-29 13:23:56 -05:00
|
|
|
/* Make sure that the response terminates correcty */
|
|
|
|
if (*s++ != delim)
|
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
2009-09-21 23:39:44 -04:00
|
|
|
}
|
2003-10-29 13:23:56 -05:00
|
|
|
|
2010-10-15 21:04:25 -04:00
|
|
|
if (*s != ')')
|
2003-10-29 13:23:56 -05:00
|
|
|
{
|
|
|
|
xfree (respline);
|
|
|
|
return FTPINVPASV;
|
2009-09-21 23:39:44 -04:00
|
|
|
}
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
*port = tport;
|
|
|
|
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
return FTPOK;
|
|
|
|
}
|
2003-10-29 13:23:56 -05:00
|
|
|
#endif
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
|
|
/* Sends the TYPE request to the server. */
|
|
|
|
uerr_t
|
2003-11-20 20:48:11 -05:00
|
|
|
ftp_type (int csock, int type)
|
1999-12-02 02:42:23 -05:00
|
|
|
{
|
|
|
|
char *request, *respline;
|
|
|
|
int nwritten;
|
|
|
|
uerr_t err;
|
|
|
|
char stype[2];
|
|
|
|
|
|
|
|
/* Construct argument. */
|
|
|
|
stype[0] = type;
|
|
|
|
stype[1] = 0;
|
|
|
|
/* Send TYPE request. */
|
|
|
|
request = ftp_request ("TYPE", stype);
|
2005-06-19 18:34:58 -04:00
|
|
|
nwritten = fd_write (csock, request, strlen (request), -1);
|
1999-12-02 02:42:23 -05:00
|
|
|
if (nwritten < 0)
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
1999-12-02 02:42:23 -05:00
|
|
|
return WRITEFAILED;
|
|
|
|
}
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
1999-12-02 02:42:23 -05:00
|
|
|
/* Get appropriate response. */
|
2003-11-20 20:48:11 -05:00
|
|
|
err = ftp_response (csock, &respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
if (err != FTPOK)
|
2005-05-16 11:19:12 -04:00
|
|
|
return err;
|
1999-12-02 02:42:23 -05:00
|
|
|
if (*respline != '2')
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
return FTPUNKNOWNTYPE;
|
|
|
|
}
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
/* All OK. */
|
|
|
|
return FTPOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Changes the working directory by issuing a CWD command to the
|
|
|
|
server. */
|
|
|
|
uerr_t
|
2003-11-20 20:48:11 -05:00
|
|
|
ftp_cwd (int csock, const char *dir)
|
1999-12-02 02:42:23 -05:00
|
|
|
{
|
|
|
|
char *request, *respline;
|
|
|
|
int nwritten;
|
|
|
|
uerr_t err;
|
|
|
|
|
|
|
|
/* Send CWD request. */
|
|
|
|
request = ftp_request ("CWD", dir);
|
2005-06-19 18:34:58 -04:00
|
|
|
nwritten = fd_write (csock, request, strlen (request), -1);
|
1999-12-02 02:42:23 -05:00
|
|
|
if (nwritten < 0)
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
1999-12-02 02:42:23 -05:00
|
|
|
return WRITEFAILED;
|
|
|
|
}
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
1999-12-02 02:42:23 -05:00
|
|
|
/* Get appropriate response. */
|
2003-11-20 20:48:11 -05:00
|
|
|
err = ftp_response (csock, &respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
if (err != FTPOK)
|
2005-05-16 11:19:12 -04:00
|
|
|
return err;
|
1999-12-02 02:42:23 -05:00
|
|
|
if (*respline == '5')
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
return FTPNSFOD;
|
|
|
|
}
|
|
|
|
if (*respline != '2')
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
return FTPRERR;
|
|
|
|
}
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
/* All OK. */
|
|
|
|
return FTPOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sends REST command to the FTP server. */
|
|
|
|
uerr_t
|
2005-02-23 17:21:04 -05:00
|
|
|
ftp_rest (int csock, wgint offset)
|
1999-12-02 02:42:23 -05:00
|
|
|
{
|
|
|
|
char *request, *respline;
|
|
|
|
int nwritten;
|
|
|
|
uerr_t err;
|
|
|
|
|
2005-02-23 17:21:04 -05:00
|
|
|
request = ftp_request ("REST", number_to_static_string (offset));
|
2005-06-19 18:34:58 -04:00
|
|
|
nwritten = fd_write (csock, request, strlen (request), -1);
|
1999-12-02 02:42:23 -05:00
|
|
|
if (nwritten < 0)
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
1999-12-02 02:42:23 -05:00
|
|
|
return WRITEFAILED;
|
|
|
|
}
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
1999-12-02 02:42:23 -05:00
|
|
|
/* Get appropriate response. */
|
2003-11-20 20:48:11 -05:00
|
|
|
err = ftp_response (csock, &respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
if (err != FTPOK)
|
2005-05-16 11:19:12 -04:00
|
|
|
return err;
|
1999-12-02 02:42:23 -05:00
|
|
|
if (*respline != '3')
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
return FTPRESTFAIL;
|
|
|
|
}
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
/* All OK. */
|
|
|
|
return FTPOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sends RETR command to the FTP server. */
|
|
|
|
uerr_t
|
2003-11-20 20:48:11 -05:00
|
|
|
ftp_retr (int csock, const char *file)
|
1999-12-02 02:42:23 -05:00
|
|
|
{
|
|
|
|
char *request, *respline;
|
|
|
|
int nwritten;
|
|
|
|
uerr_t err;
|
|
|
|
|
|
|
|
/* Send RETR request. */
|
|
|
|
request = ftp_request ("RETR", file);
|
2005-06-19 18:34:58 -04:00
|
|
|
nwritten = fd_write (csock, request, strlen (request), -1);
|
1999-12-02 02:42:23 -05:00
|
|
|
if (nwritten < 0)
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
1999-12-02 02:42:23 -05:00
|
|
|
return WRITEFAILED;
|
|
|
|
}
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
1999-12-02 02:42:23 -05:00
|
|
|
/* Get appropriate response. */
|
2003-11-20 20:48:11 -05:00
|
|
|
err = ftp_response (csock, &respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
if (err != FTPOK)
|
2005-05-16 11:19:12 -04:00
|
|
|
return err;
|
1999-12-02 02:42:23 -05:00
|
|
|
if (*respline == '5')
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
return FTPNSFOD;
|
|
|
|
}
|
|
|
|
if (*respline != '1')
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
return FTPRERR;
|
|
|
|
}
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
/* All OK. */
|
|
|
|
return FTPOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sends the LIST command to the server. If FILE is NULL, send just
|
|
|
|
`LIST' (no space). */
|
|
|
|
uerr_t
|
2013-10-23 01:30:14 -04:00
|
|
|
ftp_list (int csock, const char *file, bool avoid_list_a, bool avoid_list,
|
|
|
|
bool *list_a_used)
|
1999-12-02 02:42:23 -05:00
|
|
|
{
|
|
|
|
char *request, *respline;
|
|
|
|
int nwritten;
|
|
|
|
uerr_t err;
|
2006-03-09 08:50:03 -05:00
|
|
|
bool ok = false;
|
2008-05-31 01:42:36 -04:00
|
|
|
size_t i = 0;
|
2013-10-23 01:30:14 -04:00
|
|
|
|
|
|
|
/* 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. */
|
2014-11-20 03:51:35 -05:00
|
|
|
static const char *list_commands[] = {
|
|
|
|
"LIST -a",
|
|
|
|
"LIST"
|
|
|
|
};
|
|
|
|
|
|
|
|
*list_a_used = false;
|
2006-03-09 08:50:03 -05:00
|
|
|
|
2013-10-23 01:30:14 -04:00
|
|
|
if (avoid_list_a)
|
|
|
|
{
|
|
|
|
i = countof (list_commands)- 1;
|
|
|
|
DEBUGP (("(skipping \"LIST -a\")"));
|
|
|
|
}
|
|
|
|
|
2008-04-22 17:48:36 -04:00
|
|
|
|
2006-03-09 08:50:03 -05:00
|
|
|
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;
|
|
|
|
}
|
2007-08-02 23:38:21 -04:00
|
|
|
else if (*respline == '1')
|
2006-03-09 08:50:03 -05:00
|
|
|
{
|
|
|
|
err = FTPOK;
|
|
|
|
ok = true;
|
2013-10-23 01:30:14 -04:00
|
|
|
/* Which list command was used? */
|
|
|
|
*list_a_used = (i == 0);
|
2006-03-09 08:50:03 -05:00
|
|
|
}
|
2009-09-21 23:39:44 -04:00
|
|
|
else
|
2006-03-09 08:50:03 -05:00
|
|
|
{
|
2007-08-02 23:38:21 -04:00
|
|
|
err = FTPRERR;
|
2006-03-09 08:50:03 -05:00
|
|
|
}
|
|
|
|
xfree (respline);
|
|
|
|
}
|
|
|
|
++i;
|
2013-10-23 01:30:14 -04:00
|
|
|
if ((avoid_list) && (i == 1))
|
|
|
|
{
|
|
|
|
/* I skip LIST */
|
|
|
|
++i;
|
|
|
|
DEBUGP (("(skipping \"LIST\")"));
|
|
|
|
}
|
2006-03-09 08:50:03 -05:00
|
|
|
} while (i < countof (list_commands) && !ok);
|
2009-09-21 23:39:44 -04:00
|
|
|
|
2006-03-09 08:50:03 -05:00
|
|
|
return err;
|
1999-12-02 02:42:23 -05:00
|
|
|
}
|
2000-11-21 11:48:39 -05:00
|
|
|
|
|
|
|
/* Sends the SYST command to the server. */
|
|
|
|
uerr_t
|
2013-10-23 01:30:14 -04:00
|
|
|
ftp_syst (int csock, enum stype *server_type, enum ustype *unix_type)
|
2000-11-21 11:48:39 -05:00
|
|
|
{
|
|
|
|
char *request, *respline;
|
|
|
|
int nwritten;
|
|
|
|
uerr_t err;
|
2014-06-09 03:40:37 -04:00
|
|
|
char *ftp_last_respline;
|
2000-11-21 11:48:39 -05:00
|
|
|
|
|
|
|
/* Send SYST request. */
|
|
|
|
request = ftp_request ("SYST", NULL);
|
2005-06-19 18:34:58 -04:00
|
|
|
nwritten = fd_write (csock, request, strlen (request), -1);
|
2000-11-21 11:48:39 -05:00
|
|
|
if (nwritten < 0)
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
2000-11-21 11:48:39 -05:00
|
|
|
return WRITEFAILED;
|
|
|
|
}
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
2001-12-01 16:37:40 -05:00
|
|
|
|
2000-11-21 11:48:39 -05:00
|
|
|
/* Get appropriate response. */
|
2003-11-20 20:48:11 -05:00
|
|
|
err = ftp_response (csock, &respline);
|
2000-11-21 11:48:39 -05:00
|
|
|
if (err != FTPOK)
|
2005-05-16 11:19:12 -04:00
|
|
|
return err;
|
2000-11-21 11:48:39 -05:00
|
|
|
if (*respline == '5')
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
2000-11-21 11:48:39 -05:00
|
|
|
return FTPSRVERR;
|
|
|
|
}
|
|
|
|
|
2014-06-09 03:40:37 -04:00
|
|
|
ftp_last_respline = strdup (respline);
|
|
|
|
|
2000-11-21 11:48:39 -05:00
|
|
|
/* Skip the number (215, but 200 (!!!) in case of VMS) */
|
|
|
|
strtok (respline, " ");
|
2003-10-29 13:23:56 -05:00
|
|
|
|
2000-11-21 11:48:39 -05:00
|
|
|
/* Which system type has been reported (we are interested just in the
|
|
|
|
first word of the server response)? */
|
|
|
|
request = strtok (NULL, " ");
|
|
|
|
|
2013-10-23 01:30:14 -04:00
|
|
|
*unix_type = UST_OTHER;
|
|
|
|
|
2007-01-09 09:37:03 -05:00
|
|
|
if (request == NULL)
|
|
|
|
*server_type = ST_OTHER;
|
2014-11-20 04:52:25 -05:00
|
|
|
else if (!c_strcasecmp (request, "VMS"))
|
2000-12-05 17:29:47 -05:00
|
|
|
*server_type = ST_VMS;
|
2014-11-20 04:52:25 -05:00
|
|
|
else if (!c_strcasecmp (request, "UNIX"))
|
2013-10-23 01:30:14 -04:00
|
|
|
{
|
|
|
|
*server_type = ST_UNIX;
|
|
|
|
/* 2013-10-17 Andrea Urbani (matfanjol)
|
|
|
|
I check more in depth the system type */
|
2014-11-20 04:52:25 -05:00
|
|
|
if (!c_strncasecmp (ftp_last_respline, "215 UNIX Type: L8", 17))
|
2013-10-23 01:30:14 -04:00
|
|
|
*unix_type = UST_TYPE_L8;
|
2014-11-20 04:52:25 -05:00
|
|
|
else if (!c_strncasecmp (ftp_last_respline,
|
2013-10-23 01:30:14 -04:00
|
|
|
"215 UNIX MultiNet Unix Emulation V5.3(93)", 41))
|
|
|
|
*unix_type = UST_MULTINET;
|
|
|
|
}
|
2014-11-20 04:52:25 -05:00
|
|
|
else if (!c_strcasecmp (request, "WINDOWS_NT")
|
|
|
|
|| !c_strcasecmp (request, "WINDOWS2000"))
|
2001-12-01 16:37:40 -05:00
|
|
|
*server_type = ST_WINNT;
|
2014-11-20 04:52:25 -05:00
|
|
|
else if (!c_strcasecmp (request, "MACOS"))
|
2001-12-01 16:37:40 -05:00
|
|
|
*server_type = ST_MACOS;
|
2014-11-20 04:52:25 -05:00
|
|
|
else if (!c_strcasecmp (request, "OS/400"))
|
2003-09-18 09:46:17 -04:00
|
|
|
*server_type = ST_OS400;
|
2000-11-21 11:48:39 -05:00
|
|
|
else
|
2001-12-01 16:37:40 -05:00
|
|
|
*server_type = ST_OTHER;
|
2000-11-21 11:48:39 -05:00
|
|
|
|
2014-06-09 03:40:37 -04:00
|
|
|
xfree (ftp_last_respline);
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
2000-11-21 11:48:39 -05:00
|
|
|
/* All OK. */
|
|
|
|
return FTPOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sends the PWD command to the server. */
|
|
|
|
uerr_t
|
2003-11-20 20:48:11 -05:00
|
|
|
ftp_pwd (int csock, char **pwd)
|
2000-11-21 11:48:39 -05:00
|
|
|
{
|
|
|
|
char *request, *respline;
|
|
|
|
int nwritten;
|
|
|
|
uerr_t err;
|
|
|
|
|
|
|
|
/* Send PWD request. */
|
|
|
|
request = ftp_request ("PWD", NULL);
|
2005-06-19 18:34:58 -04:00
|
|
|
nwritten = fd_write (csock, request, strlen (request), -1);
|
2000-11-21 11:48:39 -05:00
|
|
|
if (nwritten < 0)
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
2000-11-21 11:48:39 -05:00
|
|
|
return WRITEFAILED;
|
|
|
|
}
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (request);
|
2000-11-21 11:48:39 -05:00
|
|
|
/* Get appropriate response. */
|
2003-11-20 20:48:11 -05:00
|
|
|
err = ftp_response (csock, &respline);
|
2000-11-21 11:48:39 -05:00
|
|
|
if (err != FTPOK)
|
2005-05-16 11:19:12 -04:00
|
|
|
return err;
|
2000-11-21 11:48:39 -05:00
|
|
|
if (*respline == '5')
|
|
|
|
{
|
2005-06-15 16:11:50 -04:00
|
|
|
err:
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
2000-11-21 11:48:39 -05:00
|
|
|
return FTPSRVERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Skip the number (257), leading citation mark, trailing citation mark
|
|
|
|
and everything following it. */
|
|
|
|
strtok (respline, "\"");
|
|
|
|
request = strtok (NULL, "\"");
|
2005-06-15 16:11:50 -04:00
|
|
|
if (!request)
|
|
|
|
/* Treat the malformed response as an error, which the caller has
|
|
|
|
to handle gracefully anyway. */
|
|
|
|
goto err;
|
2003-10-29 13:23:56 -05:00
|
|
|
|
2000-11-22 11:58:28 -05:00
|
|
|
/* Has the `pwd' been already allocated? Free! */
|
2014-11-29 11:54:20 -05:00
|
|
|
xfree (*pwd);
|
2000-11-21 11:48:39 -05:00
|
|
|
|
|
|
|
*pwd = xstrdup (request);
|
|
|
|
|
2000-11-22 11:58:28 -05:00
|
|
|
xfree (respline);
|
2000-11-21 11:48:39 -05:00
|
|
|
/* All OK. */
|
|
|
|
return FTPOK;
|
|
|
|
}
|
2001-11-21 19:24:28 -05:00
|
|
|
|
2001-11-20 16:01:27 -05:00
|
|
|
/* Sends the SIZE command to the server, and returns the value in 'size'.
|
|
|
|
* If an error occurs, size is set to zero. */
|
|
|
|
uerr_t
|
2005-02-23 17:21:04 -05:00
|
|
|
ftp_size (int csock, const char *file, wgint *size)
|
2001-11-20 16:01:27 -05:00
|
|
|
{
|
|
|
|
char *request, *respline;
|
|
|
|
int nwritten;
|
|
|
|
uerr_t err;
|
|
|
|
|
|
|
|
/* Send PWD request. */
|
|
|
|
request = ftp_request ("SIZE", file);
|
2005-06-19 18:34:58 -04:00
|
|
|
nwritten = fd_write (csock, request, strlen (request), -1);
|
2001-11-20 16:01:27 -05:00
|
|
|
if (nwritten < 0)
|
|
|
|
{
|
|
|
|
xfree (request);
|
|
|
|
*size = 0;
|
|
|
|
return WRITEFAILED;
|
|
|
|
}
|
|
|
|
xfree (request);
|
|
|
|
/* Get appropriate response. */
|
2003-11-20 20:48:11 -05:00
|
|
|
err = ftp_response (csock, &respline);
|
2001-11-20 16:01:27 -05:00
|
|
|
if (err != FTPOK)
|
|
|
|
{
|
|
|
|
*size = 0;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
if (*respline == '5')
|
|
|
|
{
|
2009-09-21 23:39:44 -04:00
|
|
|
/*
|
2001-11-20 16:01:27 -05:00
|
|
|
* Probably means SIZE isn't supported on this server.
|
2009-09-21 23:39:44 -04:00
|
|
|
* Error is nonfatal since SIZE isn't in RFC 959
|
2001-11-20 16:01:27 -05:00
|
|
|
*/
|
|
|
|
xfree (respline);
|
|
|
|
*size = 0;
|
|
|
|
return FTPOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
errno = 0;
|
2005-02-23 17:21:04 -05:00
|
|
|
*size = str_to_wgint (respline + 4, NULL, 10);
|
|
|
|
if (errno)
|
2001-11-20 16:01:27 -05:00
|
|
|
{
|
2009-09-21 23:39:44 -04:00
|
|
|
/*
|
2001-11-20 16:01:27 -05:00
|
|
|
* Couldn't parse the response for some reason. On the (few)
|
|
|
|
* tests I've done, the response is 213 <SIZE> with nothing else -
|
|
|
|
* maybe something a bit more resilient is necessary. It's not a
|
|
|
|
* fatal error, however.
|
|
|
|
*/
|
|
|
|
xfree (respline);
|
|
|
|
*size = 0;
|
|
|
|
return FTPOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
xfree (respline);
|
|
|
|
/* All OK. */
|
|
|
|
return FTPOK;
|
|
|
|
}
|
2001-11-21 19:24:28 -05:00
|
|
|
|
|
|
|
/* If URL's params are of the form "type=X", return character X.
|
|
|
|
Otherwise, return 'I' (the default type). */
|
|
|
|
char
|
|
|
|
ftp_process_type (const char *params)
|
|
|
|
{
|
|
|
|
if (params
|
|
|
|
&& 0 == strncasecmp (params, "type=", 5)
|
|
|
|
&& params[5] != '\0')
|
2007-10-14 17:46:24 -04:00
|
|
|
return c_toupper (params[5]);
|
2001-11-21 19:24:28 -05:00
|
|
|
else
|
|
|
|
return 'I';
|
|
|
|
}
|