[BACK]Return to ftpcmd.y CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / libexec / ftpd

Annotation of src/libexec/ftpd/ftpcmd.y, Revision 1.38.2.1

1.38.2.1! wrstuden    1: /*     $NetBSD: ftpcmd.y,v 1.43 1999/12/21 12:52:18 lukem Exp $        */
        !             2:
        !             3: /*-
        !             4:  * Copyright (c) 1997-1999 The NetBSD Foundation, Inc.
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * This code is derived from software contributed to The NetBSD Foundation
        !             8:  * by Luke Mewburn.
        !             9:  *
        !            10:  * Redistribution and use in source and binary forms, with or without
        !            11:  * modification, are permitted provided that the following conditions
        !            12:  * are met:
        !            13:  * 1. Redistributions of source code must retain the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer.
        !            15:  * 2. Redistributions in binary form must reproduce the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer in the
        !            17:  *    documentation and/or other materials provided with the distribution.
        !            18:  * 3. All advertising materials mentioning features or use of this software
        !            19:  *    must display the following acknowledgement:
        !            20:  *        This product includes software developed by the NetBSD
        !            21:  *        Foundation, Inc. and its contributors.
        !            22:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            23:  *    contributors may be used to endorse or promote products derived
        !            24:  *    from this software without specific prior written permission.
        !            25:  *
        !            26:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            27:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            28:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            29:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            30:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            31:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            32:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            33:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            34:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            35:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            36:  * POSSIBILITY OF SUCH DAMAGE.
        !            37:  */
1.5       cgd        38:
1.1       cgd        39: /*
1.4       deraadt    40:  * Copyright (c) 1985, 1988, 1993, 1994
                     41:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd        42:  *
                     43:  * Redistribution and use in source and binary forms, with or without
                     44:  * modification, are permitted provided that the following conditions
                     45:  * are met:
                     46:  * 1. Redistributions of source code must retain the above copyright
                     47:  *    notice, this list of conditions and the following disclaimer.
                     48:  * 2. Redistributions in binary form must reproduce the above copyright
                     49:  *    notice, this list of conditions and the following disclaimer in the
                     50:  *    documentation and/or other materials provided with the distribution.
                     51:  * 3. All advertising materials mentioning features or use of this software
                     52:  *    must display the following acknowledgement:
                     53:  *     This product includes software developed by the University of
                     54:  *     California, Berkeley and its contributors.
                     55:  * 4. Neither the name of the University nor the names of its contributors
                     56:  *    may be used to endorse or promote products derived from this software
                     57:  *    without specific prior written permission.
                     58:  *
                     59:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     60:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     61:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     62:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     63:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     64:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     65:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     66:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     67:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     68:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     69:  * SUCH DAMAGE.
                     70:  *
1.4       deraadt    71:  *     @(#)ftpcmd.y    8.3 (Berkeley) 4/6/94
1.1       cgd        72:  */
                     73:
                     74: /*
                     75:  * Grammar for FTP commands.
                     76:  * See RFC 959.
                     77:  */
                     78:
                     79: %{
1.13      christos   80: #include <sys/cdefs.h>
1.1       cgd        81:
                     82: #ifndef lint
1.5       cgd        83: #if 0
1.4       deraadt    84: static char sccsid[] = "@(#)ftpcmd.y   8.3 (Berkeley) 4/6/94";
1.5       cgd        85: #else
1.38.2.1! wrstuden   86: __RCSID("$NetBSD: ftpcmd.y,v 1.43 1999/12/21 12:52:18 lukem Exp $");
1.5       cgd        87: #endif
1.1       cgd        88: #endif /* not lint */
                     89:
                     90: #include <sys/param.h>
                     91: #include <sys/socket.h>
                     92: #include <sys/stat.h>
1.4       deraadt    93:
1.1       cgd        94: #include <netinet/in.h>
                     95: #include <arpa/ftp.h>
1.15      mrg        96: #include <arpa/inet.h>
1.4       deraadt    97:
                     98: #include <ctype.h>
                     99: #include <errno.h>
                    100: #include <glob.h>
                    101: #include <pwd.h>
                    102: #include <setjmp.h>
1.1       cgd       103: #include <signal.h>
1.4       deraadt   104: #include <stdio.h>
                    105: #include <stdlib.h>
                    106: #include <string.h>
1.1       cgd       107: #include <syslog.h>
                    108: #include <time.h>
1.18      lukem     109: #include <tzfile.h>
1.1       cgd       110: #include <unistd.h>
1.32      itojun    111: #include <netdb.h>
1.26      explorer  112:
                    113: #ifdef KERBEROS5
1.36      christos  114: #include <krb5/krb5.h>
1.26      explorer  115: #endif
1.4       deraadt   116:
                    117: #include "extern.h"
1.1       cgd       118:
                    119: off_t  restart_point;
                    120:
                    121: static int cmd_type;
                    122: static int cmd_form;
                    123: static int cmd_bytesz;
                    124: char   cbuf[512];
                    125: char   *fromname;
1.22      lukem     126: int    hasyyerrored;
1.1       cgd       127:
1.24      lukem     128: extern jmp_buf         errcatch;
                    129:
1.1       cgd       130: %}
                    131:
1.4       deraadt   132: %union {
                    133:        int     i;
                    134:        char   *s;
                    135: }
                    136:
1.1       cgd       137: %token
                    138:        A       B       C       E       F       I
                    139:        L       N       P       R       S       T
1.32      itojun    140:        ALL
1.1       cgd       141:
1.4       deraadt   142:        SP      CRLF    COMMA
1.1       cgd       143:
1.23      lukem     144:        USER    PASS    ACCT    CWD     CDUP    SMNT
                    145:        QUIT    REIN    PORT    PASV    TYPE    STRU
                    146:        MODE    RETR    STOR    STOU    APPE    ALLO
                    147:        REST    RNFR    RNTO    ABOR    DELE    RMD
                    148:        MKD     PWD     LIST    NLST    SITE    SYST
                    149:        STAT    HELP    NOOP
                    150:
1.25      lukem     151:        AUTH    ADAT    PROT    PBSZ    CCC     MIC
                    152:        CONF    ENC
                    153:
1.23      lukem     154:        FEAT    OPTS
1.21      lukem     155:
                    156:        SIZE    MDTM
1.1       cgd       157:
1.32      itojun    158:        LPRT    LPSV    EPRT    EPSV
                    159:
1.23      lukem     160:        MAIL    MLFL    MRCP    MRSQ    MSAM    MSND
                    161:        MSOM
                    162:
1.38.2.1! wrstuden  163:        CHMOD   IDLE    RATEGET RATEPUT UMASK
1.1       cgd       164:
                    165:        LEXERR
                    166:
1.4       deraadt   167: %token <s> STRING
1.32      itojun    168: %token <s> ALL
1.4       deraadt   169: %token <i> NUMBER
                    170:
1.38.2.1! wrstuden  171: %type  <i> check_login check_modify check_upload octal_number byte_size
1.25      lukem     172: %type  <i> struct_code mode_code type_code form_code decimal_integer
1.4       deraadt   173: %type  <s> pathstring pathname password username
1.25      lukem     174: %type  <s> mechanism_name base64data prot_code
1.4       deraadt   175:
1.1       cgd       176: %start cmd_list
                    177:
                    178: %%
                    179:
1.4       deraadt   180: cmd_list
                    181:        : /* empty */
1.23      lukem     182:
1.4       deraadt   183:        | cmd_list cmd
                    184:                {
1.22      lukem     185:                        fromname = NULL;
1.1       cgd       186:                        restart_point = (off_t) 0;
                    187:                }
1.23      lukem     188:
1.4       deraadt   189:        | cmd_list rcmd
1.23      lukem     190:
1.1       cgd       191:        ;
                    192:
1.4       deraadt   193: cmd
1.23      lukem     194:                                                /* RFC 959 */
1.4       deraadt   195:        : USER SP username CRLF
                    196:                {
                    197:                        user($3);
                    198:                        free($3);
                    199:                }
1.23      lukem     200:
1.4       deraadt   201:        | PASS SP password CRLF
                    202:                {
                    203:                        pass($3);
1.38.2.1! wrstuden  204:                        memset($3, 0, strlen($3));
1.4       deraadt   205:                        free($3);
1.1       cgd       206:                }
1.23      lukem     207:
                    208:        | CWD check_login CRLF
                    209:                {
                    210:                        if ($2)
                    211:                                cwd(pw->pw_dir);
                    212:                }
                    213:
                    214:        | CWD check_login SP pathname CRLF
                    215:                {
                    216:                        if ($2 && $4 != NULL)
                    217:                                cwd($4);
                    218:                        if ($4 != NULL)
                    219:                                free($4);
                    220:                }
                    221:
                    222:        | CDUP check_login CRLF
                    223:                {
                    224:                        if ($2)
                    225:                                cwd("..");
                    226:                }
                    227:
                    228:        | QUIT CRLF
                    229:                {
1.27      lukem     230:                        if (logged_in) {
1.28      lukem     231:                                lreply(221, "");
                    232:                                lreply(0,
1.27      lukem     233:            "Data traffic for this session was %qd byte%s in %qd file%s.",
1.30      ross      234:                                    (qdfmt_t)total_data, PLURAL(total_data),
                    235:                                    (qdfmt_t)total_files, PLURAL(total_files));
1.28      lukem     236:                                lreply(0,
1.27      lukem     237:            "Total traffic for this session was %qd byte%s in %qd transfer%s.",
1.30      ross      238:                                    (qdfmt_t)total_bytes, PLURAL(total_bytes),
                    239:                                    (qdfmt_t)total_xfers, PLURAL(total_xfers));
1.31      lukem     240:                        }
                    241:                        reply(221,
                    242:                            "Thank you for using the FTP service on %s.",
                    243:                            hostname);
                    244:                        if (logged_in) {
1.27      lukem     245:                                syslog(LOG_INFO,
                    246:                                    "Data traffic: %qd byte%s in %qd file%s",
1.30      ross      247:                                    (qdfmt_t)total_data, PLURAL(total_data),
                    248:                                    (qdfmt_t)total_files, PLURAL(total_files));
1.27      lukem     249:                                syslog(LOG_INFO,
                    250:                                  "Total traffic: %qd byte%s in %qd transfer%s",
1.30      ross      251:                                    (qdfmt_t)total_bytes, PLURAL(total_bytes),
                    252:                                    (qdfmt_t)total_xfers, PLURAL(total_xfers));
1.27      lukem     253:                        }
1.31      lukem     254:
1.23      lukem     255:                        dologout(0);
                    256:                }
                    257:
