
# line 42 "ftpcmd.y"

#ifndef lint
static char sccsid[] = "@(#)ftpcmd.y    5.24 (Berkeley) 2/25/91";
#endif /* not lint */

#include "config.h"
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/ftp.h>
#include <stdio.h>
#include <signal.h>
#include <ctype.h>
#include <pwd.h>
#include <setjmp.h>
#include <syslog.h>
#include <time.h>
#include <string.h>
#include <limits.h>
#include "support/ftw.h"
#include "extensions.h"
#include "pathnames.h"

extern  int dolreplies;
extern  char ls_long[50];
extern  char ls_short[50];
extern  struct sockaddr_in data_dest;
extern  int logged_in;
extern  struct passwd *pw;
extern  int anonymous;
extern  int logging;
extern  int log_commands;
extern  int type;
extern  int form;
extern  int debug;
extern  int timeout;
extern  int maxtimeout;
extern  int pdata;
extern  char hostname[], remotehost[];
#ifdef SETPROCTITLE
extern  char proctitle[];
#endif
extern  char *globerr;
extern  int usedefault;
extern  int transflag;
extern  char tmpline[];
extern  int data;
char    **ftpglob();
off_t   restart_point;

extern  char    *strunames[];
extern  char    *typenames[];
extern  char    *modenames[];
extern  char    *formnames[];

static  int cmd_type;
static  int cmd_form;
static  int cmd_bytesz;
char    cbuf[512];
char    *fromname;

static void toolong();


# line 128 "ftpcmd.y"
typedef union  {
    char    *String;
    int     Number;
} YYSTYPE;
# define A 257
# define B 258
# define C 259
# define E 260
# define F 261
# define I 262
# define L 263
# define N 264
# define P 265
# define R 266
# define S 267
# define T 268
# define SP 269
# define CRLF 270
# define COMMA 271
# define STRING 272
# define NUMBER 273
# define USER 274
# define PASS 275
# define ACCT 276
# define REIN 277
# define QUIT 278
# define PORT 279
# define PASV 280
# define TYPE 281
# define STRU 282
# define MODE 283
# define RETR 284
# define STOR 285
# define APPE 286
# define MLFL 287
# define MAIL 288
# define MSND 289
# define MSOM 290
# define MSAM 291
# define MRSQ 292
# define MRCP 293
# define ALLO 294
# define REST 295
# define RNFR 296
# define RNTO 297
# define ABOR 298
# define DELE 299
# define CWD 300
# define LIST 301
# define NLST 302
# define SITE 303
# define STAT 304
# define HELP 305
# define NOOP 306
# define MKD 307
# define RMD 308
# define PWD 309
# define CDUP 310
# define STOU 311
# define SMNT 312
# define SYST 313
# define SIZE 314
# define MDTM 315
# define UMASK 316
# define IDLE 317
# define CHMOD 318
# define GROUP 319
# define GPASS 320
# define NEWER 321
# define MINFO 322
# define INDEX 323
# define EXEC 324
# define ALIAS 325
# define CDPATH 326
# define GROUPS 327
# define LEXERR 328
#define yyclearin yychar = -1
#define yyerrok yyerrflag = 0
extern int yychar;
extern short yyerrflag;
#ifndef YYMAXDEPTH
#define YYMAXDEPTH 150
#endif
YYSTYPE yylval, yyval;
# define YYERRCODE 256

# line 858 "ftpcmd.y"


extern jmp_buf errcatch;

#define CMD 0   /* beginning of command */
#define ARGS    1   /* expect miscellaneous arguments */
#define STR1    2   /* expect SP followed by STRING */
#define STR2    3   /* expect STRING */
#define OSTR    4   /* optional SP then STRING */
#define ZSTR1   5   /* SP then optional STRING */
#define ZSTR2   6   /* optional STRING after SP */
#define SITECMD 7   /* SITE command */
#define NSTR    8   /* Number followed by a string */
#define STR3    9   /* expect STRING followed by optional SP then STRING */

struct tab {
    char    *name;
    short   token;
    short   state;
    short   implemented;    /* 1 if command is implemented */
    char    *help;
};

