1999-12-02 02:42:23 -05:00
|
|
|
|
/* Basic FTP routines.
|
2000-11-01 20:50:03 -05:00
|
|
|
|
Copyright (C) 1995, 1996, 1997, 1998, 2000 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
|
|
|
|
|
the Free Software Foundation; either version 2 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
|
2001-05-27 15:35:15 -04:00
|
|
|
|
along with Wget; if not, write to the Free Software
|
2002-05-17 22:16:36 -04:00
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
|
|
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. */
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
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>
|
|
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
|
# include <string.h>
|
|
|
|
|
#else
|
|
|
|
|
# include <strings.h>
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
|
# include <unistd.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
|
|
#include "wget.h"
|
|
|
|
|
#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"
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
|
|
|
|
char ftp_last_respline[128];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
skipped. The last line is determined as described in RFC959. */
|
|
|
|
|
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
|
|
|
|
{
|
2003-11-20 20:48:11 -05:00
|
|
|
|
char *line = fd_read_line (fd);
|
|
|
|
|
if (!line)
|
|
|
|
|
return FTPRERR;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
if (opt.server_response)
|
2005-03-04 14:34:31 -05:00
|
|
|
|
logputs (LOG_NOTQUIET, escnonprint (line));
|
1999-12-02 02:42:23 -05:00
|
|
|
|
else
|
2005-03-04 14:34:31 -05:00
|
|
|
|
DEBUGP (("%s", escnonprint (line)));
|
2003-11-20 20:48:11 -05:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
res = concat_strings (command, " ", value, "\r\n", (char *) 0);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
|
|
/* Get greeting. */
|
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-03-19 12:35:15 -05: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 FTPSRVERR;
|
|
|
|
|
}
|
2000-11-22 11:58:28 -05:00
|
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
/* Send USER username. */
|
|
|
|
|
request = ftp_request ("USER", acc);
|
2003-11-20 20:48:11 -05: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)
|
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
/* 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 "
|
|
|
|
|
};
|
|
|
|
|
int 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
|
|
|
|
{
|
2003-11-01 11:36:43 -05:00
|
|
|
|
int l = strlen (skey_head[i]);
|
|
|
|
|
if (0 == strncasecmp (skey_head[i], respline, l))
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
2003-11-01 11:36:43 -05:00
|
|
|
|
/* Extract the sequence from SEED. */
|
|
|
|
|
for (; ISDIGIT (*seed); seed++)
|
|
|
|
|
skey_sequence = 10 * skey_sequence + *seed - '0';
|
|
|
|
|
if (*seed == ' ')
|
|
|
|
|
++seed;
|
2001-02-13 02:44:59 -05:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
xfree (respline);
|
|
|
|
|
return FTPLOGREFUSED;
|
|
|
|
|
}
|
2003-11-01 11:36:43 -05:00
|
|
|
|
/* Replace the password with the SKEY response to the
|
|
|
|
|
challenge. */
|
|
|
|
|
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);
|
2003-11-20 20:48:11 -05: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)
|
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
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
|
2003-10-30 19:18:08 -05: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;
|
|
|
|
|
|
|
|
|
|
assert (addr != NULL);
|
2003-10-29 18:13:25 -05:00
|
|
|
|
assert (addr->type == IPV4_ADDRESS);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
assert (buf != NULL);
|
|
|
|
|
/* buf must contain the argument of PORT (of the form a,b,c,d,e,f). */
|
|
|
|
|
assert (buflen >= 6 * 4);
|
|
|
|
|
|
2003-10-29 18:13:25 -05:00
|
|
|
|
ptr = ADDRESS_IPV4_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
|
|
|
|
|
2003-10-29 18:13:25 -05:00
|
|
|
|
assert (addr.type == IPV4_ADDRESS);
|
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);
|
2003-11-20 20:48:11 -05: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)
|
|
|
|
|
{
|
|
|
|
|
xfree (respline);
|
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
|
2003-10-30 19:18:08 -05: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)
|
|
|
|
|
{
|
|
|
|
|
unsigned char *ptr;
|
|
|
|
|
|
|
|
|
|
assert (addr != NULL);
|
2003-10-29 18:13:25 -05:00
|
|
|
|
assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
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)
|
|
|
|
|
{
|
2003-10-29 18:13:25 -05:00
|
|
|
|
case IPV4_ADDRESS:
|
|
|
|
|
ptr = ADDRESS_IPV4_DATA (addr);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4,
|
|
|
|
|
ptr[0], ptr[1], ptr[2], ptr[3], 2,
|
2003-10-30 19:18:08 -05:00
|
|
|
|
(port & 0xff00) >> 8, port & 0xff);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
buf[buflen - 1] = '\0';
|
|
|
|
|
break;
|
2003-10-29 18:13:25 -05:00
|
|
|
|
case IPV6_ADDRESS:
|
|
|
|
|
ptr = ADDRESS_IPV6_DATA (addr);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
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,
|
2003-10-30 19:18:08 -05:00
|
|
|
|
(port & 0xff00) >> 8, port & 0xff);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
buf[buflen - 1] = '\0';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
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
|
|
|
|
|
2003-10-29 18:13:25 -05:00
|
|
|
|
assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
|
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);
|
2003-11-20 20:48:11 -05: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)
|
|
|
|
|
{
|
|
|
|
|
xfree (respline);
|
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
|
2003-10-30 19:18:08 -05: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;
|
|
|
|
|
|
|
|
|
|
assert (addr != NULL);
|
2003-10-29 18:13:25 -05:00
|
|
|
|
assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
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
|
|
|
|
|
* 1 char for af (1-2) and 5 chars for port (0-65535) */
|
|
|
|
|
assert (buflen >= 4 + INET6_ADDRSTRLEN + 1 + 5);
|
|
|
|
|
|
|
|
|
|
/* Construct the argument of EPRT (of the form |af|addr|port|). */
|
2003-10-29 18:13:25 -05:00
|
|
|
|
afnum = (addr->type == IPV4_ADDRESS ? 1 : 2);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
snprintf (buf, buflen, "|%d|%s|%d|", afnum, pretty_print_address (addr), port);
|
|
|
|
|
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. */
|
|
|
|
|
uerr_t
|
2003-11-20 20:48:11 -05:00
|
|
|
|
ftp_eprt (int csock, int *local_sock)
|
2003-10-29 13:23:56 -05:00
|
|
|
|
{
|
|
|
|
|
uerr_t err;
|
|
|
|
|
char *request, *respline;
|
|
|
|
|
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 EPRT (of the form |af|addr|port|).
|
|
|
|
|
* 4 chars for the | separators, ENABLE_IPV6_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. */
|
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
|
|
|
|
|
2003-10-29 18:13:25 -05:00
|
|
|
|
assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
|
/* Setting port to 0 lets the system choose a free port. */
|
|
|
|
|
port = 0;
|
2002-01-24 00:45:54 -05:00
|
|
|
|
|
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 LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
|
|
|
|
|
ip_address_to_eprt_repr (&addr, port, bytes, sizeof (bytes));
|
2002-01-24 00:45:54 -05:00
|
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
|
/* Send PORT request. */
|
2003-10-29 13:23:56 -05:00
|
|
|
|
request = ftp_request ("EPRT", bytes);
|
2003-11-20 20:48:11 -05: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);
|
2003-11-20 10:19:59 -05:00
|
|
|
|
fd_close (*local_sock);
|
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)
|
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
|
xfree (respline);
|
2003-11-20 10:19:59 -05:00
|
|
|
|
fd_close (*local_sock);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
if (*respline != '2')
|
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
|
xfree (respline);
|
2003-11-20 10:19:59 -05:00
|
|
|
|
fd_close (*local_sock);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
return FTPPORTERR;
|
|
|
|
|
}
|
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
|
|
|
|
|
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. */
|
2003-11-20 20:48:11 -05: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)
|
|
|
|
|
{
|
|
|
|
|
xfree (respline);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
if (*respline != '2')
|
|
|
|
|
{
|
|
|
|
|
xfree (respline);
|
|
|
|
|
return FTPNOPASV;
|
|
|
|
|
}
|
|
|
|
|
/* Parse the request. */
|
|
|
|
|
s = respline;
|
|
|
|
|
for (s += 4; *s && !ISDIGIT (*s); s++);
|
|
|
|
|
if (!*s)
|
|
|
|
|
return FTPINVPASV;
|
2003-10-29 13:23:56 -05:00
|
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
|
{
|
|
|
|
|
tmp[i] = 0;
|
|
|
|
|
for (; ISDIGIT (*s); s++)
|
|
|
|
|
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
|
|
|
|
|
2003-10-29 18:13:25 -05:00
|
|
|
|
addr->type = IPV4_ADDRESS;
|
|
|
|
|
memcpy (ADDRESS_IPV4_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. */
|
2003-11-20 20:48:11 -05: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)
|
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
if (*respline != '2')
|
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
return FTPNOPASV;
|
2003-10-29 13:23:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse the response. */
|
1999-12-02 02:42:23 -05:00
|
|
|
|
s = respline;
|
|
|
|
|
for (s += 4; *s && !ISDIGIT (*s); s++);
|
|
|
|
|
if (!*s)
|
|
|
|
|
return FTPINVPASV;
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
|
|
/* First, get the address family */
|
|
|
|
|
af = 0;
|
|
|
|
|
for (; ISDIGIT (*s); s++)
|
|
|
|
|
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;
|
|
|
|
|
for (; ISDIGIT (*s); s++)
|
|
|
|
|
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;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
for (; 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;
|
|
|
|
|
for (; ISDIGIT (*s); s++)
|
|
|
|
|
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;
|
|
|
|
|
for (; ISDIGIT (*s); s++)
|
|
|
|
|
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;
|
2002-01-24 00:45:54 -05:00
|
|
|
|
for (; ISDIGIT (*s); s++)
|
2003-10-29 13:23:56 -05:00
|
|
|
|
tmpprt[1] = (*s - '0') + 10 * tmpprt[1];
|
|
|
|
|
|
|
|
|
|
assert (s != NULL);
|
|
|
|
|
|
|
|
|
|
if (af == 4)
|
|
|
|
|
{
|
2003-10-29 18:13:25 -05:00
|
|
|
|
addr->type = IPV4_ADDRESS;
|
|
|
|
|
memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
*port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
|
|
|
|
|
DEBUGP (("lpsv addr is: %s\n", pretty_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));
|
|
|
|
|
}
|
2002-01-24 00:45:54 -05:00
|
|
|
|
else
|
2003-10-29 13:23:56 -05:00
|
|
|
|
{
|
|
|
|
|
assert (af == 6);
|
2003-10-29 18:13:25 -05:00
|
|
|
|
addr->type = IPV6_ADDRESS;
|
|
|
|
|
memcpy (ADDRESS_IPV6_DATA (addr), tmp, 16);
|
2003-10-29 13:23:56 -05:00
|
|
|
|
*port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
|
|
|
|
|
DEBUGP (("lpsv addr is: %s\n", pretty_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));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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. */
|
2003-11-07 21:57:51 -05:00
|
|
|
|
request = ftp_request ("EPSV", (ip->type == IPV4_ADDRESS ? "1" : "2"));
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
|
|
|
|
/* And send it. */
|
2003-11-20 20:48:11 -05: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)
|
|
|
|
|
{
|
|
|
|
|
xfree (respline);
|
|
|
|
|
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;
|
|
|
|
|
delim = *s++;
|
|
|
|
|
if (delim < 33 || delim > 126)
|
2002-01-24 00:45:54 -05:00
|
|
|
|
{
|
|
|
|
|
xfree (respline);
|
|
|
|
|
return FTPINVPASV;
|
2003-10-29 13:23:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 2; i++)
|
|
|
|
|
{
|
|
|
|
|
if (*s++ != delim)
|
|
|
|
|
{
|
|
|
|
|
xfree (respline);
|
|
|
|
|
return FTPINVPASV;
|
|
|
|
|
}
|
2002-01-24 00:45:54 -05:00
|
|
|
|
}
|
|
|
|
|
|
2003-10-29 13:23:56 -05:00
|
|
|
|
/* Finally, get the port number */
|
|
|
|
|
tport = 0;
|
|
|
|
|
for (i = 1; ISDIGIT (*s); s++)
|
|
|
|
|
{
|
|
|
|
|
if (i > 5)
|
|
|
|
|
{
|
|
|
|
|
xfree (respline);
|
|
|
|
|
return FTPINVPASV;
|
|
|
|
|
}
|
|
|
|
|
tport = (*s - '0') + 10 * tport;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make sure that the response terminates correcty */
|
|
|
|
|
if (*s++ != delim)
|
|
|
|
|
{
|
|
|
|
|
xfree (respline);
|
|
|
|
|
return FTPINVPASV;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*s++ != ')')
|
|
|
|
|
{
|
|
|
|
|
xfree (respline);
|
|
|
|
|
return FTPINVPASV;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*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);
|
2003-11-20 20:48:11 -05: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)
|
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
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);
|
2003-11-20 20:48:11 -05: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)
|
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
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));
|
2003-11-20 20:48:11 -05: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)
|
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
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);
|
2003-11-20 20:48:11 -05: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)
|
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
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
|
2003-11-20 20:48:11 -05:00
|
|
|
|
ftp_list (int csock, const char *file)
|
1999-12-02 02:42:23 -05:00
|
|
|
|
{
|
|
|
|
|
char *request, *respline;
|
|
|
|
|
int nwritten;
|
|
|
|
|
uerr_t err;
|
|
|
|
|
|
|
|
|
|
/* Send LIST request. */
|
|
|
|
|
request = ftp_request ("LIST", file);
|
2003-11-20 20:48:11 -05: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 respone. */
|
2003-11-20 20:48:11 -05:00
|
|
|
|
err = ftp_response (csock, &respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
if (err != FTPOK)
|
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
|
xfree (respline);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2000-11-21 11:48:39 -05:00
|
|
|
|
|
|
|
|
|
/* Sends the SYST command to the server. */
|
|
|
|
|
uerr_t
|
2003-11-20 20:48:11 -05:00
|
|
|
|
ftp_syst (int csock, enum stype *server_type)
|
2000-11-21 11:48:39 -05:00
|
|
|
|
{
|
|
|
|
|
char *request, *respline;
|
|
|
|
|
int nwritten;
|
|
|
|
|
uerr_t err;
|
|
|
|
|
|
|
|
|
|
/* Send SYST request. */
|
|
|
|
|
request = ftp_request ("SYST", NULL);
|
2003-11-20 20:48:11 -05: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)
|
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
|
xfree (respline);
|
2000-11-21 11:48:39 -05:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
if (*respline == '5')
|
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
|
xfree (respline);
|
2000-11-21 11:48:39 -05:00
|
|
|
|
return FTPSRVERR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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, " ");
|
|
|
|
|
|
|
|
|
|
if (!strcasecmp (request, "VMS"))
|
2000-12-05 17:29:47 -05:00
|
|
|
|
*server_type = ST_VMS;
|
2001-12-01 16:37:40 -05:00
|
|
|
|
else if (!strcasecmp (request, "UNIX"))
|
|
|
|
|
*server_type = ST_UNIX;
|
2003-11-08 14:20:29 -05:00
|
|
|
|
else if (!strcasecmp (request, "WINDOWS_NT")
|
|
|
|
|
|| !strcasecmp (request, "WINDOWS2000"))
|
2001-12-01 16:37:40 -05:00
|
|
|
|
*server_type = ST_WINNT;
|
|
|
|
|
else if (!strcasecmp (request, "MACOS"))
|
|
|
|
|
*server_type = ST_MACOS;
|
2003-09-18 09:46:17 -04:00
|
|
|
|
else if (!strcasecmp (request, "OS/400"))
|
|
|
|
|
*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
|
|
|
|
|
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);
|
2003-11-20 20:48:11 -05: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)
|
|
|
|
|
{
|
2000-11-22 11:58:28 -05:00
|
|
|
|
xfree (respline);
|
2000-11-21 11:48:39 -05:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
if (*respline == '5')
|
|
|
|
|
{
|
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, "\"");
|
2003-10-29 13:23:56 -05:00
|
|
|
|
|
2000-11-22 11:58:28 -05:00
|
|
|
|
/* Has the `pwd' been already allocated? Free! */
|
2003-11-02 14:56:37 -05:00
|
|
|
|
xfree_null (*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);
|
2003-11-20 20:48:11 -05: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)
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
*/
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* 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')
|
|
|
|
|
return TOUPPER (params[5]);
|
|
|
|
|
else
|
|
|
|
|
return 'I';
|
|
|
|
|
}
|