1.15      mrg       258:        | PORT check_login SP host_port CRLF
1.4       deraadt   259:                {
1.22      lukem     260:                        if ($2) {
                    261:                                        /* be paranoid, if told so */
1.16      mrg       262:                        if (curclass.checkportcmd &&
1.32      itojun    263:                            ((ntohs(data_dest.su_port) < IPPORT_RESERVED) ||
                    264:                            memcmp(&data_dest.su_sin.sin_addr,
                    265:                            &his_addr.su_sin.sin_addr,
                    266:                            sizeof(data_dest.su_sin.sin_addr)) != 0)) {
1.22      lukem     267:                                reply(500,
                    268:                                    "Illegal PORT command rejected");
1.32      itojun    269:                        } else if (epsvall) {
                    270:                                reply(501, "PORT disallowed after EPSV ALL");
1.22      lukem     271:                        } else {
                    272:                                usedefault = 0;
                    273:                                if (pdata >= 0) {
                    274:                                        (void) close(pdata);
                    275:                                        pdata = -1;
                    276:                                }
                    277:                                reply(200, "PORT command successful.");
1.15      mrg       278:                        }
1.32      itojun    279:
                    280:                        }
                    281:                }
                    282:
1.34      itojun    283:        | LPRT check_login SP host_long_port4 CRLF
1.32      itojun    284:                {
1.38.2.1! wrstuden  285:                        if ($2) {
        !           286:
1.35      itojun    287:                        /* reject invalid host_long_port4 */
                    288:                        if (data_dest.su_family != AF_INET) {
                    289:                                reply(500, "Illegal LPRT command rejected");
                    290:                                return (NULL);
                    291:                        }
1.32      itojun    292:                        /* be paranoid, if told so */
                    293:                        if (curclass.checkportcmd &&
1.34      itojun    294:                            ((ntohs(data_dest.su_port) < IPPORT_RESERVED) ||
                    295:                             memcmp(&data_dest.su_sin.sin_addr,
                    296:                                    &his_addr.su_sin.sin_addr,
                    297:                             sizeof(data_dest.su_sin.sin_addr)) != 0)) {
                    298:                                reply(500, "Illegal LPRT command rejected");
                    299:                                return (NULL);
                    300:                        }
                    301:                        if (epsvall)
                    302:                                reply(501, "LPRT disallowed after EPSV ALL");
                    303:                        else {
                    304:                                usedefault = 0;
                    305:                                if (pdata >= 0) {
                    306:                                        (void) close(pdata);
                    307:                                        pdata = -1;
                    308:                                }
                    309:                                reply(200, "LPRT command successful.");
                    310:                        }
1.38.2.1! wrstuden  311:
        !           312:                        }
1.34      itojun    313:                }
                    314:
                    315:        | LPRT check_login SP host_long_port6 CRLF
                    316:                {
1.38.2.1! wrstuden  317:                        if ($2) {
        !           318:
1.35      itojun    319:                        /* reject invalid host_long_port6 */
                    320:                        if (data_dest.su_family != AF_INET6) {
                    321:                                reply(500, "Illegal LPRT command rejected");
                    322:                                return (NULL);
                    323:                        }
1.34      itojun    324:                        /* be paranoid, if told so */
                    325:                        if (curclass.checkportcmd &&
                    326:                            ((ntohs(data_dest.su_port) < IPPORT_RESERVED) ||
                    327:                             memcmp(&data_dest.su_sin6.sin6_addr,
                    328:                                    &his_addr.su_sin6.sin6_addr,
                    329:                             sizeof(data_dest.su_sin6.sin6_addr)) != 0)) {
1.32      itojun    330:                                reply(500, "Illegal LPRT command rejected");
                    331:                                return (NULL);
                    332:                        }
                    333:                        if (epsvall)
                    334:                                reply(501, "LPRT disallowed after EPSV ALL");
                    335:                        else {
                    336:                                usedefault = 0;
                    337:                                if (pdata >= 0) {
                    338:                                        (void) close(pdata);
                    339:                                        pdata = -1;
                    340:                                }
                    341:                                reply(200, "LPRT command successful.");
1.1       cgd       342:                        }
1.38.2.1! wrstuden  343:
        !           344:                        }
1.1       cgd       345:                }
1.23      lukem     346:
1.32      itojun    347:        | EPRT check_login SP STRING CRLF
                    348:                {
                    349:                        char *tmp = NULL;
                    350:                        char *result[3];
                    351:                        char *p, *q;
                    352:                        char delim;
                    353:                        struct addrinfo hints;
                    354:                        struct addrinfo *res;
                    355:                        int i;
                    356:
1.38.2.1! wrstuden  357:                        if ($2) {
        !           358:
1.32      itojun    359:                        if (epsvall) {
                    360:                                reply(501, "EPRT disallowed after EPSV ALL");
                    361:                                goto eprt_done;
                    362:                        }
                    363:                        usedefault = 0;
                    364:                        if (pdata >= 0) {
                    365:                                (void) close(pdata);
                    366:                                pdata = -1;
                    367:                        }
                    368:
1.38.2.1! wrstuden  369:                        tmp = xstrdup($4);
1.32      itojun    370:                        p = tmp;
                    371:                        delim = p[0];
                    372:                        p++;
                    373:                        memset(result, 0, sizeof(result));
                    374:                        for (i = 0; i < 3; i++) {
                    375:                                q = strchr(p, delim);
                    376:                                if (!q || *q != delim) {
                    377:                parsefail:
1.38.2.1! wrstuden  378:                                        reply(500,
        !           379:                                            "Invalid argument, rejected.");
1.32      itojun    380:                                        usedefault = 1;
                    381:                                        goto eprt_done;
                    382:                                }
                    383:                                *q++ = '\0';
                    384:                                result[i] = p;
                    385:                                p = q;
                    386:                        }
                    387:
                    388:                        /* some more sanity check */
                    389:                        p = result[0];
                    390:                        while (*p) {
                    391:                                if (!isdigit(*p))
                    392:                                        goto parsefail;
                    393:                                p++;
                    394:                        }
                    395:                        p = result[2];
                    396:                        while (*p) {
                    397:                                if (!isdigit(*p))
                    398:                                        goto parsefail;
                    399:                                p++;
                    400:                        }
                    401:
                    402:                        memset(&hints, 0, sizeof(hints));
                    403:                        if (atoi(result[0]) == 1)
                    404:                                hints.ai_family = PF_INET;
                    405:                        if (atoi(result[0]) == 2)
                    406:                                hints.ai_family = PF_INET6;
                    407:                        else
                    408:                                hints.ai_family = PF_UNSPEC;    /*XXX*/
                    409:                        hints.ai_socktype = SOCK_STREAM;
                    410:                        if (getaddrinfo(result[1], result[2], &hints, &res))
                    411:                                goto parsefail;
                    412:                        memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
1.37      itojun    413:                        if (his_addr.su_family == AF_INET6
                    414:                         && data_dest.su_family == AF_INET6) {
                    415:                                /* XXX more sanity checks! */
                    416:                                data_dest.su_sin6.sin6_scope_id =
                    417:                                        his_addr.su_sin6.sin6_scope_id;
                    418:                        }
1.32      itojun    419:                        /* be paranoid, if told so */
                    420:                        if (curclass.checkportcmd) {
                    421:                                int fail;
                    422:                                fail = 0;
                    423:                                if (ntohs(data_dest.su_port) < IPPORT_RESERVED)
                    424:                                        fail++;
                    425:                                if (data_dest.su_family != his_addr.su_family)
                    426:                                        fail++;
                    427:                                if (data_dest.su_len != his_addr.su_len)
                    428:                                        fail++;
                    429:                                switch (data_dest.su_family) {
                    430:                                case AF_INET:
1.38.2.1! wrstuden  431:                                        fail += memcmp(
        !           432:                                            &data_dest.su_sin.sin_addr,
1.32      itojun    433:                                            &his_addr.su_sin.sin_addr,
                    434:                                            sizeof(data_dest.su_sin.sin_addr));
                    435:                                        break;
                    436:                                case AF_INET6:
1.38.2.1! wrstuden  437:                                        fail += memcmp(
        !           438:                                            &data_dest.su_sin6.sin6_addr,
1.32      itojun    439:                                            &his_addr.su_sin6.sin6_addr,
                    440:                                            sizeof(data_dest.su_sin6.sin6_addr));
                    441:                                        break;
                    442:                                default:
                    443:                                        fail++;
                    444:                                }
                    445:                                if (fail) {
                    446:                                        reply(500,
                    447:                                            "Illegal EPRT command rejected");
                    448:                                        return (NULL);
                    449:                                }
                    450:                        }
1.33      itojun    451:                        if (pdata >= 0) {
                    452:                                (void) close(pdata);
                    453:                                pdata = -1;
                    454:                        }
1.32      itojun    455:                        reply(200, "EPRT command successful.");
                    456:                eprt_done:;
1.38.2.1! wrstuden  457:                        if (tmp != NULL)
        !           458:                                free(tmp);
        !           459:
        !           460:                        }
        !           461:                        free($4);
1.32      itojun    462:                }
                    463:
1.20      tv        464:        | PASV check_login CRLF
1.4       deraadt   465:                {
1.38.2.1! wrstuden  466:                        if ($2) {
        !           467:                                if (curclass.passive)
        !           468:                                        passive();
        !           469:                                else
        !           470:                                        reply(500, "PASV mode not available.");
1.20      tv        471:                        }
1.1       cgd       472:                }
1.23      lukem     473:
1.38.2.1! wrstuden  474:        | LPSV check_login CRLF
1.32      itojun    475:                {
1.38.2.1! wrstuden  476:                        if ($2) {
        !           477:                                if (epsvall)
        !           478:                                        reply(501,
        !           479:                                            "LPSV disallowed after EPSV ALL");
        !           480:                                else
        !           481:                                        long_passive("LPSV", PF_UNSPEC);
        !           482:                        }
1.32      itojun    483:                }
                    484:
1.38.2.1! wrstuden  485:        | EPSV check_login SP NUMBER CRLF
1.32      itojun    486:                {
1.38.2.1! wrstuden  487:                        if ($2) {
        !           488:                                int pf;
        !           489:
        !           490:                                switch ($4) {
        !           491:                                case 1:
        !           492:                                        pf = PF_INET;
        !           493:                                        break;
        !           494:                                case 2:
        !           495:                                        pf = PF_INET6;
        !           496:                                        break;
        !           497:                                default:
        !           498:                                        pf = -1;        /*junk*/
        !           499:                                        break;
        !           500:                                }
        !           501:                                long_passive("EPSV", pf);
1.32      itojun    502:                        }
                    503:                }
                    504:
1.38.2.1! wrstuden  505:        | EPSV check_login SP ALL CRLF
1.32      itojun    506:                {
1.38.2.1! wrstuden  507:                        if ($2) {
1.32      itojun    508:                                reply(200, "EPSV ALL command successful.");
                    509:                                epsvall++;
                    510:                        }
                    511:                }
                    512:
1.38.2.1! wrstuden  513:        | EPSV check_login CRLF
1.32      itojun    514:                {
1.38.2.1! wrstuden  515:                        if ($2)
        !           516:                                long_passive("EPSV", PF_UNSPEC);
1.32      itojun    517:                }
                    518:
1.38.2.1! wrstuden  519:        | TYPE check_login SP type_code CRLF
1.4       deraadt   520:                {
1.38.2.1! wrstuden  521:                        if ($2) {
        !           522:
1.1       cgd       523:                        switch (cmd_type) {
                    524:
                    525:                        case TYPE_A:
                    526:                                if (cmd_form == FORM_N) {
                    527:                                        reply(200, "Type set to A.");
                    528:                                        type = cmd_type;
                    529:                                        form = cmd_form;
                    530:                                } else
                    531:                                        reply(504, "Form must be N.");
                    532:                                break;
                    533:
                    534:                        case TYPE_E:
                    535:                                reply(504, "Type E not implemented.");
                    536:                                break;
                    537:
                    538:                        case TYPE_I:
                    539:                                reply(200, "Type set to I.");
                    540:                                type = cmd_type;
                    541:                                break;
                    542:
                    543:                        case TYPE_L:
                    544: #if NBBY == 8
                    545:                                if (cmd_bytesz == 8) {
                    546:                                        reply(200,
                    547:                                            "Type set to L (byte size 8).");
                    548:                                        type = cmd_type;
                    549:                                } else
                    550:                                        reply(504, "Byte size must be 8.");
                    551: #else /* NBBY == 8 */
                    552:                                UNIMPLEMENTED for NBBY != 8
                    553: #endif /* NBBY == 8 */
                    554:                        }
1.38.2.1! wrstuden  555:
        !           556:                        }
1.1       cgd       557:                }
1.23      lukem     558:
1.38.2.1! wrstuden  559:        | STRU check_login SP struct_code CRLF
1.4       deraadt   560:                {
1.38.2.1! wrstuden  561:                        if ($2) {
        !           562:                                switch ($4) {
1.1       cgd       563:
1.38.2.1! wrstuden  564:                                case STRU_F:
        !           565:                                        reply(200, "STRU F ok.");
        !           566:                                        break;
1.1       cgd       567:
1.38.2.1! wrstuden  568:                                default:
        !           569:                                        reply(504, "Unimplemented STRU type.");
        !           570:                                }
1.1       cgd       571:                        }
                    572:                }
1.23      lukem     573:
1.38.2.1! wrstuden  574:        | MODE check_login SP mode_code CRLF
1.4       deraadt   575:                {
1.38.2.1! wrstuden  576:                        if ($2) {
        !           577:                                switch ($4) {
1.1       cgd       578:
1.38.2.1! wrstuden  579:                                case MODE_S:
        !           580:                                        reply(200, "MODE S ok.");
        !           581:                                        break;
1.1       cgd       582:
1.38.2.1! wrstuden  583:                                default:
        !           584:                                        reply(502, "Unimplemented MODE type.");
        !           585:                                }
1.1       cgd       586:                        }
                    587:                }
1.23      lukem     588:
1.4       deraadt   589:        | RETR check_login SP pathname CRLF
                    590:                {
1.1       cgd       591:                        if ($2 && $4 != NULL)
1.22      lukem     592:                                retrieve(NULL, $4);
1.1       cgd       593:                        if ($4 != NULL)
1.4       deraadt   594:                                free($4);
1.1       cgd       595:                }
1.23      lukem     596:
1.38.2.1! wrstuden  597:        | STOR check_upload SP pathname CRLF
1.4       deraadt   598:                {
1.1       cgd       599:                        if ($2 && $4 != NULL)
1.4       deraadt   600:                                store($4, "w", 0);
1.1       cgd       601:                        if ($4 != NULL)
1.4       deraadt   602:                                free($4);
1.1       cgd       603:                }
1.23      lukem     604:
1.38.2.1! wrstuden  605:        | STOU check_upload SP pathname CRLF
1.4       deraadt   606:                {
1.1       cgd       607:                        if ($2 && $4 != NULL)
1.23      lukem     608:                                store($4, "w", 1);
1.1       cgd       609:                        if ($4 != NULL)
1.4       deraadt   610:                                free($4);
1.1       cgd       611:                }
1.23      lukem     612:
1.38.2.1! wrstuden  613:        | APPE check_upload SP pathname CRLF
1.4       deraadt   614:                {
                    615:                        if ($2 && $4 != NULL)
1.23      lukem     616:                                store($4, "a", 0);
1.1       cgd       617:                        if ($4 != NULL)
1.4       deraadt   618:                                free($4);
1.1       cgd       619:                }
1.23      lukem     620:
1.38.2.1! wrstuden  621:        | ALLO check_login SP NUMBER CRLF
1.4       deraadt   622:                {
1.38.2.1! wrstuden  623:                        if ($2)
        !           624:                                reply(202, "ALLO command ignored.");
1.1       cgd       625:                }
1.23      lukem     626:
1.38.2.1! wrstuden  627:        | ALLO check_login SP NUMBER SP R SP NUMBER CRLF
1.4       deraadt   628:                {
1.38.2.1! wrstuden  629:                        if ($2)
        !           630:                                reply(202, "ALLO command ignored.");
1.1       cgd       631:                }
1.23      lukem     632:
1.38.2.1! wrstuden  633:        | RNTO check_login SP pathname CRLF
1.4       deraadt   634:                {
1.38.2.1! wrstuden  635:                        if ($2) {
        !           636:                                if (fromname) {
        !           637:                                        renamecmd(fromname, $4);
        !           638:                                        free(fromname);
        !           639:                                        fromname = NULL;
        !           640:                                } else {
        !           641:                                        reply(503, "Bad sequence of commands.");
        !           642:                                }
1.1       cgd       643:                        }
1.38.2.1! wrstuden  644:                        free($4);
1.1       cgd       645:                }
1.23      lukem     646:
1.38.2.1! wrstuden  647:        | ABOR check_login CRLF
1.4       deraadt   648:                {
1.38.2.1! wrstuden  649:                        if ($2)
        !           650:                                reply(225, "ABOR command successful.");
1.1       cgd       651:                }
1.23      lukem     652:
                    653:        | DELE check_modify SP pathname CRLF
1.4       deraadt   654:                {
1.23      lukem     655:                        if ($2 && $4 != NULL)
                    656:                                delete($4);
                    657:                        if ($4 != NULL)
                    658:                                free($4);
1.1       cgd       659:                }
1.23      lukem     660:
                    661:        | RMD check_modify SP pathname CRLF
1.4       deraadt   662:                {
1.1       cgd       663:                        if ($2 && $4 != NULL)
1.23      lukem     664:                                removedir($4);
1.1       cgd       665:                        if ($4 != NULL)
1.4       deraadt   666:                                free($4);
1.1       cgd       667:                }
                    668:
1.12      lukem     669:        | MKD check_modify SP pathname CRLF
1.4       deraadt   670:                {
1.1       cgd       671:                        if ($2 && $4 != NULL)
1.4       deraadt   672:                                makedir($4);
1.1       cgd       673:                        if ($4 != NULL)
1.4       deraadt   674:                                free($4);
1.1       cgd       675:                }
1.23      lukem     676:
                    677:        | PWD check_login CRLF
                    678:                {
                    679:                        if ($2)
                    680:                                pwd();
                    681:                }
                    682:
                    683:        | LIST check_login CRLF
                    684:                {
1.38.2.1! wrstuden  685:                        char *argv[] = { INTERNAL_LS, "-lgA", NULL };
        !           686:
1.23      lukem     687:                        if ($2)
1.38.2.1! wrstuden  688:                                retrieve(argv, "");
1.23      lukem     689:                }
                    690:
                    691:        | LIST check_login SP pathname CRLF
1.4       deraadt   692:                {
1.38.2.1! wrstuden  693:                        char *argv[] = { INTERNAL_LS, "-lgA", NULL, NULL };
        !           694:
        !           695:                        if ($2 && $4 != NULL) {
        !           696:                                argv[2] = $4;
        !           697:                                retrieve(argv, $4);
        !           698:                        }
1.1       cgd       699:                        if ($4 != NULL)
1.4       deraadt   700:                                free($4);
1.1       cgd       701:                }
1.23      lukem     702:
                    703:        | NLST check_login CRLF
1.4       deraadt   704:                {
1.1       cgd       705:                        if ($2)
1.23      lukem     706:                                send_file_list(".");
1.1       cgd       707:                }
1.23      lukem     708:
                    709:        | NLST check_login SP STRING CRLF
1.4       deraadt   710:                {
1.38.2.1! wrstuden  711:                        if ($2)
1.23      lukem     712:                                send_file_list($4);
1.38.2.1! wrstuden  713:                        free($4);
1.1       cgd       714:                }
1.23      lukem     715:
1.4       deraadt   716:        | SITE SP HELP CRLF
                    717:                {
1.22      lukem     718:                        help(sitetab, NULL);
1.1       cgd       719:                }
1.23      lukem     720:
1.38.2.1! wrstuden  721:        | SITE SP CHMOD check_modify SP octal_number SP pathname CRLF
        !           722:                {
        !           723:                        if ($4 && ($8 != NULL)) {
        !           724:                                if ($6 > 0777)
        !           725:                                        reply(501,
        !           726:                                "CHMOD: Mode value must be between 0 and 0777");
        !           727:                                else if (chmod($8, $6) < 0)
        !           728:                                        perror_reply(550, $8);
        !           729:                                else
        !           730:                                        reply(200, "CHMOD command successful.");
        !           731:                        }
        !           732:                        if ($8 != NULL)
        !           733:                                free($8);
        !           734:                }
        !           735:
1.4       deraadt   736:        | SITE SP HELP SP STRING CRLF
                    737:                {
                    738:                        help(sitetab, $5);
1.38.2.1! wrstuden  739:                        free($5);
        !           740:                }
        !           741:
        !           742:        | SITE SP IDLE check_login CRLF
        !           743:                {
        !           744:                        if ($4) {
        !           745:                                reply(200,
        !           746:                            "Current IDLE time limit is %d seconds; max %d",
        !           747:                                    curclass.timeout, curclass.maxtimeout);
        !           748:                        }
        !           749:                }
        !           750:
        !           751:        | SITE SP IDLE check_login SP NUMBER CRLF
        !           752:                {
        !           753:                        if ($4) {
        !           754:                                if ($6 < 30 || $6 > curclass.maxtimeout) {
        !           755:                                        reply(501,
        !           756:                            "IDLE time limit must be between 30 and %d seconds",
        !           757:                                            curclass.maxtimeout);
        !           758:                                } else {
        !           759:                                        curclass.timeout = $6;
        !           760:                                        (void) alarm(curclass.timeout);
        !           761:                                        reply(200,
        !           762:                                            "IDLE time limit set to %d seconds",
        !           763:                                            curclass.timeout);
        !           764:                                }
        !           765:                        }
        !           766:                }
        !           767:
        !           768:        | SITE SP RATEGET check_login CRLF
        !           769:                {
        !           770:                        if ($4) {
        !           771:                                reply(200, "Current RATEGET is %d bytes/sec",
        !           772:                                    curclass.rateget);
        !           773:                        }
        !           774:                }
        !           775:
        !           776:        | SITE SP RATEGET check_login SP STRING CRLF
        !           777:                {
        !           778:                        char *p = $6;
        !           779:                        int rate;
        !           780:
        !           781:                        if ($4) {
        !           782:                                rate = strsuftoi(p);
        !           783:                                if (rate == -1)
        !           784:                                        reply(501, "Invalid RATEGET %s", p);
        !           785:                                else if (curclass.maxrateget &&
        !           786:                                    rate > curclass.maxrateget)
        !           787:                                        reply(501,
        !           788:                                "RATEGET %d is larger than maximum RATEGET %d",
        !           789:                                            rate, curclass.maxrateget);
        !           790:                                else {
        !           791:                                        curclass.rateget = rate;
        !           792:                                        reply(200,
        !           793:                                            "RATEGET set to %d bytes/sec",
        !           794:                                            curclass.rateget);
        !           795:                                }
        !           796:                        }
        !           797:                        free($6);
        !           798:                }
        !           799:
        !           800:        | SITE SP RATEPUT check_login CRLF
        !           801:                {
        !           802:                        if ($4) {
        !           803:                                reply(200, "Current RATEPUT is %d bytes/sec",
        !           804:                                    curclass.rateput);
        !           805:                        }
        !           806:                }
        !           807:
        !           808:        | SITE SP RATEPUT check_login SP STRING CRLF
        !           809:                {
        !           810:                        char *p = $6;
        !           811:                        int rate;
        !           812:
        !           813:                        if ($4) {
        !           814:                                rate = strsuftoi(p);
        !           815:                                if (rate == -1)
        !           816:                                        reply(501, "Invalid RATEPUT %s", p);
        !           817:                                else if (curclass.maxrateput &&
        !           818:                                    rate > curclass.maxrateput)
        !           819:                                        reply(501,
        !           820:                                "RATEPUT %d is larger than maximum RATEPUT %d",
        !           821:                                            rate, curclass.maxrateput);
        !           822:                                else {
        !           823:                                        curclass.rateput = rate;
        !           824:                                        reply(200,
        !           825:                                            "RATEPUT set to %d bytes/sec",
        !           826:                                            curclass.rateput);
        !           827:                                }
        !           828:                        }
        !           829:                        free($6);
1.1       cgd       830:                }
1.23      lukem     831:
1.4       deraadt   832:        | SITE SP UMASK check_login CRLF
                    833:                {
1.1       cgd       834:                        int oldmask;
                    835:
                    836:                        if ($4) {
                    837:                                oldmask = umask(0);
                    838:                                (void) umask(oldmask);
                    839:                                reply(200, "Current UMASK is %03o", oldmask);
                    840:                        }
                    841:                }
1.23      lukem     842:
1.12      lukem     843:        | SITE SP UMASK check_modify SP octal_number CRLF
1.4       deraadt   844:                {
1.1       cgd       845:                        int oldmask;
                    846:
                    847:                        if ($4) {
                    848:                                if (($6 == -1) || ($6 > 0777)) {
                    849:                                        reply(501, "Bad UMASK value");
                    850:                                } else {
                    851:                                        oldmask = umask($6);
                    852:                                        reply(200,
                    853:                                            "UMASK set to %03o (was %03o)",
                    854:                                            $6, oldmask);
                    855:                                }
                    856:                        }
                    857:                }
1.23      lukem     858:
                    859:        | SYST CRLF
                    860:                {
                    861:                        reply(215, "UNIX Type: L%d %s", NBBY, version);
                    862:                }
                    863:
                    864:        | STAT check_login SP pathname CRLF
1.4       deraadt   865:                {
1.1       cgd       866:                        if ($2 && $4 != NULL)
1.23      lukem     867:                                statfilecmd($4);
1.1       cgd       868:                        if ($4 != NULL)
1.4       deraadt   869:                                free($4);
1.1       cgd       870:                }
1.23      lukem     871:
                    872:        | STAT CRLF
                    873:                {
                    874:                        statcmd();
                    875:                }
                    876:
                    877:        | HELP CRLF
                    878:                {
                    879:                        help(cmdtab, NULL);
                    880:                }
                    881:
                    882:        | HELP SP STRING CRLF
                    883:                {
                    884:                        char *cp = $3;
                    885:
                    886:                        if (strncasecmp(cp, "SITE", 4) == 0) {
                    887:                                cp = $3 + 4;
                    888:                                if (*cp == ' ')
                    889:                                        cp++;
                    890:                                if (*cp)
                    891:                                        help(sitetab, cp);
                    892:                                else
                    893:                                        help(sitetab, NULL);
                    894:                        } else
                    895:                                help(cmdtab, $3);
1.38.2.1! wrstuden  896:                        free($3);
1.23      lukem     897:                }
                    898:
                    899:        | NOOP CRLF
                    900:                {
                    901:                        reply(200, "NOOP command successful.");
                    902:                }
                    903:
1.25      lukem     904:                                                /* RFC 2228 */
                    905:        | AUTH SP mechanism_name CRLF
                    906:                {
                    907:                        reply(502, "RFC 2228 authentication not implemented.");
1.38.2.1! wrstuden  908:                        free($3);
1.25      lukem     909:                }
                    910:
                    911:        | ADAT SP base64data CRLF
                    912:                {
                    913:                        reply(503,
                    914:                            "Please set authentication state with AUTH.");
1.38.2.1! wrstuden  915:                        free($3);
1.25      lukem     916:                }
                    917:
                    918:        | PROT SP prot_code CRLF
                    919:                {
                    920:                        reply(503,
                    921:                            "Please set protection buffer size with PBSZ.");
1.38.2.1! wrstuden  922:                        free($3);
1.25      lukem     923:                }
                    924:
                    925:        | PBSZ SP decimal_integer CRLF
                    926:                {
                    927:                        reply(503,
                    928:                            "Please set authentication state with AUTH.");
                    929:                }
                    930:
                    931:        | CCC CRLF
                    932:                {
                    933:                        reply(533, "No protection enabled.");
                    934:                }
                    935:
                    936:        | MIC SP base64data CRLF
                    937:                {
                    938:                        reply(502, "RFC 2228 authentication not implemented.");
1.38.2.1! wrstuden  939:                        free($3);
1.25      lukem     940:                }
                    941:
                    942:        | CONF SP base64data CRLF
                    943:                {
                    944:                        reply(502, "RFC 2228 authentication not implemented.");
1.38.2.1! wrstuden  945:                        free($3);
1.25      lukem     946:                }
                    947:
                    948:        | ENC SP base64data CRLF
                    949:                {
                    950:                        reply(502, "RFC 2228 authentication not implemented.");
1.38.2.1! wrstuden  951:                        free($3);
1.25      lukem     952:                }
                    953:
1.23      lukem     954:                                                /* RFC 2389 */
                    955:        | FEAT CRLF
                    956:                {
                    957:                        lreply(211, "Features supported");
1.27      lukem     958:                        lreply(-1,  " MDTM");
                    959:                        lreply(-1,  " REST STREAM");
                    960:                        lreply(-1,  " SIZE");
                    961:                        reply(211,  "End");
1.23      lukem     962:                }
                    963:
                    964:        | OPTS SP STRING CRLF
1.4       deraadt   965:                {
1.23      lukem     966:
                    967:                        opts($3);
1.38.2.1! wrstuden  968:                        free($3);
1.1       cgd       969:                }
                    970:
1.23      lukem     971:
                    972:                                                /* BSD extensions */
                    973:
1.1       cgd       974:                /*
1.21      lukem     975:                 * SIZE is not in RFC 959, but Postel has blessed it and
1.1       cgd       976:                 * it will be in the updated RFC.
                    977:                 *
                    978:                 * Return size of file in a format suitable for
                    979:                 * using with RESTART (we just count bytes).
                    980:                 */
1.4       deraadt   981:        | SIZE check_login SP pathname CRLF
                    982:                {
1.1       cgd       983:                        if ($2 && $4 != NULL)
1.4       deraadt   984:                                sizecmd($4);
1.1       cgd       985:                        if ($4 != NULL)
1.4       deraadt   986:                                free($4);
1.1       cgd       987:                }
                    988:
                    989:                /*
1.21      lukem     990:                 * MDTM is not in RFC 959, but Postel has blessed it and
1.1       cgd       991:                 * it will be in the updated RFC.
                    992:                 *
                    993:                 * Return modification time of file as an ISO 3307
                    994:                 * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx
                    995:                 * where xxx is the fractional second (of any precision,
                    996:                 * not necessarily 3 digits)
                    997:                 */
1.4       deraadt   998:        | MDTM check_login SP pathname CRLF
                    999:                {
1.1       cgd      1000:                        if ($2 && $4 != NULL) {
                   1001:                                struct stat stbuf;
1.4       deraadt  1002:                                if (stat($4, &stbuf) < 0)
1.22      lukem    1003:                                        perror_reply(550, $4);
1.4       deraadt  1004:                                else if (!S_ISREG(stbuf.st_mode)) {
                   1005:                                        reply(550, "%s: not a plain file.", $4);
1.1       cgd      1006:                                } else {
1.4       deraadt  1007:                                        struct tm *t;
1.1       cgd      1008:                                        t = gmtime(&stbuf.st_mtime);
                   1009:                                        reply(213,
1.7       jtc      1010:                                            "%04d%02d%02d%02d%02d%02d",
1.18      lukem    1011:                                            TM_YEAR_BASE + t->tm_year,
1.7       jtc      1012:                                            t->tm_mon+1, t->tm_mday,
1.1       cgd      1013:                                            t->tm_hour, t->tm_min, t->tm_sec);
                   1014:                                }
                   1015:                        }
                   1016:                        if ($4 != NULL)
1.4       deraadt  1017:                                free($4);
1.1       cgd      1018:                }
1.23      lukem    1019:
1.4       deraadt  1020:        | error CRLF
                   1021:                {
1.1       cgd      1022:                        yyerrok;
                   1023:                }
                   1024:        ;
1.21      lukem    1025:
1.4       deraadt  1026: rcmd
1.38.2.1! wrstuden 1027:        : REST check_login SP byte_size CRLF
1.23      lukem    1028:                {
1.38.2.1! wrstuden 1029:                        if ($2) {
        !          1030:                                fromname = NULL;
        !          1031:                                restart_point = $4; /* XXX $3 is only "int" */
        !          1032:                                reply(350, "Restarting at %qd. %s",
        !          1033:                                    (qdfmt_t)restart_point,
1.23      lukem    1034:                            "Send STORE or RETRIEVE to initiate transfer.");
1.38.2.1! wrstuden 1035:                        }
1.23      lukem    1036:                }
1.38.2.1! wrstuden 1037:
1.23      lukem    1038:        | RNFR check_modify SP pathname CRLF
1.4       deraadt  1039:                {
1.1       cgd      1040:                        restart_point = (off_t) 0;
                   1041:                        if ($2 && $4) {
1.4       deraadt  1042:                                fromname = renamefrom($4);
1.1       cgd      1043:                        }
1.38.2.1! wrstuden 1044:                        if ($4)
        !          1045:                                free($4);
1.1       cgd      1046:                }
                   1047:        ;