struct tab cmdtab[] = {     /* In order defined in RFC 765 */
    { "USER", USER, STR1, 1,    "<sp> username" },
    { "PASS", PASS, ZSTR1, 1,   "<sp> password" },
    { "ACCT", ACCT, STR1, 0,    "(specify account)" },
    { "SMNT", SMNT, ARGS, 0,    "(structure mount)" },
    { "REIN", REIN, ARGS, 0,    "(reinitialize server state)" },
    { "QUIT", QUIT, ARGS, 1,    "(terminate service)", },
    { "PORT", PORT, ARGS, 1,    "<sp> b0, b1, b2, b3, b4" },
    { "PASV", PASV, ARGS, 1,    "(set server in passive mode)" },
    { "TYPE", TYPE, ARGS, 1,    "<sp> [ A | E | I | L ]" },
    { "STRU", STRU, ARGS, 1,    "(specify file structure)" },
    { "MODE", MODE, ARGS, 1,    "(specify transfer mode)" },
    { "RETR", RETR, STR1, 1,    "<sp> file-name" },
    { "STOR", STOR, STR1, 1,    "<sp> file-name" },
    { "APPE", APPE, STR1, 1,    "<sp> file-name" },
    { "MLFL", MLFL, OSTR, 0,    "(mail file)" },
    { "MAIL", MAIL, OSTR, 0,    "(mail to user)" },
    { "MSND", MSND, OSTR, 0,    "(mail send to terminal)" },
    { "MSOM", MSOM, OSTR, 0,    "(mail send to terminal or mailbox)" },
    { "MSAM", MSAM, OSTR, 0,    "(mail send to terminal and mailbox)" },
    { "MRSQ", MRSQ, OSTR, 0,    "(mail recipient scheme question)" },
    { "MRCP", MRCP, STR1, 0,    "(mail recipient)" },
    { "ALLO", ALLO, ARGS, 1,    "allocate storage (vacuously)" },
    { "REST", REST, ARGS, 1,    "(restart command)" },
    { "RNFR", RNFR, STR1, 1,    "<sp> file-name" },
    { "RNTO", RNTO, STR1, 1,    "<sp> file-name" },
    { "ABOR", ABOR, ARGS, 1,    "(abort operation)" },
    { "DELE", DELE, STR1, 1,    "<sp> file-name" },
    { "CWD",  CWD,  OSTR, 1,    "[ <sp> directory-name ]" },
    { "XCWD", CWD,  OSTR, 1,    "[ <sp> directory-name ]" },
    { "LIST", LIST, OSTR, 1,    "[ <sp> path-name ]" },
    { "NLST", NLST, OSTR, 1,    "[ <sp> path-name ]" },
    { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" },
    { "SYST", SYST, ARGS, 1,    "(get type of operating system)" },
    { "STAT", STAT, OSTR, 1,    "[ <sp> path-name ]" },
    { "HELP", HELP, OSTR, 1,    "[ <sp> <string> ]" },
    { "NOOP", NOOP, ARGS, 1,    "" },
    { "MKD",  MKD,  STR1, 1,    "<sp> path-name" },
    { "XMKD", MKD,  STR1, 1,    "<sp> path-name" },
    { "RMD",  RMD,  STR1, 1,    "<sp> path-name" },
    { "XRMD", RMD,  STR1, 1,    "<sp> path-name" },
    { "PWD",  PWD,  ARGS, 1,    "(return current directory)" },
    { "XPWD", PWD,  ARGS, 1,    "(return current directory)" },
    { "CDUP", CDUP, ARGS, 1,    "(change to parent directory)" },
    { "XCUP", CDUP, ARGS, 1,    "(change to parent directory)" },
    { "STOU", STOU, STR1, 1,    "<sp> file-name" },
    { "SIZE", SIZE, OSTR, 1,    "<sp> path-name" },
    { "MDTM", MDTM, OSTR, 1,    "<sp> path-name" },
    { NULL,   0,    0,    0,    0 }
};

struct tab sitetab[] = {
    { "UMASK", UMASK, ARGS, 1,  "[ <sp> umask ]" },
    { "IDLE",  IDLE,  ARGS, 1,  "[ <sp> maximum-idle-time ]" },
    { "CHMOD", CHMOD, NSTR, 1,  "<sp> mode <sp> file-name" },
    { "HELP",  HELP,  OSTR, 1,  "[ <sp> <string> ]" },
    { "GROUP", GROUP, STR1, 1,  "<sp> access-group" },
    { "GPASS", GPASS, STR1, 1,  "<sp> access-password" },
    { "NEWER", NEWER, STR3, 1,  "<sp> YYYYMMDDHHMMSS [ <sp> path-name ]" },
    { "MINFO", MINFO, STR3, 1,  "<sp> YYYYMMDDHHMMSS [ <sp> path-name ]" },
    { "INDEX", INDEX, STR1, 1,  "<sp> pattern" },
    { "EXEC",  EXEC,  STR1, 1,  "<sp> command [ <sp> arguments ]" },
    { "ALIAS", ALIAS, OSTR, 1,  "[ <sp> alias ] " },
    { "CDPATH", CDPATH, OSTR, 1,  "[ <sp> ] " },
    { "GROUPS", GROUPS, OSTR, 1,  "[ <sp> ] " },
    { NULL,    0,     0,    0,  0 }
};

struct tab *
lookup(p, cmd)
    register struct tab *p;
    char *cmd;
{

    for (; p->name != NULL; p++)
        if (strcmp(cmd, p->name) == 0)
            return (p);
    return (0);
}

#include <arpa/telnet.h>

/*
 * getline - a hacked up version of fgets to ignore TELNET escape codes.
 */
char *
getline(s, n, iop)
    char *s;
    register FILE *iop;
{
    register c;
    register char *cs;

    cs = s;
/* tmpline may contain saved command from urgent mode interruption */
    for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) {
        *cs++ = tmpline[c];
        if (tmpline[c] == '\n') {
            *cs++ = '\0';
            if (debug)
                syslog(LOG_DEBUG, "command: %s", s);
            tmpline[0] = '\0';
            return(s);
        }
        if (c == 0)
            tmpline[0] = '\0';
    }
    while ((c = getc(iop)) != EOF) {
        c &= 0377;
        if (c == IAC) {
            if ((c = getc(iop)) != EOF) {
            c &= 0377;
            switch (c) {
            case WILL:
            case WONT:
                c = getc(iop);
                printf("%c%c%c", IAC, DONT, 0377&c);
                (void) fflush(stdout);
                continue;
            case DO:
            case DONT:
                c = getc(iop);
                printf("%c%c%c", IAC, WONT, 0377&c);
                (void) fflush(stdout);
                continue;
            case IAC:
                break;
            default:
                continue;   /* ignore command */
            }
            }
        }
        *cs++ = c;
        if (--n <= 0 || c == '\n')
            break;
    }
    if (c == EOF && cs == s)
        return (NULL);
    *cs++ = '\0';
    if (debug)
        syslog(LOG_DEBUG, "command: %s", s);
    return (s);
}

static void
toolong()
{
    time_t now;

    reply(421,
      "Timeout (%d seconds): closing control connection.", timeout);
    (void) time(&now);
    if (logging) {
        syslog(LOG_INFO,
            "User %s timed out after %d seconds at %.24s",
            (pw ? pw -> pw_name : "unknown"), timeout, ctime(&now));
    }
    dologout(1);
}

yylex()
{
    static int cpos, state;
    register char *cp, *cp2;
    register struct tab *p;
    int n;
    char c, *copy();

    for (;;) {
        switch (state) {

        case CMD:
            (void) signal(SIGALRM, toolong);
            (void) alarm((unsigned) timeout);
            if (is_shutdown(!logged_in) != 0) {
                reply(221, "Server shutting down.  Goodbye.");
                dologout(0);
            }
#ifdef SETPROCTITLE
            setproctitle("%s: IDLE", proctitle);
#endif
            if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) {
                reply(221, "You could at least say goodbye.");
                dologout(0);
            }
            (void) alarm(0);
#ifdef SETPROCTITLE
            if (strncasecmp(cbuf, "PASS", 4) != 0 &&
                strncasecmp(cbuf, "SITE GPASS", 10) != 0)
                setproctitle("%s: %s", proctitle, cbuf);
#endif /* SETPROCTITLE */
            if ((cp = strchr(cbuf, '\r'))) {
                *cp++ = '\n';
                *cp = '\0';
            }
            if ((cp = strpbrk(cbuf, " \n")))
                cpos = cp - cbuf;
            if (cpos == 0)
                cpos = 4;
            c = cbuf[cpos];
            cbuf[cpos] = '\0';
            upper(cbuf);
            p = lookup(cmdtab, cbuf);
            cbuf[cpos] = c;
            if (p != 0) {
                if (p->implemented == 0) {
                    nack(p->name);
                    longjmp(errcatch,0);
                    /* NOTREACHED */
                }
                state = p->state;
                yylval.String = p->name;
                return (p->token);
            }
            break;

        case SITECMD:
            if (cbuf[cpos] == ' ') {
                cpos++;
                return (SP);
            }
            cp = &cbuf[cpos];
            if ((cp2 = strpbrk(cp, " \n")))
                cpos = cp2 - cbuf;
            c = cbuf[cpos];
            cbuf[cpos] = '\0';
            upper(cp);
            p = lookup(sitetab, cp);
            cbuf[cpos] = c;
            if (p != 0) {
                if (p->implemented == 0) {
                    state = CMD;
                    nack(p->name);
                    longjmp(errcatch,0);
                    /* NOTREACHED */
                }
                state = p->state;
                yylval.String = p->name;
                return (p->token);
            }
            state = CMD;
            break;

        case OSTR:
            if (cbuf[cpos] == '\n') {
                state = CMD;
                return (CRLF);
            }
            /* FALLTHROUGH */

        case STR1:
        case ZSTR1:
        dostr1:
            if (cbuf[cpos] == ' ') {
                cpos++;
                state = state == OSTR ? STR2 : ++state;
                return (SP);
            }
            break;

        case ZSTR2:
            if (cbuf[cpos] == '\n') {
                state = CMD;
                return (CRLF);
            }
            /* FALLTHROUGH */

        case STR2:
            cp = &cbuf[cpos];
            n = strlen(cp);
            cpos += n - 1;
            /*
             * Make sure the string is nonempty and \n terminated.
             */
            if (n > 1 && cbuf[cpos] == '\n') {
                cbuf[cpos] = '\0';
                yylval.String = copy(cp);
                cbuf[cpos] = '\n';
                state = ARGS;
                return (STRING);
            }
            break;

        case NSTR:
            if (cbuf[cpos] == ' ') {
                cpos++;
                return (SP);
            }
            if (isdigit(cbuf[cpos])) {
                cp = &cbuf[cpos];
                while (isdigit(cbuf[++cpos]))
                    ;
                c = cbuf[cpos];
                cbuf[cpos] = '\0';
                yylval.Number = atoi(cp);
                cbuf[cpos] = c;
                state = STR1;
                return (NUMBER);
            }
            state = STR1;
            goto dostr1;

        case STR3:
            if (cbuf[cpos] == ' ') {
                cpos++;
                return (SP);
            }

            cp = &cbuf[cpos];
            cp2 = strpbrk(cp, " \n");
            if (cp2 != NULL) {
                c = *cp2;
                *cp2 = '\0';
            }
            n = strlen(cp);
            cpos += n;
            /*
             * Make sure the string is nonempty and SP terminated.
             */
            if ((cp2 - cp) > 1) {
                yylval.String = copy(cp);
                cbuf[cpos] = c;
                state = OSTR;
                return (STRING);
            }
            break;

        case ARGS:
            if (isdigit(cbuf[cpos])) {
                cp = &cbuf[cpos];
                while (isdigit(cbuf[++cpos]))
                    ;
                c = cbuf[cpos];
                cbuf[cpos] = '\0';
                yylval.Number = atoi(cp);
                cbuf[cpos] = c;
                return (NUMBER);
            }
            switch (cbuf[cpos++]) {

            case '\n':
                state = CMD;
                return (CRLF);

            case ' ':
                return (SP);

            case ',':
                return (COMMA);

            case 'A':
            case 'a':
                return (A);

            case 'B':
            case 'b':
                return (B);

            case 'C':
            case 'c':
                return (C);

            case 'E':
            case 'e':
                return (E);

            case 'F':
            case 'f':
                return (F);

            case 'I':
            case 'i':
                return (I);

            case 'L':
            case 'l':
                return (L);

            case 'N':
            case 'n':
                return (N);

            case 'P':
            case 'p':
                return (P);

            case 'R':
            case 'r':
                return (R);

            case 'S':
            case 's':
                return (S);

            case 'T':
            case 't':
                return (T);

            }
            break;

        default:
            fatal("Unknown state in scanner.");
        }
        yyerror((char *)NULL);
        state = CMD;
        longjmp(errcatch,0);
    }
}

