diff options
author | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 1999-12-08 13:15:22 +0000 |
---|---|---|
committer | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 1999-12-08 13:15:22 +0000 |
commit | 484ffacaeb80ae7d76c14c94e481c6a5e02fe3cc (patch) | |
tree | 773772ec7853df32406e943f79716f9caf63b4ca /libexec/ftpd/ftpcmd.y | |
parent | 608666bc5b614c4a821f9571e6e7516c490a1d2e (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.y | 281 |
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': |