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