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

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

CVSweb <webmaster@jp.NetBSD.org>