[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.83.2.1

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

CVSweb <webmaster@jp.NetBSD.org>