summaryrefslogtreecommitdiff
path: root/libexec
diff options
context:
space:
mode:
Diffstat (limited to 'libexec')
-rw-r--r--libexec/ftpd/Makefile5
-rw-r--r--libexec/ftpd/extern.h43
-rw-r--r--libexec/ftpd/ftpcmd.y281
-rw-r--r--libexec/ftpd/ftpd.c478
-rw-r--r--libexec/ftpd/logwtmp.c2
-rw-r--r--libexec/ftpd/popen.c3
6 files changed, 716 insertions, 96 deletions
diff --git a/libexec/ftpd/Makefile b/libexec/ftpd/Makefile
index ed079b0a150..6a12e7f2601 100644
--- a/libexec/ftpd/Makefile
+++ b/libexec/ftpd/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.14 1999/02/26 00:15:54 art Exp $
+# $OpenBSD: Makefile,v 1.15 1999/12/08 13:15:21 itojun Exp $
# $NetBSD: Makefile,v 1.13 1996/02/16 02:07:41 cgd Exp $
# @(#)Makefile 8.2 (Berkeley) 4/4/94
@@ -17,6 +17,9 @@ LSDIR = ${.CURDIR}/../../bin/ls
SRCS += ls.c cmp.c print.c stat_flags.c util.c
CFLAGS += -I${LSDIR}
+# not really used
+CPPFLAGS+=-DINET6
+
.if (${SKEY} == "yes")
CFLAGS+=-DSKEY
LDADD+= -lskey
diff --git a/libexec/ftpd/extern.h b/libexec/ftpd/extern.h
index 6fffb87f5f2..cd92578a36a 100644
--- a/libexec/ftpd/extern.h
+++ b/libexec/ftpd/extern.h
@@ -1,5 +1,34 @@
/* $NetBSD: extern.h,v 1.2 1995/04/11 02:44:49 cgd Exp $ */
+/*
+ * Copyright (C) 1997 and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
@@ -50,6 +79,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 *));
@@ -68,3 +98,16 @@ void yyerror __P((char *));
void toolong __P((int));
int yyparse __P((void));
+
+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 c146e989bbf..232747892a3 100644
--- a/libexec/ftpd/ftpcmd.y
+++ b/libexec/ftpd/ftpcmd.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: ftpcmd.y,v 1.17 1999/10/08 14:40:35 deraadt Exp $ */
+/* $OpenBSD: ftpcmd.y,v 1.18 1999/12/08 13:15:21 itojun Exp $ */
/* $NetBSD: ftpcmd.y,v 1.7 1996/04/08 19:03:11 jtc Exp $ */
/*
@@ -47,7 +47,7 @@
#if 0
static char sccsid[] = "@(#)ftpcmd.y 8.3 (Berkeley) 4/6/94";
#else
-static char rcsid[] = "$OpenBSD: ftpcmd.y,v 1.17 1999/10/08 14:40:35 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: ftpcmd.y,v 1.18 1999/12/08 13:15:21 itojun Exp $";
#endif
#endif /* not lint */
@@ -71,10 +71,11 @@ static char rcsid[] = "$OpenBSD: ftpcmd.y,v 1.17 1999/10/08 14:40:35 deraadt Exp
#include <syslog.h>
#include <time.h>
#include <unistd.h>
+#include <netdb.h>
#include "extern.h"
-extern struct sockaddr_in data_dest;
+extern union sockunion data_dest;
extern int logged_in;
extern struct passwd *pw;
extern int guest;
@@ -91,7 +92,7 @@ extern int usedefault;
extern int transflag;
extern char tmpline[];
extern int portcheck;
-extern struct sockaddr_in his_addr;
+extern union sockunion his_addr;
off_t restart_point;
@@ -111,6 +112,7 @@ char *fromname;
%token
A B C E F I
L N P R S T
+ ALL
SP CRLF COMMA
@@ -122,17 +124,20 @@ char *fromname;
STAT HELP NOOP MKD RMD PWD
CDUP STOU SMNT SYST SIZE MDTM
+ LPRT LPSV EPRT EPSV
+
UMASK IDLE CHMOD
LEXERR
%token <s> STRING
+%token <s> ALL
%token <i> NUMBER
%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 <i> host_port
+%type <i> host_port host_long_port4 host_long_port6
%start cmd_list
@@ -168,14 +173,14 @@ cmd
reply(500,
"Illegal PORT rejected (range errors).");
} else if (portcheck &&
- ntohs(data_dest.sin_port) < IPPORT_RESERVED) {
+ ntohs(data_dest.su_sin.sin_port) < IPPORT_RESERVED) {
usedefault = 1;
reply(500,
"Illegal PORT rejected (reserved port).");
} else if (portcheck &&
- memcmp(&data_dest.sin_addr,
- &his_addr.sin_addr,
- sizeof data_dest.sin_addr)) {
+ 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 rejected (address wrong).");
@@ -189,12 +194,174 @@ cmd
}
}
}
+ | LPRT check_login SP host_long_port4 CRLF
+ {
+ /* reject invalid host_long_port4 */
+ if ($4) {
+ reply(500, "Illegal LPRT command rejected");
+ usedefault = 1;
+ } else if (epsvall) {
+ reply(501, "LPRT disallowed after EPSV ALL");
+ usedefault = 1;
+ } else {
+ usedefault = 0;
+ if (pdata >= 0) {
+ (void) close(pdata);
+ pdata = -1;
+ }
+ reply(200, "LPRT command successful.");
+ }
+ }
+
+ | LPRT check_login SP host_long_port6 CRLF
+ {
+ /* reject invalid host_long_port6 */
+ if ($4) {
+ reply(500, "Illegal LPRT command rejected");
+ usedefault = 1;
+ } else if (epsvall) {
+ reply(501, "LPRT disallowed after EPSV ALL");
+ usedefault = 1;
+ } else {
+ usedefault = 0;
+ if (pdata >= 0) {
+ (void) close(pdata);
+ pdata = -1;
+ }
+ reply(200, "LPRT command successful.");
+ }
+ }
+
+ | EPRT check_login SP STRING CRLF
+ {
+ char *tmp = NULL;
+ char *result[3];
+ char *p, *q;
+ char delim;
+ struct addrinfo hints;
+ struct addrinfo *res;
+ int i;
+
+ if (epsvall) {
+ reply(501, "EPRT disallowed after EPSV ALL");
+ goto eprt_done;
+ }
+ usedefault = 0;
+ if (pdata >= 0) {
+ (void) close(pdata);
+ pdata = -1;
+ }
+
+ /*XXX checks for login */
+
+ tmp = strdup($4);
+ 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, "Invalid argument, rejected.");
+ if (tmp)
+ free(tmp);
+ usedefault = 1;
+ goto eprt_done;
+ }
+ *q++ = '\0';
+ result[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++;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ if (atoi(result[0]) == 1)
+ hints.ai_family = PF_INET;
+ if (atoi(result[0]) == 2)
+ hints.ai_family = PF_INET6;
+ else
+ hints.ai_family = PF_UNSPEC; /*XXX*/
+ hints.ai_socktype = SOCK_STREAM;
+ if (getaddrinfo(result[1], result[2], &hints, &res))
+ goto parsefail;
+ memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
+ 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;
+ }
+ free(tmp);
+ tmp = NULL;
+ if (pdata >= 0) {
+ (void) close(pdata);
+ pdata = -1;
+ }
+ reply(200, "EPRT command successful.");
+ eprt_done:;
+ }
+
| PASV check_login CRLF
{
if ($2) {
passive();
}
}
+ | LPSV CRLF
+ {
+ if (epsvall)
+ reply(501, "LPSV disallowed after EPSV ALL");
+ else
+ long_passive("LPSV", PF_UNSPEC);
+ }
+ | EPSV SP NUMBER CRLF
+ {
+ int pf;
+ switch ($3) {
+ case 1:
+ pf = PF_INET;
+ break;
+ case 2:
+ pf = PF_INET6;
+ break;
+ default:
+ pf = -1; /*junk*/
+ break;
+ }
+ long_passive("EPSV", pf);
+ }
+ | EPSV SP ALL CRLF
+ {
+ if (!logged_in) {
+ syslog(LOG_NOTICE, "long passive but not logged in");
+ reply(503, "Login with USER first.");
+ } else {
+ reply(200, "EPSV ALL command successful.");
+ epsvall++;
+ }
+ }
+ | EPSV CRLF
+ {
+ long_passive("EPSV", PF_UNSPEC);
+ }
| TYPE check_login SP type_code CRLF
{
if ($2) {
@@ -620,17 +787,93 @@ host_port
$9 < 0 || $9 > 255 || $11 < 0 || $11 > 255) {
$$ = 1;
} else {
- data_dest.sin_len = sizeof(struct sockaddr_in);
- data_dest.sin_family = AF_INET;
- p = (char *)&data_dest.sin_port;
+ data_dest.su_sin.sin_len = sizeof(struct sockaddr_in);
+ data_dest.su_sin.sin_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;
$$ = 0;
}
}
;
+host_long_port4
+ : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER
+ {
+ char *a, *p;
+
+ /* reject invalid LPRT command */
+ if ($1 != 4 || $3 != 4
+ || $5 < 0 || $5 > 255 || $7 < 0 || $7 > 255
+ || $9 < 0 || $9 > 255 || $11 < 0 || $11 > 255
+ || $13 != 2
+ || $15 < 0 || $15 > 255 || $17 < 0 || $17 > 255) {
+ $$ = 1;
+ } else {
+ 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;
+ $$ = 0;
+ }
+ }
+ ;
+
+host_long_port6
+ : 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;
+
+ /* reject invalid LPRT command */
+ if ($1 != 6 || $3 != 16
+ || $5 < 0 || $5 > 255 || $7 < 0 || $7 > 255
+ || $9 < 0 || $9 > 255 || $11 < 0 || $11 > 255
+ || $13 < 0 || $13 > 255 || $15 < 0 || $15 > 255
+ || $17 < 0 || $17 > 255 || $19 < 0 || $19 > 255
+ || $21 < 0 || $21 > 255 || $23 < 0 || $23 > 255
+ || $25 < 0 || $25 > 255 || $27 < 0 || $27 > 255
+ || $29 < 0 || $29 > 255 || $31 < 0 || $31 > 255
+ || $33 < 0 || $33 > 255 || $35 < 0 || $35 > 255
+ || $37 != 2
+ || $39 < 0 || $39 > 255 || $41 < 0 || $41 > 255) {
+ $$ = 1;
+ } else {
+ data_dest.su_sin6.sin6_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;
+ }
+
+ $$ = 0;
+ }
+ }
+ ;
+
form_code
: N
{
@@ -831,7 +1074,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)" },
@@ -888,6 +1135,8 @@ static struct tab *
static void sizecmd __P((char *));
static int yylex __P((void));
+extern int epsvall;
+
static struct tab *
lookup(p, cmd)
struct tab *p;
@@ -1148,6 +1397,12 @@ yylex()
cbuf[cpos] = c;
return (NUMBER);
}
+ if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0
+ && !isalnum(cbuf[cpos + 3])) {
+ yylval.s = strdup("ALL");
+ cpos += 3;
+ return ALL;
+ }
switch (cbuf[cpos++]) {
case '\n':
diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c
index 23a1120a08a..e9c4b2446d1 100644
--- a/libexec/ftpd/ftpd.c
+++ b/libexec/ftpd/ftpd.c
@@ -1,7 +1,36 @@
-/* $OpenBSD: ftpd.c,v 1.62 1999/12/03 01:22:46 millert Exp $ */
+/* $OpenBSD: ftpd.c,v 1.63 1999/12/08 13:15:21 itojun Exp $ */
/* $NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $ */
/*
+ * Copyright (C) 1997 and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
* Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
@@ -111,12 +140,12 @@ static char version[] = "Version 6.4/OpenBSD";
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 = 0;
int data;
@@ -142,6 +171,7 @@ int mode;
int doutmp = 0; /* update utmp file */
int usedefault = 1; /* for data transfers */
int pdata = -1; /* for passive mode */
+int family = AF_INET;
sig_atomic_t transflag;
off_t file_size;
off_t byte_count;
@@ -172,6 +202,8 @@ char *krbtkfile_env = NULL;
char *ident = NULL;
+int epsvall = 0;
+
/*
* Timeout intervals for retrying connections
* to hosts that don't accept PORT cmds. This
@@ -210,7 +242,7 @@ static void ack __P((char *));
static void myoob __P((int));
static int checkuser __P((char *, char *));
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 *));
@@ -224,7 +256,7 @@ static struct passwd *
sgetpwnam __P((char *));
static char *sgetsave __P((char *));
static void reapchild __P((int));
-static int check_host __P((struct sockaddr_in *));
+static int check_host __P((struct sockaddr *));
static void usage __P((void));
void logxfer __P((char *, off_t, time_t));
@@ -242,7 +274,7 @@ curdir()
return (guest ? path+1 : path);
}
-char *argstr = "AdDhlMSt:T:u:UvP";
+char *argstr = "AdDhlMSt:T:u:UvP46";
static void
usage()
@@ -335,6 +367,14 @@ main(argc, argv, envp)
debug = 1;
break;
+ case '4':
+ family = AF_INET;
+ break;
+
+ case '6':
+ family = AF_INET6;
+ break;
+
default:
usage();
break;
@@ -373,7 +413,7 @@ main(argc, argv, envp)
* 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);
@@ -381,11 +421,20 @@ main(argc, argv, envp)
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.s_addr = INADDR_ANY;
- server_addr.sin_port = sv->s_port;
+ memset(&server_addr, 0, sizeof(server_addr));
+ server_addr.su_sin.sin_family = family;
+ switch (family) {
+ case AF_INET:
+ server_addr.su_len = sizeof(struct sockaddr_in);
+ server_addr.su_sin.sin_port = sv->s_port;
+ break;
+ case AF_INET6:
+ server_addr.su_len = sizeof(struct sockaddr_in6);
+ server_addr.su_sin6.sin6_port = sv->s_port;
+ break;
+ }
if (bind(ctl_sock, (struct sockaddr *)&server_addr,
- sizeof(server_addr))) {
+ server_addr.su_len)) {
syslog(LOG_ERR, "control bind: %m");
exit(1);
}
@@ -421,7 +470,7 @@ main(argc, argv, envp)
#if defined(TCPWRAPPERS)
/* ..in the child. */
- if (!check_host(&his_addr))
+ if (!check_host((struct sockaddr *)&his_addr))
exit(1);
#endif /* TCPWRAPPERS */
} else {
@@ -450,12 +499,55 @@ main(argc, argv, envp)
syslog(LOG_ERR, "getsockname (%s): %m", argv[0]);
exit(1);
}
+ if (his_addr.su_family == AF_INET6
+ && IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) {
+#if 1
+ /*
+ * IPv4 control connection arrived to AF_INET6 socket.
+ * I hate to do this, but this is the easiest solution.
+ */
+ union sockunion tmp_addr;
+ const int off = sizeof(struct in6_addr) - sizeof(struct in_addr);
+
+ tmp_addr = his_addr;
+ memset(&his_addr, 0, sizeof(his_addr));
+ his_addr.su_sin.sin_family = AF_INET;
+ his_addr.su_sin.sin_len = sizeof(his_addr.su_sin);
+ memcpy(&his_addr.su_sin.sin_addr,
+ &tmp_addr.su_sin6.sin6_addr.s6_addr[off],
+ sizeof(his_addr.su_sin.sin_addr));
+ his_addr.su_sin.sin_port = tmp_addr.su_sin6.sin6_port;
+
+ tmp_addr = ctrl_addr;
+ memset(&ctrl_addr, 0, sizeof(ctrl_addr));
+ ctrl_addr.su_sin.sin_family = AF_INET;
+ ctrl_addr.su_sin.sin_len = sizeof(ctrl_addr.su_sin);
+ memcpy(&ctrl_addr.su_sin.sin_addr,
+ &tmp_addr.su_sin6.sin6_addr.s6_addr[off],
+ sizeof(ctrl_addr.su_sin.sin_addr));
+ ctrl_addr.su_sin.sin_port = tmp_addr.su_sin6.sin6_port;
+#else
+ while (fgets(line, sizeof(line), fd) != NULL) {
+ if ((cp = strchr(line, '\n')) != NULL)
+ *cp = '\0';
+ lreply(530, "%s", line);
+ }
+ (void) fflush(stdout);
+ (void) fclose(fd);
+ reply(530,
+ "Connection from IPv4 mapped address is not supported.");
+ exit(0);
+#endif
+ }
#ifdef IP_TOS
- tos = IPTOS_LOWDELAY;
- if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
- syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+ if (his_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
- data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
+ data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1);
/* Try to handle urgent data inline */
#ifdef SO_OOBINLINE
@@ -467,7 +559,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
*/
@@ -508,14 +600,8 @@ main(argc, argv, envp)
strcpy(hostname, hp->h_name);
if (multihome) {
- hp = gethostbyaddr((char *) &ctrl_addr.sin_addr,
- sizeof (struct in_addr), AF_INET);
- if (hp != NULL) {
- strcpy(dhostname, hp->h_name);
- } else {
- /* Default. */
- strcpy(dhostname, inet_ntoa(ctrl_addr.sin_addr));
- }
+ getnameinfo((struct sockaddr *)&ctrl_addr, ctrl_addr.su_len,
+ dhostname, sizeof(dhostname), NULL, 0, 0);
}
reply(220, "%s FTP server (%s) ready.",
@@ -1112,19 +1198,18 @@ getdatasock(mode)
sigfillset(&allsigs);
sigprocmask (SIG_BLOCK, &allsigs, NULL);
(void) seteuid((uid_t)0);
- s = socket(AF_INET, SOCK_STREAM, 0);
+ s = socket(ctrl_addr.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;
@@ -1135,9 +1220,12 @@ getdatasock(mode)
sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
#ifdef IP_TOS
- on = IPTOS_THROUGHPUT;
- if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
- syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+ if (ctrl_addr.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
/*
@@ -1176,7 +1264,10 @@ dataconn(name, size, mode)
{
char sizebuf[32];
FILE *file;
- int retry = 0, tos;
+ int retry = 0;
+ in_port_t *p;
+ char *fa, *ha;
+ int alen;
file_size = size;
byte_count = 0;
@@ -1186,7 +1277,7 @@ dataconn(name, size, mode)
} else
sizebuf[0] = '\0';
if (pdata >= 0) {
- struct sockaddr_in from;
+ union sockunion from;
int s, fromlen = sizeof(from);
signal (SIGALRM, toolong);
@@ -1199,14 +1290,35 @@ dataconn(name, size, mode)
pdata = -1;
return (NULL);
}
- if (ntohs(from.sin_port) < IPPORT_RESERVED) {
+ switch (from.su_family) {
+ case AF_INET:
+ p = (in_port_t *)&from.su_sin.sin_port;
+ fa = (u_char *)&from.su_sin.sin_addr;
+ ha = (u_char *)&his_addr.su_sin.sin_addr;
+ alen = sizeof(struct in_addr);;
+ break;
+ case AF_INET6:
+ p = (in_port_t *)&from.su_sin6.sin6_port;
+ fa = (u_char *)&from.su_sin6.sin6_addr;
+ ha = (u_char *)&his_addr.su_sin6.sin6_addr;
+ alen = sizeof(struct in6_addr);;
+ break;
+ default:
+ perror_reply(425, "Can't build data connection");
+ (void) close(pdata);
+ (void) close(s);
+ pdata = -1;
+ return (NULL);
+ }
+ if (from.su_family != his_addr.su_family
+ || ntohs(*p) < IPPORT_RESERVED) {
perror_reply(425, "Can't build data connection");
(void) close(pdata);
(void) close(s);
pdata = -1;
return (NULL);
}
- if (from.sin_addr.s_addr != his_addr.sin_addr.s_addr) {
+ if (memcmp(fa, ha, alen) != 0) {
perror_reply(435, "Can't build data connection");
(void) close(pdata);
(void) close(s);
@@ -1215,11 +1327,6 @@ dataconn(name, size, mode)
}
(void) close(pdata);
pdata = s;
-#ifdef IP_TOS
- 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);
return (fdopen(pdata, mode));
@@ -1235,9 +1342,12 @@ 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 hbuf[MAXHOSTNAMELEN], pbuf[10];
+ getnameinfo((struct sockaddr *)&data_source, data_source.su_len,
+ hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ reply(425, "Can't create data socket (%s,%s): %s.",
+ hbuf, pbuf, strerror(errno));
return (NULL);
}
data = fileno(file);
@@ -1246,21 +1356,40 @@ dataconn(name, size, mode)
* attempt to connect to reserved port on client machine;
* this looks like an attack
*/
- if (ntohs(data_dest.sin_port) < IPPORT_RESERVED ||
- ntohs(data_dest.sin_port) == 2049) { /* XXX */
+ switch (data_dest.su_family) {
+ case AF_INET:
+ p = (in_port_t *)&data_dest.su_sin.sin_port;
+ fa = (u_char *)&data_dest.su_sin.sin_addr;
+ ha = (u_char *)&his_addr.su_sin.sin_addr;
+ alen = sizeof(struct in_addr);;
+ break;
+ case AF_INET6:
+ p = (in_port_t *)&data_dest.su_sin6.sin6_port;
+ fa = (u_char *)&data_dest.su_sin6.sin6_addr;
+ ha = (u_char *)&his_addr.su_sin6.sin6_addr;
+ alen = sizeof(struct in6_addr);;
+ break;
+ default:
+ perror_reply(425, "Can't build data connection");
+ (void) fclose(file);
+ pdata = -1;
+ return (NULL);
+ }
+ if (data_dest.su_family != his_addr.su_family
+ || ntohs(*p) < IPPORT_RESERVED || ntohs(*p) == 2049) { /* XXX */
perror_reply(425, "Can't build data connection");
(void) fclose(file);
data = -1;
return NULL;
}
- if (data_dest.sin_addr.s_addr != his_addr.sin_addr.s_addr) {
+ if (memcmp(fa, ha, alen) != 0) {
perror_reply(435, "Can't build data connection");
(void) fclose(file);
data = -1;
return NULL;
}
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;
@@ -1516,14 +1645,18 @@ statfilecmd(filename)
void
statcmd()
{
- struct sockaddr_in *sin;
+ union sockunion *su;
u_char *a, *p;
+ char hbuf[MAXHOSTNAMELEN];
+ int ispassive;
lreply(211, "%s FTP server status:", hostname, version);
printf(" %s\r\n", version);
+ getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
+ hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
printf(" Connected to %s", remotehost);
- if (!isdigit(remotehost[0]))
- printf(" (%s)", inet_ntoa(his_addr.sin_addr));
+ if (strcmp(remotehost, hbuf) != 0)
+ printf(" (%s)", hbuf);
printf("\r\n");
if (logged_in) {
if (guest)
@@ -1545,22 +1678,96 @@ statcmd()
#endif
printf("; STRUcture: %s; transfer MODE: %s\r\n",
strunames[stru], modenames[mode]);
+ ispassive = 0;
if (data != -1)
printf(" Data connection open\r\n");
else if (pdata != -1) {
printf(" in Passive mode");
- sin = &pasv_addr;
+ su = (union sockunion *)&pasv_addr;
+ ispassive++;
goto printaddr;
} else if (usedefault == 0) {
- printf(" PORT");
- sin = &data_dest;
+ su = (union sockunion *)&data_dest;
printaddr:
- a = (u_char *) &sin->sin_addr;
- p = (u_char *) &sin->sin_port;
+ /* PASV/PORT */
+ if (su->su_family == AF_INET) {
+ if (ispassive)
+ printf("211- PASV ");
+ else
+ printf("211- PORT ");
+ a = (u_char *) &su->su_sin.sin_addr;
+ p = (u_char *) &su->su_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]));
+ 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]));
+ }
+
+ /* LPSV/LPRT */
+ {
+ int alen, af, i;
+
+ alen = 0;
+ 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) {
+ if (ispassive)
+ printf("211- LPSV ");
+ else
+ printf("211- LPRT ");
+ printf("(%d,%d", af, alen);
+ for (i = 0; i < alen; i++)
+ printf("%d,", UC(a[alen]));
+ printf("%d,%d,%d)\r\n", 2, UC(p[0]), UC(p[1]));
#undef UC
+ }
+ }
+
+ /* EPRT/EPSV */
+epsvonly:;
+ {
+ int af;
+
+ switch (su->su_family) {
+ case AF_INET:
+ af = 1;
+ break;
+ case AF_INET6:
+ af = 2;
+ break;
+ default:
+ af = 0;
+ break;
+ }
+ if (af) {
+ char hbuf[MAXHOSTNAMELEN], pbuf[10];
+ if (getnameinfo((struct sockaddr *)su, su->su_len,
+ hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
+ NI_NUMERICHOST) == 0) {
+ if (ispassive)
+ printf("211 - EPSV ");
+ else
+ printf("211 - EPRT ");
+ printf("(|%d|%s|%s|)\r\n",
+ af, hbuf, pbuf);
+ }
+ }
+ }
} else
printf(" No data connection\r\n");
reply(211, "End of status");
@@ -1785,17 +1992,14 @@ renamecmd(from, to)
}
static void
-dolog(sin)
- struct sockaddr_in *sin;
+dolog(sa)
+ struct sockaddr *sa;
{
- struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
- sizeof(struct in_addr), AF_INET);
+ char hbuf[sizeof(remotehost)];
+
+ getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0);
+ (void) strncpy(remotehost, hbuf, sizeof(remotehost)-1);
- if (hp)
- (void) strncpy(remotehost, hp->h_name, sizeof(remotehost)-1);
- else
- (void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
- sizeof(remotehost)-1);
remotehost[sizeof(remotehost)-1] = '\0';
#ifdef HASSETPROCTITLE
snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
@@ -1899,9 +2103,9 @@ passive()
#endif
pasv_addr = ctrl_addr;
- pasv_addr.sin_port = 0;
+ pasv_addr.su_sin.sin_port = 0;
if (bind(pdata, (struct sockaddr *)&pasv_addr,
- sizeof(pasv_addr)) < 0)
+ pasv_addr.su_len) < 0)
goto pasv_error;
len = sizeof(pasv_addr);
@@ -1909,8 +2113,8 @@ passive()
goto pasv_error;
if (listen(pdata, 1) < 0)
goto pasv_error;
- a = (char *) &pasv_addr.sin_addr;
- p = (char *) &pasv_addr.sin_port;
+ a = (char *) &pasv_addr.su_sin.sin_addr;
+ p = (char *) &pasv_addr.su_sin.sin_port;
#define UC(b) (((int) b) & 0xff)
@@ -1919,6 +2123,111 @@ passive()
return;
pasv_error:
+ (void) seteuid((uid_t)pw->pw_uid);
+ (void) close(pdata);
+ pdata = -1;
+ perror_reply(425, "Can't open passive connection");
+ return;
+}
+
+/*
+ * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
+ * 229 Entering Extended Passive Mode (|||port|)
+ */
+void
+long_passive(char *cmd, int pf)
+{
+ int len;
+ register char *p, *a;
+
+ if (!logged_in) {
+ syslog(LOG_NOTICE, "long passive but not logged in");
+ reply(503, "Login with USER first.");
+ return;
+ }
+
+ 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;
+ }
+ pasv_addr = ctrl_addr;
+ pasv_addr.su_port = 0;
+ (void) seteuid((uid_t) 0);
+ if (bind(pdata, (struct sockaddr *) &pasv_addr, pasv_addr.su_len) < 0) {
+ (void) seteuid((uid_t) pw->pw_uid);
+ goto pasv_error;
+ }
+ (void) seteuid((uid_t) pw->pw_uid);
+ len = pasv_addr.su_len;
+ if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
+ goto pasv_error;
+ if (listen(pdata, 1) < 0)
+ goto pasv_error;
+ p = (char *) &pasv_addr.su_port;
+
+#define UC(b) (((int) b) & 0xff)
+
+ if (strcmp(cmd, "LPSV") == 0) {
+ switch (pasv_addr.su_family) {
+ case AF_INET:
+ a = (char *) &pasv_addr.su_sin.sin_addr;
+ 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:
+ 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;
+ }
+#undef UC
+ } 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) close(pdata);
pdata = -1;
perror_reply(425, "Can't open passive connection");
@@ -2172,13 +2481,20 @@ logxfer(name, size, start)
#if defined(TCPWRAPPERS)
static int
-check_host(sin)
- struct sockaddr_in *sin;
+check_host(sa)
+ struct sockaddr *sa;
{
- struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
- sizeof(struct in_addr), AF_INET);
- char *addr = inet_ntoa(sin->sin_addr);
+ struct sockaddr_in *sin;
+ struct hostent *hp;
+ char *addr;
+ if (sa->sa_family != AF_INET)
+ return 1; /*XXX*/
+
+ sin = (struct sockaddr_in *)sa;
+ hp = gethostbyaddr((char *)&sin->sin_addr,
+ sizeof(struct in_addr), AF_INET);
+ addr = inet_ntoa(sin->sin_addr);
if (hp) {
if (!hosts_ctl("ftpd", hp->h_name, addr, STRING_UNKNOWN)) {
syslog(LOG_NOTICE, "tcpwrappers rejected: %s [%s]",
diff --git a/libexec/ftpd/logwtmp.c b/libexec/ftpd/logwtmp.c
index 1b3416cd791..36c761210c9 100644
--- a/libexec/ftpd/logwtmp.c
+++ b/libexec/ftpd/logwtmp.c
@@ -51,6 +51,8 @@ static char rcsid[] = "$NetBSD: logwtmp.c,v 1.4 1995/04/11 02:44:58 cgd Exp $";
#include <unistd.h>
#include <stdio.h>
#include <string.h>
+
+#include <netinet/in.h>
#include "extern.h"
static int fd = -1;
diff --git a/libexec/ftpd/popen.c b/libexec/ftpd/popen.c
index c195cc2ccad..696d835b3b5 100644
--- a/libexec/ftpd/popen.c
+++ b/libexec/ftpd/popen.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: popen.c,v 1.10 1999/02/26 00:15:54 art Exp $ */
+/* $OpenBSD: popen.c,v 1.11 1999/12/08 13:15:21 itojun Exp $ */
/* $NetBSD: popen.c,v 1.5 1995/04/11 02:45:00 cgd Exp $ */
/*
@@ -58,6 +58,7 @@ static char rcsid[] = "$NetBSD: popen.c,v 1.5 1995/04/11 02:45:00 cgd Exp $";
#include <syslog.h>
#include <unistd.h>
+#include <netinet/in.h>
#include "extern.h"
/*