summaryrefslogtreecommitdiffstats
path: root/libexec
diff options
context:
space:
mode:
authorshin <shin@FreeBSD.org>2000-01-27 09:28:38 +0000
committershin <shin@FreeBSD.org>2000-01-27 09:28:38 +0000
commitce15efb7c04858f00b57c16093d4a3043809048e (patch)
tree8b3d00f78a4a5a34cc3b17e29c28b4472d93a35c /libexec
parentdcbae417f8f4365a5eea807290162acd308b720d (diff)
downloadFreeBSD-src-ce15efb7c04858f00b57c16093d4a3043809048e.zip
FreeBSD-src-ce15efb7c04858f00b57c16093d4a3043809048e.tar.gz
another tcp apps IPv6 updates.(should be make world safe)
ftp, telnet, ftpd, faithd also telnet related sync with crypto, secure, kerberosIV Obtained from: KAME project
Diffstat (limited to 'libexec')
-rw-r--r--libexec/ftpd/Makefile1
-rw-r--r--libexec/ftpd/extern.h16
-rw-r--r--libexec/ftpd/ftpcmd.y364
-rw-r--r--libexec/ftpd/ftpd.823
-rw-r--r--libexec/ftpd/ftpd.c503
-rw-r--r--libexec/ftpd/logwtmp.c23
-rw-r--r--libexec/ftpd/popen.c1
7 files changed, 812 insertions, 119 deletions
diff --git a/libexec/ftpd/Makefile b/libexec/ftpd/Makefile
index c23e85b..4ddfb53 100644
--- a/libexec/ftpd/Makefile
+++ b/libexec/ftpd/Makefile
@@ -7,6 +7,7 @@ SRCS= ftpd.c ftpcmd.y logwtmp.c popen.c skey-stuff.c
CFLAGS+=-DSETPROCTITLE -DSKEY -DLOGIN_CAP -DVIRTUAL_HOSTING -Wall \
-I${.CURDIR}/../../contrib-crypto/telnet
+CFLAGS+=-DINET6 -g
YFLAGS=
LDADD= -lskey -lmd -lcrypt -lutil
diff --git a/libexec/ftpd/extern.h b/libexec/ftpd/extern.h
index 9888cb6..684703e 100644
--- a/libexec/ftpd/extern.h
+++ b/libexec/ftpd/extern.h
@@ -49,6 +49,7 @@ void makedir __P((char *));
void nack __P((char *));
void pass __P((char *));
void passive __P((void));
+void long_passive __P((char *, int));
void perror_reply __P((int, char *));
void pwd __P((void));
void removedir __P((char *));
@@ -71,3 +72,18 @@ int yyparse __P((void));
char *skey_challenge __P((char *, struct passwd *, int));
#endif
int ls_main __P((int, char **));
+
+struct sockaddr_in;
+struct sockaddr_in6;
+union sockunion {
+ struct sockinet {
+ u_char si_len;
+ u_char si_family;
+ u_short si_port;
+ } su_si;
+ struct sockaddr_in su_sin;
+ struct sockaddr_in6 su_sin6;
+};
+#define su_len su_si.si_len
+#define su_family su_si.si_family
+#define su_port su_si.si_port
diff --git a/libexec/ftpd/ftpcmd.y b/libexec/ftpd/ftpcmd.y
index e085e29..bb5bff9 100644
--- a/libexec/ftpd/ftpcmd.y
+++ b/libexec/ftpd/ftpcmd.y
@@ -58,6 +58,7 @@ static const char rcsid[] =
#include <ctype.h>
#include <errno.h>
#include <glob.h>
+#include <netdb.h>
#include <pwd.h>
#include <setjmp.h>
#include <signal.h>
@@ -71,7 +72,7 @@ static const char rcsid[] =
#include "extern.h"
-extern struct sockaddr_in data_dest, his_addr;
+extern union sockunion data_dest, his_addr;
extern int logged_in;
extern struct passwd *pw;
extern int guest;
@@ -98,6 +99,8 @@ static int cmd_bytesz;
char cbuf[512];
char *fromname;
+extern int epsvall;
+
%}
%union {
@@ -108,6 +111,7 @@ char *fromname;
%token
A B C E F I
L N P R S T
+ ALL
SP CRLF COMMA
@@ -118,6 +122,7 @@ char *fromname;
ABOR DELE CWD LIST NLST SITE
STAT HELP NOOP MKD RMD PWD
CDUP STOU SMNT SYST SIZE MDTM
+ LPRT LPSV EPRT EPSV
UMASK IDLE CHMOD
@@ -128,7 +133,8 @@ char *fromname;
%type <i> check_login octal_number byte_size
%type <i> struct_code mode_code type_code form_code
-%type <s> pathstring pathname password username
+%type <s> pathstring pathname password username ext_arg
+%type <s> ALL
%start cmd_list
@@ -157,31 +163,194 @@ cmd
}
| PORT check_login SP host_port CRLF
{
- if ($2) {
- if (paranoid &&
- ((ntohs(data_dest.sin_port) <
- IPPORT_RESERVED) ||
- memcmp(&data_dest.sin_addr,
- &his_addr.sin_addr,
- sizeof(data_dest.sin_addr)))) {
- usedefault = 1;
+ if (epsvall) {
+ reply(501, "no PORT allowed after EPSV ALL");
+ goto port_done;
+ }
+ if (!$2)
+ goto port_done;
+ if (port_check("PORT") == 1)
+ goto port_done;
+#ifdef INET6
+ if ((his_addr.su_family != AF_INET6 ||
+ !IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr))) {
+ /* shoud never happen */
+ usedefault = 1;
+ reply(500, "Invalid address rejected.");
+ goto port_done;
+ }
+ port_check_v6("pcmd");
+#endif
+ port_done:
+ }
+ | LPRT check_login SP host_long_port CRLF
+ {
+ if (epsvall) {
+ reply(501, "no LPRT allowed after EPSV ALL");
+ goto lprt_done;
+ }
+ if (!$2)
+ goto lprt_done;
+ if (port_check("LPRT") == 1)
+ goto lprt_done;
+#ifdef INET6
+ if (his_addr.su_family != AF_INET6) {
+ usedefault = 1;
+ reply(500, "Invalid address rejected.");
+ goto lprt_done;
+ }
+ if (port_check_v6("LPRT") == 1)
+ goto lprt_done;
+#endif
+ lprt_done:
+ }
+ | EPRT check_login SP STRING CRLF
+ {
+ char delim;
+ char *tmp = NULL;
+ char *p, *q;
+ char *result[3];
+ struct addrinfo hints;
+ struct addrinfo *res;
+ int i;
+
+ if (epsvall) {
+ reply(501, "no EPRT allowed after EPSV ALL");
+ goto eprt_done;
+ }
+ if (!$2)
+ goto eprt_done;
+
+ memset(&data_dest, 0, sizeof(data_dest));
+ tmp = strdup($4);
+ if (debug)
+ syslog(LOG_DEBUG, "%s", tmp);
+ if (!tmp) {
+ fatal("not enough core");
+ /*NOTREACHED*/
+ }
+ p = tmp;
+ delim = p[0];
+ p++;
+ memset(result, 0, sizeof(result));
+ for (i = 0; i < 3; i++) {
+ q = strchr(p, delim);
+ if (!q || *q != delim) {
+ parsefail:
reply(500,
- "Illegal PORT range rejected.");
- } else {
- usedefault = 0;
- if (pdata >= 0) {
- (void) close(pdata);
- pdata = -1;
- }
- reply(200, "PORT command successful.");
+ "Invalid argument, rejected.");
+ if (tmp)
+ free(tmp);
+ usedefault = 1;
+ goto eprt_done;
}
+ *q++ = '\0';
+ result[i] = p;
+ if (debug)
+ syslog(LOG_DEBUG, "%d: %s", i, p);
+ p = q;
+ }
+
+ /* some more sanity check */
+ p = result[0];
+ while (*p) {
+ if (!isdigit(*p))
+ goto parsefail;
+ p++;
}
+ p = result[2];
+ while (*p) {
+ if (!isdigit(*p))
+ goto parsefail;
+ p++;
+ }
+
+ /* grab address */
+ memset(&hints, 0, sizeof(hints));
+ if (atoi(result[0]) == 1)
+ hints.ai_family = PF_INET;
+#ifdef INET6
+ else if (atoi(result[0]) == 2)
+ hints.ai_family = PF_INET6;
+#endif
+ else
+ hints.ai_family = PF_UNSPEC; /*XXX*/
+ hints.ai_socktype = SOCK_STREAM;
+ i = getaddrinfo(result[1], result[2], &hints, &res);
+ if (i)
+ goto parsefail;
+ memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
+#ifdef INET6
+ if (his_addr.su_family == AF_INET6
+ && data_dest.su_family == AF_INET6) {
+ /* XXX more sanity checks! */
+ data_dest.su_sin6.sin6_scope_id =
+ his_addr.su_sin6.sin6_scope_id;
+ }
+#endif
+ free(tmp);
+ tmp = NULL;
+
+ if (port_check("EPRT") == 1)
+ goto eprt_done;
+#ifdef INET6
+ if (his_addr.su_family != AF_INET6) {
+ usedefault = 1;
+ reply(500, "Invalid address rejected.");
+ goto eprt_done;
+ }
+ if (port_check_v6("EPRT") == 1)
+ goto eprt_done;
+#endif
+ eprt_done:;
}
| PASV check_login CRLF
{
- if ($2)
+ if (epsvall)
+ reply(501, "no PASV allowed after EPSV ALL");
+ else if ($2)
passive();
}
+ | LPSV check_login CRLF
+ {
+ if (epsvall)
+ reply(501, "no LPSV allowed after EPSV ALL");
+ else if ($2)
+ long_passive("LPSV", PF_UNSPEC);
+ }
+ | EPSV check_login SP NUMBER CRLF
+ {
+ if ($2) {
+ int pf;
+ switch ($4) {
+ case 1:
+ pf = PF_INET;
+ break;
+#ifdef INET6
+ case 2:
+ pf = PF_INET6;
+ break;
+#endif
+ default:
+ pf = -1; /*junk value*/
+ break;
+ }
+ long_passive("EPSV", pf);
+ }
+ }
+ | EPSV check_login SP ALL CRLF
+ {
+ if ($2) {
+ reply(200,
+ "EPSV ALL command successful.");
+ epsvall++;
+ }
+ }
+ | EPSV check_login CRLF
+ {
+ if ($2)
+ long_passive("EPSV", PF_UNSPEC);
+ }
| TYPE SP type_code CRLF
{
switch (cmd_type) {
@@ -576,15 +745,61 @@ host_port
{
char *a, *p;
- data_dest.sin_len = sizeof(struct sockaddr_in);
- data_dest.sin_family = AF_INET;
- p = (char *)&data_dest.sin_port;
+ data_dest.su_len = sizeof(struct sockaddr_in);
+ data_dest.su_family = AF_INET;
+ p = (char *)&data_dest.su_sin.sin_port;
p[0] = $9; p[1] = $11;
- a = (char *)&data_dest.sin_addr;
+ a = (char *)&data_dest.su_sin.sin_addr;
a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;
}
;
+host_long_port
+ : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER
+ {
+ char *a, *p;
+
+ memset(&data_dest, 0, sizeof(data_dest));
+ data_dest.su_len = sizeof(struct sockaddr_in6);
+ data_dest.su_family = AF_INET6;
+ p = (char *)&data_dest.su_port;
+ p[0] = $39; p[1] = $41;
+ a = (char *)&data_dest.su_sin6.sin6_addr;
+ a[0] = $5; a[1] = $7; a[2] = $9; a[3] = $11;
+ a[4] = $13; a[5] = $15; a[6] = $17; a[7] = $19;
+ a[8] = $21; a[9] = $23; a[10] = $25; a[11] = $27;
+ a[12] = $29; a[13] = $31; a[14] = $33; a[15] = $35;
+ if (his_addr.su_family == AF_INET6) {
+ /* XXX more sanity checks! */
+ data_dest.su_sin6.sin6_scope_id =
+ his_addr.su_sin6.sin6_scope_id;
+ }
+ if ($1 != 6 || $3 != 16 || $37 != 2)
+ memset(&data_dest, 0, sizeof(data_dest));
+ }
+ | NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER
+ {
+ char *a, *p;
+
+ memset(&data_dest, 0, sizeof(data_dest));
+ data_dest.su_sin.sin_len = sizeof(struct sockaddr_in);
+ data_dest.su_family = AF_INET;
+ p = (char *)&data_dest.su_port;
+ p[0] = $15; p[1] = $17;
+ a = (char *)&data_dest.su_sin.sin_addr;
+ a[0] = $5; a[1] = $7; a[2] = $9; a[3] = $11;
+ if ($1 != 4 || $3 != 4 || $13 != 2)
+ memset(&data_dest, 0, sizeof(data_dest));
+ }
+ ;
+
form_code
: N
{
@@ -774,7 +989,11 @@ struct tab cmdtab[] = { /* In order defined in RFC 765 */
{ "REIN", REIN, ARGS, 0, "(reinitialize server state)" },
{ "QUIT", QUIT, ARGS, 1, "(terminate service)", },
{ "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" },
+ { "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." },
+ { "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|" },
{ "PASV", PASV, ARGS, 1, "(set server in passive mode)" },
+ { "LPSV", LPSV, ARGS, 1, "(set server in passive mode)" },
+ { "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]" },
{ "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" },
{ "STRU", STRU, ARGS, 1, "(specify file structure)" },
{ "MODE", MODE, ARGS, 1, "(specify transfer mode)" },
@@ -829,8 +1048,11 @@ static char *copy __P((char *));
static void help __P((struct tab *, char *));
static struct tab *
lookup __P((struct tab *, char *));
+static int port_check __P((const char *));
+static int port_check_v6 __P((const char *));
static void sizecmd __P((char *));
static void toolong __P((int));
+static void v4map_data_dest __P((void));
static int yylex __P((void));
static struct tab *
@@ -1085,6 +1307,11 @@ yylex()
cbuf[cpos] = c;
return (NUMBER);
}
+ if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0
+ && !isalnum(cbuf[cpos + 3])) {
+ cpos += 3;
+ return ALL;
+ }
switch (cbuf[cpos++]) {
case '\n':
@@ -1289,3 +1516,94 @@ sizecmd(filename)
reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
}
}
+
+/* Return 1, if port check is done. Return 0, if not yet. */
+static int
+port_check(pcmd)
+ const char *pcmd;
+{
+ if (his_addr.su_family == AF_INET) {
+ if (data_dest.su_family != AF_INET) {
+ usedefault = 1;
+ reply(500, "Invalid address rejected.");
+ return 1;
+ }
+ if (paranoid &&
+ ((ntohs(data_dest.su_port) < IPPORT_RESERVED) ||
+ memcmp(&data_dest.su_sin.sin_addr,
+ &his_addr.su_sin.sin_addr,
+ sizeof(data_dest.su_sin.sin_addr)))) {
+ usedefault = 1;
+ reply(500, "Illegal PORT range rejected.");
+ } else {
+ usedefault = 0;
+ if (pdata >= 0) {
+ (void) close(pdata);
+ pdata = -1;
+ }
+ reply(200, "%s command successful.", pcmd);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+#ifdef INET6
+/* Return 1, if port check is done. Return 0, if not yet. */
+static int
+port_check_v6(pcmd)
+ const char *pcmd;
+{
+ if (his_addr.su_family == AF_INET6) {
+ if (IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr))
+ /* Convert data_dest into v4 mapped sockaddr.*/
+ v4map_data_dest();
+ if (data_dest.su_family != AF_INET6) {
+ usedefault = 1;
+ reply(500, "Invalid address rejected.");
+ return 1;
+ }
+ if (paranoid &&
+ ((ntohs(data_dest.su_port) < IPPORT_RESERVED) ||
+ memcmp(&data_dest.su_sin6.sin6_addr,
+ &his_addr.su_sin6.sin6_addr,
+ sizeof(data_dest.su_sin6.sin6_addr)))) {
+ usedefault = 1;
+ reply(500, "Illegal PORT range rejected.");
+ } else {
+ usedefault = 0;
+ if (pdata >= 0) {
+ (void) close(pdata);
+ pdata = -1;
+ }
+ reply(200, "%s command successful.", pcmd);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static void
+v4map_data_dest()
+{
+ struct in_addr savedaddr;
+ int savedport;
+
+ if (data_dest.su_family != AF_INET) {
+ usedefault = 1;
+ reply(500, "Invalid address rejected.");
+ return;
+ }
+
+ savedaddr = data_dest.su_sin.sin_addr;
+ savedport = data_dest.su_port;
+
+ memset(&data_dest, 0, sizeof(data_dest));
+ data_dest.su_sin6.sin6_len = sizeof(struct sockaddr_in6);
+ data_dest.su_sin6.sin6_family = AF_INET6;
+ data_dest.su_sin6.sin6_port = savedport;
+ memset((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[10], 0xff, 2);
+ memcpy((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[12],
+ (caddr_t)&savedaddr, sizeof(savedaddr));
+}
+#endif
diff --git a/libexec/ftpd/ftpd.8 b/libexec/ftpd/ftpd.8
index 8f2cca7..fb10aa6 100644
--- a/libexec/ftpd/ftpd.8
+++ b/libexec/ftpd/ftpd.8
@@ -32,7 +32,7 @@
.\" @(#)ftpd.8 8.2 (Berkeley) 4/19/94
.\" $FreeBSD$
.\"
-.Dd April 19, 1994
+.Dd January 27, 2000
.Dt FTPD 8
.Os BSD 4.2
.Sh NAME
@@ -41,6 +41,8 @@
Internet File Transfer Protocol server
.Sh SYNOPSIS
.Nm ftpd
+.Op Fl 4
+.Op Fl 6
.Op Fl d
.Op Fl l Op Fl l
.Op Fl A
@@ -135,6 +137,20 @@ When
.Fl D
is specified, write the daemon's process ID to
.Ar file .
+.It Fl 6
+When
+.Fl D
+is specified, accept connections via AF_INET6 socket.
+.It Fl 4
+When
+.Fl D
+is specified, accept IPv4 connections.
+When
+.Fl 6
+is also specified, accept IPv4 connection via AF_INET6 socket.
+When
+.Fl 6
+is not specified, accept IPv4 connection via AF_INET socket.
.It Fl A
Allow only anonymous ftp access.
.El
@@ -203,6 +219,10 @@ The case of the requests is ignored.
.It XMKD Ta "make a directory (deprecated)"
.It XPWD Ta "print the current working directory (deprecated)"
.It XRMD Ta "remove a directory (deprecated)"
+.It LPSV Ta "prepare for server-to-server transfer, multiprotocol"
+.It LPRT Ta "specify data connection port, multiprotocol"
+.It EPSV Ta "prepare for server-to-server transfer, multiprotocol"
+.It EPRT Ta "specify data connection port, multiprotocol"
.El
.Pp
The following non-standard or
@@ -453,3 +473,4 @@ The
.Nm
command appeared in
.Bx 4.2 .
+IPv6 support was added in WIDE Hydrangea IPv6 stack kit.
diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c
index 0f9d20c..cd72ed2 100644
--- a/libexec/ftpd/ftpd.c
+++ b/libexec/ftpd/ftpd.c
@@ -110,15 +110,20 @@ static const char rcsid[] =
static char version[] = "Version 6.00LS";
#undef main
+/* wrapper for KAME-special getnameinfo() */
+#ifndef NI_WITHSCOPEID
+#define NI_WITHSCOPEID 0
+#endif
+
extern off_t restart_point;
extern char cbuf[];
-struct sockaddr_in server_addr;
-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;
+union sockunion server_addr;
+union sockunion ctrl_addr;
+union sockunion data_source;
+union sockunion data_dest;
+union sockunion his_addr;
+union sockunion pasv_addr;
int daemon_mode;
int data;
@@ -155,9 +160,11 @@ char *hostname;
#ifdef VIRTUAL_HOSTING
char *ftpuser;
+int epsvall = 0;
+
static struct ftphost {
struct ftphost *next;
- struct in_addr hostaddr;
+ union sockunion hostaddr;
char *hostname;
char *anonuser;
char *statfile;
@@ -176,7 +183,6 @@ char *tty = ttyline; /* for klogin */
static int auth_pam __P((struct passwd**, const char*));
#endif
-struct in_addr bind_address;
char *pid_file = NULL;
/*
@@ -200,7 +206,7 @@ char proctitle[LINE_MAX]; /* initial part of title */
#ifdef SKEY
int pwok = 0;
-char addr_string[20]; /* XXX */
+char addr_string[INET6_ADDRSTRLEN]; /* XXX */
#endif
#define LOGCMD(cmd, file) \
@@ -224,13 +230,13 @@ char addr_string[20]; /* XXX */
#ifdef VIRTUAL_HOSTING
static void inithosts __P((void));
-static void selecthost __P((struct in_addr *));
+static void selecthost __P((union sockunion *));
#endif
static void ack __P((char *));
static void myoob __P((int));
static int checkuser __P((char *, char *, int));
static FILE *dataconn __P((char *, off_t, char *));
-static void dolog __P((struct sockaddr_in *));
+static void dolog __P((struct sockaddr *));
static char *curdir __P((void));
static void end_login __P((void));
static FILE *getdatasock __P((char *));
@@ -266,6 +272,10 @@ main(argc, argv, envp)
int addrlen, ch, on = 1, tos;
char *cp, line[LINE_MAX];
FILE *fd;
+ int error;
+ char *bindname = NULL;
+ int family = AF_UNSPEC;
+ int enable_v4 = 0;
tzset(); /* in case no timezone database in ~ftp */
@@ -280,8 +290,7 @@ main(argc, argv, envp)
#endif /* OLD_SETPROCTITLE */
- bind_address.s_addr = htonl(INADDR_ANY);
- while ((ch = getopt(argc, argv, "AdlDSURt:T:u:va:p:")) != -1) {
+ while ((ch = getopt(argc, argv, "AdlDSURt:T:u:va:p:46")) != -1) {
switch (ch) {
case 'D':
daemon_mode++;
@@ -320,8 +329,7 @@ main(argc, argv, envp)
break;
case 'a':
- if (!inet_aton(optarg, &bind_address))
- errx(1, "invalid address for -a");
+ bindname = optarg;
break;
case 'p':
@@ -347,6 +355,16 @@ main(argc, argv, envp)
debug = 1;
break;
+ case '4':
+ enable_v4 = 1;
+ if (family == AF_UNSPEC)
+ family = AF_INET;
+ break;
+
+ case '6':
+ family = AF_INET6;
+ break;
+
default:
warnx("unknown flag -%c ignored", optopt);
break;
@@ -366,7 +384,7 @@ main(argc, argv, envp)
if (daemon_mode) {
int ctl_sock, fd;
- struct servent *sv;
+ struct addrinfo hints, *res;
/*
* Detach from parent.
@@ -376,30 +394,56 @@ main(argc, argv, envp)
exit(1);
}
(void) signal(SIGCHLD, reapchild);
- /*
- * Get port number for ftp/tcp.
- */
- sv = getservbyname("ftp", "tcp");
- if (sv == NULL) {
- syslog(LOG_ERR, "getservbyname for ftp failed");
+ /* init bind_sa */
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = family == AF_UNSPEC ? AF_INET : family;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ hints.ai_flags = AI_PASSIVE;
+ error = getaddrinfo(bindname, "ftp", &hints, &res);
+ if (error) {
+ if (family == AF_UNSPEC) {
+ hints.ai_family = AF_UNSPEC;
+ error = getaddrinfo(bindname, "ftp", &hints,
+ &res);
+ }
+ if (error == 0 && res->ai_addr != NULL)
+ family = res->ai_addr->sa_family;
+ }
+ if (error) {
+ syslog(LOG_ERR, gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ syslog(LOG_ERR, strerror(errno));
+ exit(1);
+ }
+ if (res->ai_addr == NULL) {
+ syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname);
exit(1);
}
/*
* Open a socket, bind it to the FTP port, and start
* listening.
*/
- ctl_sock = socket(AF_INET, SOCK_STREAM, 0);
+ ctl_sock = socket(family, SOCK_STREAM, 0);
if (ctl_sock < 0) {
syslog(LOG_ERR, "control socket: %m");
exit(1);
}
if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on)) < 0)
- syslog(LOG_ERR, "control setsockopt: %m");;
- server_addr.sin_family = AF_INET;
- server_addr.sin_addr = bind_address;
- server_addr.sin_port = sv->s_port;
- if (bind(ctl_sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) {
+ syslog(LOG_ERR, "control setsockopt: %m");
+#ifdef IPV6_BINDV6ONLY
+ if (family == AF_INET6 && enable_v4 == 0) {
+ if (setsockopt(ctl_sock, IPPROTO_IPV6, IPV6_BINDV6ONLY,
+ (char *)&on, sizeof (on)) < 0)
+ syslog(LOG_ERR,
+ "control setsockopt(IPV6_BINDV6ONLY): %m");
+ }
+#endif /* IPV6_BINDV6ONLY */
+ memcpy(&server_addr, res->ai_addr, res->ai_addr->sa_len);
+ if (bind(ctl_sock, (struct sockaddr *)&server_addr,
+ server_addr.su_len) < 0) {
syslog(LOG_ERR, "control bind: %m");
exit(1);
}
@@ -434,7 +478,7 @@ main(argc, argv, envp)
* children to handle them.
*/
while (1) {
- addrlen = sizeof(his_addr);
+ addrlen = server_addr.su_len;
fd = accept(ctl_sock, (struct sockaddr *)&his_addr, &addrlen);
if (fork() == 0) {
/* child */
@@ -459,7 +503,9 @@ main(argc, argv, envp)
syslog(LOG_ERR, "signal: %m");
#ifdef SKEY
- strncpy(addr_string, inet_ntoa(his_addr.sin_addr), sizeof(addr_string));
+ getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
+ addr_string, sizeof(addr_string) - 1, NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
#endif
addrlen = sizeof(ctrl_addr);
if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
@@ -468,12 +514,15 @@ main(argc, argv, envp)
}
#ifdef VIRTUAL_HOSTING
/* select our identity from virtual host table */
- selecthost(&ctrl_addr.sin_addr);
+ selecthost(&ctrl_addr);
#endif
#ifdef IP_TOS
+ if (ctrl_addr.su_family == AF_INET)
+ {
tos = IPTOS_LOWDELAY;
if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+ }
#endif
/*
* Disable Nagle on the control channel so that we don't have to wait
@@ -482,7 +531,7 @@ main(argc, argv, envp)
if (setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
syslog(LOG_WARNING, "control setsockopt TCP_NODELAY: %m");
- data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
+ data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1);
/* set this here so klogin can use it... */
(void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
@@ -497,7 +546,7 @@ main(argc, argv, envp)
if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
syslog(LOG_ERR, "fcntl F_SETOWN: %m");
#endif
- dolog(&his_addr);
+ dolog((struct sockaddr *)&his_addr);
/*
* Set up default state
*/
@@ -567,9 +616,9 @@ inithosts()
{
FILE *fp;
char *cp;
- struct hostent *hp;
struct ftphost *hrp, *lhrp;
char line[1024];
+ struct addrinfo hints, *res, *ai;
/*
* Fill in the default host information
@@ -579,20 +628,28 @@ inithosts()
if ((hrp = malloc(sizeof(struct ftphost))) == NULL ||
(hrp->hostname = strdup(line)) == NULL)
fatal("Ran out of memory.");
- memset(&hrp->hostaddr, 0, sizeof hrp->hostaddr);
- if ((hp = gethostbyname(hrp->hostname)) != NULL)
- (void) memcpy(&hrp->hostaddr,
- hp->h_addr_list[0],
- sizeof(hrp->hostaddr));
+ memset(&hrp->hostaddr, 0, sizeof(hrp->hostaddr));
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_UNSPEC;
+ getaddrinfo(hrp->hostname, NULL, &hints, &res);
+ if (res)
+ memcpy(&hrp->hostaddr, res->ai_addr, res->ai_addrlen);
hrp->statfile = _PATH_FTPDSTATFILE;
hrp->welcome = _PATH_FTPWELCOME;
hrp->loginmsg = _PATH_FTPLOGINMESG;
hrp->anonuser = "ftp";
hrp->next = NULL;
thishost = firsthost = lhrp = hrp;
+ freeaddrinfo(res);
if ((fp = fopen(_PATH_FTPHOSTS, "r")) != NULL) {
+ int addrsize, error;
+ void *addr;
+ struct hostent *hp;
+
while (fgets(line, sizeof(line), fp) != NULL) {
- int i;
+ int i, hp_error;
if ((cp = strchr(line, '\n')) == NULL) {
/* ignore long lines */
@@ -606,13 +663,21 @@ inithosts()
/* skip comments and empty lines */
if (cp == NULL || line[0] == '#')
continue;
- /* first, try a standard gethostbyname() */
- if ((hp = gethostbyname(cp)) == NULL)
+
+ hints.ai_flags = 0;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_PASSIVE;
+ error = getaddrinfo(cp, NULL, &hints, &res);
+ if (error != NULL)
continue;
+ for (ai = res; ai != NULL && ai->ai_addr != NULL;
+ ai = ai->ai_next)
+ {
+
for (hrp = firsthost; hrp != NULL; hrp = hrp->next) {
if (memcmp(&hrp->hostaddr,
- hp->h_addr_list[0],
- sizeof(hrp->hostaddr)) == 0)
+ ai->ai_addr,
+ ai->ai_addr->sa_len) == 0)
break;
}
if (hrp == NULL) {
@@ -628,16 +693,32 @@ inithosts()
lhrp = hrp;
}
(void) memcpy(&hrp->hostaddr,
- hp->h_addr_list[0],
- sizeof(hrp->hostaddr));
+ ai->ai_addr,
+ ai->ai_addr->sa_len);
/*
* determine hostname to use.
- * force defined name if it is a valid alias
+ * force defined name if there is a valid alias
* otherwise fallback to primary hostname
*/
- if ((hp = gethostbyaddr((char*)&hrp->hostaddr,
- sizeof(hrp->hostaddr),
- AF_INET)) != NULL) {
+ /* XXX: getaddrinfo() can't do alias check */
+ switch(hrp->hostaddr.su_family) {
+ case AF_INET:
+ addr = &((struct sockaddr_in *)&hrp->hostaddr)->sin_addr;
+ addrsize = sizeof(struct sockaddr_in);
+ break;
+ case AF_INET6:
+ addr = &((struct sockaddr_in6 *)&hrp->hostaddr)->sin6_addr;
+ addrsize = sizeof(struct sockaddr_in6);
+ break;
+ default:
+ /* should not reach here */
+ free(hrp);
+ continue;
+ /* NOTREACHED */
+ }
+ if ((hp = getipnodebyaddr((char*)addr, addrsize,
+ hrp->hostaddr.su_family,
+ &hp_error)) != NULL) {
if (strcmp(cp, hp->h_name) != 0) {
if (hp->h_aliases == NULL)
cp = hp->h_name;
@@ -652,6 +733,7 @@ inithosts()
}
}
hrp->hostname = strdup(cp);
+ freehostent(hp);
/* ok, now we now peel off the rest */
i = 0;
while (i < 4 && (cp = strtok(NULL, " \t")) != NULL) {
@@ -673,25 +755,55 @@ inithosts()
}
++i;
}
+ /* XXX: re-initialization for getaddrinfo() loop */
+ cp = strtok(line, " \t");
+ }
}
(void) fclose(fp);
}
}
static void
-selecthost(a)
- struct in_addr *a;
+selecthost(su)
+ union sockunion *su;
{
struct ftphost *hrp;
+ u_int16_t port;
+#ifdef INET6
+ struct in6_addr *mapped_in6 = NULL;
+#endif
+
+#ifdef INET6
+ /*
+ * XXX IPv4 mapped IPv6 addr consideraton,
+ * specified in rfc2373.
+ */
+ if (su->su_family == AF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED(&su->su_sin6.sin6_addr))
+ mapped_in6 = &su->su_sin6.sin6_addr;
+#endif
hrp = thishost = firsthost; /* default */
+ port = su->su_port;
+ su->su_port = 0;
while (hrp != NULL) {
- if (memcmp(a, &hrp->hostaddr, sizeof(hrp->hostaddr)) == 0) {
+ if (memcmp(su, &hrp->hostaddr, sizeof(hrp->hostaddr)) == 0) {
+ thishost = hrp;
+ break;
+ }
+#ifdef INET6
+ /* XXX IPv4 mapped IPv6 addr consideraton */
+ if (hrp->hostaddr.su_family == AF_INET && mapped_in6 != NULL &&
+ (memcmp(&mapped_in6->s6_addr[12],
+ &hrp->hostaddr.su_sin.sin_addr,
+ sizeof(struct in_addr)) == 0)) {
thishost = hrp;
break;
}
+#endif
hrp = hrp->next;
}
+ su->su_port = port;
/* setup static variables as appropriate */
hostname = thishost->hostname;
ftpuser = thishost->anonuser;
@@ -1107,8 +1219,9 @@ skip:
if ((lc = login_getpwclass(pw)) != NULL) {
char remote_ip[MAXHOSTNAMELEN];
- strncpy(remote_ip, inet_ntoa(his_addr.sin_addr),
- sizeof(remote_ip) - 1);
+ getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
+ remote_ip, sizeof(remote_ip) - 1, NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
remote_ip[sizeof(remote_ip) - 1] = 0;
if (!auth_hostok(lc, remotehost, remote_ip)) {
syslog(LOG_INFO|LOG_AUTH,
@@ -1402,19 +1515,19 @@ getdatasock(mode)
if (data >= 0)
return (fdopen(data, mode));
(void) seteuid((uid_t)0);
- s = socket(AF_INET, SOCK_STREAM, 0);
+
+ s = socket(data_dest.su_family, SOCK_STREAM, 0);
if (s < 0)
goto bad;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(char *) &on, sizeof(on)) < 0)
goto bad;
/* anchor socket to avoid multi-homing problems */
- data_source.sin_len = sizeof(struct sockaddr_in);
- data_source.sin_family = AF_INET;
- data_source.sin_addr = ctrl_addr.sin_addr;
+ data_source = ctrl_addr;
+ data_source.su_port = htons(20); /* ftp-data port */
for (tries = 1; ; tries++) {
if (bind(s, (struct sockaddr *)&data_source,
- sizeof(data_source)) >= 0)
+ data_source.su_len) >= 0)
break;
if (errno != EADDRINUSE || tries > 10)
goto bad;
@@ -1422,9 +1535,12 @@ getdatasock(mode)
}
(void) seteuid((uid_t)pw->pw_uid);
#ifdef IP_TOS
+ if (data_source.su_family == AF_INET)
+ {
on = IPTOS_THROUGHPUT;
if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+ }
#endif
#ifdef TCP_NOPUSH
/*
@@ -1470,8 +1586,8 @@ dataconn(name, size, mode)
else
*sizebuf = '\0';
if (pdata >= 0) {
- struct sockaddr_in from;
- int s, fromlen = sizeof(from);
+ union sockunion from;
+ int s, fromlen = ctrl_addr.su_len;
struct timeval timeout;
fd_set set;
@@ -1491,9 +1607,12 @@ dataconn(name, size, mode)
(void) close(pdata);
pdata = s;
#ifdef IP_TOS
+ if (from.su_family == AF_INET)
+ {
tos = IPTOS_THROUGHPUT;
(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
sizeof(int));
+ }
#endif
reply(150, "Opening %s mode data connection for '%s'%s.",
type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
@@ -1510,14 +1629,18 @@ dataconn(name, size, mode)
usedefault = 1;
file = getdatasock(mode);
if (file == NULL) {
- reply(425, "Can't create data socket (%s,%d): %s.",
- inet_ntoa(data_source.sin_addr),
- ntohs(data_source.sin_port), strerror(errno));
+ char hostbuf[BUFSIZ], portbuf[BUFSIZ];
+ getnameinfo((struct sockaddr *)&data_source,
+ data_source.su_len, hostbuf, sizeof(hostbuf) - 1,
+ portbuf, sizeof(portbuf),
+ NI_NUMERICHOST|NI_NUMERICSERV|NI_WITHSCOPEID);
+ reply(425, "Can't create data socket (%s,%s): %s.",
+ hostbuf, portbuf, strerror(errno));
return (NULL);
}
data = fileno(file);
while (connect(data, (struct sockaddr *)&data_dest,
- sizeof(data_dest)) < 0) {
+ data_dest.su_len) < 0) {
if (errno == EADDRINUSE && retry < swaitmax) {
sleep((unsigned) swaitint);
retry += swaitint;
@@ -1768,14 +1891,20 @@ statfilecmd(filename)
void
statcmd()
{
- struct sockaddr_in *sin;
+ union sockunion *su;
u_char *a, *p;
+ char hname[INET6_ADDRSTRLEN];
+ int ispassive;
lreply(211, "%s FTP server status:", hostname, version);
printf(" %s\r\n", version);
printf(" Connected to %s", remotehost);
- if (!isdigit(remotehost[0]))
- printf(" (%s)", inet_ntoa(his_addr.sin_addr));
+ if (!getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
+ hname, sizeof(hname) - 1, NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID)) {
+ if (strcmp(hname, remotehost) != 0)
+ printf(" (%s)", hname);
+ }
printf("\r\n");
if (logged_in) {
if (guest)
@@ -1800,18 +1929,85 @@ statcmd()
if (data != -1)
printf(" Data connection open\r\n");
else if (pdata != -1) {
- printf(" in Passive mode");
- sin = &pasv_addr;
+ ispassive = 1;
+ su = &pasv_addr;
goto printaddr;
} else if (usedefault == 0) {
- printf(" PORT");
- sin = &data_dest;
+ ispassive = 0;
+ su = &data_dest;
printaddr:
- a = (u_char *) &sin->sin_addr;
- p = (u_char *) &sin->sin_port;
#define UC(b) (((int) b) & 0xff)
- printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
- UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
+ if (epsvall) {
+ printf(" EPSV only mode (EPSV ALL)\r\n");
+ goto epsvonly;
+ }
+
+ /* PORT/PASV */
+ if (su->su_family == AF_INET) {
+ a = (u_char *) &su->su_sin.sin_addr;
+ p = (u_char *) &su->su_sin.sin_port;
+ printf(" %s (%d,%d,%d,%d,%d,%d)\r\n",
+ ispassive ? "PASV" : "PORT",
+ UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
+ UC(p[0]), UC(p[1]));
+ }
+
+ /* LPRT/LPSV */
+ {
+ int alen, af, i;
+
+ switch (su->su_family) {
+ case AF_INET:
+ a = (u_char *) &su->su_sin.sin_addr;
+ p = (u_char *) &su->su_sin.sin_port;
+ alen = sizeof(su->su_sin.sin_addr);
+ af = 4;
+ break;
+ case AF_INET6:
+ a = (u_char *) &su->su_sin6.sin6_addr;
+ p = (u_char *) &su->su_sin6.sin6_port;
+ alen = sizeof(su->su_sin6.sin6_addr);
+ af = 6;
+ break;
+ default:
+ af = 0;
+ break;
+ }
+ if (af) {
+ printf(" %s (%d,%d,", ispassive ? "LPSV" : "LPRT",
+ af, alen);
+ for (i = 0; i < alen; i++)
+ printf("%d,", UC(a[i]));
+ printf("%d,%d,%d)\r\n", 2, UC(p[0]), UC(p[1]));
+ }
+ }
+
+epsvonly:;
+ /* EPRT/EPSV */
+ {
+ int af;
+
+ switch (su->su_family) {
+ case AF_INET:
+ af = 1;
+ break;
+ case AF_INET6:
+ af = 2;
+ break;
+ default:
+ af = 0;
+ break;
+ }
+ if (af) {
+ if (!getnameinfo((struct sockaddr *)su, su->su_len,
+ hname, sizeof(hname) - 1, NULL, 0,
+ NI_NUMERICHOST)) {
+ printf(" %s |%d|%s|%d|\r\n",
+ ispassive ? "EPSV" : "EPRT",
+ af, hname, htons(su->su_port));
+ }
+ }
+ }
#undef UC
} else
printf(" No data connection\r\n");
@@ -2015,10 +2211,12 @@ renamecmd(from, to)
}
static void
-dolog(sin)
- struct sockaddr_in *sin;
+dolog(who)
+ struct sockaddr *who;
{
- realhostname(remotehost, sizeof(remotehost) - 1, &sin->sin_addr);
+ int error;
+
+ realhostname_sa(remotehost, sizeof(remotehost) - 1, who, who->sa_len);
#ifdef SETPROCTITLE
#ifdef VIRTUAL_HOSTING
@@ -2039,8 +2237,16 @@ dolog(sin)
remotehost, hostname);
else
#endif
+ {
+ char who_name[MAXHOSTNAMELEN];
+
+ error = getnameinfo(who, who->sa_len,
+ who_name, sizeof(who_name) - 1,
+ NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
syslog(LOG_INFO, "connection from %s (%s)", remotehost,
- inet_ntoa(sin->sin_addr));
+ error == 0 ? who_name : "");
+ }
}
}
@@ -2112,7 +2318,7 @@ passive()
if (pdata >= 0) /* close old port if one set */
close(pdata);
- pdata = socket(AF_INET, SOCK_STREAM, 0);
+ pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
if (pdata < 0) {
perror_reply(425, "Can't open passive connection");
return;
@@ -2121,7 +2327,7 @@ passive()
(void) seteuid((uid_t)0);
#ifdef IP_PORTRANGE
- {
+ if (ctrl_addr.su_family == AF_INET) {
int on = restricted_data_ports ? IP_PORTRANGE_HIGH
: IP_PORTRANGE_DEFAULT;
@@ -2132,9 +2338,8 @@ passive()
#endif
pasv_addr = ctrl_addr;
- pasv_addr.sin_port = 0;
- if (bind(pdata, (struct sockaddr *)&pasv_addr,
- sizeof(pasv_addr)) < 0)
+ pasv_addr.su_port = 0;
+ if (bind(pdata, (struct sockaddr *)&pasv_addr, pasv_addr.su_len) < 0)
goto pasv_error;
(void) seteuid((uid_t)pw->pw_uid);
@@ -2144,8 +2349,15 @@ passive()
goto pasv_error;
if (listen(pdata, 1) < 0)
goto pasv_error;
- a = (char *) &pasv_addr.sin_addr;
- p = (char *) &pasv_addr.sin_port;
+ if (pasv_addr.su_family == AF_INET)
+ a = (char *) &pasv_addr.su_sin.sin_addr;
+ else if (pasv_addr.su_family == AF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED(&pasv_addr.su_sin6.sin6_addr))
+ a = (char *) &pasv_addr.su_sin6.sin6_addr.s6_addr[12];
+ else
+ goto pasv_error;
+
+ p = (char *) &pasv_addr.su_port;
#define UC(b) (((int) b) & 0xff)
@@ -2162,6 +2374,121 @@ pasv_error:
}
/*
+ * Long Passive defined in RFC 1639.
+ * 228 Entering Long Passive Mode
+ * (af, hal, h1, h2, h3,..., pal, p1, p2...)
+ */
+
+void
+long_passive(cmd, pf)
+ char *cmd;
+ int pf;
+{
+ int len;
+ char *p, *a;
+
+ if (pdata >= 0) /* close old port if one set */
+ close(pdata);
+
+ if (pf != PF_UNSPEC) {
+ if (ctrl_addr.su_family != pf) {
+ switch (ctrl_addr.su_family) {
+ case AF_INET:
+ pf = 1;
+ break;
+ case AF_INET6:
+ pf = 2;
+ break;
+ default:
+ pf = 0;
+ break;
+ }
+ /*
+ * XXX
+ * only EPRT/EPSV ready clients will understand this
+ */
+ if (strcmp(cmd, "EPSV") == 0 && pf) {
+ reply(522, "Network protocol mismatch, "
+ "use (%d)", pf);
+ } else
+ reply(501, "Network protocol mismatch"); /*XXX*/
+
+ return;
+ }
+ }
+
+ pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
+ if (pdata < 0) {
+ perror_reply(425, "Can't open passive connection");
+ return;
+ }
+
+ (void) seteuid((uid_t)0);
+
+ pasv_addr = ctrl_addr;
+ pasv_addr.su_port = 0;
+ len = pasv_addr.su_len;
+
+ if (bind(pdata, (struct sockaddr *)&pasv_addr, len) < 0)
+ goto pasv_error;
+
+ (void) seteuid((uid_t)pw->pw_uid);
+
+ if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
+ goto pasv_error;
+ if (listen(pdata, 1) < 0)
+ goto pasv_error;
+
+#define UC(b) (((int) b) & 0xff)
+
+ if (strcmp(cmd, "LPSV") == 0) {
+ p = (char *)&pasv_addr.su_port;
+ switch (pasv_addr.su_family) {
+ case AF_INET:
+ a = (char *) &pasv_addr.su_sin.sin_addr;
+ v4_reply:
+ reply(228,
+"Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d)",
+ 4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
+ 2, UC(p[0]), UC(p[1]));
+ return;
+ case AF_INET6:
+ if (IN6_IS_ADDR_V4MAPPED(&pasv_addr.su_sin6.sin6_addr)) {
+ a = (char *) &pasv_addr.su_sin6.sin6_addr.s6_addr[12];
+ goto v4_reply;
+ }
+ a = (char *) &pasv_addr.su_sin6.sin6_addr;
+ reply(228,
+"Entering Long Passive Mode "
+"(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",
+ 6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
+ UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
+ UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
+ UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
+ 2, UC(p[0]), UC(p[1]));
+ return;
+ }
+ } else if (strcmp(cmd, "EPSV") == 0) {
+ switch (pasv_addr.su_family) {
+ case AF_INET:
+ case AF_INET6:
+ reply(229, "Entering Extended Passive Mode (|||%d|)",
+ ntohs(pasv_addr.su_port));
+ return;
+ }
+ } else {
+ /* more proper error code? */
+ }
+
+pasv_error:
+ (void) seteuid((uid_t)pw->pw_uid);
+ (void) close(pdata);
+ pdata = -1;
+ perror_reply(425, "Can't open passive connection");
+ return;
+}
+
+/*
* Generate unique name for file with basename "local".
* The file named "local" is already known to exist.
* Generates failure reply on error.
diff --git a/libexec/ftpd/logwtmp.c b/libexec/ftpd/logwtmp.c
index d3f2ec5..2ac57d1 100644
--- a/libexec/ftpd/logwtmp.c
+++ b/libexec/ftpd/logwtmp.c
@@ -43,6 +43,7 @@ static const char rcsid[] =
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <sys/socket.h>
#include <fcntl.h>
#include <time.h>
@@ -68,15 +69,23 @@ ftpd_logwtmp(line, name, host)
struct stat buf;
if (strlen(host) > UT_HOSTSIZE) {
- struct hostent *hp = gethostbyname(host);
+ struct addrinfo hints, *res;
+ int error;
+ static char hostbuf[BUFSIZ];
- if (hp != NULL) {
- struct in_addr in;
-
- memmove(&in, hp->h_addr, sizeof(in));
- host = inet_ntoa(in);
- } else
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ error = getaddrinfo(host, NULL, &hints, &res);
+ if (error)
host = "invalid hostname";
+ else {
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ hostbuf, sizeof(hostbuf), NULL, 0,
+ NI_NUMERICHOST);
+ host = hostbuf;
+ if (strlen(host) > UT_HOSTSIZE)
+ host[UT_HOSTSIZE] = '\0';
+ }
}
if (fd < 0 && (fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0)
diff --git a/libexec/ftpd/popen.c b/libexec/ftpd/popen.c
index 606d17a..82cfd58 100644
--- a/libexec/ftpd/popen.c
+++ b/libexec/ftpd/popen.c
@@ -44,6 +44,7 @@ static const char rcsid[] =
#include <sys/types.h>
#include <sys/wait.h>
+#include <netinet/in.h>
#include <errno.h>
#include <glob.h>
OpenPOWER on IntegriCloud