upper(s)
    register char *s;
{
    while (*s != '\0') {
        if (islower(*s))
            *s = toupper(*s);
        s++;
    }
}

char *
copy(s)
    char *s;
{
    char *p;

    p = malloc((unsigned) strlen(s) + 1);
    if (p == NULL)
        fatal("Ran out of memory.");
    (void) strcpy(p, s);
    return (p);
}

help(ctab, s)
    struct tab *ctab;
    char *s;
{
    register struct tab *c;
    register int width, NCMDS;
    char *type;

    if (ctab == sitetab)
        type = "SITE ";
    else
        type = "";
    width = 0, NCMDS = 0;
    for (c = ctab; c->name != NULL; c++) {
        int len = strlen(c->name);

        if (len > width)
            width = len;
        NCMDS++;
    }
    width = (width + 8) &~ 7;
    if (s == 0) {
        register int i, j, w;
        int columns, lines;

        lreply(214, "The following %scommands are recognized %s.",
            type, "(* =>'s unimplemented)");
        columns = 76 / width;
        if (columns == 0)
            columns = 1;
        lines = (NCMDS + columns - 1) / columns;
        for (i = 0; i < lines; i++) {
            printf("   ");
            for (j = 0; j < columns; j++) {
                c = ctab + j * lines + i;
                printf("%s%c", c->name,
                    c->implemented ? ' ' : '*');
                if (c + lines >= &ctab[NCMDS])
                    break;
                w = strlen(c->name) + 1;
                while (w < width) {
                    putchar(' ');
                    w++;
                }
            }
            printf("\r\n");
        }
        (void) fflush(stdout);
        reply(214, "Direct comments to ftp-bugs@%s.", hostname);
        return;
    }
    upper(s);
    c = lookup(ctab, s);
    if (c == (struct tab *)NULL) {
        reply(502, "Unknown command %s.", s);
        return;
    }
    if (c->implemented)
        reply(214, "Syntax: %s%s %s", type, c->name, c->help);
    else
        reply(214, "%s%-*s\t%s; unimplemented.", type, width,
            c->name, c->help);
}

sizecmd(filename)
char *filename;
{
    switch (type) {
    case TYPE_L:
    case TYPE_I: {
        struct stat stbuf;
        if (stat(filename, &stbuf) < 0 ||
            (stbuf.st_mode&S_IFMT) != S_IFREG)
            reply(550, "%s: not a plain file.", filename);
        else
            reply(213, "%lu", stbuf.st_size);
        break;}
    case TYPE_A: {
        FILE *fin;
        register int c;
        register long count;
        struct stat stbuf;
        fin = fopen(filename, "r");
        if (fin == NULL) {
            perror_reply(550, filename);
            return;
        }
        if (fstat(fileno(fin), &stbuf) < 0 ||
            (stbuf.st_mode&S_IFMT) != S_IFREG) {
            reply(550, "%s: not a plain file.", filename);
            (void) fclose(fin);
            return;
        }

        count = 0;
        while((c=getc(fin)) != EOF) {
            if (c == '\n')  /* will get expanded to \r\n */
                count++;
            count++;
        }
        (void) fclose(fin);

        reply(213, "%ld", count);
        break;}
    default:
        reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
    }
}

site_exec(cmd)
char *cmd;
{
    char buf[MAXPATHLEN];
    char *sp = (char *) strchr(cmd, ' '), *slash, *t;
    FILE *cmdf, *ftpd_popen();

    /* sanitize the command-string */
    
    if (sp == 0)  {
        while ((slash = strchr (cmd, '/')) != 0)
            cmd = slash + 1;
    } else {
        while (sp && (slash = (char *) strchr(cmd, '/')) 
               && (slash < sp))
            cmd = slash+1;
    }
    
    for (t = cmd;  *t && !isspace(*t);  t++) {
        if (isupper(*t)) {
            *t = tolower(*t);
        }
    }

    /* build the command */
    if (strlen(_PATH_EXECPATH) + strlen(cmd) + 1 > sizeof(buf))
        return;
    sprintf(buf, "%s/%s", _PATH_EXECPATH, cmd);

    cmdf = ftpd_popen(buf, "r", 0);
    if (!cmdf) {
        perror_reply(550, cmd);
        if (log_commands)
            syslog(LOG_INFO, "SITE EXEC (FAIL: %m): %s", cmd);
    } else {
        int lines = 0;

        lreply(200, cmd);
        while (fgets(buf, sizeof buf, cmdf)) {
            int len = strlen(buf);

            if (len>0 && buf[len-1]=='\n')
                buf[--len] = '\0';
            lreply(200, buf);
            if (++lines >= 20) {
                lreply(200, "*** Truncated ***");
                break;
            }
        }
        reply(200, " (end of '%s')", cmd);
        if (log_commands)
            syslog(LOG_INFO, "SITE EXEC (lines: %d): %s", lines, cmd);
        ftpd_pclose(cmdf);
    }
}