1.4       deraadt  1048:
                   1049: username
                   1050:        : STRING
1.1       cgd      1051:        ;
                   1052:
1.4       deraadt  1053: password
                   1054:        : /* empty */
                   1055:                {
                   1056:                        $$ = (char *)calloc(1, sizeof(char));
1.1       cgd      1057:                }
1.23      lukem    1058:
1.4       deraadt  1059:        | STRING
1.1       cgd      1060:        ;
                   1061:
1.4       deraadt  1062: byte_size
                   1063:        : NUMBER
1.1       cgd      1064:        ;
                   1065:
1.4       deraadt  1066: host_port
                   1067:        : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
1.1       cgd      1068:                NUMBER COMMA NUMBER
1.4       deraadt  1069:                {
                   1070:                        char *a, *p;
1.1       cgd      1071:
1.32      itojun   1072:                        data_dest.su_len = sizeof(struct sockaddr_in);
                   1073:                        data_dest.su_family = AF_INET;
                   1074:                        p = (char *)&data_dest.su_sin.sin_port;
1.6       mycroft  1075:                        p[0] = $9; p[1] = $11;
1.32      itojun   1076:                        a = (char *)&data_dest.su_sin.sin_addr;
1.1       cgd      1077:                        a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;
                   1078:                }
                   1079:        ;
                   1080:
1.34      itojun   1081: host_long_port4
                   1082:        : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
                   1083:                NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
                   1084:                NUMBER
                   1085:                {
                   1086:                        char *a, *p;
                   1087:
                   1088:                        data_dest.su_sin.sin_len =
                   1089:                                sizeof(struct sockaddr_in);
                   1090:                        data_dest.su_family = AF_INET;
                   1091:                        p = (char *)&data_dest.su_port;
                   1092:                        p[0] = $15; p[1] = $17;
                   1093:                        a = (char *)&data_dest.su_sin.sin_addr;
                   1094:                        a[0] =  $5;  a[1] =  $7;  a[2] =  $9;  a[3] = $11;
1.35      itojun   1095:
                   1096:                        /* reject invalid LPRT command */
                   1097:                        if ($1 != 4 || $3 != 4 || $13 != 2)
                   1098:                                memset(&data_dest, 0, sizeof(data_dest));
1.34      itojun   1099:                }
                   1100:        ;
                   1101:
                   1102: host_long_port6
1.32      itojun   1103:        : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
                   1104:                NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
                   1105:                NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
                   1106:                NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
                   1107:                NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
                   1108:                NUMBER
                   1109:                {
                   1110:                        char *a, *p;
                   1111:
                   1112:                        data_dest.su_sin6.sin6_len =
                   1113:                                sizeof(struct sockaddr_in6);
                   1114:                        data_dest.su_family = AF_INET6;
                   1115:                        p = (char *)&data_dest.su_port;
                   1116:                        p[0] = $39; p[1] = $41;
                   1117:                        a = (char *)&data_dest.su_sin6.sin6_addr;
                   1118:                         a[0] =  $5;  a[1] =  $7;  a[2] =  $9;  a[3] = $11;
                   1119:                         a[4] = $13;  a[5] = $15;  a[6] = $17;  a[7] = $19;
                   1120:                         a[8] = $21;  a[9] = $23; a[10] = $25; a[11] = $27;
                   1121:                        a[12] = $29; a[13] = $31; a[14] = $33; a[15] = $35;
1.37      itojun   1122:                        if (his_addr.su_family == AF_INET6) {
                   1123:                                /* XXX more sanity checks! */
                   1124:                                data_dest.su_sin6.sin6_scope_id =
                   1125:                                        his_addr.su_sin6.sin6_scope_id;
                   1126:                        }
1.35      itojun   1127:
                   1128:                        /* reject invalid LPRT command */
                   1129:                        if ($1 != 6 || $3 != 16 || $37 != 2)
                   1130:                                memset(&data_dest, 0, sizeof(data_dest));
1.32      itojun   1131:                }
                   1132:        ;
                   1133:
1.4       deraadt  1134: form_code
                   1135:        : N
                   1136:                {
                   1137:                        $$ = FORM_N;
                   1138:                }
1.23      lukem    1139:
1.4       deraadt  1140:        | T
                   1141:                {
                   1142:                        $$ = FORM_T;
                   1143:                }
1.23      lukem    1144:
1.4       deraadt  1145:        | C
                   1146:                {
                   1147:                        $$ = FORM_C;
                   1148:                }
1.1       cgd      1149:        ;
                   1150:
1.4       deraadt  1151: type_code
                   1152:        : A
                   1153:                {
                   1154:                        cmd_type = TYPE_A;
                   1155:                        cmd_form = FORM_N;
                   1156:                }
1.23      lukem    1157:
1.4       deraadt  1158:        | A SP form_code
                   1159:                {
                   1160:                        cmd_type = TYPE_A;
                   1161:                        cmd_form = $3;
                   1162:                }
1.23      lukem    1163:
1.4       deraadt  1164:        | E
                   1165:                {
                   1166:                        cmd_type = TYPE_E;
                   1167:                        cmd_form = FORM_N;
                   1168:                }
1.23      lukem    1169:
1.4       deraadt  1170:        | E SP form_code
                   1171:                {
                   1172:                        cmd_type = TYPE_E;
                   1173:                        cmd_form = $3;
                   1174:                }
1.23      lukem    1175:
1.4       deraadt  1176:        | I
                   1177:                {
                   1178:                        cmd_type = TYPE_I;
                   1179:                }
1.23      lukem    1180:
1.4       deraadt  1181:        | L
                   1182:                {
                   1183:                        cmd_type = TYPE_L;
                   1184:                        cmd_bytesz = NBBY;
                   1185:                }
1.23      lukem    1186:
1.4       deraadt  1187:        | L SP byte_size
                   1188:                {
                   1189:                        cmd_type = TYPE_L;
                   1190:                        cmd_bytesz = $3;
                   1191:                }
1.23      lukem    1192:
1.4       deraadt  1193:                /* this is for a bug in the BBN ftp */
                   1194:        | L byte_size
                   1195:                {
                   1196:                        cmd_type = TYPE_L;
                   1197:                        cmd_bytesz = $2;
                   1198:                }
1.1       cgd      1199:        ;
                   1200:
1.4       deraadt  1201: struct_code
                   1202:        : F
                   1203:                {
                   1204:                        $$ = STRU_F;
                   1205:                }
1.23      lukem    1206:
1.4       deraadt  1207:        | R
                   1208:                {
                   1209:                        $$ = STRU_R;
                   1210:                }
1.23      lukem    1211:
1.4       deraadt  1212:        | P
                   1213:                {
                   1214:                        $$ = STRU_P;
                   1215:                }
1.1       cgd      1216:        ;
                   1217:
1.4       deraadt  1218: mode_code
                   1219:        : S
                   1220:                {
                   1221:                        $$ = MODE_S;
                   1222:                }
1.23      lukem    1223:
1.4       deraadt  1224:        | B
                   1225:                {
                   1226:                        $$ = MODE_B;
                   1227:                }
1.23      lukem    1228:
1.4       deraadt  1229:        | C
                   1230:                {
                   1231:                        $$ = MODE_C;
                   1232:                }
1.1       cgd      1233:        ;
                   1234:
1.4       deraadt  1235: pathname
                   1236:        : pathstring
                   1237:                {
                   1238:                        /*
                   1239:                         * Problem: this production is used for all pathname
                   1240:                         * processing, but only gives a 550 error reply.
1.9       lukem    1241:                         * This is a valid reply in some cases but not in
                   1242:                         * others.
1.4       deraadt  1243:                         */
                   1244:                        if (logged_in && $1 && *$1 == '~') {
                   1245:                                glob_t gl;
                   1246:                                int flags =
1.19      kleink   1247:                                 GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
1.4       deraadt  1248:
1.9       lukem    1249:                                if ($1[1] == '\0')
1.23      lukem    1250:                                        $$ = xstrdup(pw->pw_dir);
1.9       lukem    1251:                                else {
                   1252:                                        memset(&gl, 0, sizeof(gl));
                   1253:                                        if (glob($1, flags, NULL, &gl) ||
                   1254:                                            gl.gl_pathc == 0) {
                   1255:                                                reply(550, "not found");
                   1256:                                                $$ = NULL;
                   1257:                                        } else
1.23      lukem    1258:                                                $$ = xstrdup(gl.gl_pathv[0]);
1.9       lukem    1259:                                        globfree(&gl);
1.4       deraadt  1260:                                }
                   1261:                                free($1);
                   1262:                        } else
                   1263:                                $$ = $1;
                   1264:                }
1.1       cgd      1265:        ;
                   1266:
1.4       deraadt  1267: pathstring
                   1268:        : STRING
1.1       cgd      1269:        ;
                   1270:
1.4       deraadt  1271: octal_number
                   1272:        : NUMBER
                   1273:                {
                   1274:                        int ret, dec, multby, digit;
1.1       cgd      1275:
1.4       deraadt  1276:                        /*
                   1277:                         * Convert a number that was read as decimal number
                   1278:                         * to what it would be if it had been read as octal.
                   1279:                         */
                   1280:                        dec = $1;
                   1281:                        multby = 1;
                   1282:                        ret = 0;
                   1283:                        while (dec) {
                   1284:                                digit = dec%10;
                   1285:                                if (digit > 7) {
                   1286:                                        ret = -1;
                   1287:                                        break;
                   1288:                                }
                   1289:                                ret += digit * multby;
                   1290:                                multby *= 8;
                   1291:                                dec /= 10;
1.1       cgd      1292:                        }
1.4       deraadt  1293:                        $$ = ret;
1.1       cgd      1294:                }
                   1295:        ;
                   1296:
1.25      lukem    1297: mechanism_name
                   1298:        : STRING
                   1299:        ;
                   1300:
                   1301: base64data
                   1302:        : STRING
                   1303:        ;
                   1304:
                   1305: prot_code
                   1306:        : STRING
                   1307:        ;
                   1308:
                   1309: decimal_integer
                   1310:        : NUMBER
                   1311:        ;
                   1312:
1.4       deraadt  1313: check_login
                   1314:        : /* empty */
                   1315:                {
                   1316:                        if (logged_in)
                   1317:                                $$ = 1;
                   1318:                        else {
                   1319:                                reply(530, "Please login with USER and PASS.");
                   1320:                                $$ = 0;
1.22      lukem    1321:                                hasyyerrored = 1;
1.4       deraadt  1322:                        }
1.1       cgd      1323:                }
                   1324:        ;
