# 2.11BSD#431 - /usr/src/libexec/ftpd/ftpcmd.y

##### Functions

    _copy             X
    _getline          X
    _help             X
    _lookup           X
    _sizecmd          X
    _upper            X
    _yylex            X

##### Variables

    _cmdtab           X
    _sitetab          X

##### Macros

    ARGS              X
    CMD               X
    NSTR              X
    OSTR              X
    SITECMD           X
    STR1              X
    STR2              X
    ZSTR1             X
    ZSTR2             X

##### struct's

    tab               X

       1: /*
       2:  * Copyright (c) 1985, 1988 Regents of the University of California.
       3:  * All rights reserved.
       4:  *
       5:  * Redistribution and use in source and binary forms are permitted
       6:  * provided that the above copyright notice and this paragraph are
       7:  * duplicated in all such forms and that any documentation,
       8:  * advertising materials, and other materials related to such
       9:  * distribution and use acknowledge that the software was developed
      10:  * by the University of California, Berkeley.  The name of the
      11:  * University may not be used to endorse or promote products derived
      12:  * from this software without specific prior written permission.
      13:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
      14:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
      15:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
      16:  *
      17:  *	@(#)ftpcmd.y	5.20 (Berkeley) 2/28/89
      18:  */
      19:
      20: /*
      21:  * Grammar for FTP commands.
      22:  * See RFC 959.
      23:  */
      24:
      25: %{
      26:
      27: #ifndef lint
      28: static char sccsid[] = "@(#)ftpcmd.y	5.20 (Berkeley) 2/28/89";
      29: #endif /* not lint */
      30:
      31: #include <sys/param.h>
      32: #include <sys/socket.h>
      33:
      34: #include <netinet/in.h>
      35:
      36: #include <arpa/ftp.h>
      37:
      38: #include <stdio.h>
      39: #include <signal.h>
      40: #include <ctype.h>
      41: #include <pwd.h>
      42: #include <setjmp.h>
      43: #include <syslog.h>
      44: #include <sys/stat.h>
      45: #include <time.h>
      46:
      47: extern  struct sockaddr_in data_dest;
      48: extern  int logged_in;
      49: extern  struct passwd *pw;
      50: extern  int guest;
      51: extern  int logging;
      52: extern  int type;
      53: extern  int form;
      54: extern  int debug;
      55: extern  int timeout;
      56: extern  int maxtimeout;
      57: extern  int pdata;
      58: extern  char hostname[], remotehost[];
      59: extern  char proctitle[];
      60: extern  char *globerr;
      61: extern  int usedefault;
      62: extern  int transflag;
      63: extern  char tmpline[];
      64: char    **glob();
      65:
      66: off_t   restart_point;
      67:
      68: static  int cmd_type;
      69: static  int cmd_form;
      70: static  int cmd_bytesz;
      71: char    cbuf[512];
      72: char    *fromname;
      73:
      74: char    *index();
      75: %}
      76:
      77: %token
      78:     A   B   C   E   F   I
      79:     L   N   P   R   S   T
      80:
      81:     SP  CRLF    COMMA   STRING  NUMBER
      82:
      83:     USER    PASS    ACCT    REIN    QUIT    PORT
      84:     PASV    TYPE    STRU    MODE    RETR    STOR
      85:     APPE    MLFL    MAIL    MSND    MSOM    MSAM
      86:     MRSQ    MRCP    ALLO    REST    RNFR    RNTO
      87:     ABOR    DELE    CWD LIST    NLST    SITE
      88:     STAT    HELP    NOOP    MKD RMD PWD
      89:     CDUP    STOU    SMNT    SYST    SIZE    MDTM
      90:
      91:     UMASK   IDLE    CHMOD
      92:
      93:     LEXERR
      94:
      95: %start  cmd_list
      96:
      97: %%
      98:
      99: cmd_list:   /* empty */
     100:     |   cmd_list cmd
     101:         = {
     102:             fromname = (char *) 0;
     103:             restart_point = (off_t) 0;
     104:         }
     105:     |   cmd_list rcmd
     106:     ;
     107:
     108: cmd:        USER SP username CRLF
     109:         = {
     110:             user((char *) $3);
     111:             free((char *) $3);
     112:         }
     113:     |   PASS SP password CRLF
     114:         = {
     115:             pass((char *) $3);
     116:             free((char *) $3);
     117:         }
     118:     |   PORT SP host_port CRLF
     119:         = {
     120:             usedefault = 0;
     121:             if (pdata >= 0) {
     122:                 (void) close(pdata);
     123:                 pdata = -1;
     124:             }
     125:             reply(200, "PORT command successful.");
     126:         }
     127:     |   PASV CRLF
     128:         = {
     129:             passive();
     130:         }
     131:     |   TYPE SP type_code CRLF
     132:         = {
     133:             switch (cmd_type) {
     134:
     135:             case TYPE_A:
     136:                 if (cmd_form == FORM_N) {
     137:                     reply(200, "Type set to A.");
     138:                     type = cmd_type;
     139:                     form = cmd_form;
     140:                 } else
     141:                     reply(504, "Form must be N.");
     142:                 break;
     143:
     144:             case TYPE_E:
     145:                 reply(504, "Type E not implemented.");
     146:                 break;
     147:
     148:             case TYPE_I:
     149:                 reply(200, "Type set to I.");
     150:                 type = cmd_type;
     151:                 break;
     152:
     153:             case TYPE_L:
     154: #if NBBY == 8
     155:                 if (cmd_bytesz == 8) {
     156:                     reply(200,
     157:                         "Type set to L (byte size 8).");
     158:                     type = cmd_type;
     159:                 } else
     160:                     reply(504, "Byte size must be 8.");
     161: #else /* NBBY == 8 */
     162:                 UNIMPLEMENTED for NBBY != 8
     163: #endif /* NBBY == 8 */
     164:             }
     165:         }
     166:     |   STRU SP struct_code CRLF
     167:         = {
     168:             switch ($3) {
     169:
     170:             case STRU_F:
     171:                 reply(200, "STRU F ok.");
     172:                 break;
     173:
     174:             default:
     175:                 reply(504, "Unimplemented STRU type.");
     176:             }
     177:         }
     178:     |   MODE SP mode_code CRLF
     179:         = {
     180:             switch ($3) {
     181:
     182:             case MODE_S:
     183:                 reply(200, "MODE S ok.");
     184:                 break;
     185:
     186:             default:
     187:                 reply(502, "Unimplemented MODE type.");
     188:             }
     189:         }
     190:     |   ALLO SP NUMBER CRLF
     191:         = {
     192:             reply(202, "ALLO command ignored.");
     193:         }
     194:     |   ALLO SP NUMBER SP R SP NUMBER CRLF
     195:         = {
     196:             reply(202, "ALLO command ignored.");
     197:         }
     198:     |   RETR check_login SP pathname CRLF
     199:         = {
     200:             if ($2 && $4 != NULL)
     201:                 retrieve((char *) 0, (char *) $4);
     202:             if ($4 != NULL)
     203:                 free((char *) $4);
     204:         }
     205:     |   STOR check_login SP pathname CRLF
     206:         = {
     207:             if ($2 && $4 != NULL)
     208:                 store((char *) $4, "w", 0);
     209:             if ($4 != NULL)
     210:                 free((char *) $4);
     211:         }
     212:     |   APPE check_login SP pathname CRLF
     213:         = {
     214:             if ($2 && $4 != NULL)
     215:                 store((char *) $4, "a", 0);
     216:             if ($4 != NULL)
     217:                 free((char *) $4);
     218:         }
     219:     |   NLST check_login CRLF
     220:         = {
     221:             if ($2)
     222:                 send_file_list(".");
     223:         }
     224:     |   NLST check_login SP STRING CRLF
     225:         = {
     226:             if ($2 && $4 != NULL)
     227:                 send_file_list((char *) $4);
     228:             if ($4 != NULL)
     229:                 free((char *) $4);
     230:         }
     231:     |   LIST check_login CRLF
     232:         = {
     233:             if ($2)
     234:                 retrieve("/bin/ls -lgA", "");
     235:         }
     236:     |   LIST check_login SP pathname CRLF
     237:         = {
     238:             if ($2 && $4 != NULL)
     239:                 retrieve("/bin/ls -lgA %s", (char *) $4);
     240:             if ($4 != NULL)
     241:                 free((char *) $4);
     242:         }
     243:     |   STAT check_login SP pathname CRLF
     244:         = {
     245:             if ($2 && $4 != NULL)
     246:                 statfilecmd((char *) $4);
     247:             if ($4 != NULL)
     248:                 free((char *) $4);
     249:         }
     250:     |   STAT CRLF
     251:         = {
     252:             statcmd();
     253:         }
     254:     |   DELE check_login SP pathname CRLF
     255:         = {
     256:             if ($2 && $4 != NULL)
     257:                 delete((char *) $4);
     258:             if ($4 != NULL)
     259:                 free((char *) $4);
     260:         }
     261:     |   RNTO SP pathname CRLF
     262:         = {
     263:             if (fromname) {
     264:                 renamecmd(fromname, (char *) $3);
     265:                 free(fromname);
     266:                 fromname = (char *) 0;
     267:             } else {
     268:                 reply(503, "Bad sequence of commands.");
     269:             }
     270:             free((char *) $3);
     271:         }
     272:     |   ABOR CRLF
     273:         = {
     274:             reply(225, "ABOR command successful.");
     275:         }
     276:     |   CWD check_login CRLF
     277:         = {
     278:             if ($2)
     279:                 cwd(pw->pw_dir);
     280:         }
     281:     |   CWD check_login SP pathname CRLF
     282:         = {
     283:             if ($2 && $4 != NULL)
     284:                 cwd((char *) $4);
     285:             if ($4 != NULL)
     286:                 free((char *) $4);
     287:         }
     288:     |   HELP CRLF
     289:         = {
     290:             help(cmdtab, (char *) 0);
     291:         }
     292:     |   HELP SP STRING CRLF
     293:         = {
     294:             register char *cp = (char *)$3;
     295:
     296:             if (strncasecmp(cp, "SITE", 4) == 0) {
     297:                 cp = (char *)$3 + 4;
     298:                 if (*cp == ' ')
     299:                     cp++;
     300:                 if (*cp)
     301:                     help(sitetab, cp);
     302:                 else
     303:                     help(sitetab, (char *) 0);
     304:             } else
     305:                 help(cmdtab, (char *) $3);
     306:         }
     307:     |   NOOP CRLF
     308:         = {
     309:             reply(200, "NOOP command successful.");
     310:         }
     311:     |   MKD check_login SP pathname CRLF
     312:         = {
     313:             if ($2 && $4 != NULL)
     314:                 makedir((char *) $4);
     315:             if ($4 != NULL)
     316:                 free((char *) $4);
     317:         }
     318:     |   RMD check_login SP pathname CRLF
     319:         = {
     320:             if ($2 && $4 != NULL)
     321:                 removedir((char *) $4);
     322:             if ($4 != NULL)
     323:                 free((char *) $4);
     324:         }
     325:     |   PWD check_login CRLF
     326:         = {
     327:             if ($2)
     328:                 pwd();
     329:         }
     330:     |   CDUP check_login CRLF
     331:         = {
     332:             if ($2)
     333:                 cwd("..");
     334:         }
     335:     |   SITE SP HELP CRLF
     336:         = {
     337:             help(sitetab, (char *) 0);
     338:         }
     339:     |   SITE SP HELP SP STRING CRLF
     340:         = {
     341:             help(sitetab, (char *) $5);
     342:         }
     343:     |   SITE SP UMASK check_login CRLF
     344:         = {
     345:             int oldmask;
     346:
     347:             if ($4) {
     348:                 oldmask = umask(0);
     349:                 (void) umask(oldmask);
     350:                 reply(200, "Current UMASK is %03o", oldmask);
     351:             }
     352:         }
     353:     |   SITE SP UMASK check_login SP octal_number CRLF
     354:         = {
     355:             int oldmask;
     356:
     357:             if ($4) {
     358:                 if (($6 == -1) || ($6 > 0777)) {
     359:                     reply(501, "Bad UMASK value");
     360:                 } else {
     361:                     oldmask = umask($6);
     362:                     reply(200,
     363:                         "UMASK set to %03o (was %03o)",
     364:                         $6, oldmask);
     365:                 }
     366:             }
     367:         }
     368:     |   SITE SP CHMOD check_login SP octal_number SP pathname CRLF
     369:         = {
     370:             if ($4 && ($8 != NULL)) {
     371:                 if ($6 > 0777)
     372:                     reply(501,
     373:                 "CHMOD: Mode value must be between 0 and 0777");
     374:                 else if (chmod((char *) $8, $6) < 0)
     375:                     perror_reply(550, (char *) $8);
     376:                 else
     377:                     reply(200, "CHMOD command successful.");
     378:             }
     379:             if ($8 != NULL)
     380:                 free((char *) $8);
     381:         }
     382:     |   SITE SP IDLE CRLF
     383:         = {
     384:             reply(200,
     385:                 "Current IDLE time limit is %d seconds; max %d",
     386:                 timeout, maxtimeout);
     387:         }
     388:     |   SITE SP IDLE SP NUMBER CRLF
     389:         = {
     390:             if ($5 < 30 || $5 > maxtimeout) {
     391:                 reply(501,
     392:             "Maximum IDLE time must be between 30 and %d seconds",
     393:                     maxtimeout);
     394:             } else {
     395:                 timeout = $5;
     396:                 (void) alarm((unsigned) timeout);
     397:                 reply(200,
     398:                     "Maximum IDLE time set to %d seconds",
     399:                     timeout);
     400:             }
     401:         }
     402:     |   STOU check_login SP pathname CRLF
     403:         = {
     404:             if ($2 && $4 != NULL)
     405:                 store((char *) $4, "w", 1);
     406:             if ($4 != NULL)
     407:                 free((char *) $4);
     408:         }
     409:     |   SYST CRLF
     410:         = {
     411: #ifdef unix
     412: #ifdef BSD
     413:             reply(215, "UNIX Type: L%d Version: BSD-%d",
     414:                 NBBY, BSD);
     415: #else /* BSD */
     416:             reply(215, "UNIX Type: L%d", NBBY);
     417: #endif /* BSD */
     418: #else /* unix */
     419:             reply(215, "UNKNOWN Type: L%d", NBBY);
     420: #endif /* unix */
     421:         }
     422:
     423:         /*
     424: 		 * SIZE is not in RFC959, but Postel has blessed it and
     425: 		 * it will be in the updated RFC.
     426: 		 *
     427: 		 * Return size of file in a format suitable for
     428: 		 * using with RESTART (we just count bytes).
     429: 		 */
     430:     |   SIZE check_login SP pathname CRLF
     431:         = {
     432:             if ($2 && $4 != NULL)
     433:                 sizecmd((char *) $4);
     434:             if ($4 != NULL)
     435:                 free((char *) $4);
     436:         }
     437:
     438:         /*
     439: 		 * MDTM is not in RFC959, but Postel has blessed it and
     440: 		 * it will be in the updated RFC.
     441: 		 *
     442: 		 * Return modification time of file as an ISO 3307
     443: 		 * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx
     444: 		 * where xxx is the fractional second (of any precision,
     445: 		 * not necessarily 3 digits)
     446: 		 */
     447:     |   MDTM check_login SP pathname CRLF
     448:         = {
     449:             if ($2 && $4 != NULL) {
     450:                 struct stat stbuf;
     451:                 if (stat((char *) $4, &stbuf) < 0)
     452:                     perror_reply(550, "%s", (char *) $4);
     453:                 else if ((stbuf.st_mode&S_IFMT) != S_IFREG) {
     454:                     reply(550, "%s: not a plain file.",
     455:                         (char *) $4);
     456:                 } else {
     457:                     register struct tm *t;
     458:                     struct tm *gmtime();
     459:                     t = gmtime(&stbuf.st_mtime);
     460:                     reply(213,
     461:                         "19%02d%02d%02d%02d%02d%02d",
     462:                         t->tm_year, t->tm_mon+1, t->tm_mday,
     463:                         t->tm_hour, t->tm_min, t->tm_sec);
     464:                 }
     465:             }
     466:             if ($4 != NULL)
     467:                 free((char *) $4);
     468:         }
     469:     |   QUIT CRLF
     470:         = {
     471:             reply(221, "Goodbye.");
     472:             dologout(0);
     473:         }
     474:     |   error CRLF
     475:         = {
     476:             yyerrok;
     477:         }
     478:     ;
     479: rcmd:       RNFR check_login SP pathname CRLF
     480:         = {
     481:             char *renamefrom();
     482:
     483:             restart_point = (off_t) 0;
     484:             if ($2 && $4) {
     485:                 fromname = renamefrom((char *) $4);
     486:                 if (fromname == (char *) 0 && $4) {
     487:                     free((char *) $4);
     488:                 }
     489:             }
     490:         }
     491:     |   REST SP STRING CRLF
     492:         = {
     493:             long atol();
     494:
     495:             fromname = (char *) 0;
     496:             restart_point = atol($3);
     497:             reply(350, "Restarting at %ld. %s", restart_point,
     498:                 "Send STORE or RETRIEVE to initiate transfer.");
     499:         }
     500:     ;
     501:
     502: username:   STRING
     503:     ;
     504:
     505: password:   /* empty */
     506:         = {
     507:             *(char **)&($$) = (char *)calloc(1, sizeof (char));
     508:         }
     509:     |   STRING
     510:     ;
     511:
     512: byte_size:  NUMBER
     513:     ;
     514:
     515: host_port:  NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
     516:         NUMBER COMMA NUMBER
     517:         = {
     518:             register char *a, *p;
     519:
     520:             a = (char *)&data_dest.sin_addr;
     521:             a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;
     522:             p = (char *)&data_dest.sin_port;
     523:             p[0] = $9; p[1] = $11;
     524:             data_dest.sin_family = AF_INET;
     525:         }
     526:     ;
     527:
     528: form_code:  N
     529:     = {
     530:         $$ = FORM_N;
     531:     }
     532:     |   T
     533:     = {
     534:         $$ = FORM_T;
     535:     }
     536:     |   C
     537:     = {
     538:         $$ = FORM_C;
     539:     }
     540:     ;
     541:
     542: type_code:  A
     543:     = {
     544:         cmd_type = TYPE_A;
     545:         cmd_form = FORM_N;
     546:     }
     547:     |   A SP form_code
     548:     = {
     549:         cmd_type = TYPE_A;
     550:         cmd_form = $3;
     551:     }
     552:     |   E
     553:     = {
     554:         cmd_type = TYPE_E;
     555:         cmd_form = FORM_N;
     556:     }
     557:     |   E SP form_code
     558:     = {
     559:         cmd_type = TYPE_E;
     560:         cmd_form = $3;
     561:     }
     562:     |   I
     563:     = {
     564:         cmd_type = TYPE_I;
     565:     }
     566:     |   L
     567:     = {
     568:         cmd_type = TYPE_L;
     569:         cmd_bytesz = NBBY;
     570:     }
     571:     |   L SP byte_size
     572:     = {
     573:         cmd_type = TYPE_L;
     574:         cmd_bytesz = $3;
     575:     }
     576:     /* this is for a bug in the BBN ftp */
     577:     |   L byte_size
     578:     = {
     579:         cmd_type = TYPE_L;
     580:         cmd_bytesz = $2;
     581:     }
     582:     ;
     583:
     584: struct_code:    F
     585:     = {
     586:         $$ = STRU_F;
     587:     }
     588:     |   R
     589:     = {
     590:         $$ = STRU_R;
     591:     }
     592:     |   P
     593:     = {
     594:         $$ = STRU_P;
     595:     }
     596:     ;
     597:
     598: mode_code:  S
     599:     = {
     600:         $$ = MODE_S;
     601:     }
     602:     |   B
     603:     = {
     604:         $$ = MODE_B;
     605:     }
     606:     |   C
     607:     = {
     608:         $$ = MODE_C;
     609:     }
     610:     ;
     611:
     612: pathname:   pathstring
     613:     = {
     614:         /*
     615: 		 * Problem: this production is used for all pathname
     616: 		 * processing, but only gives a 550 error reply.
     617: 		 * This is a valid reply in some cases but not in others.
     618: 		 */
     619:         if (logged_in && $1 && strncmp((char *) $1, "~", 1) == 0) {
     620:             *(char **)&($$) = *glob((char *) $1);
     621:             if (globerr != NULL) {
     622:                 reply(550, globerr);
     623:                 $$ = NULL;
     624:             }
     625:             free((char *) $1);
     626:         } else
     627:             $$ = $1;
     628:     }
     629:     ;
     630:
     631: pathstring: STRING
     632:     ;
     633:
     634: octal_number:   NUMBER
     635:     = {
     636:         register int ret, dec, multby, digit;
     637:
     638:         /*
     639: 		 * Convert a number that was read as decimal number
     640: 		 * to what it would be if it had been read as octal.
     641: 		 */
     642:         dec = $1;
     643:         multby = 1;
     644:         ret = 0;
     645:         while (dec) {
     646:             digit = dec%10;
     647:             if (digit > 7) {
     648:                 ret = -1;
     649:                 break;
     650:             }
     651:             ret += digit * multby;
     652:             multby *= 8;
     653:             dec /= 10;
     654:         }
     655:         $$ = ret;
     656:     }
     657:     ;
     658:
     659: check_login:    /* empty */
     660:     = {
     661:         if (logged_in)
     662:             $$ = 1;
     663:         else {
     664:             reply(530, "Please login with USER and PASS.");
     665:             $$ = 0;
     666:         }
     667:     }
     668:     ;
     669:
     670: %%
     671:
     672: extern jmp_buf errcatch;
     673:
     674: #define CMD 0   /* beginning of command */
     675: #define ARGS    1   /* expect miscellaneous arguments */
     676: #define STR1    2   /* expect SP followed by STRING */
     677: #define STR2    3   /* expect STRING */
     678: #define OSTR    4   /* optional SP then STRING */
     679: #define ZSTR1   5   /* SP then optional STRING */
     680: #define ZSTR2   6   /* optional STRING after SP */
     681: #define SITECMD 7   /* SITE command */
     682: #define NSTR    8   /* Number followed by a string */
     683:
     684: struct tab {
     685:     char    *name;
     686:     short   token;
     687:     short   state;
     688:     short   implemented;    /* 1 if command is implemented */
     689:     char    *help;
     690: };
     691:
     692: struct tab cmdtab[] = {     /* In order defined in RFC 765 */
     693:     { "USER", USER, STR1, 1,    "<sp> username" },
     694:     { "PASS", PASS, ZSTR1, 1,   "<sp> password" },
     695:     { "ACCT", ACCT, STR1, 0,    "(specify account)" },
     696:     { "SMNT", SMNT, ARGS, 0,    "(structure mount)" },
     697:     { "REIN", REIN, ARGS, 0,    "(reinitialize server state)" },
     698:     { "QUIT", QUIT, ARGS, 1,    "(terminate service)", },
     699:     { "PORT", PORT, ARGS, 1,    "<sp> b0, b1, b2, b3, b4" },
     700:     { "PASV", PASV, ARGS, 1,    "(set server in passive mode)" },
     701:     { "TYPE", TYPE, ARGS, 1,    "<sp> [ A | E | I | L ]" },
     702:     { "STRU", STRU, ARGS, 1,    "(specify file structure)" },
     703:     { "MODE", MODE, ARGS, 1,    "(specify transfer mode)" },
     704:     { "RETR", RETR, STR1, 1,    "<sp> file-name" },
     705:     { "STOR", STOR, STR1, 1,    "<sp> file-name" },
     706:     { "APPE", APPE, STR1, 1,    "<sp> file-name" },
     707:     { "MLFL", MLFL, OSTR, 0,    "(mail file)" },
     708:     { "MAIL", MAIL, OSTR, 0,    "(mail to user)" },
     709:     { "MSND", MSND, OSTR, 0,    "(mail send to terminal)" },
     710:     { "MSOM", MSOM, OSTR, 0,    "(mail send to terminal or mailbox)" },
     711:     { "MSAM", MSAM, OSTR, 0,    "(mail send to terminal and mailbox)" },
     712:     { "MRSQ", MRSQ, OSTR, 0,    "(mail recipient scheme question)" },
     713:     { "MRCP", MRCP, STR1, 0,    "(mail recipient)" },
     714:     { "ALLO", ALLO, ARGS, 1,    "allocate storage (vacuously)" },
     715:     { "REST", REST, STR1, 1,    "(restart command)" },
     716:     { "RNFR", RNFR, STR1, 1,    "<sp> file-name" },
     717:     { "RNTO", RNTO, STR1, 1,    "<sp> file-name" },
     718:     { "ABOR", ABOR, ARGS, 1,    "(abort operation)" },
     719:     { "DELE", DELE, STR1, 1,    "<sp> file-name" },
     720:     { "CWD",  CWD,  OSTR, 1,    "[ <sp> directory-name ]" },
     721:     { "XCWD", CWD,  OSTR, 1,    "[ <sp> directory-name ]" },
     722:     { "LIST", LIST, OSTR, 1,    "[ <sp> path-name ]" },
     723:     { "NLST", NLST, OSTR, 1,    "[ <sp> path-name ]" },
     724:     { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" },
     725:     { "SYST", SYST, ARGS, 1,    "(get type of operating system)" },
     726:     { "STAT", STAT, OSTR, 1,    "[ <sp> path-name ]" },
     727:     { "HELP", HELP, OSTR, 1,    "[ <sp> <string> ]" },
     728:     { "NOOP", NOOP, ARGS, 1,    "" },
     729:     { "MKD",  MKD,  STR1, 1,    "<sp> path-name" },
     730:     { "XMKD", MKD,  STR1, 1,    "<sp> path-name" },
     731:     { "RMD",  RMD,  STR1, 1,    "<sp> path-name" },
     732:     { "XRMD", RMD,  STR1, 1,    "<sp> path-name" },
     733:     { "PWD",  PWD,  ARGS, 1,    "(return current directory)" },
     734:     { "XPWD", PWD,  ARGS, 1,    "(return current directory)" },
     735:     { "CDUP", CDUP, ARGS, 1,    "(change to parent directory)" },
     736:     { "XCUP", CDUP, ARGS, 1,    "(change to parent directory)" },
     737:     { "STOU", STOU, STR1, 1,    "<sp> file-name" },
     738:     { "SIZE", SIZE, OSTR, 1,    "<sp> path-name" },
     739:     { "MDTM", MDTM, OSTR, 1,    "<sp> path-name" },
     740:     { NULL,   0,    0,    0,    0 }
     741: };
     742:
     743: struct tab sitetab[] = {
     744:     { "UMASK", UMASK, ARGS, 1,  "[ <sp> umask ]" },
     745:     { "IDLE", IDLE, ARGS, 1,    "[ <sp> maximum-idle-time ]" },
     746:     { "CHMOD", CHMOD, NSTR, 1,  "<sp> mode <sp> file-name" },
     747:     { "HELP", HELP, OSTR, 1,    "[ <sp> <string> ]" },
     748:     { NULL,   0,    0,    0,    0 }
     749: };
     750:
     751: struct tab *
     752: lookup(p, cmd)
     753:     register struct tab *p;
     754:     char *cmd;
     755: {
     756:
     757:     for (; p->name != NULL; p++)
     758:         if (strcmp(cmd, p->name) == 0)
     759:             return (p);
     760:     return (0);
     761: }
     762:
     763: #include <arpa/telnet.h>
     764:
     765: /*
     766:  * getline - a hacked up version of fgets to ignore TELNET escape codes.
     767:  */
     768: char *
     769: getline(s, n, iop)
     770:     char *s;
     771:     register FILE *iop;
     772: {
     773:     register c;
     774:     register char *cs;
     775:
     776:     cs = s;
     777: /* tmpline may contain saved command from urgent mode interruption */
     778:     for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) {
     779:         *cs++ = tmpline[c];
     780:         if (tmpline[c] == '\n') {
     781:             *cs++ = '\0';
     782:             if (debug)
     783:                 syslog(LOG_DEBUG, "command: %s", s);
     784:             tmpline[0] = '\0';
     785:             return(s);
     786:         }
     787:         if (c == 0)
     788:             tmpline[0] = '\0';
     789:     }
     790:     while ((c = getc(iop)) != EOF) {
     791:         c &= 0377;
     792:         if (c == IAC) {
     793:             if ((c = getc(iop)) != EOF) {
     794:             c &= 0377;
     795:             switch (c) {
     796:             case WILL:
     797:             case WONT:
     798:                 c = getc(iop);
     799:                 printf("%c%c%c", IAC, DONT, 0377&c);
     800:                 (void) fflush(stdout);
     801:                 continue;
     802:             case DO:
     803:             case DONT:
     804:                 c = getc(iop);
     805:                 printf("%c%c%c", IAC, WONT, 0377&c);
     806:                 (void) fflush(stdout);
     807:                 continue;
     808:             case IAC:
     809:                 break;
     810:             default:
     811:                 continue;   /* ignore command */
     812:             }
     813:             }
     814:         }
     815:         *cs++ = c;
     816:         if (--n <= 0 || c == '\n')
     817:             break;
     818:     }
     819:     if (c == EOF && cs == s)
     820:         return (NULL);
     821:     *cs++ = '\0';
     822:     if (debug)
     823:         syslog(LOG_DEBUG, "command: %s", s);
     824:     return (s);
     825: }
     826:
     827: static int
     828: toolong()
     829: {
     830:     time_t now;
     831:     extern char *ctime();
     832:     extern time_t time();
     833:
     834:     reply(421,
     835:       "Timeout (%d seconds): closing control connection.", timeout);
     836:     (void) time(&now);
     837:     if (logging) {
     838:         syslog(LOG_INFO,
     839:             "User %s timed out after %d seconds at %s",
     840:             (pw ? pw -> pw_name : "unknown"), timeout, ctime(&now));
     841:     }
     842:     dologout(1);
     843: }
     844:
     845: yylex()
     846: {
     847:     static int cpos, state;
     848:     register char *cp, *cp2;
     849:     register struct tab *p;
     850:     int n;
     851:     char c, *strpbrk();
     852:     char *copy();
     853:
     854:     for (;;) {
     855:         switch (state) {
     856:
     857:         case CMD:
     858:             (void) signal(SIGALRM, toolong);
     859:             (void) alarm((unsigned) timeout);
     860:             if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) {
     861:                 reply(221, "You could at least say goodbye.");
     862:                 dologout(0);
     863:             }
     864:             (void) alarm(0);
     865: #ifdef SETPROCTITLE
     866:             if (strncasecmp(cbuf, "PASS", 4) != NULL)
     867:                 setproctitle("%s: %s", proctitle, cbuf);
     868: #endif /* SETPROCTITLE */
     869:             if ((cp = index(cbuf, '\r'))) {
     870:                 *cp++ = '\n';
     871:                 *cp = '\0';
     872:             }
     873:             if ((cp = strpbrk(cbuf, " \n")))
     874:                 cpos = cp - cbuf;
     875:             if (cpos == 0)
     876:                 cpos = 4;
     877:             c = cbuf[cpos];
     878:             cbuf[cpos] = '\0';
     879:             upper(cbuf);
     880:             p = lookup(cmdtab, cbuf);
     881:             cbuf[cpos] = c;
     882:             if (p != 0) {
     883:                 if (p->implemented == 0) {
     884:                     nack(p->name);
     885:                     longjmp(errcatch,0);
     886:                     /* NOTREACHED */
     887:                 }
     888:                 state = p->state;
     889:                 *(char **)&yylval = p->name;
     890:                 return (p->token);
     891:             }
     892:             break;
     893:
     894:         case SITECMD:
     895:             if (cbuf[cpos] == ' ') {
     896:                 cpos++;
     897:                 return (SP);
     898:             }
     899:             cp = &cbuf[cpos];
     900:             if ((cp2 = strpbrk(cp, " \n")))
     901:                 cpos = cp2 - cbuf;
     902:             c = cbuf[cpos];
     903:             cbuf[cpos] = '\0';
     904:             upper(cp);
     905:             p = lookup(sitetab, cp);
     906:             cbuf[cpos] = c;
     907:             if (p != 0) {
     908:                 if (p->implemented == 0) {
     909:                     state = CMD;
     910:                     nack(p->name);
     911:                     longjmp(errcatch,0);
     912:                     /* NOTREACHED */
     913:                 }
     914:                 state = p->state;
     915:                 *(char **)&yylval = p->name;
     916:                 return (p->token);
     917:             }
     918:             state = CMD;
     919:             break;
     920:
     921:         case OSTR:
     922:             if (cbuf[cpos] == '\n') {
     923:                 state = CMD;
     924:                 return (CRLF);
     925:             }
     926:             /* FALLTHROUGH */
     927:
     928:         case STR1:
     929:         case ZSTR1:
     930:         dostr1:
     931:             if (cbuf[cpos] == ' ') {
     932:                 cpos++;
     933:                 state = state == OSTR ? STR2 : ++state;
     934:                 return (SP);
     935:             }
     936:             break;
     937:
     938:         case ZSTR2:
     939:             if (cbuf[cpos] == '\n') {
     940:                 state = CMD;
     941:                 return (CRLF);
     942:             }
     943:             /* FALLTHROUGH */
     944:
     945:         case STR2:
     946:             cp = &cbuf[cpos];
     947:             n = strlen(cp);
     948:             cpos += n - 1;
     949:             /*
     950: 			 * Make sure the string is nonempty and \n terminated.
     951: 			 */
     952:             if (n > 1 && cbuf[cpos] == '\n') {
     953:                 cbuf[cpos] = '\0';
     954:                 *(char **)&yylval = copy(cp);
     955:                 cbuf[cpos] = '\n';
     956:                 state = ARGS;
     957:                 return (STRING);
     958:             }
     959:             break;
     960:
     961:         case NSTR:
     962:             if (cbuf[cpos] == ' ') {
     963:                 cpos++;
     964:                 return (SP);
     965:             }
     966:             if (isdigit(cbuf[cpos])) {
     967:                 cp = &cbuf[cpos];
     968:                 while (isdigit(cbuf[++cpos]))
     969:                     ;
     970:                 c = cbuf[cpos];
     971:                 cbuf[cpos] = '\0';
     972:                 yylval = atoi(cp);
     973:                 cbuf[cpos] = c;
     974:                 state = STR1;
     975:                 return (NUMBER);
     976:             }
     977:             state = STR1;
     978:             goto dostr1;
     979:
     980:         case ARGS:
     981:             if (isdigit(cbuf[cpos])) {
     982:                 cp = &cbuf[cpos];
     983:                 while (isdigit(cbuf[++cpos]))
     984:                     ;
     985:                 c = cbuf[cpos];
     986:                 cbuf[cpos] = '\0';
     987:                 yylval = atoi(cp);
     988:                 cbuf[cpos] = c;
     989:                 return (NUMBER);
     990:             }
     991:             switch (cbuf[cpos++]) {
     992:
     993:             case '\n':
     994:                 state = CMD;
     995:                 return (CRLF);
     996:
     997:             case ' ':
     998:                 return (SP);
     999:
    1000:             case ',':
    1001:                 return (COMMA);
    1002:
    1003:             case 'A':
    1004:             case 'a':
    1005:                 return (A);
    1006:
    1007:             case 'B':
    1008:             case 'b':
    1009:                 return (B);
    1010:
    1011:             case 'C':
    1012:             case 'c':
    1013:                 return (C);
    1014:
    1015:             case 'E':
    1016:             case 'e':
    1017:                 return (E);
    1018:
    1019:             case 'F':
    1020:             case 'f':
    1021:                 return (F);
    1022:
    1023:             case 'I':
    1024:             case 'i':
    1025:                 return (I);
    1026:
    1027:             case 'L':
    1028:             case 'l':
    1029:                 return (L);
    1030:
    1031:             case 'N':
    1032:             case 'n':
    1033:                 return (N);
    1034:
    1035:             case 'P':
    1036:             case 'p':
    1037:                 return (P);
    1038:
    1039:             case 'R':
    1040:             case 'r':
    1041:                 return (R);
    1042:
    1043:             case 'S':
    1044:             case 's':
    1045:                 return (S);
    1046:
    1047:             case 'T':
    1048:             case 't':
    1049:                 return (T);
    1050:
    1051:             }
    1052:             break;
    1053:
    1054:         default:
    1055:             fatal("Unknown state in scanner.");
    1056:         }
    1057:         yyerror((char *) 0);
    1058:         state = CMD;
    1059:         longjmp(errcatch,0);
    1060:     }
    1061: }
    1062:
    1063: upper(s)
    1064:     register char *s;
    1065: {
    1066:     while (*s != '\0') {
    1067:         if (islower(*s))
    1068:             *s = toupper(*s);
    1069:         s++;
    1070:     }
    1071: }
    1072:
    1073: char *
    1074: copy(s)
    1075:     char *s;
    1076: {
    1077:     char *p;
    1078:     extern char *malloc(), *strcpy();
    1079:
    1080:     p = malloc((unsigned) strlen(s) + 1);
    1081:     if (p == NULL)
    1082:         fatal("Ran out of memory.");
    1083:     (void) strcpy(p, s);
    1084:     return (p);
    1085: }
    1086:
    1087: help(ctab, s)
    1088:     struct tab *ctab;
    1089:     char *s;
    1090: {
    1091:     register struct tab *c;
    1092:     register int width, NCMDS;
    1093:     char *type;
    1094:
    1095:     if (ctab == sitetab)
    1096:         type = "SITE ";
    1097:     else
    1098:         type = "";
    1099:     width = 0, NCMDS = 0;
    1100:     for (c = ctab; c->name != NULL; c++) {
    1101:         int len = strlen(c->name);
    1102:
    1103:         if (len > width)
    1104:             width = len;
    1105:         NCMDS++;
    1106:     }
    1107:     width = (width + 8) &~ 7;
    1108:     if (s == 0) {
    1109:         register int i, j, w;
    1110:         int columns, lines;
    1111:
    1112:         lreply(214, "The following %scommands are recognized %s.",
    1113:             type, "(* =>'s unimplemented)");
    1114:         columns = 76 / width;
    1115:         if (columns == 0)
    1116:             columns = 1;
    1117:         lines = (NCMDS + columns - 1) / columns;
    1118:         for (i = 0; i < lines; i++) {
    1119:             printf("   ");
    1120:             for (j = 0; j < columns; j++) {
    1121:                 c = ctab + j * lines + i;
    1122:                 printf("%s%c", c->name,
    1123:                     c->implemented ? ' ' : '*');
    1124:                 if (c + lines >= &ctab[NCMDS])
    1125:                     break;
    1126:                 w = strlen(c->name) + 1;
    1127:                 while (w < width) {
    1128:                     putchar(' ');
    1129:                     w++;
    1130:                 }
    1131:             }
    1132:             printf("\r\n");
    1133:         }
    1134:         (void) fflush(stdout);
    1135:         reply(214, "Direct comments to ftp-bugs@%s.", hostname);
    1136:         return;
    1137:     }
    1138:     upper(s);
    1139:     c = lookup(ctab, s);
    1140:     if (c == (struct tab *)0) {
    1141:         reply(502, "Unknown command %s.", s);
    1142:         return;
    1143:     }
    1144:     if (c->implemented)
    1145:         reply(214, "Syntax: %s%s %s", type, c->name, c->help);
    1146:     else
    1147:         reply(214, "%s%-*s\t%s; unimplemented.", type, width,
    1148:             c->name, c->help);
    1149: }
    1150:
    1151: sizecmd(filename)
    1152: char *filename;
    1153: {
    1154:     switch (type) {
    1155:     case TYPE_L:
    1156:     case TYPE_I: {
    1157:         struct stat stbuf;
    1158:         if (stat(filename, &stbuf) < 0 ||
    1159:             (stbuf.st_mode&S_IFMT) != S_IFREG)
    1160:             reply(550, "%s: not a plain file.", filename);
    1161:         else
    1162:             reply(213, "%lu", stbuf.st_size);
    1163:         break;}
    1164:     case TYPE_A: {
    1165:         FILE *fin;
    1166:         register int c;
    1167:         long count;
    1168:         struct stat stbuf;
    1169:         fin = fopen(filename, "r");
    1170:         if (fin == NULL) {
    1171:             perror_reply(550, filename);
    1172:             return;
    1173:         }
    1174:         if (fstat(fileno(fin), &stbuf) < 0 ||
    1175:             (stbuf.st_mode&S_IFMT) != S_IFREG) {
    1176:             reply(550, "%s: not a plain file.", filename);
    1177:             (void) fclose(fin);
    1178:             return;
    1179:         }
    1180:
    1181:         count = 0;
    1182:         while((c=getc(fin)) != EOF) {
    1183:             if (c == '\n')  /* will get expanded to \r\n */
    1184:                 count++;
    1185:             count++;
    1186:         }
    1187:         (void) fclose(fin);
    1188:
    1189:         reply(213, "%ld", count);
    1190:         break;}
    1191:     default:
    1192:         reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
    1193:     }
    1194: }