alias (s)
char *s;
{
    struct aclmember *entry = NULL;

    if (s != (char *)NULL) {
        while (getaclentry("alias", &entry) && ARG0 && ARG1 != NULL)
            if (!strcmp(ARG0, s)) {
                reply (214, "%s is an alias for %s.", ARG0, ARG1);
                return;
            }
        reply (502, "Unknown alias %s.", s);
        return;
    }

    lreply(214, "The following aliases are available.");

    while (getaclentry("alias", &entry) && ARG0 && ARG1 != NULL)
        printf ("   %-8s %s\r\n", ARG0, ARG1);
    (void) fflush (stdout);

    reply(214, "");
}

cdpath ()
{
    struct aclmember *entry = NULL;

    lreply(214, "The cdpath is:");
    while (getaclentry("cdpath", &entry) && ARG0 != NULL)
        printf ("  %s\r\n", ARG0);
    (void) fflush (stdout);
    reply(214, "");
}

void
print_groups()
{
    gid_t  groups[NGROUPS_MAX];
    int    ngroups = 0;

    if ( (ngroups = getgroups(NGROUPS_MAX, groups)) < 0 ) {
        return;
    }

    lreply(214, "Group membership is:");
    ngroups--;

    for (; ngroups >= 0; ngroups--)
        lreply(214, "  %d", groups[ngroups]);

    (void) fflush (stdout);
    reply(214, "");
}
short yyexca[] ={
-1, 1,
	0, -1,
	-2, 0,
	};
# define YYNPROD 86
# define YYLAST 391
short yyact[]={

  34, 137, 247, 245, 240, 129, 225, 224, 214, 198,
 129, 176,  91,  77, 103, 222, 243, 221,   4,   5,
 220, 219,  33,   6,   7,   8,   9,  10,  12,  13,
  14,  75,  73, 205, 194, 146, 106, 246,  11,  36,
  35,  19,  20,  18,  21,  16,  15,  28,  17,  22,
  23,  24,  25,  26,  27,  29, 111,  30,  31,  32,
 244, 235, 231, 230, 183, 210, 133, 112, 114, 113,
 115, 116, 117, 118, 119, 120, 121, 123, 122, 196,
 195, 168, 167, 160, 159, 156, 155, 142, 141, 105,
 104,  98,  97,  96,  95,  57,  56, 242, 241, 236,
 234, 233, 229, 228, 226, 223, 216, 212, 209, 208,
 207, 206, 193, 192, 191, 190, 189, 188, 187, 186,
 185, 184, 180, 175, 170, 169, 152, 178, 150, 140,
 139, 179, 134, 101, 132, 131, 130, 110, 109,  69,
  68,  65,  58,  54,  51,  40, 232, 227, 211, 204,
 203, 202, 201, 200, 199, 197, 136, 135, 127, 126,
 125, 124, 108, 107, 100,  99,  94,  93,  92,  89,
  90,  71,  63,  53,  44,  43,  42,  41,  88,  39,
  84,  38,  37,  79,  86,  85,  80,  74,  81,  82,
  72, 213, 128,  78, 177,  76,   3,   2,   1,  83,
  87, 102,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0, 143, 144, 145,   0,
   0,   0, 147, 148, 149,   0,   0,   0,   0, 151,
   0, 153, 154,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,  45,   0,   0,   0, 171, 172,
 173, 174,   0,   0,   0,   0,   0,   0,  46,  47,
  48,  49,  50,  52,   0, 138,  55,   0,   0,  59,
  60,  61,  62,   0,  64,   0,  66,  67,   0,   0,
  70,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
 182, 181,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0, 237,   0,   0,   0, 238, 239, 157, 158,   0,
 161, 162, 163, 164, 165, 166,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0, 218, 215,
 217 };
short yypact[]={

-1000,-256,-1000,-1000, -87, -88, -90,-125, -92, -93,
 -94, -95,-1000,-1000,-1000,-1000,-1000,-126,-1000, -96,
-127,-1000,-174,-128,-1000,-1000,-1000,-1000, -97,-1000,
-129,-1000,-1000,-130,-131,-1000, -98,-240,-241,-260,
-1000, -74, -81, -89,-261,-101,-102,-103,-176,-178,
-104,-1000,-105,-258,-1000,-180,-1000,-236,-1000,-106,
-107,-132,-133,-249,-108,-1000,-109,-110,-1000,-1000,
-111,-263,-134,-1000,-135,-1000,-136,-205,-138,-112,
-113,-1000,-268,-140,-1000,-1000,-1000,-141,-1000,-1000,
-1000,-182,-258,-258,-258,-1000,-237,-1000,-258,-258,
-258,-142,-1000,-1000,-1000,-258,-144,-258,-258,-1000,
-1000,-184,-1000,-1000,-186,-1000,-1000,-1000,-1000,-1000,
-1000,-188,-145,-146,-258,-258,-258,-258,-147,-1000,
-1000,-1000,-1000,-262,-1000,-137,-137,-263,-1000,-1000,
-1000,-1000,-202,-149,-150,-151,-152,-153,-154,-155,
-1000,-156,-1000,-157,-158,-1000,-238,-190,-114,-1000,
-264,-115,-116,-117,-118,-119,-120,-1000,-239,-1000,
-1000,-159,-160,-161,-162,-1000,-206,-1000,-1000,-1000,
-1000,-1000,-1000,-121,-1000,-1000,-1000,-1000,-1000,-1000,
-1000,-1000,-1000,-1000,-163,-1000,-265,-265,-164,-240,
-241,-251,-252,-255,-257,-165,-1000,-1000,-1000,-1000,
-266,-267,-1000,-166,-1000,-122,-1000,-167,-168,-207,
-123,-169,-170,-1000,-210,-171,-1000,-258,-1000,-1000,
-1000,-258,-258,-1000,-1000,-269,-1000,-172,-173,-254,
-211,-1000,-1000,-1000,-270,-234,-271,-1000 };
short yypgo[]={

   0, 187, 133, 201, 190, 192, 254, 194, 200, 191,
 199, 198, 197, 196, 195, 193 };
short yyr1[]={

   0,  11,  11,  11,  12,  12,  12,  12,  12,  12,
  12,  12,  12,  12,  12,  12,  12,  12,  12,  12,
  12,  12,  12,  12,  12,  12,  12,  12,  12,  12,
  12,  12,  12,  12,  12,  12,  12,  12,  12,  12,
  12,  12,  12,  12,  12,  12,  12,  12,  12,  12,
  12,  12,  12,  12,  13,  13,  13,  13,  13,  13,
   4,   1,   1,   5,  14,   7,   7,   7,  15,  15,
  15,  15,  15,  15,  15,  15,  10,  10,  10,   8,
   8,   8,   2,   3,   9,   6 };
short yyr2[]={

   0,   0,   2,   2,   4,   4,   4,   2,   4,   4,
   4,   4,   8,   5,   5,   5,   3,   5,   3,   5,
   5,   2,   5,   4,   2,   3,   5,   2,   4,   2,
   5,   5,   3,   3,   4,   6,   5,   7,   9,   4,
   6,   7,   7,   7,   9,   9,   7,   7,   5,   2,
   5,   5,   2,   2,   5,   4,   4,   6,   4,   4,
   1,   0,   1,   1,  11,   1,   1,   1,   1,   3,
   1,   3,   1,   1,   3,   2,   1,   1,   1,   1,
   1,   1,   1,   1,   1,   0 };
