minor changes to make rx.c compile
[unix-history] / usr / src / libexec / ftpd / ftpcmd.y
CommitLineData
25d264e2
SL
1/*
2 * Grammar for FTP commands.
3 * See RFC 765.
4 */
5
6%{
7
8#ifndef lint
0597ed04 9static char sccsid[] = "@(#)ftpcmd.y 4.7 83/02/02";
25d264e2
SL
10#endif
11
12#include <sys/types.h>
13#include <sys/socket.h>
14
15#include <netinet/in.h>
16
17#include <stdio.h>
18#include <ctype.h>
19#include <pwd.h>
20#include <setjmp.h>
21#include "ftp.h"
22
23extern struct sockaddr_in data_dest;
24extern int logged_in;
25extern struct passwd *pw;
26extern int guest;
27extern int logging;
28extern int type;
29extern int form;
30extern int debug;
31extern char hostname[];
32extern char *globerr;
1d92d63d 33extern int usedefault;
25d264e2
SL
34char **glob();
35
36static int cmd_type;
37static int cmd_form;
38static int cmd_bytesz;
39
25d264e2
SL
40char *index();
41%}
42
43%token
44 A B C E F I
45 L N P R S T
46
47 SP CRLF COMMA STRING NUMBER
48
49 USER PASS ACCT REIN QUIT PORT
50 PASV TYPE STRU MODE RETR STOR
51 APPE MLFL MAIL MSND MSOM MSAM
52 MRSQ MRCP ALLO REST RNFR RNTO
53 ABOR DELE CWD LIST NLST SITE
54 STAT HELP NOOP XMKD XRMD XPWD
55 XCUP
56
57 LEXERR
58
59%start cmd_list
60
61%%
62
63cmd_list: /* empty */
64 | cmd_list cmd
65 ;
66
67cmd: USER SP username CRLF
68 = {
69 extern struct passwd *getpwnam();
70
5914191e
SL
71 if (strcmp($3, "ftp") == 0 ||
72 strcmp($3, "anonymous") == 0) {
73 if ((pw = getpwnam("ftp")) != NULL) {
74 guest = 1;
75 reply(331,
25d264e2 76 "Guest login ok, send ident as password.");
5914191e 77 }
0597ed04 78 } else if (checkuser($3)) {
25d264e2
SL
79 guest = 0;
80 pw = getpwnam($3);
81 reply(331, "Password required for %s.", $3);
82 }
25d264e2 83 if (pw == NULL)
19501145
SL
84 reply(530, "User %s unknown.", $3);
85 free($3);
25d264e2
SL
86 }
87 | PASS SP password CRLF
88 = {
89 pass($3);
90 free($3);
91 }
92 | PORT SP host_port CRLF
93 = {
1d92d63d 94 usedefault = 0;
25d264e2
SL
95 ack($1);
96 }
97 | TYPE SP type_code CRLF
98 = {
99 switch (cmd_type) {
100
101 case TYPE_A:
102 if (cmd_form == FORM_N) {
103 reply(200, "Type set to A.");
104 type = cmd_type;
105 form = cmd_form;
106 } else
107 reply(504, "Form must be N.");
108 break;
109
110 case TYPE_E:
111 reply(504, "Type E not implemented.");
112 break;
113
114 case TYPE_I:
115 reply(200, "Type set to I.");
116 type = cmd_type;
117 break;
118
119 case TYPE_L:
120 if (cmd_bytesz == 8) {
121 reply(200,
122 "Type set to L (byte size 8).");
123 type = cmd_type;
124 } else
125 reply(504, "Byte size must be 8.");
126 }
127 }
128 | STRU SP struct_code CRLF
129 = {
130 switch ($3) {
131
132 case STRU_F:
133 reply(200, "STRU F ok.");
134 break;
135
136 default:
137 reply(502, "Unimplemented STRU type.");
138 }
139 }
140 | MODE SP mode_code CRLF
141 = {
142 switch ($3) {
143
144 case MODE_S:
145 reply(200, "MODE S ok.");
146 break;
147
148 default:
149 reply(502, "Unimplemented MODE type.");
150 }
151 }
152 | ALLO SP NUMBER CRLF
153 = {
154 ack($1);
155 }
156 | RETR check_login SP pathname CRLF
157 = {
8365e2f7 158 if ($2 && $4 != NULL)
25d264e2 159 retrieve(0, $4);
8365e2f7
SL
160 if ($4 != NULL)
161 free($4);
25d264e2
SL
162 }
163 | STOR check_login SP pathname CRLF
164 = {
8365e2f7 165 if ($2 && $4 != NULL)
25d264e2 166 store($4, "w");
8365e2f7
SL
167 if ($4 != NULL)
168 free($4);
25d264e2
SL
169 }
170 | APPE check_login SP pathname CRLF
171 = {
8365e2f7 172 if ($2 && $4 != NULL)
25d264e2 173 store($4, "a");
8365e2f7
SL
174 if ($4 != NULL)
175 free($4);
25d264e2
SL
176 }
177 | NLST check_login CRLF
178 = {
179 if ($2)
868e5613 180 retrieve("/bin/ls -C", "");
25d264e2
SL
181 }
182 | NLST check_login SP pathname CRLF
183 = {
8365e2f7 184 if ($2 && $4 != NULL)
868e5613 185 retrieve("/bin/ls -C %s", $4);
8365e2f7
SL
186 if ($4 != NULL)
187 free($4);
25d264e2
SL
188 }
189 | LIST check_login CRLF
190 = {
191 if ($2)
868e5613 192 retrieve("/bin/ls -lg", "");
25d264e2
SL
193 }
194 | LIST check_login SP pathname CRLF
195 = {
8365e2f7 196 if ($2 && $4 != NULL)
868e5613 197 retrieve("/bin/ls -lg %s", $4);
8365e2f7
SL
198 if ($4 != NULL)
199 free($4);
25d264e2
SL
200 }
201 | DELE check_login SP pathname CRLF
202 = {
8365e2f7 203 if ($2 && $4 != NULL)
25d264e2 204 delete($4);
8365e2f7
SL
205 if ($4 != NULL)
206 free($4);
25d264e2
SL
207 }
208 | CWD check_login CRLF
209 = {
210 if ($2)
211 cwd(pw->pw_dir);
212 }
213 | CWD check_login SP pathname CRLF
214 = {
8365e2f7 215 if ($2 && $4 != NULL)
25d264e2 216 cwd($4);
8365e2f7
SL
217 if ($4 != NULL)
218 free($4);
25d264e2
SL
219 }
220 | rename_cmd
221 | HELP CRLF
222 = {
223 help(0);
224 }
225 | HELP SP STRING CRLF
226 = {
227 help($3);
228 }
229 | NOOP CRLF
230 = {
231 ack($1);
232 }
233 | XMKD check_login SP pathname CRLF
234 = {
8365e2f7
SL
235 if ($2 && $4 != NULL)
236 makedir($4);
237 if ($4 != NULL)
238 free($4);
25d264e2
SL
239 }
240 | XRMD check_login SP pathname CRLF
241 = {
8365e2f7
SL
242 if ($2 && $4 != NULL)
243 removedir($4);
244 if ($4 != NULL)
245 free($4);
25d264e2
SL
246 }
247 | XPWD check_login CRLF
248 = {
249 if ($2)
8365e2f7 250 pwd();
25d264e2
SL
251 }
252 | XCUP check_login CRLF
253 = {
254 if ($2)
255 cwd("..");
256 }
257 | QUIT CRLF
258 = {
259 reply(221, "Goodbye.");
260 exit(0);
261 }
262 | error CRLF
263 = {
264 yyerrok;
265 }
266 ;
267
268username: STRING
269 ;
270
271password: STRING
272 ;
273
274byte_size: NUMBER
275 ;
276
277host_port: NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
278 NUMBER COMMA NUMBER
279 = {
280 register char *a, *p;
281
282 a = (char *)&data_dest.sin_addr;
283 a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;
284 p = (char *)&data_dest.sin_port;
285 p[0] = $9; p[1] = $11;
5914191e 286 data_dest.sin_family = AF_INET;
25d264e2
SL
287 }
288 ;
289
290form_code: N
291 = {
292 $$ = FORM_N;
293 }
294 | T
295 = {
296 $$ = FORM_T;
297 }
298 | C
299 = {
300 $$ = FORM_C;
301 }
302 ;
303
304type_code: A
305 = {
306 cmd_type = TYPE_A;
307 cmd_form = FORM_N;
308 }
309 | A SP form_code
310 = {
311 cmd_type = TYPE_A;
312 cmd_form = $3;
313 }
314 | E
315 = {
316 cmd_type = TYPE_E;
317 cmd_form = FORM_N;
318 }
319 | E SP form_code
320 = {
321 cmd_type = TYPE_E;
322 cmd_form = $3;
323 }
324 | I
325 = {
326 cmd_type = TYPE_I;
327 }
328 | L
329 = {
330 cmd_type = TYPE_L;
331 cmd_bytesz = 8;
332 }
333 | L SP byte_size
334 = {
335 cmd_type = TYPE_L;
336 cmd_bytesz = $3;
337 }
338 /* this is for a bug in the BBN ftp */
339 | L byte_size
340 = {
341 cmd_type = TYPE_L;
342 cmd_bytesz = $2;
343 }
344 ;
345
346struct_code: F
347 = {
348 $$ = STRU_F;
349 }
350 | R
351 = {
352 $$ = STRU_R;
353 }
354 | P
355 = {
356 $$ = STRU_P;
357 }
358 ;
359
360mode_code: S
361 = {
362 $$ = MODE_S;
363 }
364 | B
365 = {
366 $$ = MODE_B;
367 }
368 | C
369 = {
370 $$ = MODE_C;
371 }
372 ;
373
374pathname: pathstring
375 = {
376 if ($1 && strncmp($1, "~", 1) == 0) {
377 $$ = (int)*glob($1);
8365e2f7 378 if (globerr != NULL) {
25d264e2 379 reply(550, globerr);
8365e2f7
SL
380 $$ = NULL;
381 }
25d264e2
SL
382 free($1);
383 } else
384 $$ = $1;
385 }
386 ;
387
388pathstring: STRING
389 ;
390
391rename_cmd: rename_from rename_to
392 = {
393 if ($1 && $2)
394 renamecmd($1, $2);
395 else
396 reply(503, "Bad sequence of commands.");
397 if ($1)
398 free($1);
399 if ($2)
400 free($2);
401 }
402 ;
403
404rename_from: RNFR check_login SP pathname CRLF
405 = {
406 char *from = 0, *renamefrom();
407
8365e2f7 408 if ($2 && $4)
25d264e2 409 from = renamefrom($4);
8365e2f7 410 if (from == 0 && $4)
25d264e2
SL
411 free($4);
412 $$ = (int)from;
413 }
414 ;
415
416rename_to: RNTO SP pathname CRLF
417 = {
418 $$ = $3;
419 }
420 ;
421
422check_login: /* empty */
423 = {
424 if (logged_in)
425 $$ = 1;
426 else {
427 reply(530, "Please login with USER and PASS.");
428 $$ = 0;
429 }
430 }
431 ;
432
433%%
434
435extern jmp_buf errcatch;
436
437#define CMD 0 /* beginning of command */
438#define ARGS 1 /* expect miscellaneous arguments */
439#define STR1 2 /* expect SP followed by STRING */
440#define STR2 3 /* expect STRING */
441#define OSTR 4 /* optional STRING */
442
443struct tab {
444 char *name;
445 short token;
446 short state;
447 short implemented; /* 1 if command is implemented */
448 char *help;
449};
450
451struct tab cmdtab[] = { /* In order defined in RFC 765 */
452 { "USER", USER, STR1, 1, "<sp> username" },
453 { "PASS", PASS, STR1, 1, "<sp> password" },
454 { "ACCT", ACCT, STR1, 0, "(specify account)" },
455 { "REIN", REIN, ARGS, 0, "(reinitialize server state)" },
456 { "QUIT", QUIT, ARGS, 1, "(terminate service)", },
457 { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" },
458 { "PASV", PASV, ARGS, 0, "(set server in passive mode)" },
459 { "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" },
460 { "STRU", STRU, ARGS, 1, "(specify file structure)" },
461 { "MODE", MODE, ARGS, 1, "(specify transfer mode)" },
462 { "RETR", RETR, STR1, 1, "<sp> file-name" },
463 { "STOR", STOR, STR1, 1, "<sp> file-name" },
464 { "APPE", APPE, STR1, 1, "<sp> file-name" },
465 { "MLFL", MLFL, OSTR, 0, "(mail file)" },
466 { "MAIL", MAIL, OSTR, 0, "(mail to user)" },
467 { "MSND", MSND, OSTR, 0, "(mail send to terminal)" },
468 { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" },
469 { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" },
470 { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" },
471 { "MRCP", MRCP, STR1, 0, "(mail recipient)" },
472 { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" },
473 { "REST", REST, STR1, 0, "(restart command)" },
474 { "RNFR", RNFR, STR1, 1, "<sp> file-name" },
475 { "RNTO", RNTO, STR1, 1, "<sp> file-name" },
476 { "ABOR", ABOR, ARGS, 0, "(abort operation)" },
477 { "DELE", DELE, STR1, 1, "<sp> file-name" },
478 { "CWD", CWD, OSTR, 1, "[ <sp> directory-name]" },
479 { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" },
480 { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" },
481 { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" },
482 { "SITE", SITE, STR1, 0, "(get site parameters)" },
483 { "STAT", STAT, OSTR, 0, "(get server status)" },
484 { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" },
485 { "NOOP", NOOP, ARGS, 1, "" },
486 { "XMKD", XMKD, STR1, 1, "<sp> path-name" },
487 { "XRMD", XRMD, STR1, 1, "<sp> path-name" },
488 { "XPWD", XPWD, ARGS, 1, "(return current directory)" },
489 { "XCUP", XCUP, ARGS, 1, "(change to parent directory)" },
490 { NULL, 0, 0, 0, 0 }
491};
492
493struct tab *
494lookup(cmd)
495 char *cmd;
496{
497 register struct tab *p;
498
499 for (p = cmdtab; p->name != NULL; p++)
500 if (strcmp(cmd, p->name) == 0)
501 return (p);
502 return (0);
503}
504
505#include "../telnet/telnet.h"
506
507/*
508 * getline - a hacked up version of fgets to ignore TELNET escape codes.
509 */
510char *
511getline(s, n, iop)
512 char *s;
513 register FILE *iop;
514{
515 register c;
516 register char *cs;
517
518 cs = s;
519 while (--n > 0 && (c = getc(iop)) >= 0) {
520 while (c == IAC) {
521 c = getc(iop); /* skip command */
522 c = getc(iop); /* try next char */
523 }
524 *cs++ = c;
525 if (c=='\n')
526 break;
527 }
528 if (c < 0 && cs == s)
529 return (NULL);
530 *cs++ = '\0';
8365e2f7
SL
531 fprintf(stderr, "FTPD: command: %s", s);
532 if (c != '\n')
533 putc('\n', stderr);
25d264e2
SL
534 fflush(stderr);
535 return (s);
536}
537
538yylex()
539{
540 static char cbuf[512];
541 static int cpos, state;
542 register char *cp;
543 register struct tab *p;
544 int n;
545 char c;
546
547 for (;;) {
548 switch (state) {
549
550 case CMD:
551 if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) {
552 reply(221, "You could at least say goodbye.");
553 exit(0);
554 }
555 if (index(cbuf, '\r')) {
556 cp = index(cbuf, '\r');
557 cp[0] = '\n'; cp[1] = 0;
558 }
559 if (index(cbuf, ' '))
560 cpos = index(cbuf, ' ') - cbuf;
561 else
562 cpos = 4;
563 c = cbuf[cpos];
564 cbuf[cpos] = '\0';
565 upper(cbuf);
566 p = lookup(cbuf);
567 cbuf[cpos] = c;
568 if (p != 0) {
569 if (p->implemented == 0) {
570 nack(p->name);
571 longjmp(errcatch);
572 /* NOTREACHED */
573 }
574 state = p->state;
575 yylval = (int) p->name;
576 return (p->token);
577 }
578 break;
579
580 case OSTR:
581 if (cbuf[cpos] == '\n') {
582 state = CMD;
583 return (CRLF);
584 }
585 /* FALL THRU */
586
587 case STR1:
588 if (cbuf[cpos] == ' ') {
589 cpos++;
590 state = STR2;
591 return (SP);
592 }
593 break;
594
595 case STR2:
596 cp = &cbuf[cpos];
597 n = strlen(cp);
598 cpos += n - 1;
599 /*
600 * Make sure the string is nonempty and \n terminated.
601 */
602 if (n > 1 && cbuf[cpos] == '\n') {
603 cbuf[cpos] = '\0';
604 yylval = copy(cp);
605 cbuf[cpos] = '\n';
606 state = ARGS;
607 return (STRING);
608 }
609 break;
610
611 case ARGS:
612 if (isdigit(cbuf[cpos])) {
613 cp = &cbuf[cpos];
614 while (isdigit(cbuf[++cpos]))
615 ;
616 c = cbuf[cpos];
617 cbuf[cpos] = '\0';
618 yylval = atoi(cp);
619 cbuf[cpos] = c;
620 return (NUMBER);
621 }
622 switch (cbuf[cpos++]) {
623
624 case '\n':
625 state = CMD;
626 return (CRLF);
627
628 case ' ':
629 return (SP);
630
631 case ',':
632 return (COMMA);
633
634 case 'A':
635 case 'a':
636 return (A);
637
638 case 'B':
639 case 'b':
640 return (B);
641
642 case 'C':
643 case 'c':
644 return (C);
645
646 case 'E':
647 case 'e':
648 return (E);
649
650 case 'F':
651 case 'f':
652 return (F);
653
654 case 'I':
655 case 'i':
656 return (I);
657
658 case 'L':
659 case 'l':
660 return (L);
661
662 case 'N':
663 case 'n':
664 return (N);
665
666 case 'P':
667 case 'p':
668 return (P);
669
670 case 'R':
671 case 'r':
672 return (R);
673
674 case 'S':
675 case 's':
676 return (S);
677
678 case 'T':
679 case 't':
680 return (T);
681
682 }
683 break;
684
685 default:
686 fatal("Unknown state in scanner.");
687 }
688 yyerror();
689 state = CMD;
690 longjmp(errcatch);
691 }
692}
693
694upper(s)
695 char *s;
696{
697 while (*s != '\0') {
698 if (islower(*s))
699 *s = toupper(*s);
700 s++;
701 }
702}
703
704copy(s)
705 char *s;
706{
707 char *p;
708 extern char *malloc();
709
710 p = malloc(strlen(s) + 1);
711 if (p == NULL)
712 fatal("Ran out of memory.");
713 strcpy(p, s);
714 return ((int)p);
715}
716
717help(s)
718 char *s;
719{
720 register struct tab *c;
721 register int width, NCMDS;
722
723 width = 0, NCMDS = 0;
724 for (c = cmdtab; c->name != NULL; c++) {
725 int len = strlen(c->name);
726
727 if (c->implemented == 0)
728 len++;
729 if (len > width)
730 width = len;
731 NCMDS++;
732 }
733 width = (width + 8) &~ 7;
734 if (s == 0) {
735 register int i, j, w;
736 int columns, lines;
737
738 lreply(214,
739 "The following commands are recognized (* =>'s unimplemented).");
740 columns = 76 / width;
741 if (columns == 0)
742 columns = 1;
743 lines = (NCMDS + columns - 1) / columns;
744 for (i = 0; i < lines; i++) {
745 printf(" ");
746 for (j = 0; j < columns; j++) {
747 c = cmdtab + j * lines + i;
748 printf("%s%c", c->name,
749 c->implemented ? ' ' : '*');
8365e2f7 750 if (c + lines >= &cmdtab[NCMDS])
25d264e2 751 break;
25d264e2
SL
752 w = strlen(c->name);
753 while (w < width) {
754 putchar(' ');
755 w++;
756 }
757 }
758 printf("\r\n");
759 }
760 fflush(stdout);
761 reply(214, "Direct comments to ftp-bugs@%s.", hostname);
762 return;
763 }
764 upper(s);
765 c = lookup(s);
766 if (c == (struct tab *)0) {
767 reply(504, "Unknown command %s.", s);
768 return;
769 }
770 if (c->implemented)
771 reply(214, "Syntax: %s %s", c->name, c->help);
772 else
773 reply(214, "%-*s\t%s; unimplemented.", width, c->name, c->help);
774}