#### Defined functions

_copy defined in line 1073; used 2 times

- in line 852, 954

_getline defined in line 768; used 3 times

- in line 860
- in /usr/src/libexec/ftpd/ftpd.c line 75, 1169

_help defined in line 1087; used 9 times

- in line 290, 301-305(3), 337-341(2), 689, 1145-1148(2)

_lookup defined in line 751; used 3 times

- in line 880, 905, 1139

_sizecmd defined in line 1151; used 1 times

- in line 433

_toolong defined in line 827; used 1 times

- in line 858

_upper defined in line 1063; used 4 times

- in line 879, 904, 1138
- in /usr/src/libexec/ftpd/ftpd.c line 1173

_yylex defined in line 845; never used

#### Defined variables

_cmdtab defined in line 692; used 3 times

- in line 290, 305, 880

_sitetab defined in line 743; used 6 times

- in line 301-303(2), 337-341(2), 905, 1095

#### Defined struct's

tab defined in line 684; used 16 times

- in line 692(2), 743(2), 751-753(4), 849(2), 1088-1091(4), 1140(2)

#### Defined macros

ARGS defined in line 675; used 19 times

- in line 696-703(8), 714-718(2), 725-736(6), 744-745(2), 956

CMD defined in line 674; used 6 times

- in line 909, 918-923(2), 940, 994, 1058

NSTR defined in line 682; used 1 times

- in line 746

OSTR defined in line 678; used 16 times

- in line 707-712(6), 720-727(6), 738-739(2), 747, 933

SITECMD defined in line 681; used 1 times

- in line 724

STR1 defined in line 676; used 17 times

- in line 693-695(2), 704-706(3), 713-719(5), 729-737(5), 974-977(2)

STR2 defined in line 677; used 1 times

- in line 933

ZSTR1 defined in line 679; used 1 times

- in line 694

ZSTR2 defined in line 680; never used

Last modified: 1990-02-21 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 3365 |