short yychk[]={

-1000, -11, -12, -13, 274, 275, 279, 280, 281, 282,
 283, 294, 284, 285, 286, 302, 301, 304, 299, 297,
 298, 300, 305, 306, 307, 308, 309, 310, 303, 311,
 313, 314, 315, 278, 256, 296, 295, 269, 269, 269,
 270, 269, 269, 269, 269,  -6,  -6,  -6,  -6,  -6,
  -6, 270,  -6, 269, 270,  -6, 270, 269, 270,  -6,
  -6,  -6,  -6, 269,  -6, 270,  -6,  -6, 270, 270,
  -6, 269,  -4, 272,  -1, 272, -14, 273, -15, 257,
 260, 262, 263, -10, 261, 266, 265,  -8, 267, 258,
 259, 273, 269, 269, 269, 270, 269, 270, 269, 269,
 269,  -2,  -3, 272, 270, 269, 272, 269, 269, 270,
 270, 305, 316, 318, 317, 319, 320, 321, 322, 323,
 324, 325, 327, 326, 269, 269, 269, 269,  -5, 273,
 270, 270, 270, 271, 270, 269, 269, 269,  -5, 270,
 270, 270, 269,  -2,  -2,  -2, 272,  -2,  -2,  -2,
 270,  -2, 270,  -2,  -2, 270, 269,  -6,  -6, 270,
 269,  -6,  -6,  -6,  -6,  -6,  -6, 270, 269, 270,
 270,  -2,  -2,  -2,  -2, 270, 273,  -7, 264, 268,
 259,  -7,  -5, 266, 270, 270, 270, 270, 270, 270,
 270, 270, 270, 270, 272, 270, 269, 269, 273, 269,
 269, 269, 269, 269, 269, 272, 270, 270, 270, 270,
 271, 269, 270,  -9, 273,  -9, 270,  -4,  -1, 272,
 272, 272, 272, 270, 273, 273, 270, 269, 270, 270,
 270, 269, 269, 270, 270, 271, 270,  -2,  -2,  -2,
 273, 270, 270, 270, 271, 273, 271, 273 };
short yydef[]={

   1,  -2,   2,   3,   0,   0,   0,   0,   0,   0,
   0,   0,  85,  85,  85,  85,  85,  85,  85,   0,
   0,  85,   0,   0,  85,  85,  85,  85,   0,  85,
   0,  85,  85,   0,   0,  85,   0,   0,  61,   0,
   7,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,  21,   0,   0,  24,   0,  27,   0,  29,   0,
   0,   0,   0,   0,   0,  49,   0,   0,  52,  53,
   0,   0,   0,  60,   0,  62,   0,   0,   0,  68,
  70,  72,  73,   0,  76,  77,  78,   0,  79,  80,
  81,   0,   0,   0,   0,  16,   0,  18,   0,   0,
   0,   0,  82,  83,  25,   0,   0,   0,   0,  32,
  33,   0,  85,  85,   0,  85,  85,  85,  85,  85,
  85,   0,   0,   0,   0,   0,   0,   0,   0,  63,
   4,   5,   6,   0,   8,   0,   0,   0,  75,   9,
  10,  11,   0,   0,   0,   0,   0,   0,   0,   0,
  23,   0,  28,   0,   0,  34,   0,   0,   0,  39,
   0,   0,   0,   0,   0,   0,   0,  56,   0,  58,
  59,   0,   0,   0,   0,  55,   0,  69,  65,  66,
  67,  71,  74,   0,  13,  14,  15,  17,  19,  20,
  22,  26,  30,  31,   0,  36,   0,   0,   0,   0,
  61,   0,   0,   0,   0,   0,  48,  50,  51,  54,
   0,   0,  35,   0,  84,   0,  40,   0,   0,   0,
   0,   0,   0,  57,   0,   0,  37,   0,  41,  42,
  43,   0,   0,  46,  47,   0,  12,   0,   0,   0,
   0,  38,  44,  45,   0,   0,   0,  64 };
#ifndef lint
static char yaccpar_sccsid[] = "@(#)yaccpar	4.1	(Berkeley)	2/11/83";
#endif

#
# define YYFLAG -1000
# define YYERROR goto yyerrlab
# define YYACCEPT return(0)
# define YYABORT return(1)

/*	parser for yacc output	*/

#ifdef YYDEBUG
int yydebug = 0; /* 1 for debugging */
#endif
YYSTYPE yyv[YYMAXDEPTH]; /* where the values are stored */
int yychar = -1; /* current input token number */
int yynerrs = 0;  /* number of errors */
short yyerrflag = 0;  /* error recovery flag */

yyparse() {

	short yys[YYMAXDEPTH];
	short yyj, yym;
	register YYSTYPE *yypvt;
	register short yystate, *yyps, yyn;
	register YYSTYPE *yypv;
	register short *yyxi;

	yystate = 0;
	yychar = -1;
	yynerrs = 0;
	yyerrflag = 0;
	yyps= &yys[-1];
	yypv= &yyv[-1];

 yystack:    /* put a state and value onto the stack */

#ifdef YYDEBUG
	if( yydebug  ) printf( "state %d, char 0%o\n", yystate, yychar );
#endif
		if( ++yyps> &yys[YYMAXDEPTH] ) { yyerror( "yacc stack overflow" ); return(1); }
		*yyps = yystate;
		++yypv;
		*yypv = yyval;

 yynewstate:

	yyn = yypact[yystate];

	if( yyn<= YYFLAG ) goto yydefault; /* simple state */

	if( yychar<0 ) if( (yychar=yylex())<0 ) yychar=0;
	if( (yyn += yychar)<0 || yyn >= YYLAST ) goto yydefault;

	if( yychk[ yyn=yyact[ yyn ] ] == yychar ){ /* valid shift */
		yychar = -1;
		yyval = yylval;
		yystate = yyn;
		if( yyerrflag > 0 ) --yyerrflag;
		goto yystack;
		}

 yydefault:
	/* default state action */

	if( (yyn=yydef[yystate]) == -2 ) {
		if( yychar<0 ) if( (yychar=yylex())<0 ) yychar = 0;
		/* look through exception table */

		for( yyxi=yyexca; (*yyxi!= (-1)) || (yyxi[1]!=yystate) ; yyxi += 2 ) ; /* VOID */

		while( *(yyxi+=2) >= 0 ){
			if( *yyxi == yychar ) break;
			}
		if( (yyn = yyxi[1]) < 0 ) return(0);   /* accept */
		}

	if( yyn == 0 ){ /* error */
		/* error ... attempt to resume parsing */

		switch( yyerrflag ){

		case 0:   /* brand new error */

			yyerror( "syntax error" );
		yyerrlab:
			++yynerrs;

		case 1:
		case 2: /* incompletely recovered error ... try again */

			yyerrflag = 3;

			/* find a state where "error" is a legal shift action */

			while ( yyps >= yys ) {
			   yyn = yypact[*yyps] + YYERRCODE;
			   if( yyn>= 0 && yyn < YYLAST && yychk[yyact[yyn]] == YYERRCODE ){
			      yystate = yyact[yyn];  /* simulate a shift of "error" */
			      goto yystack;
			      }
			   yyn = yypact[*yyps];

			   /* the current yyps has no shift onn "error", pop stack */

#ifdef YYDEBUG
			   if( yydebug ) printf( "error recovery pops state %d, uncovers %d\n", *yyps, yyps[-1] );
#endif
			   --yyps;
			   --yypv;
			   }

			/* there is no state on the stack with an error shift ... abort */

	yyabort:
			return(1);


		case 3:  /* no shift yet; clobber input char */

#ifdef YYDEBUG
			if( yydebug ) printf( "error recovery discards char %d\n", yychar );
#endif

			if( yychar == 0 ) goto yyabort; /* don't discard EOF, quit */
			yychar = -1;
			goto yynewstate;   /* try again in the same state */

			}

		}

	/* reduction by production yyn */

#ifdef YYDEBUG
		if( yydebug ) printf("reduce %d\n",yyn);
#endif
		yyps -= yyr2[yyn];
		yypvt = yypv;
		yypv -= yyr2[yyn];
		yyval = yypv[1];
		yym=yyn;
			/* consult goto table to find next state */
		yyn = yyr1[yyn];
		yyj = yypgo[yyn] + *yyps + 1;
		if( yyj>=YYLAST || yychk[ yystate = yyact[yyj] ] != -yyn ) yystate = yyact[yypgo[yyn]];
		switch(yym){
			
case 2:
# line 143 "ftpcmd.y"
 {
            fromname = 0;
            restart_point = 0;
        } break;
case 4:
# line 151 "ftpcmd.y"
 {
            user(yypvt[-1].String);
            if (log_commands) syslog(LOG_INFO, "USER %s", yypvt[-1].String);
            free(yypvt[-1].String);
        } break;
case 5:
# line 157 "ftpcmd.y"
 {
            if (log_commands)
                if (anonymous)
                    syslog(LOG_INFO, "PASS %s", yypvt[-1].String);
                else
                    syslog(LOG_INFO, "PASS password");

            pass(yypvt[-1].String);
            free(yypvt[-1].String);
        } break;
case 6:
# line 168 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "PORT");
            usedefault = 0;
            if (pdata >= 0) {
                (void) close(pdata);
                pdata = -1;
            }
            reply(200, "PORT command successful.");
        } break;
case 7:
# line 178 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "PASV");
            passive();
        } break;
