Annotation of 43BSDReno/pgrm/yacc/test/ftp.y, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.