diff options
| author | aidan <aidan@NetBSD.org> | 2001-04-01 23:04:30 +0000 |
|---|---|---|
| committer | aidan <aidan@NetBSD.org> | 2001-04-01 23:04:30 +0000 |
| commit | 7f74ad2bfdb962217b4f97340b63ef02f4b3e9db (patch) | |
| tree | 80fe1d431227a7c27a05b21433743255dda03b39 /libexec/ftpd | |
| parent | 7b7d57c2da677d3211e2925022dd8f64edea2e95 (diff) | |
As threatened, handle OOB commands from within ftpcmd.y.
This involved changing the yacc syntax to be line-oriented, rather than
having it run against the entire input at once, and adding a flag to
struct tab, to indicate if or not it's acceptable for a command to occur
OOB.
Diffstat (limited to 'libexec/ftpd')
| -rw-r--r-- | libexec/ftpd/extern.h | 20 | ||||
| -rw-r--r-- | libexec/ftpd/ftpcmd.y | 179 | ||||
| -rw-r--r-- | libexec/ftpd/ftpd.c | 53 |
3 files changed, 148 insertions, 104 deletions
diff --git a/libexec/ftpd/extern.h b/libexec/ftpd/extern.h index 53abd250481..2462eb3c130 100644 --- a/libexec/ftpd/extern.h +++ b/libexec/ftpd/extern.h @@ -1,4 +1,4 @@ -/* $NetBSD: extern.h,v 1.38 2001/02/04 22:04:11 christos Exp $ */ +/* $NetBSD: extern.h,v 1.39 2001/04/01 23:04:30 aidan Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -118,6 +118,9 @@ # define STRTOLL(x,y,z) strtoll(x,y,z) #endif +#define FTP_BUFLEN 512 + +void abor(void); void blkfree(char **); void closedataconn(FILE *); char *conffilename(const char *); @@ -171,6 +174,7 @@ void show_chdir_messages(int); void sizecmd(const char *); void statcmd(void); void statfilecmd(const char *); +void statxfer(void); void store(const char *, const char *, int); LLT strsuftoll(const char *); void user(const char *); @@ -213,7 +217,8 @@ struct tab { char *name; short token; short state; - short flags; /* 1 if command implemented, 2 if has options */ + short flags; /* 1 if command implemented, 2 if has options, + 4 if can occur OOB */ char *help; char *options; }; @@ -271,9 +276,8 @@ struct ftpclass { mode_t umask; /* Umask to use */ }; -#ifndef YYEMPTY -extern int yyparse(void); -#endif +extern void ftp_loop(void); +extern void ftp_handle_line(char *); #ifndef GLOBAL #define GLOBAL extern @@ -309,11 +313,12 @@ GLOBAL struct passwd *pw; GLOBAL int quietmessages; GLOBAL char remotehost[MAXHOSTNAMELEN+1]; GLOBAL off_t restart_point; -GLOBAL char tmpline[7]; +GLOBAL char tmpline[FTP_BUFLEN]; GLOBAL sig_atomic_t transflag; GLOBAL int type; GLOBAL int usedefault; /* for data transfers */ GLOBAL const char *version; +GLOBAL int is_oob; /* total file data bytes */ GLOBAL off_t total_data_in, total_data_out, total_data; @@ -330,7 +335,8 @@ extern struct tab cmdtab[]; #define CMD_IMPLEMENTED(x) ((x)->flags != 0) -#define CMD_HAS_OPTIONS(x) ((x)->flags == 2) +#define CMD_HAS_OPTIONS(x) ((x)->flags & 0x2) +#define CMD_OOB(x) ((x)->flags & 0x4) #define CPUTC(c, f) do { \ putc(c, f); total_bytes++; total_bytes_out++; \ diff --git a/libexec/ftpd/ftpcmd.y b/libexec/ftpd/ftpcmd.y index ba014654b26..2f6a4b3eb75 100644 --- a/libexec/ftpd/ftpcmd.y +++ b/libexec/ftpd/ftpcmd.y @@ -1,4 +1,4 @@ -/* $NetBSD: ftpcmd.y,v 1.59 2000/12/18 02:32:51 lukem Exp $ */ +/* $NetBSD: ftpcmd.y,v 1.60 2001/04/01 23:04:31 aidan Exp $ */ /*- * Copyright (c) 1997-2000 The NetBSD Foundation, Inc. @@ -83,7 +83,7 @@ #if 0 static char sccsid[] = "@(#)ftpcmd.y 8.3 (Berkeley) 4/6/94"; #else -__RCSID("$NetBSD: ftpcmd.y,v 1.59 2000/12/18 02:32:51 lukem Exp $"); +__RCSID("$NetBSD: ftpcmd.y,v 1.60 2001/04/01 23:04:31 aidan Exp $"); #endif #endif /* not lint */ @@ -121,7 +121,8 @@ static int cmd_type; static int cmd_form; static int cmd_bytesz; -char cbuf[512]; +char cbuf[FTP_BUFLEN]; +char *cmdp; char *fromname; %} @@ -169,20 +170,18 @@ char *fromname; %type <s> pathstring pathname password username %type <s> mechanism_name base64data prot_code -%start cmd_list +%start cmd_sel %% -cmd_list - : /* empty */ - - | cmd_list cmd +cmd_sel + : cmd { fromname = NULL; restart_point = (off_t) 0; } - | cmd_list rcmd + | rcmd ; @@ -454,7 +453,9 @@ cmd | ABOR check_login CRLF { - if ($2) + if (is_oob) + abor(); + else if ($2) reply(225, "ABOR command successful."); } @@ -687,7 +688,10 @@ cmd | STAT CRLF { - statcmd(); + if (is_oob) + statxfer(); + else + statcmd(); } | HELP CRLF @@ -1170,6 +1174,7 @@ check_login #define SITECMD 7 /* SITE command */ #define NSTR 8 /* Number followed by a string */ #define NOARGS 9 /* No arguments allowed */ +#define EOLN 10 /* End of line */ struct tab cmdtab[] = { /* From RFC 959, in order defined (5.3.1) */ @@ -1198,7 +1203,7 @@ struct tab cmdtab[] = { { "REST", REST, ARGS, 1, "<sp> offset (restart command)" }, { "RNFR", RNFR, STR1, 1, "<sp> file-name" }, { "RNTO", RNTO, STR1, 1, "<sp> file-name" }, - { "ABOR", ABOR, NOARGS, 1, "(abort operation)" }, + { "ABOR", ABOR, NOARGS, 4, "(abort operation)" }, { "DELE", DELE, STR1, 1, "<sp> file-name" }, { "RMD", RMD, STR1, 1, "<sp> path-name" }, { "MKD", MKD, STR1, 1, "<sp> path-name" }, @@ -1207,7 +1212,7 @@ struct tab cmdtab[] = { { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" }, { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" }, { "SYST", SYST, NOARGS, 1, "(get type of operating system)" }, - { "STAT", STAT, OSTR, 1, "[ <sp> path-name ]" }, + { "STAT", STAT, OSTR, 4, "[ <sp> path-name ]" }, { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, { "NOOP", NOOP, NOARGS, 2, "" }, @@ -1217,9 +1222,9 @@ struct tab cmdtab[] = { { "PROT", PROT, STR1, 1, "<sp> prot-code" }, { "PBSZ", PBSZ, ARGS, 1, "<sp> decimal-integer" }, { "CCC", CCC, NOARGS, 1, "(Disable data protection)" }, - { "MIC", MIC, STR1, 1, "<sp> base64data" }, - { "CONF", CONF, STR1, 1, "<sp> base64data" }, - { "ENC", ENC, STR1, 1, "<sp> base64data" }, + { "MIC", MIC, STR1, 4, "<sp> base64data" }, + { "CONF", CONF, STR1, 4, "<sp> base64data" }, + { "ENC", ENC, STR1, 4, "<sp> base64data" }, /* From RFC 2389, in order defined */ { "FEAT", FEAT, NOARGS, 1, "(display extended features)" }, @@ -1418,6 +1423,29 @@ toolong(int signo) dologout(1); } +void +ftp_handle_line(char *cp) +{ + cmdp = cp; + yyparse(); +} + +void +ftp_loop(void) +{ + while (1) { + (void) signal(SIGALRM, toolong); + (void) alarm(curclass.timeout); + if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { + reply(221, "You could at least say goodbye."); + dologout(0); + } + (void) alarm(0); + ftp_handle_line(cbuf); + } + /*NOTREACHED*/ +} + static int yylex(void) { @@ -1431,33 +1459,29 @@ yylex(void) case CMD: hasyyerrored = 0; - (void) signal(SIGALRM, toolong); - (void) alarm(curclass.timeout); - if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { - reply(221, "You could at least say goodbye."); - dologout(0); - } - (void) alarm(0); - if ((cp = strchr(cbuf, '\r'))) { + if ((cp = strchr(cmdp, '\r'))) { *cp = '\0'; #if HAVE_SETPROCTITLE - if (strncasecmp(cbuf, "PASS", 4) != 0 && - strncasecmp(cbuf, "ACCT", 4) != 0) - setproctitle("%s: %s", proctitle, cbuf); + if (strncasecmp(cmdp, "PASS", 4) != 0 && + strncasecmp(cmdp, "ACCT", 4) != 0) + setproctitle("%s: %s", proctitle, cmdp); #endif /* HAVE_SETPROCTITLE */ *cp++ = '\n'; *cp = '\0'; } - if ((cp = strpbrk(cbuf, " \n"))) - cpos = cp - cbuf; + if ((cp = strpbrk(cmdp, " \n"))) + cpos = cp - cmdp; if (cpos == 0) cpos = 4; - c = cbuf[cpos]; - cbuf[cpos] = '\0'; - p = lookup(cmdtab, cbuf); - cbuf[cpos] = c; + c = cmdp[cpos]; + cmdp[cpos] = '\0'; + p = lookup(cmdtab, cmdp); + cmdp[cpos] = c; if (p != NULL) { - if (! CMD_IMPLEMENTED(p)) { + if (is_oob && ! CMD_OOB(p)) { + /* command will be handled in-band */ + return (0); + } else if (! CMD_IMPLEMENTED(p)) { reply(502, "%s command not implemented.", p->name); hasyyerrored = 1; @@ -1470,17 +1494,17 @@ yylex(void) break; case SITECMD: - if (cbuf[cpos] == ' ') { + if (cmdp[cpos] == ' ') { cpos++; return (SP); } - cp = &cbuf[cpos]; + cp = &cmdp[cpos]; if ((cp2 = strpbrk(cp, " \n"))) - cpos = cp2 - cbuf; - c = cbuf[cpos]; - cbuf[cpos] = '\0'; + cpos = cp2 - cmdp; + c = cmdp[cpos]; + cmdp[cpos] = '\0'; p = lookup(sitetab, cp); - cbuf[cpos] = c; + cmdp[cpos] = c; if (p != NULL) { if (!CMD_IMPLEMENTED(p)) { reply(502, "SITE %s command not implemented.", @@ -1495,8 +1519,8 @@ yylex(void) break; case OSTR: - if (cbuf[cpos] == '\n') { - state = CMD; + if (cmdp[cpos] == '\n') { + state = EOLN; return (CRLF); } /* FALLTHROUGH */ @@ -1504,7 +1528,7 @@ yylex(void) case STR1: case ZSTR1: dostr1: - if (cbuf[cpos] == ' ') { + if (cmdp[cpos] == ' ') { cpos++; state = state == OSTR ? STR2 : state+1; return (SP); @@ -1512,41 +1536,41 @@ yylex(void) break; case ZSTR2: - if (cbuf[cpos] == '\n') { - state = CMD; + if (cmdp[cpos] == '\n') { + state = EOLN; return (CRLF); } /* FALLTHROUGH */ case STR2: - cp = &cbuf[cpos]; + cp = &cmdp[cpos]; n = strlen(cp); cpos += n - 1; /* * Make sure the string is nonempty and \n terminated. */ - if (n > 1 && cbuf[cpos] == '\n') { - cbuf[cpos] = '\0'; + if (n > 1 && cmdp[cpos] == '\n') { + cmdp[cpos] = '\0'; yylval.s = xstrdup(cp); - cbuf[cpos] = '\n'; + cmdp[cpos] = '\n'; state = ARGS; return (STRING); } break; case NSTR: - if (cbuf[cpos] == ' ') { + if (cmdp[cpos] == ' ') { cpos++; return (SP); } - if (isdigit(cbuf[cpos])) { - cp = &cbuf[cpos]; - while (isdigit(cbuf[++cpos])) + if (isdigit(cmdp[cpos])) { + cp = &cmdp[cpos]; + while (isdigit(cmdp[++cpos])) ; - c = cbuf[cpos]; - cbuf[cpos] = '\0'; + c = cmdp[cpos]; + cmdp[cpos] = '\0'; yylval.i = atoi(cp); - cbuf[cpos] = c; + cmdp[cpos] = c; state = STR1; return (NUMBER); } @@ -1554,26 +1578,26 @@ yylex(void) goto dostr1; case ARGS: - if (isdigit(cbuf[cpos])) { - cp = &cbuf[cpos]; - while (isdigit(cbuf[++cpos])) + if (isdigit(cmdp[cpos])) { + cp = &cmdp[cpos]; + while (isdigit(cmdp[++cpos])) ; - c = cbuf[cpos]; - cbuf[cpos] = '\0'; + c = cmdp[cpos]; + cmdp[cpos] = '\0'; yylval.i = atoi(cp); - cbuf[cpos] = c; + cmdp[cpos] = c; return (NUMBER); } - if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0 - && !isalnum(cbuf[cpos + 3])) { + if (strncasecmp(&cmdp[cpos], "ALL", 3) == 0 + && !isalnum(cmdp[cpos + 3])) { yylval.s = xstrdup("ALL"); cpos += 3; return ALL; } - switch (cbuf[cpos++]) { + switch (cmdp[cpos++]) { case '\n': - state = CMD; + state = EOLN; return (CRLF); case ' ': @@ -1634,22 +1658,27 @@ yylex(void) break; case NOARGS: - if (cbuf[cpos] == '\n') { - state = CMD; + if (cmdp[cpos] == '\n') { + state = EOLN; return (CRLF); } - c = cbuf[cpos]; - cbuf[cpos] = '\0'; - reply(501, "'%s' command does not take any arguments.", cbuf); + c = cmdp[cpos]; + cmdp[cpos] = '\0'; + reply(501, "'%s' command does not take any arguments.", cmdp); hasyyerrored = 1; - cbuf[cpos] = c; + cmdp[cpos] = c; break; + case EOLN: + state = CMD; + return (0); + default: fatal("Unknown state in scanner."); } yyerror(NULL); state = CMD; + is_oob = 0; longjmp(errcatch, 0); /* NOTREACHED */ } @@ -1660,11 +1689,11 @@ yyerror(char *s) { char *cp; - if (hasyyerrored) + if (hasyyerrored || is_oob) return; - if ((cp = strchr(cbuf,'\n')) != NULL) + if ((cp = strchr(cmdp,'\n')) != NULL) *cp = '\0'; - reply(500, "'%s': command not understood.", cbuf); + reply(500, "'%s': command not understood.", cmdp); hasyyerrored = 1; } diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c index c0c6b9273de..9f1db6ef7ea 100644 --- a/libexec/ftpd/ftpd.c +++ b/libexec/ftpd/ftpd.c @@ -1,4 +1,4 @@ -/* $NetBSD: ftpd.c,v 1.122 2001/03/16 20:42:13 christos Exp $ */ +/* $NetBSD: ftpd.c,v 1.123 2001/04/01 23:04:31 aidan Exp $ */ /* * Copyright (c) 1997-2000 The NetBSD Foundation, Inc. @@ -109,7 +109,7 @@ __COPYRIGHT( #if 0 static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95"; #else -__RCSID("$NetBSD: ftpd.c,v 1.122 2001/03/16 20:42:13 christos Exp $"); +__RCSID("$NetBSD: ftpd.c,v 1.123 2001/04/01 23:04:31 aidan Exp $"); #endif #endif /* not lint */ @@ -259,6 +259,7 @@ main(int argc, char *argv[]) hostname[0] = '\0'; homedir[0] = '\0'; gidcount = 0; + is_oob = 0; version = FTPD_VERSION; /* @@ -516,8 +517,7 @@ main(int argc, char *argv[]) reply(220, "%s FTP server (%s) ready.", hostname, version); (void) setjmp(errcatch); - for (;;) - (void) yyparse(); + ftp_loop(); /* NOTREACHED */ } @@ -2184,6 +2184,29 @@ dologout(int status) _exit(status); } +void abor(void) +{ + tmpline[0] = '\0'; + is_oob = 0; + reply(426, "Transfer aborted. Data connection closed."); + reply(226, "Abort successful"); + longjmp(urgcatch, 1); +} + +void statxfer(void) +{ + tmpline[0] = '\0'; + is_oob = 0; + if (file_size != (off_t) -1) + reply(213, + "Status: " LLF " of " LLF " byte%s transferred", + (LLT)byte_count, (LLT)file_size, + PLURAL(byte_count)); + else + reply(213, "Status: " LLF " byte%s transferred", + (LLT)byte_count, PLURAL(byte_count)); +} + static void myoob(int signo) { @@ -2193,27 +2216,13 @@ myoob(int signo) if (!transflag) return; cp = tmpline; - if (getline(cp, 7, stdin) == NULL) { + if (getline(cp, sizeof(tmpline), stdin) == NULL) { reply(221, "You could at least say goodbye."); dologout(0); } - if (strcasecmp(cp, "ABOR\r\n") == 0) { - tmpline[0] = '\0'; - reply(426, "Transfer aborted. Data connection closed."); - reply(226, "Abort successful"); - longjmp(urgcatch, 1); - } - if (strcasecmp(cp, "STAT\r\n") == 0) { - tmpline[0] = '\0'; - if (file_size != (off_t) -1) - reply(213, - "Status: " LLF " of " LLF " byte%s transferred", - (LLT)byte_count, (LLT)file_size, - PLURAL(byte_count)); - else - reply(213, "Status: " LLF " byte%s transferred", - (LLT)byte_count, PLURAL(byte_count)); - } + is_oob = 1; + ftp_handle_line(cp); + is_oob = 0; } static int |