case 8:
# line 183 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "TYPE %s", typenames[cmd_type]);
            switch (cmd_type) {

            case TYPE_A:
                if (cmd_form == FORM_N) {
                    reply(200, "Type set to A.");
                    type = cmd_type;
                    form = cmd_form;
                } else
                    reply(504, "Form must be N.");
                break;

            case TYPE_E:
                reply(504, "Type E not implemented.");
                break;

            case TYPE_I:
                reply(200, "Type set to I.");
                type = cmd_type;
                break;

            case TYPE_L:
#if NBBY == 8
                if (cmd_bytesz == 8) {
                    reply(200,
                        "Type set to L (byte size 8).");
                    type = cmd_type;
                } else
                    reply(504, "Byte size must be 8.");
#else /* NBBY == 8 */
                UNIMPLEMENTED for NBBY != 8
#endif /* NBBY == 8 */
            }
        } break;
case 9:
# line 219 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "STRU %s", strunames[yypvt[-1].Number]);
            switch (yypvt[-1].Number) {

            case STRU_F:
                reply(200, "STRU F ok.");
                break;

            default:
                reply(504, "Unimplemented STRU type.");
            }
        } break;
case 10:
# line 232 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "MODE %s", modenames[yypvt[-1].Number]);
            switch (yypvt[-1].Number) {

            case MODE_S:
                reply(200, "MODE S ok.");
                break;

            default:
                reply(502, "Unimplemented MODE type.");
            }
        } break;
case 11:
# line 245 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "ALLO %d", yypvt[-1].Number);
            reply(202, "ALLO command ignored.");
        } break;
case 12:
# line 250 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "ALLO %d R %d", yypvt[-5].Number, yypvt[-1].Number);
            reply(202, "ALLO command ignored.");
        } break;
case 13:
# line 255 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "RETR %s", yypvt[-1].String);
            if (yypvt[-3].Number && yypvt[-1].String != NULL)
                retrieve((char *) NULL, yypvt[-1].String);
            if (yypvt[-1].String != NULL)
                free(yypvt[-1].String);
        } break;
case 14:
# line 263 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "STOR %s", yypvt[-1].String);
            if (yypvt[-3].Number && yypvt[-1].String != NULL)
                store(yypvt[-1].String, "w", 0);
            if (yypvt[-1].String != NULL)
                free(yypvt[-1].String);
        } break;
case 15:
# line 271 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "APPE %s", yypvt[-1].String);
            if (yypvt[-3].Number && yypvt[-1].String != NULL)
                store(yypvt[-1].String, "a", 0);
            if (yypvt[-1].String != NULL)
                free(yypvt[-1].String);
        } break;
case 16:
# line 279 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "NLST");
            if (yypvt[-1].Number)
                send_file_list(".");
        } break;
case 17:
# line 285 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "NLST %s", yypvt[-1].String);
            if (yypvt[-3].Number && yypvt[-1].String) {
                send_file_list(yypvt[-1].String);
                free(yypvt[-1].String);
            }
        } break;
case 18:
# line 293 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "LIST");
            if (yypvt[-1].Number)
        if (anonymous && dolreplies)
                retrieve(ls_long, "");
            else
                retrieve(ls_short, "");
        } break;
case 19:
# line 302 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "LIST %s", yypvt[-1].String);
            if (yypvt[-3].Number && yypvt[-1].String != NULL)
        if (anonymous && dolreplies)
                retrieve(ls_long, yypvt[-1].String);
            else
                retrieve(ls_short, yypvt[-1].String);
            if (yypvt[-1].String != NULL)
                free(yypvt[-1].String);
        } break;
case 20:
# line 313 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "STAT %s", yypvt[-1].String);
            if (yypvt[-3].Number && yypvt[-1].String != NULL)
                statfilecmd(yypvt[-1].String);
            if (yypvt[-1].String != NULL)
                free(yypvt[-1].String);
        } break;
case 21:
# line 321 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "STAT");
            statcmd();
        } break;
case 22:
# line 326 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "DELE %s", yypvt[-1].String);
            if (yypvt[-3].Number && yypvt[-1].String != NULL)
                delete(yypvt[-1].String);
            if (yypvt[-1].String != NULL)
                free(yypvt[-1].String);
        } break;
case 23:
# line 334 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "RNTO %s", yypvt[-1].String);
            if (fromname) {
                renamecmd(fromname, yypvt[-1].String);
                free(fromname);
                fromname = (char *) NULL;
            } else {
                reply(503, "Bad sequence of commands.");
            }
            free(yypvt[-1].String);
        } break;
case 24:
# line 346 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "ABOR");
            reply(225, "ABOR command successful.");
        } break;
case 25:
# line 351 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "CWD");
            if (yypvt[-1].Number)
                cwd(pw->pw_dir);
        } break;
case 26:
# line 357 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "CWD %s", yypvt[-1].String);
            if (yypvt[-3].Number && yypvt[-1].String != NULL)
                cwd(yypvt[-1].String);
            if (yypvt[-1].String != NULL)
                free(yypvt[-1].String);
        } break;
case 27:
# line 365 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "HELP");
            help(cmdtab, (char *) NULL);
        } break;
