summaryrefslogtreecommitdiff
path: root/libexec/ftpd
diff options
context:
space:
mode:
authoraidan <aidan@NetBSD.org>2001-04-01 23:04:30 +0000
committeraidan <aidan@NetBSD.org>2001-04-01 23:04:30 +0000
commit7f74ad2bfdb962217b4f97340b63ef02f4b3e9db (patch)
tree80fe1d431227a7c27a05b21433743255dda03b39 /libexec/ftpd
parent7b7d57c2da677d3211e2925022dd8f64edea2e95 (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.h20
-rw-r--r--libexec/ftpd/ftpcmd.y179
-rw-r--r--libexec/ftpd/ftpd.c53
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