1.21      lukem    1325:
1.12      lukem    1326: check_modify
1.8       cjs      1327:        : /* empty */
                   1328:                {
1.22      lukem    1329:                        if (logged_in) {
                   1330:                                if (curclass.modify)
1.12      lukem    1331:                                        $$ = 1;
1.22      lukem    1332:                                else {
1.8       cjs      1333:                                        reply(502,
1.12      lukem    1334:                                        "No permission to use this command.");
1.8       cjs      1335:                                        $$ = 0;
1.22      lukem    1336:                                        hasyyerrored = 1;
1.14      hannken  1337:                                }
1.8       cjs      1338:                        } else {
                   1339:                                reply(530, "Please login with USER and PASS.");
                   1340:                                $$ = 0;
1.22      lukem    1341:                                hasyyerrored = 1;
1.8       cjs      1342:                        }
                   1343:                }
1.1       cgd      1344:
1.38.2.1! wrstuden 1345: check_upload
        !          1346:        : /* empty */
        !          1347:                {
        !          1348:                        if (logged_in) {
        !          1349:                                if (curclass.upload)
        !          1350:                                        $$ = 1;
        !          1351:                                else {
        !          1352:                                        reply(502,
        !          1353:                                        "No permission to use this command.");
        !          1354:                                        $$ = 0;
        !          1355:                                        hasyyerrored = 1;
        !          1356:                                }
        !          1357:                        } else {
        !          1358:                                reply(530, "Please login with USER and PASS.");
        !          1359:                                $$ = 0;
        !          1360:                                hasyyerrored = 1;
        !          1361:                        }
        !          1362:                }
        !          1363:
        !          1364:
1.1       cgd      1365: %%
                   1366:
                   1367: #define        CMD     0       /* beginning of command */
                   1368: #define        ARGS    1       /* expect miscellaneous arguments */
                   1369: #define        STR1    2       /* expect SP followed by STRING */
                   1370: #define        STR2    3       /* expect STRING */
                   1371: #define        OSTR    4       /* optional SP then STRING */
                   1372: #define        ZSTR1   5       /* SP then optional STRING */
                   1373: #define        ZSTR2   6       /* optional STRING after SP */
                   1374: #define        SITECMD 7       /* SITE command */
                   1375: #define        NSTR    8       /* Number followed by a string */
1.21      lukem    1376: #define NOARGS 9       /* No arguments allowed */
1.1       cgd      1377:
                   1378: struct tab {
                   1379:        char    *name;
1.23      lukem    1380:        short    token;
                   1381:        short    state;
                   1382:        short    implemented;   /* 1 if command is implemented */
                   1383:        short    hasopts;       /* 1 if command takes options */
1.1       cgd      1384:        char    *help;
1.23      lukem    1385:        char    *options;
1.1       cgd      1386: };
                   1387:
1.21      lukem    1388: struct tab cmdtab[] = {
                   1389:                                /* From RFC 959, in order defined (5.3.1) */
1.23      lukem    1390:        { "USER", USER, STR1,   1, 0,   "<sp> username" },
                   1391:        { "PASS", PASS, ZSTR1,  1, 0,   "<sp> password" },
                   1392:        { "ACCT", ACCT, STR1,   0, 0,   "(specify account)" },
                   1393:        { "CWD",  CWD,  OSTR,   1, 0,   "[ <sp> directory-name ]" },
                   1394:        { "CDUP", CDUP, NOARGS, 1, 0,   "(change to parent directory)" },
                   1395:        { "SMNT", SMNT, ARGS,   0, 0,   "(structure mount)" },
1.38      simonb   1396:        { "QUIT", QUIT, NOARGS, 1, 0,   "(terminate service)" },
1.23      lukem    1397:        { "REIN", REIN, NOARGS, 0, 0,   "(reinitialize server state)" },
                   1398:        { "PORT", PORT, ARGS,   1, 0,   "<sp> b0, b1, b2, b3, b4" },
1.32      itojun   1399:        { "LPRT", LPRT, ARGS,   1, 0,   "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." },
                   1400:        { "EPRT", EPRT, STR1,   1, 0,   "<sp> |af|addr|port|" },
1.23      lukem    1401:        { "PASV", PASV, NOARGS, 1, 0,   "(set server in passive mode)" },
1.32      itojun   1402:        { "LPSV", LPSV, ARGS,   1, 0,   "(set server in passive mode)" },
                   1403:        { "EPSV", EPSV, ARGS,   1, 0,   "[<sp> af|ALL]" },
1.23      lukem    1404:        { "TYPE", TYPE, ARGS,   1, 0,   "<sp> [ A | E | I | L ]" },
                   1405:        { "STRU", STRU, ARGS,   1, 0,   "(specify file structure)" },
                   1406:        { "MODE", MODE, ARGS,   1, 0,   "(specify transfer mode)" },
                   1407:        { "RETR", RETR, STR1,   1, 0,   "<sp> file-name" },
                   1408:        { "STOR", STOR, STR1,   1, 0,   "<sp> file-name" },
                   1409:        { "STOU", STOU, STR1,   1, 0,   "<sp> file-name" },
                   1410:        { "APPE", APPE, STR1,   1, 0,   "<sp> file-name" },
                   1411:        { "ALLO", ALLO, ARGS,   1, 0,   "allocate storage (vacuously)" },
                   1412:        { "REST", REST, ARGS,   1, 0,   "<sp> offset (restart command)" },
                   1413:        { "RNFR", RNFR, STR1,   1, 0,   "<sp> file-name" },
                   1414:        { "RNTO", RNTO, STR1,   1, 0,   "<sp> file-name" },
                   1415:        { "ABOR", ABOR, NOARGS, 1, 0,   "(abort operation)" },
                   1416:        { "DELE", DELE, STR1,   1, 0,   "<sp> file-name" },
                   1417:        { "RMD",  RMD,  STR1,   1, 0,   "<sp> path-name" },
                   1418:        { "MKD",  MKD,  STR1,   1, 0,   "<sp> path-name" },
                   1419:        { "PWD",  PWD,  NOARGS, 1, 0,   "(return current directory)" },
                   1420:        { "LIST", LIST, OSTR,   1, 0,   "[ <sp> path-name ]" },
                   1421:        { "NLST", NLST, OSTR,   1, 0,   "[ <sp> path-name ]" },
                   1422:        { "SITE", SITE, SITECMD, 1, 0,  "site-cmd [ <sp> arguments ]" },
                   1423:        { "SYST", SYST, NOARGS, 1, 0,   "(get type of operating system)" },
                   1424:        { "STAT", STAT, OSTR,   1, 0,   "[ <sp> path-name ]" },
                   1425:        { "HELP", HELP, OSTR,   1, 0,   "[ <sp> <string> ]" },
                   1426:        { "NOOP", NOOP, NOARGS, 1, 1,   "" },
                   1427:
1.25      lukem    1428:                                /* From RFC 2228, in order defined */
                   1429:        { "AUTH", AUTH, STR1,   1, 0,   "<sp> mechanism-name" },
                   1430:        { "ADAT", ADAT, STR1,   1, 0,   "<sp> base-64-data" },
                   1431:        { "PROT", PROT, STR1,   1, 0,   "<sp> prot-code" },
                   1432:        { "PBSZ", PBSZ, ARGS,   1, 0,   "<sp> decimal-integer" },
                   1433:        { "CCC",  CCC,  NOARGS, 1, 0,   "(Disable data protection)" },
                   1434:        { "MIC",  MIC,  STR1,   1, 0,   "<sp> base64data" },
                   1435:        { "CONF", CONF, STR1,   1, 0,   "<sp> base64data" },
                   1436:        { "ENC",  ENC,  STR1,   1, 0,   "<sp> base64data" },
                   1437:
                   1438:                                /* From RFC 2389, in order defined */
1.23      lukem    1439:        { "FEAT", FEAT, NOARGS, 1, 0,   "(display extended features)" },
                   1440:        { "OPTS", OPTS, STR1,   1, 0,   "<sp> command [ <sp> options ]" },
                   1441:
                   1442:                                /* Non standardized extensions */
                   1443:        { "SIZE", SIZE, OSTR,   1, 0,   "<sp> path-name" },
                   1444:        { "MDTM", MDTM, OSTR,   1, 0,   "<sp> path-name" },
1.21      lukem    1445:
                   1446:                                /* obsolete commands */
1.23      lukem    1447:        { "MAIL", MAIL, OSTR,   0, 0,   "(mail to user)" },
                   1448:        { "MLFL", MLFL, OSTR,   0, 0,   "(mail file)" },
                   1449:        { "MRCP", MRCP, STR1,   0, 0,   "(mail recipient)" },
                   1450:        { "MRSQ", MRSQ, OSTR,   0, 0,   "(mail recipient scheme question)" },
                   1451:        { "MSAM", MSAM, OSTR,   0, 0,   "(mail send to terminal and mailbox)" },
                   1452:        { "MSND", MSND, OSTR,   0, 0,   "(mail send to terminal)" },
                   1453:        { "MSOM", MSOM, OSTR,   0, 0,   "(mail send to terminal or mailbox)" },
                   1454:        { "XCUP", CDUP, NOARGS, 1, 0,   "(change to parent directory)" },
1.38      simonb   1455:        { "XCWD", CWD,  OSTR,   1, 0,   "[ <sp> directory-name ]" },
1.23      lukem    1456:        { "XMKD", MKD,  STR1,   1, 0,   "<sp> path-name" },
                   1457:        { "XPWD", PWD,  NOARGS, 1, 0,   "(return current directory)" },
                   1458:        { "XRMD", RMD,  STR1,   1, 0,   "<sp> path-name" },
1.21      lukem    1459:
1.23      lukem    1460:        { NULL,   0,    0,      0, 0,   0 }
1.1       cgd      1461: };
                   1462:
                   1463: struct tab sitetab[] = {
1.23      lukem    1464:        { "CHMOD", CHMOD, NSTR, 1, 0,   "<sp> mode <sp> file-name" },
                   1465:        { "HELP",  HELP,  OSTR, 1, 0,   "[ <sp> <string> ]" },
1.38.2.1! wrstuden 1466:        { "IDLE",  IDLE,  ARGS, 1, 0,   "[ <sp> maximum-idle-time ]" },
        !          1467:        { "RATEGET", RATEGET, OSTR, 1,0,"[ <sp> get-throttle-rate ]" },
        !          1468:        { "RATEPUT", RATEPUT, OSTR, 1,0,"[ <sp> put-throttle-rate ]" },
        !          1469:        { "UMASK", UMASK, ARGS, 1, 0,   "[ <sp> umask ]" },
1.23      lukem    1470:        { NULL,    0,     0,    0, 0,   0 }
1.1       cgd      1471: };
                   1472:
1.23      lukem    1473: static void            help __P((struct tab *, char *));
                   1474: static struct tab     *lookup __P((struct tab *, const char *));
                   1475: static void            opts __P((const char *));
                   1476: static void            sizecmd __P((char *));
                   1477: static void            toolong __P((int));
                   1478: static int             yylex __P((void));