case 28:
# line 370 "ftpcmd.y"
 {
            register char *cp = (char *)yypvt[-1].String;

            if (log_commands) syslog(LOG_INFO, "HELP %s", yypvt[-1].String);
            if (strncasecmp(cp, "SITE", 4) == 0) {
                cp = (char *)yypvt[-1].String + 4;
                if (*cp == ' ')
                    cp++;
                if (*cp)
                    help(sitetab, cp);
                else
                    help(sitetab, (char *) NULL);
            } else
                help(cmdtab, yypvt[-1].String);
        } break;
case 29:
# line 386 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "NOOP");
            reply(200, "NOOP command successful.");
        } break;
case 30:
# line 391 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "MKD %s", yypvt[-1].String);
            if (yypvt[-3].Number && yypvt[-1].String != NULL)
                makedir(yypvt[-1].String);
            if (yypvt[-1].String != NULL)
                free(yypvt[-1].String);
        } break;
case 31:
# line 399 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "RMD %s", yypvt[-1].String);
            if (yypvt[-3].Number && yypvt[-1].String != NULL)
                removedir(yypvt[-1].String);
            if (yypvt[-1].String != NULL)
                free(yypvt[-1].String);
        } break;
case 32:
# line 407 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "PWD");
            if (yypvt[-1].Number)
                pwd();
        } break;
case 33:
# line 413 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "CDUP");
            if (yypvt[-1].Number)
                cwd("..");
        } break;
case 34:
# line 419 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "SITE HELP");
            help(sitetab, (char *) NULL);
        } break;
case 35:
# line 424 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "SITE HELP %s", yypvt[-1].String);
            help(sitetab, yypvt[-1].String);
        } break;
case 36:
# line 429 "ftpcmd.y"
 {
            mode_t oldmask;

            if (log_commands) syslog(LOG_INFO, "SITE UMASK");
            if (yypvt[-1].Number) {
                oldmask = umask(0);
                (void) umask(oldmask);
                reply(200, "Current UMASK is %03o", oldmask);
            }
        } break;
case 37:
# line 440 "ftpcmd.y"
 {
            mode_t oldmask;
            struct aclmember *entry = NULL;
            int ok = 1;

            if (log_commands) syslog(LOG_INFO, "SITE UMASK %d", yypvt[-1].Number);
            if (yypvt[-3].Number) {
                /* check for umask permission */
                while (getaclentry("umask", &entry) && ARG0 && ARG1 != NULL) {
                    if (type_match(ARG1)) 
                        if (*ARG0 == 'n')  ok = 0;
                }
                if (ok) {
                    if ((yypvt[-1].Number == -1) || (yypvt[-1].Number > 0777)) {
                        reply(501, "Bad UMASK value");
                    } else {
                        oldmask = umask((mode_t)yypvt[-1].Number);
                        reply(200, "UMASK set to %03o (was %03o)", yypvt[-1].Number, oldmask);
                    }
                } else 
                    reply(553, "Permission denied. (umask)");
            }
        } break;
case 38:
# line 464 "ftpcmd.y"
 {
            struct aclmember *entry = NULL;
            int ok = 1;

            if (log_commands) syslog(LOG_INFO, "SITE CHMOD %d %s", yypvt[-3].Number, yypvt[-1].String);
            if (yypvt[-5].Number && yypvt[-3].Number && yypvt[-1].String) {
                /* check for chmod permission */
                while (getaclentry("chmod", &entry) && ARG0 && ARG1 != NULL) {
                    if (type_match(ARG1)) 
                        if (*ARG0 == 'n')  ok = 0;
                }
                if (ok) {
                    if (yypvt[-3].Number > 0777)
                        reply(501, 
                            "CHMOD: Mode value must be between 0 and 0777");
                    else if (chmod(yypvt[-1].String, (mode_t) yypvt[-3].Number) < 0)
                        perror_reply(550, yypvt[-1].String);
                    else
                        reply(200, "CHMOD command successful.");
                    free(yypvt[-1].String);
                } else
                    reply(553, "Permission denied. (chmod)");
            }
        } break;
case 39:
# line 489 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "SITE IDLE");
            reply(200,
                "Current IDLE time limit is %d seconds; max %d",
                timeout, maxtimeout);
        } break;
case 40:
# line 496 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "SITE IDLE %d", yypvt[-1].Number);
            if (yypvt[-1].Number < 30 || yypvt[-1].Number > maxtimeout) {
                reply(501,
            "Maximum IDLE time must be between 30 and %d seconds",
                    maxtimeout);
            } else {
                timeout = yypvt[-1].Number;
                (void) alarm((unsigned) timeout);
                reply(200, "Maximum IDLE time set to %d seconds", timeout);
            }
        } break;
case 41:
# line 509 "ftpcmd.y"
 {
#ifndef NO_PRIVATE
            if (log_commands) syslog(LOG_INFO, "SITE GROUP %s", yypvt[-1].String);
            if (yypvt[-3].Number && yypvt[-1].String) priv_group(yypvt[-1].String);
            free(yypvt[-1].String);
#endif /* !NO_PRIVATE */
        } break;
case 42:
# line 517 "ftpcmd.y"
 {
#ifndef NO_PRIVATE
            if (log_commands) syslog(LOG_INFO, "SITE GPASS password");
            if (yypvt[-3].Number && yypvt[-1].String) priv_gpass(yypvt[-1].String);
            free(yypvt[-1].String);
#endif /* !NO_PRIVATE */
        } break;
case 43:
# line 525 "ftpcmd.y"
 {
            if (yypvt[-3].Number && yypvt[-1].String) newer(yypvt[-1].String, ".", 0);
            free(yypvt[-1].String);
        } break;
case 44:
# line 530 "ftpcmd.y"
 {
            if (yypvt[-5].Number && yypvt[-3].String && yypvt[-1].String) newer(yypvt[-3].String, yypvt[-1].String, 0);
            free(yypvt[-3].String);
            free(yypvt[-1].String);
        } break;
case 45:
# line 536 "ftpcmd.y"
 {
            if (yypvt[-5].Number && yypvt[-3].String && yypvt[-1].String) newer(yypvt[-3].String, yypvt[-1].String, 1);
            free(yypvt[-3].String);
            free(yypvt[-1].String);
        } break;
case 46:
# line 542 "ftpcmd.y"
 {
            /* this is just for backward compatibility since we
             * thought of INDEX before we thought of EXEC
             */
            if (yypvt[-3].Number != 0 && yypvt[-1].String != NULL) {
                char buf[MAXPATHLEN];
                if (strlen(yypvt[-1].String) + 7 <= sizeof(buf)) {
                    sprintf(buf, "index %s", (char*)yypvt[-1].String);
                    (void) site_exec(buf);
                }
            }
        } break;
case 47:
# line 555 "ftpcmd.y"
 {
            if (yypvt[-3].Number != 0 && yypvt[-1].String != NULL) {
                (void) site_exec((char*)yypvt[-1].String);
            }
        } break;
case 48:
# line 561 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "STOU %s", yypvt[-1].String);
            if (yypvt[-3].Number && yypvt[-1].String) {
                store(yypvt[-1].String, "w", 1);
                free(yypvt[-1].String);
            }
        } break;
case 49:
# line 569 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "SYST");
#ifdef unix
#ifdef BSD
            reply(215, "UNIX Type: L%d Version: BSD-%d",
                NBBY, BSD);
#else  /* BSD */
            reply(215, "UNIX Type: L%d", NBBY);
