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"
|
||||
RCSID ("$Id$");
|
||||
|
||||
struct sockaddr_in hisctladdr;
|
||||
struct sockaddr_in data_addr;
|
||||
struct sockaddr_storage hisctladdr_ss;
|
||||
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 abrtflag = 0;
|
||||
jmp_buf ptabort;
|
||||
int ptabflg;
|
||||
int ptflag = 0;
|
||||
struct sockaddr_in myctladdr;
|
||||
off_t restart_point = 0;
|
||||
|
||||
|
||||
@@ -50,77 +53,76 @@ FILE *cin, *cout;
|
||||
typedef void (*sighand) (int);
|
||||
|
||||
char *
|
||||
hookup (char *host, int port)
|
||||
hookup (const char *host, int port)
|
||||
{
|
||||
struct hostent *hp = 0;
|
||||
struct hostent *hp = NULL;
|
||||
int s, len;
|
||||
static char hostnamebuf[MaxHostNameLen];
|
||||
int error;
|
||||
int af;
|
||||
char **h;
|
||||
int ret;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (hp == NULL)
|
||||
hp = getipnodebyname (host, AF_INET6, 0, &error);
|
||||
#endif
|
||||
if (hp == NULL)
|
||||
hp = getipnodebyname (host, AF_INET, 0, &error);
|
||||
|
||||
memset (&hisctladdr, 0, sizeof (hisctladdr));
|
||||
if (inet_aton (host, &hisctladdr.sin_addr)) {
|
||||
hisctladdr.sin_family = AF_INET;
|
||||
strcpy_truncate (hostnamebuf, host, sizeof (hostnamebuf));
|
||||
} else {
|
||||
hp = gethostbyname (host);
|
||||
if (hp == NULL) {
|
||||
warnx("%s: %s", host, hstrerror(h_errno));
|
||||
warnx ("%s: %s", host, hstrerror(error));
|
||||
code = -1;
|
||||
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;
|
||||
return (0);
|
||||
}
|
||||
hisctladdr.sin_port = port;
|
||||
while (connect (s, (struct sockaddr *) & hisctladdr, sizeof (hisctladdr)) < 0) {
|
||||
if (hp && hp->h_addr_list[1]) {
|
||||
int oerrno = errno;
|
||||
char *ia;
|
||||
af = hisctladdr->sa_family = hp->h_addrtype;
|
||||
|
||||
ia = inet_ntoa (hisctladdr.sin_addr);
|
||||
errno = oerrno;
|
||||
warn ("connect to address %s", ia);
|
||||
hp->h_addr_list++;
|
||||
memmove (&hisctladdr.sin_addr,
|
||||
hp->h_addr_list[0],
|
||||
sizeof (hisctladdr.sin_addr));
|
||||
fprintf (stdout, "Trying %s...\n",
|
||||
inet_ntoa (hisctladdr.sin_addr));
|
||||
close (s);
|
||||
s = socket (hisctladdr.sin_family, SOCK_STREAM, 0);
|
||||
for (h = hp->h_addr_list;
|
||||
*h != NULL;
|
||||
++h) {
|
||||
|
||||
s = socket (af, SOCK_STREAM, 0);
|
||||
if (s < 0) {
|
||||
warn ("socket");
|
||||
code = -1;
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
warn ("connect");
|
||||
code = -1;
|
||||
goto bad;
|
||||
break;
|
||||
}
|
||||
len = sizeof (myctladdr);
|
||||
if (getsockname (s, (struct sockaddr *) & myctladdr, &len) < 0) {
|
||||
freehostent (hp);
|
||||
if (ret < 0) {
|
||||
code = -1;
|
||||
close (s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = sizeof(myctladdr_ss);
|
||||
if (getsockname (s, myctladdr, &len) < 0) {
|
||||
warn ("getsockname");
|
||||
code = -1;
|
||||
goto bad;
|
||||
}
|
||||
#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)");
|
||||
close (s);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef IPTOS_LOWDELAY
|
||||
socket_set_tos (s, IPTOS_LOWDELAY);
|
||||
#endif
|
||||
cin = fdopen (s, "r");
|
||||
cout = fdopen (s, "w");
|
||||
@@ -375,7 +377,7 @@ getreply (int expecteof)
|
||||
osa.sa_handler != SIG_IGN)
|
||||
osa.sa_handler (SIGINT);
|
||||
#endif
|
||||
if (code == 227) {
|
||||
if (code == 227 || code == 229) {
|
||||
char *p, *q;
|
||||
|
||||
pasv[0] = 0;
|
||||
@@ -1120,34 +1122,33 @@ abort:
|
||||
signal (SIGINT, oldintr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Need to start a listen on the data channel before we send the command,
|
||||
* otherwise the server's connect may fail.
|
||||
*/
|
||||
int
|
||||
initconn (void)
|
||||
static int
|
||||
parse_epsv (const char *str)
|
||||
{
|
||||
int result, len, tmpno = 0;
|
||||
int on = 1;
|
||||
int a0, a1, a2, a3, p0, p1;
|
||||
char sep;
|
||||
char *end;
|
||||
int port;
|
||||
|
||||
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;
|
||||
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
|
||||
@@ -1155,11 +1156,11 @@ initconn (void)
|
||||
* LSB. From that we'll prepare a sockaddr_in.
|
||||
*/
|
||||
|
||||
if (sscanf (pasv, "%d,%d,%d,%d,%d,%d",
|
||||
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");
|
||||
goto bad;
|
||||
return -1;
|
||||
}
|
||||
if (a0 < 0 || a0 > 255 ||
|
||||
a1 < 0 || a1 > 255 ||
|
||||
@@ -1168,66 +1169,138 @@ initconn (void)
|
||||
p0 < 0 || p0 > 255 ||
|
||||
p1 < 0 || p1 > 255) {
|
||||
printf ("Can't parse passive mode string.\n");
|
||||
goto bad;
|
||||
return -1;
|
||||
}
|
||||
memset(&data_addr, 0, sizeof(data_addr));
|
||||
data_addr.sin_family = AF_INET;
|
||||
data_addr.sin_addr.s_addr = htonl ((a0 << 24) | (a1 << 16) |
|
||||
memset (sin, 0, sizeof(*sin));
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_addr.s_addr = htonl ((a0 << 24) | (a1 << 16) |
|
||||
(a2 << 8) | a3);
|
||||
data_addr.sin_port = htons ((p0 << 8) | p1);
|
||||
sin->sin_port = htons ((p0 << 8) | p1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (connect (data, (struct sockaddr *) & data_addr,
|
||||
sizeof (data_addr)) < 0) {
|
||||
perror ("ftp: connect");
|
||||
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;
|
||||
}
|
||||
#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)");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 = myctladdr;
|
||||
if (sendport)
|
||||
data_addr.sin_port = 0; /* let system pick one */
|
||||
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 (AF_INET, SOCK_STREAM, 0);
|
||||
data = socket (data_addr->sa_family, 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) {
|
||||
socket_set_reuseaddr (data, 1);
|
||||
if (bind (data, data_addr, socket_sockaddr_size (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) {
|
||||
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) {
|
||||
unsigned int a = ntohl(data_addr.sin_addr.s_addr);
|
||||
unsigned int p = ntohs(data_addr.sin_port);
|
||||
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,
|
||||
@@ -1243,31 +1316,48 @@ noport:
|
||||
}
|
||||
return (result != COMPLETE);
|
||||
}
|
||||
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)");
|
||||
|
||||
|
||||
#ifdef IPTOS_THROUGHPUT
|
||||
socket_set_tos (data, IPTOS_THROUGHPUT);
|
||||
#endif
|
||||
return (0);
|
||||
bad:
|
||||
close (data), data = -1;
|
||||
close (data);
|
||||
data = -1;
|
||||
if (tmpno)
|
||||
sendport = 1;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Need to start a listen on the data channel before we send the command,
|
||||
* otherwise the server's connect may fail.
|
||||
*/
|
||||
int
|
||||
initconn (void)
|
||||
{
|
||||
if (passivemode)
|
||||
return passive_mode ();
|
||||
else
|
||||
return active_mode ();
|
||||
}
|
||||
|
||||
FILE *
|
||||
dataconn (char *lmode)
|
||||
{
|
||||
struct sockaddr_in from;
|
||||
int s, fromlen = sizeof (from), tos;
|
||||
struct sockaddr_storage from_ss;
|
||||
struct sockaddr *from = (struct sockaddr *)&from_ss;
|
||||
int s, fromlen = sizeof (from_ss);
|
||||
|
||||
if (passivemode)
|
||||
return (fdopen (data, lmode));
|
||||
|
||||
s = accept (data, (struct sockaddr *) & from, &fromlen);
|
||||
s = accept (data, from, &fromlen);
|
||||
if (s < 0) {
|
||||
warn ("accept");
|
||||
close (data), data = -1;
|
||||
@@ -1275,10 +1365,8 @@ dataconn (char *lmode)
|
||||
}
|
||||
close (data);
|
||||
data = s;
|
||||
#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
|
||||
tos = IPTOS_THROUGHPUT;
|
||||
if (setsockopt (s, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof (int)) < 0)
|
||||
warn ("setsockopt TOS (ignored)");
|
||||
#ifdef IPTOS_THROUGHPUT
|
||||
socket_set_tos (s, IPTOS_THROUGHPUT);
|
||||
#endif
|
||||
return (fdopen (data, lmode));
|
||||
}
|
||||
@@ -1334,8 +1422,8 @@ pswitch (int flag)
|
||||
static struct comvars {
|
||||
int connect;
|
||||
char name[MaxHostNameLen];
|
||||
struct sockaddr_in mctl;
|
||||
struct sockaddr_in hctl;
|
||||
struct sockaddr_storage mctl;
|
||||
struct sockaddr_storage hctl;
|
||||
FILE *in;
|
||||
FILE *out;
|
||||
int tpe;
|
||||
@@ -1375,10 +1463,10 @@ pswitch (int flag)
|
||||
} else
|
||||
ip->name[0] = 0;
|
||||
hostname = op->name;
|
||||
ip->hctl = hisctladdr;
|
||||
hisctladdr = op->hctl;
|
||||
ip->mctl = myctladdr;
|
||||
myctladdr = op->mctl;
|
||||
ip->hctl = hisctladdr_ss;
|
||||
hisctladdr_ss = op->hctl;
|
||||
ip->mctl = myctladdr_ss;
|
||||
myctladdr_ss = op->mctl;
|
||||
ip->in = cin;
|
||||
cin = op->in;
|
||||
ip->out = cout;
|
||||
|
@@ -44,11 +44,20 @@ static char version[] = "Version 6.00";
|
||||
extern off_t restart_point;
|
||||
extern char cbuf[];
|
||||
|
||||
struct sockaddr_in ctrl_addr;
|
||||
struct sockaddr_in data_source;
|
||||
struct sockaddr_in data_dest;
|
||||
struct sockaddr_in his_addr;
|
||||
struct sockaddr_in pasv_addr;
|
||||
struct sockaddr_storage ctrl_addr_ss;
|
||||
struct sockaddr *ctrl_addr = (struct sockaddr *)&ctrl_addr_ss;
|
||||
|
||||
struct sockaddr_storage data_source_ss;
|
||||
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;
|
||||
jmp_buf errcatch, urgcatch;
|
||||
@@ -126,7 +135,7 @@ static void myoob (int);
|
||||
static int checkuser (char *, char *);
|
||||
static int checkaccess (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 FILE *getdatasock (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.
|
||||
*/
|
||||
openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
|
||||
addrlen = sizeof(his_addr);
|
||||
if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
|
||||
addrlen = sizeof(his_addr_ss);
|
||||
if (getpeername(STDIN_FILENO, his_addr, &addrlen) < 0) {
|
||||
syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
addrlen = sizeof(ctrl_addr);
|
||||
if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
|
||||
addrlen = sizeof(ctrl_addr_ss);
|
||||
if (getsockname(STDIN_FILENO, ctrl_addr, &addrlen) < 0) {
|
||||
syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
|
||||
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");
|
||||
#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 */
|
||||
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)
|
||||
syslog(LOG_ERR, "fcntl F_SETOWN: %m");
|
||||
#endif
|
||||
dolog(&his_addr);
|
||||
dolog(his_addr);
|
||||
/*
|
||||
* Set up default state
|
||||
*/
|
||||
@@ -506,10 +518,19 @@ user(char *name)
|
||||
reply(331, "Guest login ok, type your name as password.");
|
||||
} else
|
||||
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,
|
||||
"ANONYMOUS FTP LOGIN REFUSED FROM %s(%s)",
|
||||
remotehost, inet_ntoa(his_addr.sin_addr));
|
||||
remotehost, data_addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if((auth_level & AUTH_PLAIN) == 0 && !sec_complete){
|
||||
@@ -526,12 +547,23 @@ user(char *name)
|
||||
|
||||
if (cp == NULL || checkaccess(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,
|
||||
"FTP LOGIN REFUSED FROM %s(%s), %s",
|
||||
remotehost,
|
||||
inet_ntoa(his_addr.sin_addr),
|
||||
data_addr,
|
||||
name);
|
||||
}
|
||||
pw = (struct passwd *) NULL;
|
||||
return;
|
||||
}
|
||||
@@ -725,23 +757,41 @@ int do_login(int code, char *passwd)
|
||||
remotehost,
|
||||
passwd);
|
||||
#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",
|
||||
remotehost,
|
||||
inet_ntoa(his_addr.sin_addr),
|
||||
data_addr,
|
||||
passwd);
|
||||
}
|
||||
} else {
|
||||
reply(code, "User %s logged in.", pw->pw_name);
|
||||
#ifdef HAVE_SETPROCTITLE
|
||||
snprintf(proctitle, sizeof(proctitle), "%s: %s", remotehost, pw->pw_name);
|
||||
setproctitle(proctitle);
|
||||
#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",
|
||||
remotehost,
|
||||
inet_ntoa(his_addr.sin_addr),
|
||||
data_addr,
|
||||
pw->pw_name);
|
||||
}
|
||||
}
|
||||
umask(defumask);
|
||||
return 0;
|
||||
}
|
||||
@@ -819,19 +869,27 @@ pass(char *passwd)
|
||||
* local authentication succeeded.
|
||||
*/
|
||||
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.");
|
||||
if (logging)
|
||||
syslog(LOG_NOTICE,
|
||||
"FTP LOGIN FAILED FROM %s(%s), %s",
|
||||
remotehost,
|
||||
inet_ntoa(his_addr.sin_addr),
|
||||
data_addr,
|
||||
curname);
|
||||
pw = NULL;
|
||||
if (login_attempts++ >= 5) {
|
||||
syslog(LOG_NOTICE,
|
||||
"repeated login failures from %s(%s)",
|
||||
remotehost,
|
||||
inet_ntoa(his_addr.sin_addr));
|
||||
data_addr);
|
||||
exit(0);
|
||||
}
|
||||
return;
|
||||
@@ -1068,35 +1126,31 @@ done:
|
||||
static FILE *
|
||||
getdatasock(char *mode)
|
||||
{
|
||||
int on = 1, s, t, tries;
|
||||
int s, t, tries;
|
||||
|
||||
if (data >= 0)
|
||||
return (fdopen(data, mode));
|
||||
seteuid((uid_t)0);
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
seteuid(0);
|
||||
s = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
|
||||
if (s < 0)
|
||||
goto bad;
|
||||
#if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT)
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
|
||||
(void *) &on, sizeof(on)) < 0)
|
||||
goto bad;
|
||||
#endif
|
||||
socket_set_reuseaddr (s, 1);
|
||||
/* anchor socket to avoid multi-homing problems */
|
||||
data_source.sin_family = AF_INET;
|
||||
data_source.sin_addr = ctrl_addr.sin_addr;
|
||||
socket_set_address_and_port (data_source,
|
||||
socket_get_address (ctrl_addr),
|
||||
0);
|
||||
|
||||
for (tries = 1; ; tries++) {
|
||||
if (bind(s, (struct sockaddr *)&data_source,
|
||||
sizeof(data_source)) >= 0)
|
||||
if (bind(s, data_source,
|
||||
socket_sockaddr_size (data_source)) >= 0)
|
||||
break;
|
||||
if (errno != EADDRINUSE || tries > 10)
|
||||
goto bad;
|
||||
sleep(tries);
|
||||
}
|
||||
seteuid((uid_t)pw->pw_uid);
|
||||
#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
|
||||
on = IPTOS_THROUGHPUT;
|
||||
if (setsockopt(s, IPPROTO_IP, IP_TOS, (void *)&on, sizeof(int)) < 0)
|
||||
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
|
||||
seteuid(pw->pw_uid);
|
||||
#ifdef IPTOS_THROUGHPUT
|
||||
socket_set_tos (s, IPTOS_THROUGHPUT);
|
||||
#endif
|
||||
return (fdopen(s, mode));
|
||||
bad:
|
||||
@@ -1122,10 +1176,12 @@ dataconn(char *name, off_t size, char *mode)
|
||||
else
|
||||
*sizebuf = '\0';
|
||||
if (pdata >= 0) {
|
||||
struct sockaddr_in from;
|
||||
int s, fromlen = sizeof(from);
|
||||
struct sockaddr_storage from_ss;
|
||||
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) {
|
||||
reply(425, "Can't open data connection.");
|
||||
close(pdata);
|
||||
@@ -1157,16 +1213,25 @@ dataconn(char *name, off_t size, char *mode)
|
||||
usedefault = 1;
|
||||
file = getdatasock(mode);
|
||||
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.",
|
||||
inet_ntoa(data_source.sin_addr),
|
||||
ntohs(data_source.sin_port), strerror(errno));
|
||||
data_addr,
|
||||
socket_get_port (data_source),
|
||||
strerror(errno));
|
||||
return (NULL);
|
||||
}
|
||||
data = fileno(file);
|
||||
while (connect(data, (struct sockaddr *)&data_dest,
|
||||
sizeof(data_dest)) < 0) {
|
||||
while (connect(data, data_dest,
|
||||
socket_sockaddr_size(data_dest)) < 0) {
|
||||
if (errno == EADDRINUSE && retry < swaitmax) {
|
||||
sleep((unsigned) swaitint);
|
||||
sleep(swaitint);
|
||||
retry += swaitint;
|
||||
continue;
|
||||
}
|
||||
@@ -1673,18 +1738,30 @@ renamecmd(char *from, char *to)
|
||||
}
|
||||
|
||||
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));
|
||||
#ifdef HAVE_SETPROCTITLE
|
||||
snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
|
||||
setproctitle(proctitle);
|
||||
#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)",
|
||||
remotehost,
|
||||
inet_ntoa(his_addr.sin_addr));
|
||||
data_addr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1766,31 +1843,41 @@ myoob(int signo)
|
||||
* with Rick Adams on 25 Jan 89.
|
||||
*/
|
||||
void
|
||||
passive(void)
|
||||
pasv(void)
|
||||
{
|
||||
int len;
|
||||
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) {
|
||||
perror_reply(425, "Can't open passive connection");
|
||||
return;
|
||||
}
|
||||
pasv_addr = ctrl_addr;
|
||||
pasv_addr.sin_port = 0;
|
||||
seteuid((uid_t)0);
|
||||
if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
|
||||
seteuid((uid_t)pw->pw_uid);
|
||||
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((uid_t)pw->pw_uid);
|
||||
len = sizeof(pasv_addr);
|
||||
if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
|
||||
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;
|
||||
a = (char *) &pasv_addr.sin_addr;
|
||||
p = (char *) &pasv_addr.sin_port;
|
||||
sin = (struct sockaddr_in *)pasv_addr;
|
||||
a = (char *) &sin->sin_addr;
|
||||
p = (char *) &sin->sin_port;
|
||||
|
||||
#define UC(b) (((int) b) & 0xff)
|
||||
|
||||
@@ -1805,6 +1892,109 @@ pasv_error:
|
||||
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".
|
||||
* The file named "local" is already known to exist.
|
||||
|
Reference in New Issue
Block a user