make it more AF-neutral and v6-capable
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@6631 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
@@ -34,14 +34,17 @@
|
|||||||
#include "ftp_locl.h"
|
#include "ftp_locl.h"
|
||||||
RCSID ("$Id$");
|
RCSID ("$Id$");
|
||||||
|
|
||||||
struct sockaddr_in hisctladdr;
|
struct sockaddr_storage hisctladdr_ss;
|
||||||
struct sockaddr_in data_addr;
|
struct sockaddr *hisctladdr = (struct sockaddr *)&hisctladdr_ss;
|
||||||
|
struct sockaddr_storage data_addr_ss;
|
||||||
|
struct sockaddr *data_addr = (struct sockaddr *)&data_addr_ss;
|
||||||
|
struct sockaddr_storage myctladdr_ss;
|
||||||
|
struct sockaddr *myctladdr = (struct sockaddr *)&myctladdr_ss;
|
||||||
int data = -1;
|
int data = -1;
|
||||||
int abrtflag = 0;
|
int abrtflag = 0;
|
||||||
jmp_buf ptabort;
|
jmp_buf ptabort;
|
||||||
int ptabflg;
|
int ptabflg;
|
||||||
int ptflag = 0;
|
int ptflag = 0;
|
||||||
struct sockaddr_in myctladdr;
|
|
||||||
off_t restart_point = 0;
|
off_t restart_point = 0;
|
||||||
|
|
||||||
|
|
||||||
@@ -50,77 +53,76 @@ FILE *cin, *cout;
|
|||||||
typedef void (*sighand) (int);
|
typedef void (*sighand) (int);
|
||||||
|
|
||||||
char *
|
char *
|
||||||
hookup (char *host, int port)
|
hookup (const char *host, int port)
|
||||||
{
|
{
|
||||||
struct hostent *hp = 0;
|
struct hostent *hp = NULL;
|
||||||
int s, len;
|
int s, len;
|
||||||
static char hostnamebuf[MaxHostNameLen];
|
static char hostnamebuf[MaxHostNameLen];
|
||||||
|
int error;
|
||||||
|
int af;
|
||||||
|
char **h;
|
||||||
|
int ret;
|
||||||
|
|
||||||
memset (&hisctladdr, 0, sizeof (hisctladdr));
|
#ifdef HAVE_IPV6
|
||||||
if (inet_aton (host, &hisctladdr.sin_addr)) {
|
if (hp == NULL)
|
||||||
hisctladdr.sin_family = AF_INET;
|
hp = getipnodebyname (host, AF_INET6, 0, &error);
|
||||||
strcpy_truncate (hostnamebuf, host, sizeof (hostnamebuf));
|
#endif
|
||||||
} else {
|
if (hp == NULL)
|
||||||
hp = gethostbyname (host);
|
hp = getipnodebyname (host, AF_INET, 0, &error);
|
||||||
if (hp == NULL) {
|
|
||||||
warnx("%s: %s", host, hstrerror(h_errno));
|
if (hp == NULL) {
|
||||||
code = -1;
|
warnx ("%s: %s", host, hstrerror(error));
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
hisctladdr.sin_family = hp->h_addrtype;
|
|
||||||
memmove(&hisctladdr.sin_addr,
|
|
||||||
hp->h_addr_list[0],
|
|
||||||
sizeof(hisctladdr.sin_addr));
|
|
||||||
strcpy_truncate (hostnamebuf, hp->h_name, sizeof (hostnamebuf));
|
|
||||||
}
|
|
||||||
hostname = hostnamebuf;
|
|
||||||
s = socket (hisctladdr.sin_family, SOCK_STREAM, 0);
|
|
||||||
if (s < 0) {
|
|
||||||
warn ("socket");
|
|
||||||
code = -1;
|
code = -1;
|
||||||
return (0);
|
return NULL;
|
||||||
}
|
}
|
||||||
hisctladdr.sin_port = port;
|
strcpy_truncate (hostnamebuf, hp->h_name, sizeof(hostnamebuf));
|
||||||
while (connect (s, (struct sockaddr *) & hisctladdr, sizeof (hisctladdr)) < 0) {
|
hostname = hostnamebuf;
|
||||||
if (hp && hp->h_addr_list[1]) {
|
af = hisctladdr->sa_family = hp->h_addrtype;
|
||||||
int oerrno = errno;
|
|
||||||
char *ia;
|
|
||||||
|
|
||||||
ia = inet_ntoa (hisctladdr.sin_addr);
|
for (h = hp->h_addr_list;
|
||||||
errno = oerrno;
|
*h != NULL;
|
||||||
warn ("connect to address %s", ia);
|
++h) {
|
||||||
hp->h_addr_list++;
|
|
||||||
memmove (&hisctladdr.sin_addr,
|
s = socket (af, SOCK_STREAM, 0);
|
||||||
hp->h_addr_list[0],
|
if (s < 0) {
|
||||||
sizeof (hisctladdr.sin_addr));
|
warn ("socket");
|
||||||
fprintf (stdout, "Trying %s...\n",
|
code = -1;
|
||||||
inet_ntoa (hisctladdr.sin_addr));
|
freehostent (hp);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_set_address_and_port (hisctladdr, *h, port);
|
||||||
|
|
||||||
|
ret = connect (s, hisctladdr, socket_sockaddr_size(hisctladdr));
|
||||||
|
if (ret < 0) {
|
||||||
|
char addr[256];
|
||||||
|
|
||||||
|
if (inet_ntop (af, socket_get_address(hisctladdr),
|
||||||
|
addr, sizeof(addr)) == NULL)
|
||||||
|
strcpy_truncate (addr, "unknown address",
|
||||||
|
sizeof(addr));
|
||||||
|
warn ("connect %s", addr);
|
||||||
close (s);
|
close (s);
|
||||||
s = socket (hisctladdr.sin_family, SOCK_STREAM, 0);
|
|
||||||
if (s < 0) {
|
|
||||||
warn ("socket");
|
|
||||||
code = -1;
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
warn ("connect");
|
break;
|
||||||
code = -1;
|
|
||||||
goto bad;
|
|
||||||
}
|
}
|
||||||
len = sizeof (myctladdr);
|
freehostent (hp);
|
||||||
if (getsockname (s, (struct sockaddr *) & myctladdr, &len) < 0) {
|
if (ret < 0) {
|
||||||
|
code = -1;
|
||||||
|
close (s);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = sizeof(myctladdr_ss);
|
||||||
|
if (getsockname (s, myctladdr, &len) < 0) {
|
||||||
warn ("getsockname");
|
warn ("getsockname");
|
||||||
code = -1;
|
code = -1;
|
||||||
goto bad;
|
close (s);
|
||||||
}
|
return NULL;
|
||||||
#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
|
|
||||||
{
|
|
||||||
int tos = IPTOS_LOWDELAY;
|
|
||||||
|
|
||||||
if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
|
|
||||||
warn("setsockopt TOS (ignored)");
|
|
||||||
}
|
}
|
||||||
|
#ifdef IPTOS_LOWDELAY
|
||||||
|
socket_set_tos (s, IPTOS_LOWDELAY);
|
||||||
#endif
|
#endif
|
||||||
cin = fdopen (s, "r");
|
cin = fdopen (s, "r");
|
||||||
cout = fdopen (s, "w");
|
cout = fdopen (s, "w");
|
||||||
@@ -375,7 +377,7 @@ getreply (int expecteof)
|
|||||||
osa.sa_handler != SIG_IGN)
|
osa.sa_handler != SIG_IGN)
|
||||||
osa.sa_handler (SIGINT);
|
osa.sa_handler (SIGINT);
|
||||||
#endif
|
#endif
|
||||||
if (code == 227) {
|
if (code == 227 || code == 229) {
|
||||||
char *p, *q;
|
char *p, *q;
|
||||||
|
|
||||||
pasv[0] = 0;
|
pasv[0] = 0;
|
||||||
@@ -1120,6 +1122,218 @@ abort:
|
|||||||
signal (SIGINT, oldintr);
|
signal (SIGINT, oldintr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_epsv (const char *str)
|
||||||
|
{
|
||||||
|
char sep;
|
||||||
|
char *end;
|
||||||
|
int port;
|
||||||
|
|
||||||
|
if (*str == '\0')
|
||||||
|
return -1;
|
||||||
|
sep = *str++;
|
||||||
|
if (sep != *str++)
|
||||||
|
return -1;
|
||||||
|
if (sep != *str++)
|
||||||
|
return -1;
|
||||||
|
port = strtol (str, &end, 0);
|
||||||
|
if (str == end)
|
||||||
|
return -1;
|
||||||
|
if (end[0] != sep || end[1] != '\0')
|
||||||
|
return -1;
|
||||||
|
return htons(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_pasv (struct sockaddr_in *sin, const char *str)
|
||||||
|
{
|
||||||
|
int a0, a1, a2, a3, p0, p1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* What we've got at this point is a string of comma separated
|
||||||
|
* one-byte unsigned integer values. The first four are the an IP
|
||||||
|
* address. The fifth is the MSB of the port number, the sixth is the
|
||||||
|
* LSB. From that we'll prepare a sockaddr_in.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (sscanf (str, "%d,%d,%d,%d,%d,%d",
|
||||||
|
&a0, &a1, &a2, &a3, &p0, &p1) != 6) {
|
||||||
|
printf ("Passive mode address scan failure. "
|
||||||
|
"Shouldn't happen!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (a0 < 0 || a0 > 255 ||
|
||||||
|
a1 < 0 || a1 > 255 ||
|
||||||
|
a2 < 0 || a2 > 255 ||
|
||||||
|
a3 < 0 || a3 > 255 ||
|
||||||
|
p0 < 0 || p0 > 255 ||
|
||||||
|
p1 < 0 || p1 > 255) {
|
||||||
|
printf ("Can't parse passive mode string.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset (sin, 0, sizeof(*sin));
|
||||||
|
sin->sin_family = AF_INET;
|
||||||
|
sin->sin_addr.s_addr = htonl ((a0 << 24) | (a1 << 16) |
|
||||||
|
(a2 << 8) | a3);
|
||||||
|
sin->sin_port = htons ((p0 << 8) | p1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
passive_mode (void)
|
||||||
|
{
|
||||||
|
int port;
|
||||||
|
|
||||||
|
data = socket (myctladdr->sa_family, SOCK_STREAM, 0);
|
||||||
|
if (data < 0) {
|
||||||
|
warn ("socket");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if (options & SO_DEBUG)
|
||||||
|
socket_set_debug (data);
|
||||||
|
if (command ("EPSV") != COMPLETE) {
|
||||||
|
if (command ("PASV") != COMPLETE) {
|
||||||
|
printf ("Passive mode refused.\n");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse the reply to EPSV or PASV
|
||||||
|
*/
|
||||||
|
|
||||||
|
port = parse_epsv (pasv);
|
||||||
|
if (port > 0) {
|
||||||
|
data_addr->sa_family = myctladdr->sa_family;
|
||||||
|
socket_set_address_and_port (data_addr,
|
||||||
|
socket_get_address (hisctladdr),
|
||||||
|
port);
|
||||||
|
} else {
|
||||||
|
if (parse_pasv ((struct sockaddr_in *)data_addr, pasv) < 0)
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connect (data, data_addr, socket_sockaddr_size (data_addr)) < 0) {
|
||||||
|
warn ("connect");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
#ifdef IPTOS_THROUGHPUT
|
||||||
|
socket_set_tos (data, IPTOS_THROUGHPUT);
|
||||||
|
#endif
|
||||||
|
return (0);
|
||||||
|
bad:
|
||||||
|
close (data);
|
||||||
|
data = -1;
|
||||||
|
sendport = 1;
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
active_mode (void)
|
||||||
|
{
|
||||||
|
int tmpno = 0;
|
||||||
|
int len;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
noport:
|
||||||
|
data_addr->sa_family = myctladdr->sa_family;
|
||||||
|
socket_set_address_and_port (data_addr, socket_get_address (myctladdr),
|
||||||
|
sendport ? 0 : socket_get_port (myctladdr));
|
||||||
|
|
||||||
|
if (data != -1)
|
||||||
|
close (data);
|
||||||
|
data = socket (data_addr->sa_family, SOCK_STREAM, 0);
|
||||||
|
if (data < 0) {
|
||||||
|
warn ("socket");
|
||||||
|
if (tmpno)
|
||||||
|
sendport = 1;
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if (!sendport)
|
||||||
|
socket_set_reuseaddr (data, 1);
|
||||||
|
if (bind (data, data_addr, socket_sockaddr_size (data_addr)) < 0) {
|
||||||
|
warn ("bind");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
if (options & SO_DEBUG)
|
||||||
|
socket_set_debug (data);
|
||||||
|
len = sizeof (data_addr_ss);
|
||||||
|
if (getsockname (data, data_addr, &len) < 0) {
|
||||||
|
warn ("getsockname");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
if (listen (data, 1) < 0)
|
||||||
|
warn ("listen");
|
||||||
|
if (sendport) {
|
||||||
|
char *cmd;
|
||||||
|
char addr_str[256];
|
||||||
|
int inet_af;
|
||||||
|
|
||||||
|
if (inet_ntop (data_addr->sa_family, socket_get_address (data_addr),
|
||||||
|
addr_str, sizeof(addr_str)) == NULL)
|
||||||
|
errx (1, "inet_ntop failed");
|
||||||
|
switch (data_addr->sa_family) {
|
||||||
|
case AF_INET :
|
||||||
|
inet_af = 1;
|
||||||
|
break;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
case AF_INET6 :
|
||||||
|
inet_af = 2;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default :
|
||||||
|
errx (1, "bad address family %d", data_addr->sa_family);
|
||||||
|
}
|
||||||
|
|
||||||
|
asprintf (&cmd, "EPRT |%d|%s|%d|",
|
||||||
|
inet_af, addr_str, ntohs(socket_get_port (data_addr)));
|
||||||
|
|
||||||
|
result = command (cmd);
|
||||||
|
|
||||||
|
if (result == ERROR) {
|
||||||
|
struct sockaddr_in *sin = (struct sockaddr_in *)data_addr;
|
||||||
|
|
||||||
|
unsigned int a = ntohl(sin->sin_addr.s_addr);
|
||||||
|
unsigned int p = ntohs(sin->sin_port);
|
||||||
|
|
||||||
|
if (data_addr->sa_family != AF_INET) {
|
||||||
|
warnx ("remote server doesn't support EPRT");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = command("PORT %d,%d,%d,%d,%d,%d",
|
||||||
|
(a >> 24) & 0xff,
|
||||||
|
(a >> 16) & 0xff,
|
||||||
|
(a >> 8) & 0xff,
|
||||||
|
a & 0xff,
|
||||||
|
(p >> 8) & 0xff,
|
||||||
|
p & 0xff);
|
||||||
|
if (result == ERROR && sendport == -1) {
|
||||||
|
sendport = 0;
|
||||||
|
tmpno = 1;
|
||||||
|
goto noport;
|
||||||
|
}
|
||||||
|
return (result != COMPLETE);
|
||||||
|
}
|
||||||
|
return result != COMPLETE;
|
||||||
|
}
|
||||||
|
if (tmpno)
|
||||||
|
sendport = 1;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef IPTOS_THROUGHPUT
|
||||||
|
socket_set_tos (data, IPTOS_THROUGHPUT);
|
||||||
|
#endif
|
||||||
|
return (0);
|
||||||
|
bad:
|
||||||
|
close (data);
|
||||||
|
data = -1;
|
||||||
|
if (tmpno)
|
||||||
|
sendport = 1;
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Need to start a listen on the data channel before we send the command,
|
* Need to start a listen on the data channel before we send the command,
|
||||||
* otherwise the server's connect may fail.
|
* otherwise the server's connect may fail.
|
||||||
@@ -1127,147 +1341,23 @@ abort:
|
|||||||
int
|
int
|
||||||
initconn (void)
|
initconn (void)
|
||||||
{
|
{
|
||||||
int result, len, tmpno = 0;
|
if (passivemode)
|
||||||
int on = 1;
|
return passive_mode ();
|
||||||
int a0, a1, a2, a3, p0, p1;
|
else
|
||||||
|
return active_mode ();
|
||||||
if (passivemode) {
|
|
||||||
data = socket (AF_INET, SOCK_STREAM, 0);
|
|
||||||
if (data < 0) {
|
|
||||||
perror ("ftp: socket");
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
#if defined(SO_DEBUG) && defined(HAVE_SETSOCKOPT)
|
|
||||||
if ((options & SO_DEBUG) &&
|
|
||||||
setsockopt (data, SOL_SOCKET, SO_DEBUG, (char *) &on,
|
|
||||||
sizeof (on)) < 0)
|
|
||||||
perror ("ftp: setsockopt (ignored)");
|
|
||||||
#endif
|
|
||||||
if (command ("PASV") != COMPLETE) {
|
|
||||||
printf ("Passive mode refused.\n");
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* What we've got at this point is a string of comma separated
|
|
||||||
* one-byte unsigned integer values. The first four are the an IP
|
|
||||||
* address. The fifth is the MSB of the port number, the sixth is the
|
|
||||||
* LSB. From that we'll prepare a sockaddr_in.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (sscanf (pasv, "%d,%d,%d,%d,%d,%d",
|
|
||||||
&a0, &a1, &a2, &a3, &p0, &p1) != 6) {
|
|
||||||
printf ("Passive mode address scan failure. "
|
|
||||||
"Shouldn't happen!\n");
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
if (a0 < 0 || a0 > 255 ||
|
|
||||||
a1 < 0 || a1 > 255 ||
|
|
||||||
a2 < 0 || a2 > 255 ||
|
|
||||||
a3 < 0 || a3 > 255 ||
|
|
||||||
p0 < 0 || p0 > 255 ||
|
|
||||||
p1 < 0 || p1 > 255) {
|
|
||||||
printf ("Can't parse passive mode string.\n");
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
memset(&data_addr, 0, sizeof(data_addr));
|
|
||||||
data_addr.sin_family = AF_INET;
|
|
||||||
data_addr.sin_addr.s_addr = htonl ((a0 << 24) | (a1 << 16) |
|
|
||||||
(a2 << 8) | a3);
|
|
||||||
data_addr.sin_port = htons ((p0 << 8) | p1);
|
|
||||||
|
|
||||||
if (connect (data, (struct sockaddr *) & data_addr,
|
|
||||||
sizeof (data_addr)) < 0) {
|
|
||||||
perror ("ftp: connect");
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
|
|
||||||
on = IPTOS_THROUGHPUT;
|
|
||||||
if (setsockopt (data, IPPROTO_IP, IP_TOS, (char *) &on,
|
|
||||||
sizeof (int)) < 0)
|
|
||||||
perror ("ftp: setsockopt TOS (ignored)");
|
|
||||||
#endif
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
noport:
|
|
||||||
data_addr = myctladdr;
|
|
||||||
if (sendport)
|
|
||||||
data_addr.sin_port = 0; /* let system pick one */
|
|
||||||
if (data != -1)
|
|
||||||
close (data);
|
|
||||||
data = socket (AF_INET, SOCK_STREAM, 0);
|
|
||||||
if (data < 0) {
|
|
||||||
warn ("socket");
|
|
||||||
if (tmpno)
|
|
||||||
sendport = 1;
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
#if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT)
|
|
||||||
if (!sendport)
|
|
||||||
if (setsockopt (data, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) {
|
|
||||||
warn ("setsockopt (reuse address)");
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (bind (data, (struct sockaddr *) & data_addr, sizeof (data_addr)) < 0) {
|
|
||||||
warn ("bind");
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
#if defined(SO_DEBUG) && defined(HAVE_SETSOCKOPT)
|
|
||||||
if (options & SO_DEBUG &&
|
|
||||||
setsockopt (data, SOL_SOCKET, SO_DEBUG, (char *) &on, sizeof (on)) < 0)
|
|
||||||
warn ("setsockopt (ignored)");
|
|
||||||
#endif
|
|
||||||
len = sizeof (data_addr);
|
|
||||||
if (getsockname (data, (struct sockaddr *) & data_addr, &len) < 0) {
|
|
||||||
warn ("getsockname");
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
if (listen (data, 1) < 0)
|
|
||||||
warn ("listen");
|
|
||||||
if (sendport) {
|
|
||||||
unsigned int a = ntohl(data_addr.sin_addr.s_addr);
|
|
||||||
unsigned int p = ntohs(data_addr.sin_port);
|
|
||||||
|
|
||||||
result = command("PORT %d,%d,%d,%d,%d,%d",
|
|
||||||
(a >> 24) & 0xff,
|
|
||||||
(a >> 16) & 0xff,
|
|
||||||
(a >> 8) & 0xff,
|
|
||||||
a & 0xff,
|
|
||||||
(p >> 8) & 0xff,
|
|
||||||
p & 0xff);
|
|
||||||
if (result == ERROR && sendport == -1) {
|
|
||||||
sendport = 0;
|
|
||||||
tmpno = 1;
|
|
||||||
goto noport;
|
|
||||||
}
|
|
||||||
return (result != COMPLETE);
|
|
||||||
}
|
|
||||||
if (tmpno)
|
|
||||||
sendport = 1;
|
|
||||||
#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
|
|
||||||
on = IPTOS_THROUGHPUT;
|
|
||||||
if (setsockopt (data, IPPROTO_IP, IP_TOS, (char *) &on, sizeof (int)) < 0)
|
|
||||||
warn ("setsockopt TOS (ignored)");
|
|
||||||
#endif
|
|
||||||
return (0);
|
|
||||||
bad:
|
|
||||||
close (data), data = -1;
|
|
||||||
if (tmpno)
|
|
||||||
sendport = 1;
|
|
||||||
return (1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *
|
FILE *
|
||||||
dataconn (char *lmode)
|
dataconn (char *lmode)
|
||||||
{
|
{
|
||||||
struct sockaddr_in from;
|
struct sockaddr_storage from_ss;
|
||||||
int s, fromlen = sizeof (from), tos;
|
struct sockaddr *from = (struct sockaddr *)&from_ss;
|
||||||
|
int s, fromlen = sizeof (from_ss);
|
||||||
|
|
||||||
if (passivemode)
|
if (passivemode)
|
||||||
return (fdopen (data, lmode));
|
return (fdopen (data, lmode));
|
||||||
|
|
||||||
s = accept (data, (struct sockaddr *) & from, &fromlen);
|
s = accept (data, from, &fromlen);
|
||||||
if (s < 0) {
|
if (s < 0) {
|
||||||
warn ("accept");
|
warn ("accept");
|
||||||
close (data), data = -1;
|
close (data), data = -1;
|
||||||
@@ -1275,10 +1365,8 @@ dataconn (char *lmode)
|
|||||||
}
|
}
|
||||||
close (data);
|
close (data);
|
||||||
data = s;
|
data = s;
|
||||||
#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
|
#ifdef IPTOS_THROUGHPUT
|
||||||
tos = IPTOS_THROUGHPUT;
|
socket_set_tos (s, IPTOS_THROUGHPUT);
|
||||||
if (setsockopt (s, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof (int)) < 0)
|
|
||||||
warn ("setsockopt TOS (ignored)");
|
|
||||||
#endif
|
#endif
|
||||||
return (fdopen (data, lmode));
|
return (fdopen (data, lmode));
|
||||||
}
|
}
|
||||||
@@ -1334,8 +1422,8 @@ pswitch (int flag)
|
|||||||
static struct comvars {
|
static struct comvars {
|
||||||
int connect;
|
int connect;
|
||||||
char name[MaxHostNameLen];
|
char name[MaxHostNameLen];
|
||||||
struct sockaddr_in mctl;
|
struct sockaddr_storage mctl;
|
||||||
struct sockaddr_in hctl;
|
struct sockaddr_storage hctl;
|
||||||
FILE *in;
|
FILE *in;
|
||||||
FILE *out;
|
FILE *out;
|
||||||
int tpe;
|
int tpe;
|
||||||
@@ -1375,10 +1463,10 @@ pswitch (int flag)
|
|||||||
} else
|
} else
|
||||||
ip->name[0] = 0;
|
ip->name[0] = 0;
|
||||||
hostname = op->name;
|
hostname = op->name;
|
||||||
ip->hctl = hisctladdr;
|
ip->hctl = hisctladdr_ss;
|
||||||
hisctladdr = op->hctl;
|
hisctladdr_ss = op->hctl;
|
||||||
ip->mctl = myctladdr;
|
ip->mctl = myctladdr_ss;
|
||||||
myctladdr = op->mctl;
|
myctladdr_ss = op->mctl;
|
||||||
ip->in = cin;
|
ip->in = cin;
|
||||||
cin = op->in;
|
cin = op->in;
|
||||||
ip->out = cout;
|
ip->out = cout;
|
||||||
|
@@ -44,11 +44,20 @@ static char version[] = "Version 6.00";
|
|||||||
extern off_t restart_point;
|
extern off_t restart_point;
|
||||||
extern char cbuf[];
|
extern char cbuf[];
|
||||||
|
|
||||||
struct sockaddr_in ctrl_addr;
|
struct sockaddr_storage ctrl_addr_ss;
|
||||||
struct sockaddr_in data_source;
|
struct sockaddr *ctrl_addr = (struct sockaddr *)&ctrl_addr_ss;
|
||||||
struct sockaddr_in data_dest;
|
|
||||||
struct sockaddr_in his_addr;
|
struct sockaddr_storage data_source_ss;
|
||||||
struct sockaddr_in pasv_addr;
|
struct sockaddr *data_source = (struct sockaddr *)&data_source_ss;
|
||||||
|
|
||||||
|
struct sockaddr_storage data_dest_ss;
|
||||||
|
struct sockaddr *data_dest = (struct sockaddr *)&data_dest_ss;
|
||||||
|
|
||||||
|
struct sockaddr_storage his_addr_ss;
|
||||||
|
struct sockaddr *his_addr = (struct sockaddr *)&his_addr_ss;
|
||||||
|
|
||||||
|
struct sockaddr_storage pasv_addr_ss;
|
||||||
|
struct sockaddr *pasv_addr = (struct sockaddr *)&pasv_addr_ss;
|
||||||
|
|
||||||
int data;
|
int data;
|
||||||
jmp_buf errcatch, urgcatch;
|
jmp_buf errcatch, urgcatch;
|
||||||
@@ -126,7 +135,7 @@ static void myoob (int);
|
|||||||
static int checkuser (char *, char *);
|
static int checkuser (char *, char *);
|
||||||
static int checkaccess (char *);
|
static int checkaccess (char *);
|
||||||
static FILE *dataconn (char *, off_t, char *);
|
static FILE *dataconn (char *, off_t, char *);
|
||||||
static void dolog (struct sockaddr_in *);
|
static void dolog (struct sockaddr *);
|
||||||
static void end_login (void);
|
static void end_login (void);
|
||||||
static FILE *getdatasock (char *);
|
static FILE *getdatasock (char *);
|
||||||
static char *gunique (char *);
|
static char *gunique (char *);
|
||||||
@@ -305,22 +314,25 @@ main(int argc, char **argv)
|
|||||||
* necessary for anonymous ftp's that chroot and can't do it later.
|
* necessary for anonymous ftp's that chroot and can't do it later.
|
||||||
*/
|
*/
|
||||||
openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
|
openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
|
||||||
addrlen = sizeof(his_addr);
|
addrlen = sizeof(his_addr_ss);
|
||||||
if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
|
if (getpeername(STDIN_FILENO, his_addr, &addrlen) < 0) {
|
||||||
syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
|
syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
addrlen = sizeof(ctrl_addr);
|
addrlen = sizeof(ctrl_addr_ss);
|
||||||
if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
|
if (getsockname(STDIN_FILENO, ctrl_addr, &addrlen) < 0) {
|
||||||
syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
|
syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
|
#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
|
||||||
tos = IPTOS_LOWDELAY;
|
tos = IPTOS_LOWDELAY;
|
||||||
if (setsockopt(0, IPPROTO_IP, IP_TOS, (void *)&tos, sizeof(int)) < 0)
|
if (setsockopt(STDIN_FILENO, IPPROTO_IP, IP_TOS,
|
||||||
|
(void *)&tos, sizeof(int)) < 0)
|
||||||
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
|
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
|
||||||
#endif
|
#endif
|
||||||
data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
|
data_source->sa_family = ctrl_addr->sa_family;
|
||||||
|
socket_set_port (data_source,
|
||||||
|
htons(ntohs(socket_get_port(ctrl_addr)) - 1));
|
||||||
|
|
||||||
/* set this here so it can be put in wtmp */
|
/* set this here so it can be put in wtmp */
|
||||||
snprintf(ttyline, sizeof(ttyline), "ftp%u", (unsigned)getpid());
|
snprintf(ttyline, sizeof(ttyline), "ftp%u", (unsigned)getpid());
|
||||||
@@ -345,7 +357,7 @@ main(int argc, char **argv)
|
|||||||
if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
|
if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
|
||||||
syslog(LOG_ERR, "fcntl F_SETOWN: %m");
|
syslog(LOG_ERR, "fcntl F_SETOWN: %m");
|
||||||
#endif
|
#endif
|
||||||
dolog(&his_addr);
|
dolog(his_addr);
|
||||||
/*
|
/*
|
||||||
* Set up default state
|
* Set up default state
|
||||||
*/
|
*/
|
||||||
@@ -506,10 +518,19 @@ user(char *name)
|
|||||||
reply(331, "Guest login ok, type your name as password.");
|
reply(331, "Guest login ok, type your name as password.");
|
||||||
} else
|
} else
|
||||||
reply(530, "User %s unknown.", name);
|
reply(530, "User %s unknown.", name);
|
||||||
if (!askpasswd && logging)
|
if (!askpasswd && logging) {
|
||||||
|
char data_addr[256];
|
||||||
|
|
||||||
|
if (inet_ntop (his_addr->sa_family,
|
||||||
|
socket_get_address(his_addr),
|
||||||
|
data_addr, sizeof(data_addr)) == NULL)
|
||||||
|
strcpy_truncate (data_addr, "unknown address",
|
||||||
|
sizeof(data_addr));
|
||||||
|
|
||||||
syslog(LOG_NOTICE,
|
syslog(LOG_NOTICE,
|
||||||
"ANONYMOUS FTP LOGIN REFUSED FROM %s(%s)",
|
"ANONYMOUS FTP LOGIN REFUSED FROM %s(%s)",
|
||||||
remotehost, inet_ntoa(his_addr.sin_addr));
|
remotehost, data_addr);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if((auth_level & AUTH_PLAIN) == 0 && !sec_complete){
|
if((auth_level & AUTH_PLAIN) == 0 && !sec_complete){
|
||||||
@@ -526,12 +547,23 @@ user(char *name)
|
|||||||
|
|
||||||
if (cp == NULL || checkaccess(name)) {
|
if (cp == NULL || checkaccess(name)) {
|
||||||
reply(530, "User %s access denied.", name);
|
reply(530, "User %s access denied.", name);
|
||||||
if (logging)
|
if (logging) {
|
||||||
|
char data_addr[256];
|
||||||
|
|
||||||
|
if (inet_ntop (his_addr->sa_family,
|
||||||
|
socket_get_address(his_addr),
|
||||||
|
data_addr,
|
||||||
|
sizeof(data_addr)) == NULL)
|
||||||
|
strcpy_truncate (data_addr,
|
||||||
|
"unknown address",
|
||||||
|
sizeof(data_addr));
|
||||||
|
|
||||||
syslog(LOG_NOTICE,
|
syslog(LOG_NOTICE,
|
||||||
"FTP LOGIN REFUSED FROM %s(%s), %s",
|
"FTP LOGIN REFUSED FROM %s(%s), %s",
|
||||||
remotehost,
|
remotehost,
|
||||||
inet_ntoa(his_addr.sin_addr),
|
data_addr,
|
||||||
name);
|
name);
|
||||||
|
}
|
||||||
pw = (struct passwd *) NULL;
|
pw = (struct passwd *) NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -725,22 +757,40 @@ int do_login(int code, char *passwd)
|
|||||||
remotehost,
|
remotehost,
|
||||||
passwd);
|
passwd);
|
||||||
#endif /* HAVE_SETPROCTITLE */
|
#endif /* HAVE_SETPROCTITLE */
|
||||||
if (logging)
|
if (logging) {
|
||||||
|
char data_addr[256];
|
||||||
|
|
||||||
|
if (inet_ntop (his_addr->sa_family,
|
||||||
|
socket_get_address(his_addr),
|
||||||
|
data_addr, sizeof(data_addr)) == NULL)
|
||||||
|
strcpy_truncate (data_addr, "unknown address",
|
||||||
|
sizeof(data_addr));
|
||||||
|
|
||||||
syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s(%s), %s",
|
syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s(%s), %s",
|
||||||
remotehost,
|
remotehost,
|
||||||
inet_ntoa(his_addr.sin_addr),
|
data_addr,
|
||||||
passwd);
|
passwd);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
reply(code, "User %s logged in.", pw->pw_name);
|
reply(code, "User %s logged in.", pw->pw_name);
|
||||||
#ifdef HAVE_SETPROCTITLE
|
#ifdef HAVE_SETPROCTITLE
|
||||||
snprintf(proctitle, sizeof(proctitle), "%s: %s", remotehost, pw->pw_name);
|
snprintf(proctitle, sizeof(proctitle), "%s: %s", remotehost, pw->pw_name);
|
||||||
setproctitle(proctitle);
|
setproctitle(proctitle);
|
||||||
#endif /* HAVE_SETPROCTITLE */
|
#endif /* HAVE_SETPROCTITLE */
|
||||||
if (logging)
|
if (logging) {
|
||||||
|
char data_addr[256];
|
||||||
|
|
||||||
|
if (inet_ntop (his_addr->sa_family,
|
||||||
|
socket_get_address(his_addr),
|
||||||
|
data_addr, sizeof(data_addr)) == NULL)
|
||||||
|
strcpy_truncate (data_addr, "unknown address",
|
||||||
|
sizeof(data_addr));
|
||||||
|
|
||||||
syslog(LOG_INFO, "FTP LOGIN FROM %s(%s) as %s",
|
syslog(LOG_INFO, "FTP LOGIN FROM %s(%s) as %s",
|
||||||
remotehost,
|
remotehost,
|
||||||
inet_ntoa(his_addr.sin_addr),
|
data_addr,
|
||||||
pw->pw_name);
|
pw->pw_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
umask(defumask);
|
umask(defumask);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -819,19 +869,27 @@ pass(char *passwd)
|
|||||||
* local authentication succeeded.
|
* local authentication succeeded.
|
||||||
*/
|
*/
|
||||||
if (rval) {
|
if (rval) {
|
||||||
|
char data_addr[256];
|
||||||
|
|
||||||
|
if (inet_ntop (his_addr->sa_family,
|
||||||
|
socket_get_address(his_addr),
|
||||||
|
data_addr, sizeof(data_addr)) == NULL)
|
||||||
|
strcpy_truncate (data_addr, "unknown address",
|
||||||
|
sizeof(data_addr));
|
||||||
|
|
||||||
reply(530, "Login incorrect.");
|
reply(530, "Login incorrect.");
|
||||||
if (logging)
|
if (logging)
|
||||||
syslog(LOG_NOTICE,
|
syslog(LOG_NOTICE,
|
||||||
"FTP LOGIN FAILED FROM %s(%s), %s",
|
"FTP LOGIN FAILED FROM %s(%s), %s",
|
||||||
remotehost,
|
remotehost,
|
||||||
inet_ntoa(his_addr.sin_addr),
|
data_addr,
|
||||||
curname);
|
curname);
|
||||||
pw = NULL;
|
pw = NULL;
|
||||||
if (login_attempts++ >= 5) {
|
if (login_attempts++ >= 5) {
|
||||||
syslog(LOG_NOTICE,
|
syslog(LOG_NOTICE,
|
||||||
"repeated login failures from %s(%s)",
|
"repeated login failures from %s(%s)",
|
||||||
remotehost,
|
remotehost,
|
||||||
inet_ntoa(his_addr.sin_addr));
|
data_addr);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1068,35 +1126,31 @@ done:
|
|||||||
static FILE *
|
static FILE *
|
||||||
getdatasock(char *mode)
|
getdatasock(char *mode)
|
||||||
{
|
{
|
||||||
int on = 1, s, t, tries;
|
int s, t, tries;
|
||||||
|
|
||||||
if (data >= 0)
|
if (data >= 0)
|
||||||
return (fdopen(data, mode));
|
return (fdopen(data, mode));
|
||||||
seteuid((uid_t)0);
|
seteuid(0);
|
||||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
s = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
|
||||||
if (s < 0)
|
if (s < 0)
|
||||||
goto bad;
|
goto bad;
|
||||||
#if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT)
|
socket_set_reuseaddr (s, 1);
|
||||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
|
|
||||||
(void *) &on, sizeof(on)) < 0)
|
|
||||||
goto bad;
|
|
||||||
#endif
|
|
||||||
/* anchor socket to avoid multi-homing problems */
|
/* anchor socket to avoid multi-homing problems */
|
||||||
data_source.sin_family = AF_INET;
|
socket_set_address_and_port (data_source,
|
||||||
data_source.sin_addr = ctrl_addr.sin_addr;
|
socket_get_address (ctrl_addr),
|
||||||
|
0);
|
||||||
|
|
||||||
for (tries = 1; ; tries++) {
|
for (tries = 1; ; tries++) {
|
||||||
if (bind(s, (struct sockaddr *)&data_source,
|
if (bind(s, data_source,
|
||||||
sizeof(data_source)) >= 0)
|
socket_sockaddr_size (data_source)) >= 0)
|
||||||
break;
|
break;
|
||||||
if (errno != EADDRINUSE || tries > 10)
|
if (errno != EADDRINUSE || tries > 10)
|
||||||
goto bad;
|
goto bad;
|
||||||
sleep(tries);
|
sleep(tries);
|
||||||
}
|
}
|
||||||
seteuid((uid_t)pw->pw_uid);
|
seteuid(pw->pw_uid);
|
||||||
#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
|
#ifdef IPTOS_THROUGHPUT
|
||||||
on = IPTOS_THROUGHPUT;
|
socket_set_tos (s, IPTOS_THROUGHPUT);
|
||||||
if (setsockopt(s, IPPROTO_IP, IP_TOS, (void *)&on, sizeof(int)) < 0)
|
|
||||||
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
|
|
||||||
#endif
|
#endif
|
||||||
return (fdopen(s, mode));
|
return (fdopen(s, mode));
|
||||||
bad:
|
bad:
|
||||||
@@ -1122,10 +1176,12 @@ dataconn(char *name, off_t size, char *mode)
|
|||||||
else
|
else
|
||||||
*sizebuf = '\0';
|
*sizebuf = '\0';
|
||||||
if (pdata >= 0) {
|
if (pdata >= 0) {
|
||||||
struct sockaddr_in from;
|
struct sockaddr_storage from_ss;
|
||||||
int s, fromlen = sizeof(from);
|
struct sockaddr *from = (struct sockaddr *)&from;
|
||||||
|
int s;
|
||||||
|
int fromlen = sizeof(from_ss);
|
||||||
|
|
||||||
s = accept(pdata, (struct sockaddr *)&from, &fromlen);
|
s = accept(pdata, from, &fromlen);
|
||||||
if (s < 0) {
|
if (s < 0) {
|
||||||
reply(425, "Can't open data connection.");
|
reply(425, "Can't open data connection.");
|
||||||
close(pdata);
|
close(pdata);
|
||||||
@@ -1157,16 +1213,25 @@ dataconn(char *name, off_t size, char *mode)
|
|||||||
usedefault = 1;
|
usedefault = 1;
|
||||||
file = getdatasock(mode);
|
file = getdatasock(mode);
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
|
char data_addr[256];
|
||||||
|
|
||||||
|
if (inet_ntop (data_source->sa_family,
|
||||||
|
socket_get_address(data_source),
|
||||||
|
data_addr, sizeof(data_addr)) == NULL)
|
||||||
|
strcpy_truncate (data_addr, "unknown address",
|
||||||
|
sizeof(data_addr));
|
||||||
|
|
||||||
reply(425, "Can't create data socket (%s,%d): %s.",
|
reply(425, "Can't create data socket (%s,%d): %s.",
|
||||||
inet_ntoa(data_source.sin_addr),
|
data_addr,
|
||||||
ntohs(data_source.sin_port), strerror(errno));
|
socket_get_port (data_source),
|
||||||
|
strerror(errno));
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
data = fileno(file);
|
data = fileno(file);
|
||||||
while (connect(data, (struct sockaddr *)&data_dest,
|
while (connect(data, data_dest,
|
||||||
sizeof(data_dest)) < 0) {
|
socket_sockaddr_size(data_dest)) < 0) {
|
||||||
if (errno == EADDRINUSE && retry < swaitmax) {
|
if (errno == EADDRINUSE && retry < swaitmax) {
|
||||||
sleep((unsigned) swaitint);
|
sleep(swaitint);
|
||||||
retry += swaitint;
|
retry += swaitint;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1673,18 +1738,30 @@ renamecmd(char *from, char *to)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dolog(struct sockaddr_in *sin)
|
dolog(struct sockaddr *sa)
|
||||||
{
|
{
|
||||||
|
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
|
||||||
|
|
||||||
inaddr2str (sin->sin_addr, remotehost, sizeof(remotehost));
|
inaddr2str (sin->sin_addr, remotehost, sizeof(remotehost));
|
||||||
#ifdef HAVE_SETPROCTITLE
|
#ifdef HAVE_SETPROCTITLE
|
||||||
snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
|
snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
|
||||||
setproctitle(proctitle);
|
setproctitle(proctitle);
|
||||||
#endif /* HAVE_SETPROCTITLE */
|
#endif /* HAVE_SETPROCTITLE */
|
||||||
|
|
||||||
if (logging)
|
if (logging) {
|
||||||
|
char data_addr[256];
|
||||||
|
|
||||||
|
if (inet_ntop (his_addr->sa_family,
|
||||||
|
socket_get_address(his_addr),
|
||||||
|
data_addr, sizeof(data_addr)) == NULL)
|
||||||
|
strcpy_truncate (data_addr, "unknown address",
|
||||||
|
sizeof(data_addr));
|
||||||
|
|
||||||
|
|
||||||
syslog(LOG_INFO, "connection from %s(%s)",
|
syslog(LOG_INFO, "connection from %s(%s)",
|
||||||
remotehost,
|
remotehost,
|
||||||
inet_ntoa(his_addr.sin_addr));
|
data_addr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1766,31 +1843,41 @@ myoob(int signo)
|
|||||||
* with Rick Adams on 25 Jan 89.
|
* with Rick Adams on 25 Jan 89.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
passive(void)
|
pasv(void)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
char *p, *a;
|
char *p, *a;
|
||||||
|
struct sockaddr_in *sin;
|
||||||
|
|
||||||
pdata = socket(AF_INET, SOCK_STREAM, 0);
|
if (ctrl_addr->sa_family != AF_INET) {
|
||||||
|
reply(425,
|
||||||
|
"You cannot do PASV with something that's not IPv4");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
|
||||||
if (pdata < 0) {
|
if (pdata < 0) {
|
||||||
perror_reply(425, "Can't open passive connection");
|
perror_reply(425, "Can't open passive connection");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pasv_addr = ctrl_addr;
|
pasv_addr->sa_family = ctrl_addr->sa_family;
|
||||||
pasv_addr.sin_port = 0;
|
socket_set_address_and_port (pasv_addr,
|
||||||
seteuid((uid_t)0);
|
socket_get_address (ctrl_addr),
|
||||||
if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
|
0);
|
||||||
seteuid((uid_t)pw->pw_uid);
|
seteuid(0);
|
||||||
|
if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) {
|
||||||
|
seteuid(pw->pw_uid);
|
||||||
goto pasv_error;
|
goto pasv_error;
|
||||||
}
|
}
|
||||||
seteuid((uid_t)pw->pw_uid);
|
seteuid(pw->pw_uid);
|
||||||
len = sizeof(pasv_addr);
|
len = sizeof(pasv_addr_ss);
|
||||||
if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
|
if (getsockname(pdata, pasv_addr, &len) < 0)
|
||||||
goto pasv_error;
|
goto pasv_error;
|
||||||
if (listen(pdata, 1) < 0)
|
if (listen(pdata, 1) < 0)
|
||||||
goto pasv_error;
|
goto pasv_error;
|
||||||
a = (char *) &pasv_addr.sin_addr;
|
sin = (struct sockaddr_in *)pasv_addr;
|
||||||
p = (char *) &pasv_addr.sin_port;
|
a = (char *) &sin->sin_addr;
|
||||||
|
p = (char *) &sin->sin_port;
|
||||||
|
|
||||||
#define UC(b) (((int) b) & 0xff)
|
#define UC(b) (((int) b) & 0xff)
|
||||||
|
|
||||||
@@ -1805,6 +1892,109 @@ pasv_error:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
epsv(char *proto)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
|
||||||
|
if (pdata < 0) {
|
||||||
|
perror_reply(425, "Can't open passive connection");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pasv_addr->sa_family = ctrl_addr->sa_family;
|
||||||
|
socket_set_address_and_port (pasv_addr,
|
||||||
|
socket_get_address (ctrl_addr),
|
||||||
|
0);
|
||||||
|
seteuid(0);
|
||||||
|
if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) {
|
||||||
|
seteuid(pw->pw_uid);
|
||||||
|
goto pasv_error;
|
||||||
|
}
|
||||||
|
seteuid(pw->pw_uid);
|
||||||
|
len = sizeof(pasv_addr_ss);
|
||||||
|
if (getsockname(pdata, pasv_addr, &len) < 0)
|
||||||
|
goto pasv_error;
|
||||||
|
if (listen(pdata, 1) < 0)
|
||||||
|
goto pasv_error;
|
||||||
|
|
||||||
|
reply(229, "Entering Extended Passive Mode (|||%d|)",
|
||||||
|
ntohs(socket_get_port (pasv_addr)));
|
||||||
|
return;
|
||||||
|
|
||||||
|
pasv_error:
|
||||||
|
close(pdata);
|
||||||
|
pdata = -1;
|
||||||
|
perror_reply(425, "Can't open passive connection");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eprt(char *str)
|
||||||
|
{
|
||||||
|
char *end;
|
||||||
|
char sep;
|
||||||
|
int af;
|
||||||
|
int ret;
|
||||||
|
int port;
|
||||||
|
|
||||||
|
usedefault = 0;
|
||||||
|
if (pdata >= 0) {
|
||||||
|
close(pdata);
|
||||||
|
pdata = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sep = *str++;
|
||||||
|
if (sep == '\0') {
|
||||||
|
reply(500, "Bad syntax in EPRT");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
af = strtol (str, &end, 0);
|
||||||
|
if (af == 0 || *end != sep) {
|
||||||
|
reply(500, "Bad syntax in EPRT");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
str = end + 1;
|
||||||
|
switch (af) {
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
case 2 :
|
||||||
|
data_dest->sa_family = AF_INET6;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 1 :
|
||||||
|
data_dest->sa_family = AF_INET;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
reply(522, "Network protocol %d not supported, use (1"
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
",2"
|
||||||
|
#endif
|
||||||
|
")", af);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
end = strchr (str, sep);
|
||||||
|
if (end == NULL) {
|
||||||
|
reply(500, "Bad syntax in EPRT");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*end = '\0';
|
||||||
|
ret = inet_pton (data_dest->sa_family, str,
|
||||||
|
socket_get_address (data_dest));
|
||||||
|
|
||||||
|
if (ret != 1) {
|
||||||
|
reply(500, "Bad address syntax in EPRT");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
str = end + 1;
|
||||||
|
port = strtol (str, &end, 0);
|
||||||
|
if (port == 0 || *end != sep) {
|
||||||
|
reply(500, "Bad port syntax in EPRT");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
socket_set_port (data_dest, htons(port));
|
||||||
|
reply(200, "EPRT command successful.");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate unique name for file with basename "local".
|
* Generate unique name for file with basename "local".
|
||||||
* The file named "local" is already known to exist.
|
* The file named "local" is already known to exist.
|
||||||
|
Reference in New Issue
Block a user