#endif /* BSD */
#else  /* unix */
            reply(215, "UNKNOWN Type: L%d", NBBY);
#endif /* unix */
        } break;
case 50:
# line 591 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "SIZE %s", yypvt[-1].String);
            if (yypvt[-3].Number && yypvt[-1].String) {
                sizecmd(yypvt[-1].String);
                free(yypvt[-1].String);
            }
        } break;
case 51:
# line 609 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "MDTM %s", yypvt[-1].String);
            if (yypvt[-3].Number && yypvt[-1].String) {
                struct stat stbuf;

                if (stat(yypvt[-1].String, &stbuf) < 0)
                    perror_reply(550, yypvt[-1].String);
                else if ((stbuf.st_mode&S_IFMT) != S_IFREG) {
                    reply(550, "%s: not a plain file.",
                        yypvt[-1].String);
                } else {
                    register struct tm *t;
                    struct tm *gmtime();
                    t = gmtime(&stbuf.st_mtime);
                    reply(213,
                        "19%02d%02d%02d%02d%02d%02d",
                        t->tm_year, t->tm_mon+1, t->tm_mday,
                        t->tm_hour, t->tm_min, t->tm_sec);
                }
                free(yypvt[-1].String);
            }
        } break;
case 52:
# line 632 "ftpcmd.y"
 {
            if (log_commands) syslog(LOG_INFO, "QUIT");
            reply(221, "Goodbye.");
            dologout(0);
        } break;
case 53:
# line 638 "ftpcmd.y"
 {
            yyerrok;
        } break;
case 54:
# line 643 "ftpcmd.y"
 {
            char *renamefrom();

            if (log_commands) syslog(LOG_INFO, "RNFR %s", yypvt[-1].String);
            restart_point = (off_t) 0;
            if (yypvt[-3].Number && yypvt[-1].String) {
                fromname = renamefrom(yypvt[-1].String);
                if (fromname == 0 && yypvt[-1].String) {
                    free(yypvt[-1].String);
                }
            }
        } break;
case 55:
# line 656 "ftpcmd.y"
 {
            long atol();

            fromname = 0;
            restart_point = yypvt[-1].Number;
            if (log_commands) syslog(LOG_INFO, "REST %d", restart_point);
            reply(350, "Restarting at %ld. %s", restart_point,
                "Send STORE or RETRIEVE to initiate transfer.");
        } break;
case 56:
# line 667 "ftpcmd.y"
 {
           if (log_commands) syslog(LOG_INFO, "SITE ALIAS");
           alias ((char *)NULL);
        } break;
case 57:
# line 672 "ftpcmd.y"
 {
           if (log_commands) syslog(LOG_INFO, "SITE ALIAS %s", yypvt[-1].String);
           alias (yypvt[-1].String);
        } break;
case 58:
# line 677 "ftpcmd.y"
 {
           if (log_commands) syslog(LOG_INFO, "SITE GROUPS");
           print_groups () ;
        } break;
case 59:
# line 682 "ftpcmd.y"
 {
           if (log_commands) syslog(LOG_INFO, "SITE CDPATH");
           cdpath () ;
        } break;
case 61:
# line 692 "ftpcmd.y"
 {
            yyval.String = malloc(1);
            yyval.String[0] = '\0';
        } break;
case 64:
# line 704 "ftpcmd.y"
 {
            register char *a, *p;

            a = (char *)&data_dest.sin_addr;
            a[0] = yypvt[-10].Number; a[1] = yypvt[-8].Number; a[2] = yypvt[-6].Number; a[3] = yypvt[-4].Number;
            p = (char *)&data_dest.sin_port;
            p[0] = yypvt[-2].Number; p[1] = yypvt[-0].Number;
            data_dest.sin_family = AF_INET;
        } break;
case 65:
# line 716 "ftpcmd.y"
 {
        yyval.Number = FORM_N;
    } break;
case 66:
# line 720 "ftpcmd.y"
 {
        yyval.Number = FORM_T;
    } break;
case 67:
# line 724 "ftpcmd.y"
 {
        yyval.Number = FORM_C;
    } break;
case 68:
# line 730 "ftpcmd.y"
 {
        cmd_type = TYPE_A;
        cmd_form = FORM_N;
    } break;
case 69:
# line 735 "ftpcmd.y"
 {
        cmd_type = TYPE_A;
        cmd_form = yypvt[-0].Number;
    } break;
case 70:
# line 740 "ftpcmd.y"
 {
        cmd_type = TYPE_E;
        cmd_form = FORM_N;
    } break;
case 71:
# line 745 "ftpcmd.y"
 {
        cmd_type = TYPE_E;
        cmd_form = yypvt[-0].Number;
    } break;
case 72:
# line 750 "ftpcmd.y"
 {
        cmd_type = TYPE_I;
    } break;
case 73:
# line 754 "ftpcmd.y"
 {
        cmd_type = TYPE_L;
        cmd_bytesz = NBBY;
    } break;
case 74:
# line 759 "ftpcmd.y"
 {
        cmd_type = TYPE_L;
        cmd_bytesz = yypvt[-0].Number;
    } break;
case 75:
# line 765 "ftpcmd.y"
 {
        cmd_type = TYPE_L;
        cmd_bytesz = yypvt[-0].Number;
    } break;
case 76:
# line 772 "ftpcmd.y"
 {
        yyval.Number = STRU_F;
    } break;
case 77:
# line 776 "ftpcmd.y"
 {
        yyval.Number = STRU_R;
    } break;
case 78:
# line 780 "ftpcmd.y"
 {
        yyval.Number = STRU_P;
    } break;
case 79:
# line 786 "ftpcmd.y"
 {
        yyval.Number = MODE_S;
    } break;
case 80:
# line 790 "ftpcmd.y"
 {
        yyval.Number = MODE_B;
    } break;
case 81:
# line 794 "ftpcmd.y"
 {
        yyval.Number = MODE_C;
    } break;
case 82:
# line 800 "ftpcmd.y"
 {
        /*
         * Problem: this production is used for all pathname
         * processing, but only gives a 550 error reply.
         * This is a valid reply in some cases but not in others.
         */
        if (logged_in && yypvt[-0].String && strncmp(yypvt[-0].String, "~", 1) == 0) {
            yyval.String = *ftpglob(yypvt[-0].String);
            if (globerr) {
                reply(550, globerr);
                yyval.String = NULL;
            }
            free(yypvt[-0].String);
        } else
            yyval.String = yypvt[-0].String;
    } break;
case 84:
# line 822 "ftpcmd.y"
 {
        register int ret, dec, multby, digit;

        /*
         * Convert a number that was read as decimal number
         * to what it would be if it had been read as octal.
         */
        dec = yypvt[-0].Number;
        multby = 1;
        ret = 0;
        while (dec) {
            digit = dec%10;
            if (digit > 7) {
                ret = -1;
                break;
            }
            ret += digit * multby;
            multby *= 8;
            dec /= 10;
        }
        yyval.Number = ret;
    } break;
case 85:
# line 847 "ftpcmd.y"
 {
        if (logged_in)
            yyval.Number = 1;
        else {
            if (log_commands) syslog(LOG_INFO, "cmd failure - not logged in");
            reply(530, "Please login with USER and PASS.");
            yyval.Number = 0;
        }
    } break; 
		}
		goto yystack;  /* stack new state and value */

	}