1.4       deraadt  1479:
1.32      itojun   1480: extern int epsvall;
                   1481:
1.4       deraadt  1482: static struct tab *
1.1       cgd      1483: lookup(p, cmd)
1.4       deraadt  1484:        struct tab *p;
1.23      lukem    1485:        const char *cmd;
1.1       cgd      1486: {
                   1487:
                   1488:        for (; p->name != NULL; p++)
1.23      lukem    1489:                if (strcasecmp(cmd, p->name) == 0)
1.1       cgd      1490:                        return (p);
                   1491:        return (0);
                   1492: }
                   1493:
                   1494: #include <arpa/telnet.h>
                   1495:
                   1496: /*
                   1497:  * getline - a hacked up version of fgets to ignore TELNET escape codes.
                   1498:  */
                   1499: char *
                   1500: getline(s, n, iop)
                   1501:        char *s;
1.4       deraadt  1502:        int n;
                   1503:        FILE *iop;
1.1       cgd      1504: {
1.27      lukem    1505:        off_t b;
1.4       deraadt  1506:        int c;
1.21      lukem    1507:        char *cs;
1.1       cgd      1508:
                   1509:        cs = s;
                   1510: /* tmpline may contain saved command from urgent mode interruption */
                   1511:        for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) {
                   1512:                *cs++ = tmpline[c];
                   1513:                if (tmpline[c] == '\n') {
                   1514:                        *cs++ = '\0';
                   1515:                        if (debug)
                   1516:                                syslog(LOG_DEBUG, "command: %s", s);
                   1517:                        tmpline[0] = '\0';
                   1518:                        return(s);
                   1519:                }
                   1520:                if (c == 0)
                   1521:                        tmpline[0] = '\0';
                   1522:        }
                   1523:        while ((c = getc(iop)) != EOF) {
1.27      lukem    1524:                total_bytes++;
                   1525:                total_bytes_in++;
1.1       cgd      1526:                c &= 0377;
                   1527:                if (c == IAC) {
                   1528:                    if ((c = getc(iop)) != EOF) {
1.27      lukem    1529:                        total_bytes++;
                   1530:                        total_bytes_in++;
1.1       cgd      1531:                        c &= 0377;
                   1532:                        switch (c) {
                   1533:                        case WILL:
                   1534:                        case WONT:
                   1535:                                c = getc(iop);
1.27      lukem    1536:                                total_bytes++;
                   1537:                                total_bytes_in++;
                   1538:                                b = printf("%c%c%c", IAC, DONT, 0377&c);
                   1539:                                total_bytes += b;
                   1540:                                total_bytes_out += b;
1.1       cgd      1541:                                (void) fflush(stdout);
                   1542:                                continue;
                   1543:                        case DO:
                   1544:                        case DONT:
                   1545:                                c = getc(iop);
1.27      lukem    1546:                                total_bytes++;
                   1547:                                total_bytes_in++;
                   1548:                                b = printf("%c%c%c", IAC, WONT, 0377&c);
                   1549:                                total_bytes += b;
                   1550:                                total_bytes_out += b;
1.1       cgd      1551:                                (void) fflush(stdout);
                   1552:                                continue;
                   1553:                        case IAC:
                   1554:                                break;
                   1555:                        default:
                   1556:                                continue;       /* ignore command */
                   1557:                        }
                   1558:                    }
                   1559:                }
                   1560:                *cs++ = c;
                   1561:                if (--n <= 0 || c == '\n')
                   1562:                        break;
                   1563:        }
                   1564:        if (c == EOF && cs == s)
                   1565:                return (NULL);
                   1566:        *cs++ = '\0';
1.4       deraadt  1567:        if (debug) {
1.38.2.1! wrstuden 1568:                if (curclass.type != CLASS_GUEST &&
        !          1569:                    strncasecmp("pass ", s, 5) == 0) {
1.4       deraadt  1570:                        /* Don't syslog passwords */
                   1571:                        syslog(LOG_DEBUG, "command: %.5s ???", s);
                   1572:                } else {
1.21      lukem    1573:                        char *cp;
                   1574:                        int len;
1.4       deraadt  1575:
                   1576:                        /* Don't syslog trailing CR-LF */
                   1577:                        len = strlen(s);
                   1578:                        cp = s + len - 1;
                   1579:                        while (cp >= s && (*cp == '\n' || *cp == '\r')) {
                   1580:                                --cp;
                   1581:                                --len;
                   1582:                        }
                   1583:                        syslog(LOG_DEBUG, "command: %.*s", len, s);
                   1584:                }
                   1585:        }
1.1       cgd      1586:        return (s);
                   1587: }
                   1588:
                   1589: static void
1.4       deraadt  1590: toolong(signo)
                   1591:        int signo;
1.1       cgd      1592: {
                   1593:
                   1594:        reply(421,
1.12      lukem    1595:            "Timeout (%d seconds): closing control connection.",
                   1596:            curclass.timeout);
1.4       deraadt  1597:        if (logging)
                   1598:                syslog(LOG_INFO, "User %s timed out after %d seconds",
1.38.2.1! wrstuden 1599:                    (pw ? pw->pw_name : "unknown"), curclass.timeout);
1.1       cgd      1600:        dologout(1);
                   1601: }
                   1602:
1.4       deraadt  1603: static int
1.1       cgd      1604: yylex()
                   1605: {
                   1606:        static int cpos, state;
1.4       deraadt  1607:        char *cp, *cp2;
                   1608:        struct tab *p;
1.22      lukem    1609:        int n;
1.4       deraadt  1610:        char c;
1.1       cgd      1611:
1.23      lukem    1612:        switch (state) {
1.1       cgd      1613:
1.23      lukem    1614:        case CMD:
                   1615:                hasyyerrored = 0;
                   1616:                (void) signal(SIGALRM, toolong);
                   1617:                (void) alarm(curclass.timeout);
                   1618:                if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) {
                   1619:                        reply(221, "You could at least say goodbye.");
                   1620:                        dologout(0);
                   1621:                }
                   1622:                (void) alarm(0);
1.38.2.1! wrstuden 1623:                if ((cp = strchr(cbuf, '\r'))) {
        !          1624:                        *cp = '\0';
1.3       cgd      1625: #ifdef HASSETPROCTITLE
1.38.2.1! wrstuden 1626:                        if (strncasecmp(cbuf, "PASS", 4) != 0)
        !          1627:                                setproctitle("%s: %s", proctitle, cbuf);
1.3       cgd      1628: #endif /* HASSETPROCTITLE */
1.23      lukem    1629:                        *cp++ = '\n';
                   1630:                        *cp = '\0';
                   1631:                }
                   1632:                if ((cp = strpbrk(cbuf, " \n")))
                   1633:                        cpos = cp - cbuf;
                   1634:                if (cpos == 0)
                   1635:                        cpos = 4;
                   1636:                c = cbuf[cpos];
                   1637:                cbuf[cpos] = '\0';
                   1638:                p = lookup(cmdtab, cbuf);
                   1639:                cbuf[cpos] = c;
                   1640:                if (p != NULL) {
                   1641:                        if (p->implemented == 0) {
                   1642:                                reply(502, "%s command not implemented.",
                   1643:                                    p->name);
                   1644:                                hasyyerrored = 1;
                   1645:                                break;
                   1646:                        }
                   1647:                        state = p->state;
                   1648:                        yylval.s = p->name;
                   1649:                        return (p->token);
                   1650:                }
                   1651:                break;
                   1652:
                   1653:        case SITECMD:
                   1654:                if (cbuf[cpos] == ' ') {
                   1655:                        cpos++;
                   1656:                        return (SP);
                   1657:                }
                   1658:                cp = &cbuf[cpos];
                   1659:                if ((cp2 = strpbrk(cp, " \n")))
                   1660:                        cpos = cp2 - cbuf;
                   1661:                c = cbuf[cpos];
                   1662:                cbuf[cpos] = '\0';
                   1663:                p = lookup(sitetab, cp);
                   1664:                cbuf[cpos] = c;
                   1665:                if (p != NULL) {
                   1666:                        if (p->implemented == 0) {
                   1667:                                reply(502, "SITE %s command not implemented.",
                   1668:                                    p->name);
                   1669:                                hasyyerrored = 1;
                   1670:                                break;
                   1671:                        }
                   1672:                        state = p->state;
                   1673:                        yylval.s = p->name;
                   1674:                        return (p->token);
                   1675:                }
                   1676:                break;
                   1677:
                   1678:        case OSTR:
                   1679:                if (cbuf[cpos] == '\n') {
                   1680:                        state = CMD;
                   1681:                        return (CRLF);
                   1682:                }
                   1683:                /* FALLTHROUGH */
                   1684:
                   1685:        case STR1:
                   1686:        case ZSTR1:
                   1687:        dostr1:
                   1688:                if (cbuf[cpos] == ' ') {
                   1689:                        cpos++;
1.38.2.1! wrstuden 1690:                        state = state == OSTR ? STR2 : state+1;
1.23      lukem    1691:                        return (SP);
                   1692:                }
                   1693:                break;
                   1694:
                   1695:        case ZSTR2:
                   1696:                if (cbuf[cpos] == '\n') {
                   1697:                        state = CMD;
                   1698:                        return (CRLF);
                   1699:                }
                   1700:                /* FALLTHROUGH */
                   1701:
                   1702:        case STR2:
                   1703:                cp = &cbuf[cpos];
                   1704:                n = strlen(cp);
                   1705:                cpos += n - 1;
                   1706:                /*
                   1707:                 * Make sure the string is nonempty and \n terminated.
                   1708:                 */
                   1709:                if (n > 1 && cbuf[cpos] == '\n') {
                   1710:                        cbuf[cpos] = '\0';
                   1711:                        yylval.s = xstrdup(cp);
                   1712:                        cbuf[cpos] = '\n';
                   1713:                        state = ARGS;
                   1714:                        return (STRING);
                   1715:                }
                   1716:                break;
                   1717:
                   1718:        case NSTR:
                   1719:                if (cbuf[cpos] == ' ') {
                   1720:                        cpos++;
                   1721:                        return (SP);
                   1722:                }
                   1723:                if (isdigit(cbuf[cpos])) {
                   1724:                        cp = &cbuf[cpos];
                   1725:                        while (isdigit(cbuf[++cpos]))
                   1726:                                ;
1.1       cgd      1727:                        c = cbuf[cpos];
                   1728:                        cbuf[cpos] = '\0';
1.23      lukem    1729:                        yylval.i = atoi(cp);
1.1       cgd      1730:                        cbuf[cpos] = c;
1.23      lukem    1731:                        state = STR1;
                   1732:                        return (NUMBER);
                   1733:                }
                   1734:                state = STR1;
                   1735:                goto dostr1;
1.1       cgd      1736:
1.23      lukem    1737:        case ARGS:
                   1738:                if (isdigit(cbuf[cpos])) {
1.1       cgd      1739:                        cp = &cbuf[cpos];
1.23      lukem    1740:                        while (isdigit(cbuf[++cpos]))
                   1741:                                ;
1.1       cgd      1742:                        c = cbuf[cpos];
                   1743:                        cbuf[cpos] = '\0';
1.23      lukem    1744:                        yylval.i = atoi(cp);
1.1       cgd      1745:                        cbuf[cpos] = c;
1.23      lukem    1746:                        return (NUMBER);
1.32      itojun   1747:                }
                   1748:                if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0
                   1749:                 && !isalnum(cbuf[cpos + 3])) {
                   1750:                        yylval.s = xstrdup("ALL");
                   1751:                        cpos += 3;
                   1752:                        return ALL;
1.23      lukem    1753:                }
                   1754:                switch (cbuf[cpos++]) {
                   1755:
                   1756:                case '\n':
1.1       cgd      1757:                        state = CMD;
1.23      lukem    1758:                        return (CRLF);
                   1759:
                   1760:                case ' ':
                   1761:                        return (SP);
                   1762:
                   1763:                case ',':
                   1764:                        return (COMMA);
                   1765:
                   1766:                case 'A':
                   1767:                case 'a':
                   1768:                        return (A);
                   1769:
                   1770:                case 'B':
                   1771:                case 'b':
                   1772:                        return (B);
                   1773:
                   1774:                case 'C':
                   1775:                case 'c':
                   1776:                        return (C);
                   1777:
                   1778:                case 'E':
                   1779:                case 'e':
                   1780:                        return (E);
                   1781:
                   1782:                case 'F':
                   1783:                case 'f':
                   1784:                        return (F);
                   1785:
                   1786:                case 'I':
                   1787:                case 'i':
                   1788:                        return (I);
1.1       cgd      1789:
1.23      lukem    1790:                case 'L':
                   1791:                case 'l':
                   1792:                        return (L);
1.1       cgd      1793:
1.23      lukem    1794:                case 'N':
                   1795:                case 'n':
                   1796:                        return (N);
1.1       cgd      1797:
1.23      lukem    1798:                case 'P':
                   1799:                case 'p':
                   1800:                        return (P);
1.1       cgd      1801:
1.23      lukem    1802:                case 'R':
                   1803:                case 'r':
                   1804:                        return (R);
1.1       cgd      1805:
1.23      lukem    1806:                case 'S':
                   1807:                case 's':
                   1808:                        return (S);
1.1       cgd      1809:
1.23      lukem    1810:                case 'T':
                   1811:                case 't':
                   1812:                        return (T);
1.1       cgd      1813:
1.23      lukem    1814:                }
                   1815:                break;
