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

unix.superglobalmegacorp.com

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