summaryrefslogtreecommitdiff
path: root/libexec/ftpd/ftpcmd.y
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>1999-12-08 13:15:22 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>1999-12-08 13:15:22 +0000
commit484ffacaeb80ae7d76c14c94e481c6a5e02fe3cc (patch)
tree773772ec7853df32406e943f79716f9caf63b4ca /libexec/ftpd/ftpcmd.y
parent608666bc5b614c4a821f9571e6e7516c490a1d2e (diff)
IPv6 support from KAME.
XXX kerberos and tcp_wrapper needs checking
Diffstat (limited to 'libexec/ftpd/ftpcmd.y')
-rw-r--r--libexec/ftpd/ftpcmd.y281
1 files changed, 268 insertions, 13 deletions
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':