1.21      lukem    1816:
1.23      lukem    1817:        case NOARGS:
                   1818:                if (cbuf[cpos] == '\n') {
                   1819:                        state = CMD;
                   1820:                        return (CRLF);
1.1       cgd      1821:                }
1.23      lukem    1822:                c = cbuf[cpos];
                   1823:                cbuf[cpos] = '\0';
                   1824:                reply(501, "'%s' command does not take any arguments.", cbuf);
                   1825:                hasyyerrored = 1;
                   1826:                cbuf[cpos] = c;
                   1827:                break;
                   1828:
                   1829:        default:
                   1830:                fatal("Unknown state in scanner.");
1.1       cgd      1831:        }
1.23      lukem    1832:        yyerror(NULL);
                   1833:        state = CMD;
                   1834:        longjmp(errcatch, 0);
                   1835:        /* NOTREACHED */
1.1       cgd      1836: }
                   1837:
1.22      lukem    1838: /* ARGSUSED */
                   1839: void
                   1840: yyerror(s)
                   1841:        char *s;
                   1842: {
                   1843:        char *cp;
                   1844:
                   1845:        if (hasyyerrored)
                   1846:                return;
                   1847:        if ((cp = strchr(cbuf,'\n')) != NULL)
                   1848:                *cp = '\0';
                   1849:        reply(500, "'%s': command not understood.", cbuf);
                   1850:        hasyyerrored = 1;
                   1851: }
                   1852:
1.4       deraadt  1853: static void
1.1       cgd      1854: help(ctab, s)
                   1855:        struct tab *ctab;
                   1856:        char *s;
                   1857: {
1.4       deraadt  1858:        struct tab *c;
                   1859:        int width, NCMDS;
1.27      lukem    1860:        off_t b;
1.1       cgd      1861:        char *type;
                   1862:
                   1863:        if (ctab == sitetab)
                   1864:                type = "SITE ";
                   1865:        else
                   1866:                type = "";
                   1867:        width = 0, NCMDS = 0;
                   1868:        for (c = ctab; c->name != NULL; c++) {
                   1869:                int len = strlen(c->name);
                   1870:
                   1871:                if (len > width)
                   1872:                        width = len;
                   1873:                NCMDS++;
                   1874:        }
                   1875:        width = (width + 8) &~ 7;
                   1876:        if (s == 0) {
1.4       deraadt  1877:                int i, j, w;
1.1       cgd      1878:                int columns, lines;
                   1879:
1.28      lukem    1880:                lreply(214, "");
                   1881:                lreply(0, "The following %scommands are recognized.", type);
1.27      lukem    1882:                lreply(0, "(`-' = not implemented, `+' = supports options)");
1.1       cgd      1883:                columns = 76 / width;
                   1884:                if (columns == 0)
                   1885:                        columns = 1;
                   1886:                lines = (NCMDS + columns - 1) / columns;
                   1887:                for (i = 0; i < lines; i++) {
1.28      lukem    1888:                        b = printf("    ");
1.27      lukem    1889:                        total_bytes += b;
                   1890:                        total_bytes_out += b;
1.1       cgd      1891:                        for (j = 0; j < columns; j++) {
                   1892:                                c = ctab + j * lines + i;
1.27      lukem    1893:                                b = printf("%s", c->name);
                   1894:                                total_bytes += b;
                   1895:                                total_bytes_out += b;
1.23      lukem    1896:                                w = strlen(c->name);
                   1897:                                if (! c->implemented) {
1.24      lukem    1898:                                        putchar('-');
1.28      lukem    1899:                                        total_bytes++;
                   1900:                                        total_bytes_out++;
1.23      lukem    1901:                                        w++;
                   1902:                                }
                   1903:                                if (c->hasopts) {
                   1904:                                        putchar('+');
1.28      lukem    1905:                                        total_bytes++;
                   1906:                                        total_bytes_out++;
1.23      lukem    1907:                                        w++;
                   1908:                                }
1.1       cgd      1909:                                if (c + lines >= &ctab[NCMDS])
                   1910:                                        break;
                   1911:                                while (w < width) {
                   1912:                                        putchar(' ');
1.28      lukem    1913:                                        total_bytes++;
                   1914:                                        total_bytes_out++;
1.1       cgd      1915:                                        w++;
                   1916:                                }
                   1917:                        }
1.27      lukem    1918:                        b = printf("\r\n");
                   1919:                        total_bytes += b;
                   1920:                        total_bytes_out += b;
1.1       cgd      1921:                }
                   1922:                (void) fflush(stdout);
                   1923:                reply(214, "Direct comments to ftp-bugs@%s.", hostname);
                   1924:                return;
                   1925:        }
                   1926:        c = lookup(ctab, s);
                   1927:        if (c == (struct tab *)0) {
                   1928:                reply(502, "Unknown command %s.", s);
                   1929:                return;
                   1930:        }
                   1931:        if (c->implemented)
                   1932:                reply(214, "Syntax: %s%s %s", type, c->name, c->help);
                   1933:        else
1.23      lukem    1934:                reply(214, "%s%-*s\t%s; not implemented.", type, width,
1.1       cgd      1935:                    c->name, c->help);
                   1936: }
                   1937:
1.4       deraadt  1938: static void
1.1       cgd      1939: sizecmd(filename)
1.4       deraadt  1940:        char *filename;
1.1       cgd      1941: {
                   1942:        switch (type) {
                   1943:        case TYPE_L:
                   1944:        case TYPE_I: {
                   1945:                struct stat stbuf;
1.4       deraadt  1946:                if (stat(filename, &stbuf) < 0 || !S_ISREG(stbuf.st_mode))
1.1       cgd      1947:                        reply(550, "%s: not a plain file.", filename);
                   1948:                else
1.30      ross     1949:                        reply(213, "%qu", (qufmt_t)stbuf.st_size);
1.4       deraadt  1950:                break; }
1.1       cgd      1951:        case TYPE_A: {
                   1952:                FILE *fin;
1.4       deraadt  1953:                int c;
                   1954:                off_t count;
1.1       cgd      1955:                struct stat stbuf;
                   1956:                fin = fopen(filename, "r");
                   1957:                if (fin == NULL) {
                   1958:                        perror_reply(550, filename);
                   1959:                        return;
                   1960:                }
1.4       deraadt  1961:                if (fstat(fileno(fin), &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) {
1.1       cgd      1962:                        reply(550, "%s: not a plain file.", filename);
                   1963:                        (void) fclose(fin);
                   1964:                        return;
                   1965:                }
                   1966:
                   1967:                count = 0;
                   1968:                while((c=getc(fin)) != EOF) {
                   1969:                        if (c == '\n')  /* will get expanded to \r\n */
                   1970:                                count++;
                   1971:                        count++;
                   1972:                }
                   1973:                (void) fclose(fin);
                   1974:
1.30      ross     1975:                reply(213, "%qd", (qdfmt_t)count);
1.4       deraadt  1976:                break; }
1.1       cgd      1977:        default:
                   1978:                reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
                   1979:        }
                   1980: }
1.22      lukem    1981:
1.23      lukem    1982: static void
                   1983: opts(command)
                   1984:        const char *command;
                   1985: {
                   1986:        struct tab *c;
                   1987:        char *ep;
                   1988:
                   1989:        if ((ep = strchr(command, ' ')) != NULL)
                   1990:                *ep++ = '\0';
                   1991:        c = lookup(cmdtab, command);
                   1992:        if (c == NULL) {
                   1993:                reply(502, "Unknown command %s.", command);
                   1994:                return;
                   1995:        }
                   1996:        if (c->implemented == 0) {
                   1997:                reply(502, "%s command not implemented.", c->name);
                   1998:                return;
                   1999:        }
                   2000:        if (c->hasopts == 0) {
                   2001:                reply(501, "%s command does not support persistent options.",
                   2002:                    c->name);
                   2003:                return;
                   2004:        }
                   2005:
1.38.2.1! wrstuden 2006:        if (ep != NULL && *ep != '\0')
        !          2007:                REASSIGN(c->options, xstrdup(ep));
1.23      lukem    2008:        if (c->options != NULL)
                   2009:                reply(200, "Options for %s are '%s'.", c->name, c->options);
                   2010:        else
                   2011:                reply(200, "No options defined for %s.", c->name);
                   2012: }

CVSweb <webmaster@jp.NetBSD.org>