#include <sys/cdefs.h>
#ifndef lint
#if 0
static char yysccsid[] = "@(#)yaccpar	1.9 (Berkeley) 02/21/93";
#else
__IDSTRING(yyrcsid, "$NetBSD: skeleton.c,v 1.14 1997/10/20 03:41:16 lukem Exp $");
#endif
#endif
#include <stdlib.h>
#define YYBYACC 1
#define YYMAJOR 1
#define YYMINOR 9
#define YYLEX yylex()
#define YYEMPTY -1
#define yyclearin (yychar=(YYEMPTY))
#define yyerrok (yyerrflag=0)
#define YYRECOVERING (yyerrflag!=0)
#define YYPREFIX "yy"
#line 42 "ftpcmd.y"

#ifndef lint
#if 0
static char sccsid[] = "@(#)ftpcmd.y	8.3 (Berkeley) 4/6/94";
#endif
#endif /* not lint */

#if 0
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/libexec/ftpd/ftpcmd.y,v 1.64 2004/11/18 13:46:29 yar Exp $");
#endif

#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>

#include <netinet/in.h>
#include <arpa/ftp.h>

#include <ctype.h>
#include <errno.h>

#ifdef LINUX /* Linux port */
#include "bsdglob.h"
#else /* BSD source */
#include <glob.h>
#endif /* BSD source */

#include <limits.h>
#ifdef USE_MD5
#ifdef USE_SSL
#include "md5hl.h"
#else /* !USE_SSL */
#include <md5.h>
#endif /* USE_SSL */
#endif /* USE_MD5 */
#include <netdb.h>
#include <pwd.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>

#include "extern.h"
#include "pathnames.h"

#ifdef LINUX /* Linux port */
#include <libutil.h>
#endif /* Linux port */

#include <port_base.h>

#include "ssl_port_ftpd.h"
#ifdef USE_SSL
#include "sslapp.h"
extern	void do_ssl_start();
#endif /* USE_SSL */

extern	union sockunion data_dest, his_addr;
extern	int hostinfo;
extern	int logged_in;
extern	struct passwd *pw;
extern	int guest;
extern	char *homedir;
extern 	int ftpdparanoid;
extern	int logging;
extern	int type;
extern	int form;
extern	int ftpdebug;
extern	int timeout;
extern	int maxtimeout;
extern  int pdata;
extern	char *hostname;
extern	char proctitle[];
extern	int usedefault;
extern  char tmpline[];
extern	int readonly;
extern	int noepsv;
extern	int noretr;
extern	int noguestretr;
extern	char *typenames[]; /* defined in <arpa/ftp.h> included from ftpd.c */

off_t	restart_point;

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

extern	int epsvall;

#line 141 "ftpcmd.y"
typedef union {
	struct {
		off_t	o;
		int	i;
	} u;
	char   *s;
} YYSTYPE;
#line 126 "ftpcmd.c"
#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 ALL 269
#define SP 270
#define CRLF 271
#define COMMA 272
#define USER 273
#define PASS 274
#define ACCT 275
#define REIN 276
#define QUIT 277
#define PORT 278
#define PASV 279
#define TYPE 280
#define STRU 281
#define MODE 282
#define RETR 283
#define STOR 284
#define APPE 285
#define MLFL 286
#define MAIL 287
#define MSND 288
#define MSOM 289
#define MSAM 290
#define MRSQ 291
#define MRCP 292
#define ALLO 293
#define REST 294
#define RNFR 295
#define RNTO 296
#define ABOR 297
#define DELE 298
#define CWD 299
#define LIST 300
#define NLST 301
#define SITE 302
#define STAT 303
#define HELP 304
#define NOOP 305
#define MKD 306
#define RMD 307
#define PWD 308
#define CDUP 309
#define STOU 310
#define SMNT 311
#define SYST 312
#define SIZE 313
#define MDTM 314
#define LPRT 315
#define LPSV 316
#define EPRT 317
#define EPSV 318
#define UMASK 319
#define IDLE 320
#define CHMOD 321
#define MDFIVE 322
#define FEAT 323
#define OPTS 324
#define AUTH 325
#define PROT 326
#define PBSZ 327
#define LEXERR 328
#define NOTIMPL 329
#define SYNTERR 330
#define STRING 331
#define NUMBER 332
#define YYERRCODE 256
short yylhs[] = {                                        -1,
    0,    0,    0,   18,   18,   18,   18,   18,   18,   18,
   18,   18,   18,   18,   18,   18,   18,   18,   18,   18,
   18,   18,   18,   18,   18,   18,   18,   18,   18,   18,
   18,   18,   18,   18,   18,   18,   18,   18,   18,   18,
   18,   18,   18,   18,   18,   18,   18,   18,   18,   18,
   18,   18,   18,   18,   18,   18,   18,   18,   18,   18,
   18,   18,   18,   19,   19,   13,   12,   12,   16,   17,
    3,   15,   20,   21,   21,    9,    9,    9,    8,    8,
    8,    8,    8,    8,    8,    8,    6,    6,    6,    7,
    7,    7,   11,   10,    2,    1,    5,    4,   14,
};
short yylen[] = {                                         2,
    0,    2,    2,    4,    4,    5,    4,    4,    2,    5,
    5,    5,    3,    3,    5,    5,    3,    5,    5,    5,
    5,    9,    5,    5,    5,    3,    5,    3,    5,    5,
    3,    5,    5,    3,    3,    5,    2,    4,    2,    5,
    5,    3,    3,    4,    6,    7,    5,    7,    9,    5,
    7,    5,    3,    5,    5,    2,    4,    2,    1,    3,
    1,    3,    1,    5,    5,    1,    0,    1,    1,    1,
    1,    1,   11,   41,   17,    1,    1,    1,    1,    3,
    1,    3,    1,    1,    3,    2,    1,    1,    1,    1,
    1,    1,    1,    1,    1,    0,    0,    0,    0,
};
short yydefred[] = {                                      1,
    0,   63,    0,    0,    0,   96,   96,   96,   96,   96,
   96,   98,   98,   96,   96,   98,   98,   96,   98,   96,
   96,   96,    0,   96,    0,    0,   98,   98,   96,   96,
   98,   96,   96,   96,   96,   96,   97,   97,    0,    0,
    0,   99,    0,   59,   61,    2,    3,    0,    0,    9,
   58,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,   37,   39,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,   56,    0,    0,    0,    0,
   66,    0,   68,    0,    0,   13,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,   34,    0,    0,   35,
    0,   28,    0,   26,    0,   96,   98,   96,   60,   62,
    0,    0,   31,    0,    0,    0,   42,   43,    0,   53,
    0,    0,    0,   14,    0,    0,   17,    0,   69,    0,
    0,   72,    0,    7,    8,    0,    0,    0,    0,   83,
    0,    0,   87,   89,   88,    0,   91,   92,   90,    0,
   94,   93,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,   44,    0,    0,    0,    0,    0,
   38,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,   57,    4,   70,    0,    5,    0,   10,    0,    0,
    0,   71,   86,   18,   19,   20,   23,   24,   25,    0,
   21,   65,   64,   33,   32,   36,   29,   27,    0,    0,
   47,    0,    0,    0,   50,   30,   40,   41,   52,   54,
   55,    0,   11,   12,   16,   15,    6,    0,   78,   76,
   77,   80,   82,   85,    0,   45,   95,    0,    0,    0,
    0,    0,    0,    0,   48,    0,   46,   51,    0,    0,
    0,    0,    0,    0,   22,   49,    0,    0,    0,    0,
    0,    0,    0,    0,    0,   73,    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,   74,
};
short yydgoto[] = {                                       1,
   52,  248,  203,   58,   84,  156,  160,  152,  242,  162,
  163,   94,   92,   89,  143,  140,  195,   46,   47,  147,
  188,
};
short yysindex[] = {                                      0,
 -121,    0, -257, -220, -268,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0, -255,    0, -208, -254,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0, -229, -251,
 -226,    0, -222,    0,    0,    0,    0, -309, -278,    0,
    0, -214, -207, -204, -195, -190, -184, -177, -165, -164,
 -163, -162, -161, -182, -160, -199, -197, -186, -252, -180,
 -239,    0,    0, -159, -158, -157, -156, -154, -153, -151,
 -150, -149, -148, -146, -175,    0, -218, -206, -144, -215,
    0, -143,    0, -142, -202,    0, -181, -178, -249, -200,
 -200, -200, -198, -196, -200, -200,    0, -200, -200,    0,
 -200,    0, -200,    0, -173,    0,    0,    0,    0,    0,
 -188, -200,    0, -138, -200, -200,    0,    0, -200,    0,
 -200, -200, -194,    0, -192, -267,    0, -134,    0, -131,
 -189,    0, -127,    0,    0, -126, -124, -125, -122,    0,
 -264, -120,    0,    0,    0, -117,    0,    0,    0, -106,
    0,    0, -105, -104, -103, -171, -102, -100,  -81,  -73,
  -72,  -71,  -70, -119,    0, -169,  -63,  -60, -167,  -58,
    0,  -57,  -56,  -55,  -54,  -53, -123,  -52,  -51,  -50,
  -49,    0,    0,    0,  -48,    0, -108,    0, -248, -248,
 -107,    0,    0,    0,    0,    0,    0,    0,    0, -116,
    0,    0,    0,    0,    0,    0,    0,    0,  -45,  -98,
    0,  -98, -200,  -97,    0,    0,    0,    0,    0,    0,
    0,  -96,    0,    0,    0,    0,    0,  -61,    0,    0,
    0,    0,    0,    0,  -43,    0,    0,  -42,  -40,  -39,
  -38,  -44,  -95,  -94,    0, -200,    0,    0,  -93,  -41,
  -31,  -30,  -29,  -90,    0,    0,  -88,  -27,  -26,  -85,
  -84,  -23,  -22,  -80,  -79,    0,  -21,  -78,  -17,  -76,
  -15,  -74,  -13,  -69,  -12,  -68,  -11,  -67,  -10,  -66,
   -5,  -64,   -3,  -62,   -1,  -59,    2,  -47,    3,  -46,
    4,  -37,    5,  -36,    6,  -35,    0,
};
short yyrindex[] = {                                      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,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    1,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,  -33,    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,    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,    8,    9,    0,
   11,    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,
    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,    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,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,   12,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,
};
short yygindex[] = {                                      0,
   25,   59,   83,   10,  132,    0,    0,    0,   88,  -99,
 -101,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,
};
#define YYTABLESIZE 297
short yytable[] = {                                     164,
  165,  190,   51,  168,  169,  201,  170,  171,  157,  158,
  239,  172,   48,  173,   69,  240,   73,  159,   87,  241,
  180,   91,   59,  182,  183,   62,   63,  184,   65,  185,
  186,   53,   54,   55,   56,   57,   74,   75,   60,   61,
   78,   86,   64,   88,   66,   67,   68,   90,   70,   49,
   50,  115,   93,   76,   77,   95,   79,   80,   81,   82,
   83,   71,   72,   96,  191,   97,  116,  202,  117,  118,
  109,  110,  111,  112,   98,  148,  119,  120,  149,   99,
  150,  151,  153,  113,  114,  100,  154,  155,  107,  122,
  123,  124,  101,  121,  136,  137,  174,  175,  210,  211,
  220,  221,  224,  225,  102,  103,  104,  105,  106,  108,
  125,  126,  138,  127,  128,  129,  142,  130,  131,  132,
  133,  250,  134,  135,  139,  141,  177,  144,  145,  146,
  161,  179,  181,  166,    2,  167,  192,  187,  189,  193,
  176,  194,  178,  196,  199,  197,  198,  200,  232,  245,
  204,    3,    4,  205,  262,    5,    6,    7,    8,    9,
   10,   11,   12,   13,  206,  207,  208,  209,  212,   85,
  213,   14,   15,   16,   17,   18,   19,   20,   21,   22,
   23,   24,   25,   26,   27,   28,   29,   30,   31,  214,
   32,   33,   34,   35,   36,   37,   38,  215,  216,  217,
  218,   39,   40,   41,   42,   43,  222,   44,   45,  223,
  253,  219,  226,  227,  228,  229,  230,  231,  233,  234,
  235,  236,  237,  238,  202,  246,  254,  259,  255,  256,
  264,  257,  258,  247,  251,  252,  260,  261,  263,  265,
  266,  268,  267,  269,  270,  271,  272,  273,  274,  275,
  278,  276,  277,  279,  280,  281,  282,  283,  284,  286,
  288,  290,  285,  287,  289,  291,  292,  293,  294,  295,
  296,   67,  297,  298,  300,  302,  304,  306,   79,   81,
  249,   84,   75,  244,  299,  301,   96,  243,    0,    0,
    0,    0,    0,    0,  303,  305,  307,
};
short yycheck[] = {                                     101,
  102,  269,  271,  105,  106,  270,  108,  109,  258,  259,
  259,  111,  270,  113,  270,  264,  271,  267,  270,  268,
  122,  331,   13,  125,  126,   16,   17,  129,   19,  131,
  132,    7,    8,    9,   10,   11,   27,   28,   14,   15,
   31,  271,   18,  270,   20,   21,   22,  270,   24,  270,
  271,  304,  331,   29,   30,  270,   32,   33,   34,   35,
   36,  270,  271,  271,  332,  270,  319,  332,  321,  322,
  270,  271,  270,  271,  270,  257,  329,  330,  260,  270,
  262,  263,  261,  270,  271,  270,  265,  266,  271,  270,
  271,  331,  270,   69,  270,  271,  270,  271,  270,  271,
  270,  271,  270,  271,  270,  270,  270,  270,  270,  270,
  270,  270,  331,  271,  271,  270,  332,  271,  270,  270,
  270,  223,  271,  270,  331,  270,  117,  271,  271,  332,
  331,  320,  271,  332,  256,  332,  271,  332,  331,  271,
  116,  331,  118,  271,  270,  272,  271,  270,  272,  266,
  271,  273,  274,  271,  256,  277,  278,  279,  280,  281,
  282,  283,  284,  285,  271,  271,  271,  271,  271,   38,
  271,  293,  294,  295,  296,  297,  298,  299,  300,  301,
  302,  303,  304,  305,  306,  307,  308,  309,  310,  271,
  312,  313,  314,  315,  316,  317,  318,  271,  271,  271,
  271,  323,  324,  325,  326,  327,  270,  329,  330,  270,
  272,  331,  271,  271,  271,  271,  271,  271,  271,  271,
  271,  271,  271,  332,  332,  271,  270,  272,  271,  270,
  272,  271,  271,  332,  332,  332,  332,  332,  332,  271,
  271,  332,  272,  332,  272,  272,  332,  332,  272,  272,
  272,  332,  332,  332,  272,  332,  272,  332,  272,  272,
  272,  272,  332,  332,  332,  332,  272,  332,  272,  332,
  272,  271,  332,  272,  272,  272,  272,  272,  271,  271,
  222,  271,  271,  201,  332,  332,  320,  200,   -1,   -1,
   -1,   -1,   -1,   -1,  332,  332,  332,
};
#define YYFINAL 1
#ifndef YYDEBUG
#define YYDEBUG 0
#endif
#define YYMAXTOKEN 332
#if YYDEBUG
char *yyname[] = {
"end-of-file",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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"A","B","C","E","F","I","L","N",
"P","R","S","T","ALL","SP","CRLF","COMMA","USER","PASS","ACCT","REIN","QUIT",
"PORT","PASV","TYPE","STRU","MODE","RETR","STOR","APPE","MLFL","MAIL","MSND",
"MSOM","MSAM","MRSQ","MRCP","ALLO","REST","RNFR","RNTO","ABOR","DELE","CWD",
"LIST","NLST","SITE","STAT","HELP","NOOP","MKD","RMD","PWD","CDUP","STOU",
"SMNT","SYST","SIZE","MDTM","LPRT","LPSV","EPRT","EPSV","UMASK","IDLE","CHMOD",
"MDFIVE","FEAT","OPTS","AUTH","PROT","PBSZ","LEXERR","NOTIMPL","SYNTERR",
"STRING","NUMBER",
};
char *yyrule[] = {
"$accept : cmd_list",
"cmd_list :",
"cmd_list : cmd_list cmd",
"cmd_list : cmd_list rcmd",
"cmd : AUTH SP auth_type CRLF",
"cmd : PBSZ SP buffer_size CRLF",
"cmd : PROT check_login_apbu SP protection_level CRLF",
"cmd : USER SP username CRLF",
"cmd : PASS SP password CRLF",
"cmd : PASS CRLF",
"cmd : PORT check_login SP host_port CRLF",
"cmd : LPRT check_login SP host_long_port CRLF",
"cmd : EPRT check_login_epsv SP STRING CRLF",
"cmd : PASV check_login CRLF",
"cmd : LPSV check_login CRLF",
"cmd : EPSV check_login_epsv SP NUMBER CRLF",
"cmd : EPSV check_login_epsv SP ALL CRLF",
"cmd : EPSV check_login_epsv CRLF",
"cmd : TYPE check_login SP type_code CRLF",
"cmd : STRU check_login SP struct_code CRLF",
"cmd : MODE check_login SP mode_code CRLF",
"cmd : ALLO check_login SP NUMBER CRLF",
"cmd : ALLO check_login SP NUMBER SP R SP NUMBER CRLF",
"cmd : RETR check_login SP pathname CRLF",
"cmd : STOR check_login_ro SP pathname CRLF",
"cmd : APPE check_login_ro SP pathname CRLF",
"cmd : NLST check_login CRLF",
"cmd : NLST check_login SP pathstring CRLF",
"cmd : LIST check_login CRLF",
"cmd : LIST check_login SP pathstring CRLF",
"cmd : STAT check_login SP pathname CRLF",
"cmd : STAT check_login CRLF",
"cmd : DELE check_login_ro SP pathname CRLF",
"cmd : RNTO check_login_ro SP pathname CRLF",
"cmd : ABOR check_login CRLF",
"cmd : CWD check_login CRLF",
"cmd : CWD check_login SP pathname CRLF",
"cmd : HELP CRLF",
"cmd : HELP SP STRING CRLF",
"cmd : NOOP CRLF",
"cmd : MKD check_login_ro SP pathname CRLF",
"cmd : RMD check_login_ro SP pathname CRLF",
"cmd : PWD check_login CRLF",
"cmd : CDUP check_login CRLF",
"cmd : SITE SP HELP CRLF",
"cmd : SITE SP HELP SP STRING CRLF",
"cmd : SITE SP MDFIVE check_login SP pathname CRLF",
"cmd : SITE SP UMASK check_login CRLF",
"cmd : SITE SP UMASK check_login SP octal_number CRLF",
"cmd : SITE SP CHMOD check_login_ro SP octal_number SP pathname CRLF",
"cmd : SITE SP check_login IDLE CRLF",
"cmd : SITE SP check_login IDLE SP NUMBER CRLF",
"cmd : STOU check_login_ro SP pathname CRLF",
"cmd : SYST check_login CRLF",
"cmd : SIZE check_login SP pathname CRLF",
"cmd : MDTM check_login SP pathname CRLF",
"cmd : FEAT CRLF",
"cmd : OPTS SP STRING CRLF",
"cmd : QUIT CRLF",
"cmd : NOTIMPL",
"cmd : SITE SP NOTIMPL",
"cmd : SYNTERR",
"cmd : SITE SP SYNTERR",
"cmd : error",
"rcmd : RNFR check_login_ro SP pathname CRLF",
"rcmd : REST check_login SP NUMBER CRLF",
"username : STRING",
"password :",
"password : STRING",
"auth_type : STRING",
"protection_level : STRING",
"byte_size : NUMBER",
"buffer_size : NUMBER",
"host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER",
"host_long_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER",
"host_long_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER",
"form_code : N",
"form_code : T",
"form_code : C",
"type_code : A",
"type_code : A SP form_code",
"type_code : E",
"type_code : E SP form_code",
"type_code : I",
"type_code : L",
"type_code : L SP byte_size",
"type_code : L byte_size",
"struct_code : F",
"struct_code : R",
"struct_code : P",
"mode_code : S",
"mode_code : B",
"mode_code : C",
"pathname : pathstring",
"pathstring : STRING",
"octal_number : NUMBER",
"check_login :",
"check_login_epsv :",
"check_login_ro :",
"check_login_apbu :",
};
#endif
#ifdef YYSTACKSIZE
#undef YYMAXDEPTH
#define YYMAXDEPTH YYSTACKSIZE
#else
#ifdef YYMAXDEPTH
#define YYSTACKSIZE YYMAXDEPTH
#else
#define YYSTACKSIZE 10000
#define YYMAXDEPTH 10000
#endif
#endif
#define YYINITSTACKSIZE 200
int yydebug;
int yynerrs;
int yyerrflag;
int yychar;
short *yyssp;
YYSTYPE *yyvsp;
YYSTYPE yyval;
YYSTYPE yylval;
short *yyss;
short *yysslim;
YYSTYPE *yyvs;
int yystacksize;
#line 1252 "ftpcmd.y"

#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	/* optional 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	NOARGS	9	/* No arguments allowed */
#define	OARGS	10	/* optional miscellaneous arguments */

#define	MAXGLOBARGS	1000

#define	MAXASIZE	10240	/* Deny ASCII SIZE on files larger than that */

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

struct tab cmdtab[] = {		/* In order defined in related documents */
/* RFC 959 */
	{ "USER", USER, STR1, 1,	"<sp> username" },
	{ "PASS", PASS, ZSTR1, 1,	"[<sp> [password]]" },
	{ "ACCT", ACCT, STR1, 0,	"(specify account)" },
	{ "CWD",  CWD,  OSTR, 1,	"[ <sp> directory-name ]" },
	{ "CDUP", CDUP, NOARGS, 1,	"(change to parent directory)" },
	{ "SMNT", SMNT, ARGS, 0,	"(structure mount)" },
	{ "REIN", REIN, NOARGS, 0,	"(reinitialize server state)" },
	{ "QUIT", QUIT, NOARGS, 1,	"(terminate service)" },
	{ "PORT", PORT, ARGS, 1,	"<sp> b0, b1, b2, b3, b4, b5" },
	{ "PASV", PASV, NOARGS, 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" },
	{ "STOU", STOU, STR1, 1,	"<sp> file-name" },
	{ "APPE", APPE, STR1, 1,	"<sp> file-name" },
	{ "ALLO", ALLO, ARGS, 1,	"allocate storage (vacuously)" },
	{ "REST", REST, ARGS, 1,	"<sp> offset (restart command)" },
	{ "RNFR", RNFR, STR1, 1,	"<sp> file-name" },
	{ "RNTO", RNTO, STR1, 1,	"<sp> file-name" },
	{ "ABOR", ABOR, NOARGS, 1,	"(abort operation)" },
	{ "DELE", DELE, STR1, 1,	"<sp> file-name" },
	{ "RMD",  RMD,  STR1, 1,	"<sp> path-name" },
	{ "MKD",  MKD,  STR1, 1,	"<sp> path-name" },
	{ "PWD",  PWD,  NOARGS, 1,	"(return current directory)" },
	{ "LIST", LIST, OSTR, 1,	"[ <sp> path-name ]" },
	{ "NLST", NLST, OSTR, 1,	"[ <sp> path-name ]" },
	{ "SITE", SITE, SITECMD, 1,	"site-cmd [ <sp> arguments ]" },
	{ "SYST", SYST, NOARGS, 1,	"(get type of operating system)" },
	{ "STAT", STAT, OSTR, 1,	"[ <sp> path-name ]" },
	{ "HELP", HELP, OSTR, 1,	"[ <sp> <string> ]" },
	{ "NOOP", NOOP, NOARGS, 1,	"" },
/* RFC 1639 */
	{ "LPRT", LPRT, ARGS, 1,	"<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." },
	{ "LPSV", LPSV, NOARGS, 1,	"(set server in passive mode)" },
/* RFC 2428 */
	{ "EPRT", EPRT, STR1, 1,	"<sp> |af|addr|port|" },
	{ "EPSV", EPSV, OARGS, 1,	"[<sp> af|ALL]" },
/* obsoleted commands (RFC 751, ...) */
	{ "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)" },
	{ "XCWD", CWD,	OSTR, 1,	"[ <sp> directory-name ]" },
	{ "XMKD", MKD,  STR1, 1,	"<sp> path-name" },
	{ "XRMD", RMD,  STR1, 1,	"<sp> path-name" },
	{ "XPWD", PWD,  NOARGS, 1,	"(return current directory)" },
	{ "XCUP", CDUP, NOARGS, 1,	"(change to parent directory)" },
/* RFC 3659 */
	{ "SIZE", SIZE, STR1, 1,	"<sp> path-name" },
	{ "MDTM", MDTM, STR1, 1,	"<sp> path-name" },
/* RFC 2389 */
	{ "FEAT", FEAT, NOARGS, 1,	"(return list of supported extensions)" },
	{ "OPTS", OPTS, STR1,	1,	"<sp> command [ <sp> options ]" },
/* RFC 2228 */
#ifdef USE_SSL
	{ "AUTH", AUTH, STR1, 1,	"<sp> mechanism-name" },
	{ "PBSZ", PBSZ, ARGS, 1,	"<sp> decimal-integer" },
	{ "PROT", PROT, STR1, 1,	"<sp> prot-code" },
#else /* !USE_SSL */
	{ "AUTH", AUTH, STR1, 0,	"<sp> mechanism-name" },
	{ "PBSZ", PBSZ, ARGS, 0,	"<sp> decimal-integer" },
	{ "PROT", PROT, STR1, 0,	"<sp> prot-code" },
#endif /* USE_SSL */
	{ NULL,   0,    0,    0,	0 }
};

struct tab sitetab[] = {
#ifdef USE_MD5
	{ "MD5", MDFIVE, STR1, 1,	"<sp> file-name" },
#else /* !USE_MD5 */
	{ "MD5", MDFIVE, STR1, 0,	"<sp> file-name" },
#endif /* USE_MD5 */
	{ "UMASK", UMASK, OARGS, 1,	"[ <sp> umask ]" },
	{ "IDLE", IDLE, OARGS, 1,	"[ <sp> maximum-idle-time ]" },
	{ "CHMOD", CHMOD, NSTR, 1,	"<sp> mode <sp> file-name" },
	{ "HELP", HELP, OSTR, 1,	"[ <sp> <string> ]" },
	{ NULL,   0,    0,    0,	0 }
};

static char	*copy(char *);
static char	*expglob(char *);
static char	*exptilde(char *);
static void	 help(struct tab *, char *);
static struct tab *
		 lookup(struct tab *, char *);
static void	 opts(char *);
static int	 port_check(const char *);
#ifdef INET6
static int	 port_check_v6(const char *);
#endif
static void	 sizecmd(char *);
static void	 toolong(int);
#ifdef INET6
static void	 v4map_data_dest(void);
#endif
static int	 yylex(void);

static struct tab *
lookup(struct tab *p, char *cmd)
{

	for (; p->name != NULL; p++)
		if (strcasecmp(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(char *s, int n, FILE *iop)
{
	int c;
	register char *cs;
	sigset_t sset, osset;
	char buf[16];

	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 (ftpdebug)
				syslog(LOG_DEBUG, "command: %s", s);
			tmpline[0] = '\0';
			return(s);
		}
		if (c == 0)
			tmpline[0] = '\0';
	}
	/* SIGURG would interrupt stdio if not blocked during the read loop */
	sigemptyset(&sset);
	sigaddset(&sset, SIGURG);
#ifdef USE_SSL /* "pseudo-OOB" with SSL */
	sigaddset(&sset, SIGIO);
#endif /*USE_SSL*/
	sigprocmask(SIG_BLOCK, &sset, &osset);
	while ((c = GETC(iop)) != EOF) {
		c &= 0377;
		if (c == IAC) {
		    if ((c = GETC(iop)) == EOF)
				goto got_eof;
			c &= 0377;
			switch (c) {
			case WILL:
			case WONT:
				if ((c = GETC(iop)) == EOF)
					goto got_eof;
				snprintf(buf, sizeof(buf), "%c%c%c", IAC, DONT,
					0377&c);
#ifdef USE_SSL
				if (ssl_active_flag)
					ssl_write(ssl_con, buf, strlen(buf));
				else
#endif /* USE_SSL */
					fwrite(buf, strlen(buf), 1, stdout);
				(void) FFLUSH(stdout);
				continue;
			case DO:
			case DONT:
				if ((c = GETC(iop)) == EOF)
					goto got_eof;
				snprintf(buf, sizeof(buf), "%c%c%c", IAC, WONT,
					0377&c);
#ifdef USE_SSL
				if (ssl_active_flag)
					ssl_write(ssl_con, buf, strlen(buf));
				else
#endif /* USE_SSL */
					fwrite(buf, strlen(buf), 1, stdout);
				(void) FFLUSH(stdout);
				continue;
			case IAC:
				break;
			default:
				continue;	/* ignore command */
			}
		}
		*cs++ = c;
		if (--n <= 0 || c == '\n')
			break;
	}
got_eof:
	sigprocmask(SIG_SETMASK, &osset, NULL);
	if (c == EOF && cs == s)
		return (NULL);
	*cs++ = '\0';
	if (ftpdebug) {
		if (!guest && strncasecmp("pass ", s, 5) == 0) {
			/* Don't syslog passwords */
			syslog(LOG_DEBUG, "command: %.5s ???", s);
		} else {
			register char *cp;
			register int len;

			/* Don't syslog trailing CR-LF */
			len = strlen(s);
			cp = s + len - 1;
			while (cp >= s && (*cp == '\n' || *cp == '\r')) {
				--cp;
				--len;
			}
			syslog(LOG_DEBUG, "command: %.*s", len, s);
		}
	}
	return (s);
}

static void
toolong(int signo)
{

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

/*
 * Basic syntax checking for informational purposes.
 * arguments:
 *	cmd  - an FTP command presented by the item of the FTP command table;
 *	cbuf - the buffer (with removed '\r' symbols), which contains the FTP
 *	       command code and the argument field.
 *	cpos - the position (starting from 0) of the symbol which is next
 *	       after the end of the command code.
 * return:
 *	0 - syntax error is found.
 *	1 - in other cases.
 * notes:
 *	This function checks only the requirement of the arguments and doesn't
 *	perform the verification of the syntax of the argument field.
 */
static int
check_syntax(struct tab *cmd, char *cbuf, size_t cpos)
{
	if ( (cmd->state == NOARGS && cbuf[cpos] != '\n') ||
	    (cmd->state != NOARGS && cmd->state != OARGS && cmd->state != OSTR
	    && cmd->state != ZSTR1 && cbuf[cpos] == '\n') )
		return 0;
	return 1;
}

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

	for (;;) {
		switch (state) {

		case CMD:
			(void) signal(SIGALRM, toolong);
			(void) alarm(timeout);
			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)
				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) {
				yylval.s = p->name;
				if (!p->implemented)
					return (NOTIMPL); /* state remains CMD */
				if ( !check_syntax(p, cbuf, cpos) ) {
					return (SYNTERR); /* state remains CMD */
				}
				state = p->state;
				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 (guest == 0 && p != 0) {
				yylval.s = p->name;
				if (!p->implemented) {
					state = CMD;
					return (NOTIMPL);
				}
				if ( !check_syntax(p, cbuf, cpos) ) {
					state = CMD;
					return (SYNTERR);
				}
				state = p->state;
				return (p->token);
			}
			state = CMD;
			break;

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

		case STR1:
		dostr1:
			if (cbuf[cpos] == ' ') {
				cpos++;
				state = state == OSTR ? STR2 : state+1;
				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.s = 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.u.i = atoi(cp);
				cbuf[cpos] = c;
				state = STR1;
				return (NUMBER);
			}
			state = STR1;
			goto dostr1;

		case OARGS:
		case ARGS:
			if (isdigit(cbuf[cpos])) {
				cp = &cbuf[cpos];
				while (isdigit(cbuf[++cpos]))
					;
				c = cbuf[cpos];
				cbuf[cpos] = '\0';
				yylval.u.i = atoi(cp);
				yylval.u.o = strtoull(cp, NULL, 10);
				cbuf[cpos] = c;
				return (NUMBER);
			}
			if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0
			 && !isalnum(cbuf[cpos + 3])) {
				cpos += 3;
				return ALL;
			}
			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;

		case NOARGS:
			if (cbuf[cpos] == '\n') {
				state = CMD;
				return (CRLF);
			}
			break;

		default:
			fatalerror("Unknown state in scanner.");
		}
		state = CMD;
		return (LEXERR);
	}
}

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

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

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

static void
help(struct tab *ctab, char *s)
{
	struct tab *c;
	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) {
		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) {
					PRINTF(" ");
					w++;
				}
			}
			PRINTF("\r\n");
		}
		(void) FFLUSH(stdout);
		if (hostinfo)
			reply(214, "Direct comments to ftp-bugs@%s.", hostname);
		else
			reply(214, "End.");
		return;
	}
	upper(s);
	c = lookup(ctab, s);
	if (c == 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);
}

static void
sizecmd(char *filename)
{
	switch (type) {
	case TYPE_L:
	case TYPE_I: {
		struct stat stbuf;
		if (stat(filename, &stbuf) < 0)
			perror_reply(550, filename);
		else if (!S_ISREG(stbuf.st_mode))
			reply(550, "%s: not a plain file.", filename);
		else
			reply(213, "%jd", (intmax_t)stbuf.st_size);
		break; }
	case TYPE_A: {
		FILE *fin;
		int c;
		off_t count;
		struct stat stbuf;
		fin = fopen(filename, "r");
		if (fin == NULL) {
			perror_reply(550, filename);
			return;
		}
		if (fstat(fileno(fin), &stbuf) < 0) {
			perror_reply(550, filename);
			(void) fclose(fin);
			return;
		} else if (!S_ISREG(stbuf.st_mode)) {
			reply(550, "%s: not a plain file.", filename);
			(void) fclose(fin);
			return;
		} else if (stbuf.st_size > MAXASIZE) {
			reply(550, "%s: too large for type A SIZE.", 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, "%jd", (intmax_t)count);
		break; }
	default:
		reply(504, "SIZE not implemented for type %s.",
		           typenames[type]);
	}
}

/* Return 1, if port check is done. Return 0, if not yet. */
static int
port_check(const char *pcmd)
{
	if (his_addr.su_family == AF_INET) {
		if (data_dest.su_family != AF_INET) {
			usedefault = 1;
			reply(500, "Invalid address rejected.");
			return 1;
		}
		if (ftpdparanoid &&
		    ((ntohs(data_dest.su_port) < IPPORT_RESERVED) ||
		     memcmp(&data_dest.su_sin.sin_addr,
			    &his_addr.su_sin.sin_addr,
			    sizeof(data_dest.su_sin.sin_addr)))) {
			usedefault = 1;
			reply(500, "Illegal PORT range rejected.");
		} else {
			usedefault = 0;
			if (pdata >= 0) {
				(void) close(pdata);
				pdata = -1;
			}
			reply(200, "%s command successful.", pcmd);
		}
		return 1;
	}
	return 0;
}

static int
check_login1(void)
{
	if (logged_in)
		return 1;
	else {
		reply(530, "Please login with USER and PASS.");
		return 0;
	}
}

/*
 * Replace leading "~user" in a pathname by the user's login directory.
 * Returned string will be in a freshly malloced buffer unless it's NULL.
 */
static char *
exptilde(char *s)
{
	char *p, *q;
	char *path, *user;
	struct passwd *ppw;

	if ((p = strdup(s)) == NULL)
		return (NULL);
	if (*p != '~')
		return (p);

	user = p + 1;	/* skip tilde */
	if ((path = strchr(p, '/')) != NULL)
		*(path++) = '\0'; /* separate ~user from the rest of path */
	if (*user == '\0') /* no user specified, use the current user */
		user = pw->pw_name;
	/* read passwd even for the current user since we may be chrooted */
	if ((ppw = getpwnam(user)) != NULL) {
		/* user found, substitute login directory for ~user */
		if (path)
			asprintf(&q, "%s/%s", ppw->pw_dir, path);
		else
			q = strdup(ppw->pw_dir);
		free(p);
		p = q;
	} else {
		/* user not found, undo the damage */
		if (path)
			path[-1] = '/';
	}
	return (p);
}

/*
 * Expand glob(3) patterns possibly present in a pathname.
 * Avoid expanding to a pathname including '\r' or '\n' in order to
 * not disrupt the FTP protocol.
 * The expansion found must be unique.
 * Return the result as a malloced string, or NULL if an error occured.
 *
 * 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.
 */
static char *
expglob(char *s)
{
	char *p, **pp, *rval;
	int flags = GLOB_BRACE | GLOB_NOCHECK;
	int n;
	glob_t gl;

	memset(&gl, 0, sizeof(gl));
	flags |= GLOB_LIMIT;
	gl.gl_matchc = MAXGLOBARGS;
#ifdef LINUX /* Linux port */
	if (bsdglob(s, flags, NULL, &gl) == 0 && gl.gl_pathc != 0) {
#else /* BSD source */
	if (glob(s, flags, NULL, &gl) == 0 && gl.gl_pathc != 0) {
#endif /* BSD source */
		for (pp = gl.gl_pathv, p = NULL, n = 0; *pp; pp++)
			if (*(*pp + strcspn(*pp, "\r\n")) == '\0') {
				p = *pp;
				n++;
			}
		if (n == 0)
			rval = strdup(s);
		else if (n == 1)
			rval = strdup(p);
		else {
			reply(550, "Wildcard is ambiguous.");
			rval = NULL;
		}
	} else {
		reply(550, "Wildcard expansion error.");
		rval = NULL;
	}
	globfree(&gl);
	return (rval);
}

#ifdef INET6
/* Return 1, if port check is done. Return 0, if not yet. */
static int
port_check_v6(const char *pcmd)
{
	if (his_addr.su_family == AF_INET6) {
		if (IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr))
			/* Convert data_dest into v4 mapped sockaddr.*/
			v4map_data_dest();
		if (data_dest.su_family != AF_INET6) {
			usedefault = 1;
			reply(500, "Invalid address rejected.");
			return 1;
		}
		if (ftpdparanoid &&
		    ((ntohs(data_dest.su_port) < IPPORT_RESERVED) ||
		     memcmp(&data_dest.su_sin6.sin6_addr,
			    &his_addr.su_sin6.sin6_addr,
			    sizeof(data_dest.su_sin6.sin6_addr)))) {
			usedefault = 1;
			reply(500, "Illegal PORT range rejected.");
		} else {
			usedefault = 0;
			if (pdata >= 0) {
				(void) close(pdata);
				pdata = -1;
			}
			reply(200, "%s command successful.", pcmd);
		}
		return 1;
	}
	return 0;
}

static void
v4map_data_dest(void)
{
	struct in_addr savedaddr;
	int savedport;

	if (data_dest.su_family != AF_INET) {
		usedefault = 1;
		reply(500, "Invalid address rejected.");
		return;
	}

	savedaddr = data_dest.su_sin.sin_addr;
	savedport = data_dest.su_port;

	memset(&data_dest, 0, sizeof(data_dest));
#ifndef LINUX /* BSD source */
	data_dest.su_sin6.sin6_len = sizeof(struct sockaddr_in6);
#endif
	data_dest.su_sin6.sin6_family = AF_INET6;
	data_dest.su_sin6.sin6_port = savedport;
	memset((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[10], 0xff, 2);
	memcpy((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[12],
	       (caddr_t)&savedaddr, sizeof(savedaddr));
}
#endif

/*
 * An implementation of the OPTS command defined in RFC 2389.
 * arguments:
 *	command - the string with next syntax:
 *	          command-name [ SP command-options ]
 * return:
 *	none
 * notes:
 *	command-name: any FTP command which allows option setting;
 *	command-options: format specified by individual FTP command.
 */
void
opts(char *command)
{
	struct tab *c;
	char *s;

	if ((s = strchr(command, ' ')) != NULL)
		*s++ = '\0';
	c = lookup(cmdtab, command);

	/*
	 * Simple cases.
	 */
	/* Check if the command is known. */
	if (c == NULL) {
		reply(500, "%s: command not understood.", command);
		return;
	}
	/* Check if the command is implemented. */
	if (!c->implemented) {
		reply(502, "%s command not implemented.", c->name);
		return;
	}

	/*
	 * The commands for whose the OPTS command is defined.
	 */
	/* none at this moment */

	/*
	 * Default case.
	 */
	reply(501, "OPTS command is not defined for %s.", c->name);
}
#line 1441 "ftpcmd.c"
/* allocate initial stack or double stack size, up to YYMAXDEPTH */
int yyparse __P((void));
static int yygrowstack __P((void));
static int yygrowstack()
{
    int newsize, i;
    short *newss;
    YYSTYPE *newvs;

    if ((newsize = yystacksize) == 0)
        newsize = YYINITSTACKSIZE;
    else if (newsize >= YYMAXDEPTH)
        return -1;
    else if ((newsize *= 2) > YYMAXDEPTH)
        newsize = YYMAXDEPTH;
    i = yyssp - yyss;
    if ((newss = (short *)realloc(yyss, newsize * sizeof *newss)) == NULL)
        return -1;
    yyss = newss;
    yyssp = newss + i;
    if ((newvs = (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs)) == NULL)
        return -1;
    yyvs = newvs;
    yyvsp = newvs + i;
    yystacksize = newsize;
    yysslim = yyss + newsize - 1;
    return 0;
}

#define YYABORT goto yyabort
#define YYREJECT goto yyabort
#define YYACCEPT goto yyaccept
#define YYERROR goto yyerrlab
int
yyparse()
{
    int yym, yyn, yystate;
#if YYDEBUG
    char *yys;

    if ((yys = getenv("YYDEBUG")) != NULL)
    {
        yyn = *yys;
        if (yyn >= '0' && yyn <= '9')
            yydebug = yyn - '0';
    }
#endif

    yynerrs = 0;
    yyerrflag = 0;
    yychar = (-1);

    if (yyss == NULL && yygrowstack()) goto yyoverflow;
    yyssp = yyss;
    yyvsp = yyvs;
    *yyssp = yystate = 0;

yyloop:
    if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
    if (yychar < 0)
    {
        if ((yychar = yylex()) < 0) yychar = 0;
#if YYDEBUG
        if (yydebug)
        {
            yys = 0;
            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
            if (!yys) yys = "illegal-symbol";
            printf("%sdebug: state %d, reading %d (%s)\n",
                    YYPREFIX, yystate, yychar, yys);
        }
#endif
    }
    if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
    {
#if YYDEBUG
        if (yydebug)
            printf("%sdebug: state %d, shifting to state %d\n",
                    YYPREFIX, yystate, yytable[yyn]);
#endif
        if (yyssp >= yysslim && yygrowstack())
        {
            goto yyoverflow;
        }
        *++yyssp = yystate = yytable[yyn];
        *++yyvsp = yylval;
        yychar = (-1);
        if (yyerrflag > 0)  --yyerrflag;
        goto yyloop;
    }
    if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
    {
        yyn = yytable[yyn];
        goto yyreduce;
    }
    if (yyerrflag) goto yyinrecovery;
    goto yynewerror;
yynewerror:
    yyerror("syntax error");
    goto yyerrlab;
yyerrlab:
    ++yynerrs;
yyinrecovery:
    if (yyerrflag < 3)
    {
        yyerrflag = 3;
        for (;;)
        {
            if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
                    yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
            {
#if YYDEBUG
                if (yydebug)
                    printf("%sdebug: state %d, error recovery shifting\
 to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
#endif
                if (yyssp >= yysslim && yygrowstack())
                {
                    goto yyoverflow;
                }
                *++yyssp = yystate = yytable[yyn];
                *++yyvsp = yylval;
                goto yyloop;
            }
            else
            {
#if YYDEBUG
                if (yydebug)
                    printf("%sdebug: error recovery discarding state %d\n",
                            YYPREFIX, *yyssp);
#endif
                if (yyssp <= yyss) goto yyabort;
                --yyssp;
                --yyvsp;
            }
        }
    }
    else
    {
        if (yychar == 0) goto yyabort;
#if YYDEBUG
        if (yydebug)
        {
            yys = 0;
            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
            if (!yys) yys = "illegal-symbol";
            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
                    YYPREFIX, yystate, yychar, yys);
        }
#endif
        yychar = (-1);
        goto yyloop;
    }
yyreduce:
#if YYDEBUG
    if (yydebug)
        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
                YYPREFIX, yystate, yyn, yyrule[yyn]);
#endif
    yym = yylen[yyn];
    yyval = yyvsp[1-yym];
    switch (yyn)
    {
case 2:
#line 190 "ftpcmd.y"
{
			if (fromname)
				free(fromname);
			fromname = NULL;
			restart_point = 0;
		}
break;
case 4:
#line 201 "ftpcmd.y"
{
#ifdef USE_SSL
		/* Compatibility with early implementations of SSL upgrade. */
		if (!strcasecmp(yyvsp[-1].s, "SSL")
		    && (ssl_secure_flags & SSL_USE_COMPAT)) {
			reply(!ssl_uorc_flag ? 234 : 334,
			     "AUTH SSL command successful.");

			/* Initialize the TLS/SSL session. */
			ssl_compat_flag = 1;
			do_ssl_start();
			ssl_encrypt_data = 1;

		/* Implementation of the FTP-TLS v12 IETF draft. */
		} else if (!strcasecmp(yyvsp[-1].s, "TLS")
			    && (ssl_secure_flags & SSL_USE_TLS)) {
			reply(234, "AUTH TLS command successful.");

			/* Initialize the TLS/SSL session. */
			do_ssl_start();
		} else {
			reply(504,
			    "AUTH: security mechanism '%s' not supported.", yyvsp[-1].s);
		}

		if (yyvsp[-1].s != NULL)
			free(yyvsp[-1].s);
#endif /* USE_SSL */
		}
break;
case 5:
#line 231 "ftpcmd.y"
{
#ifdef USE_SSL
			if (ssl_active_flag) {
				reply(200, "PBSZ command successful (PBSZ=0).");
				PBSZ_used_flag = 1;
			} else {
				reply(503, "Use AUTH command first.");
			}
#endif /* USE_SSL */
		}
break;
case 6:
#line 242 "ftpcmd.y"
{
#ifdef USE_SSL
		if(yyvsp[-3].u.i) {
		    if (ssl_compat_flag) {
			reply(504, "PROT command not available in FTP-SSL "
				   "compatibility mode.");
			goto prot_end;
		    } else if (ssl_active_flag && PBSZ_used_flag) {
			if (!strcasecmp(yyvsp[-1].s, "C")) {
			    ssl_encrypt_data = 0;
			} else if (!strcasecmp(yyvsp[-1].s, "P")) {
			    ssl_encrypt_data = 1;
			} else {
			    reply(504, "Protection level '%s' not supported.",
				 yyvsp[-1].s);
			    goto prot_end;
			}

			reply(200, "Protection level set to %s.",
			     ssl_encrypt_data ? "Private" : "Clear");
			if (logging)
			    syslog(LOG_NOTICE,
				  "data connection protection level set to %s",
				  ssl_encrypt_data ? "Private" : "Clear");
		    } else {
			reply(503, "Use AUTH and PBSZ commands first.");
			goto prot_end;
		    }
		}

		prot_end:
		if (yyvsp[-1].s != NULL)
		    free(yyvsp[-1].s);
#endif /* USE_SSL */
		}
break;
case 7:
#line 278 "ftpcmd.y"
{
#ifdef USE_SSL
			if (!(ssl_secure_flags & SSL_USE_NONSECURE)
			    && !ssl_active_flag) {
				reply(504, "TLS/SSL protection required.");
				goto user_end;
			}
#endif /* USE_SSL */
			user(yyvsp[-1].s);
		user_end:
			free(yyvsp[-1].s);
		}
break;
case 8:
#line 291 "ftpcmd.y"
{
#ifdef USE_SSL
			if (!(ssl_secure_flags & SSL_USE_NONSECURE)
			    && !ssl_active_flag) {
				reply(504, "TLS/SSL protection required.");
				goto pass_end;
			}
#endif /* USE_SSL */
			pass(yyvsp[-1].s);
		pass_end:
			free(yyvsp[-1].s);
		}
break;
case 9:
#line 304 "ftpcmd.y"
{
#ifdef USE_SSL
			if (!(ssl_secure_flags & SSL_USE_NONSECURE)
			    && !ssl_active_flag) {
				reply(504, "TLS/SSL protection required.");
				goto passnull_end;
			}
#endif /* USE_SSL */
			pass("");
		passnull_end:
			;
		}
break;
case 10:
#line 317 "ftpcmd.y"
{
			if (epsvall) {
				reply(501, "No PORT allowed after EPSV ALL.");
				goto port_done;
			}
			if (!yyvsp[-3].u.i)
				goto port_done;
			if (port_check("PORT") == 1)
				goto port_done;
#ifdef INET6
			if ((his_addr.su_family != AF_INET6 ||
			     !IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr))) {
				/* shoud never happen */
				usedefault = 1;
				reply(500, "Invalid address rejected.");
				goto port_done;
			}
			port_check_v6("pcmd");
#endif
		port_done:
			;
		}
break;
case 11:
#line 340 "ftpcmd.y"
{
			if (epsvall) {
				reply(501, "No LPRT allowed after EPSV ALL.");
				goto lprt_done;
			}
			if (!yyvsp[-3].u.i)
				goto lprt_done;
			if (port_check("LPRT") == 1)
				goto lprt_done;
#ifdef INET6
			if (his_addr.su_family != AF_INET6) {
				usedefault = 1;
				reply(500, "Invalid address rejected.");
				goto lprt_done;
			}
			if (port_check_v6("LPRT") == 1)
				goto lprt_done;
#endif
		lprt_done:
			;
		}
break;
case 12:
#line 362 "ftpcmd.y"
{
			char delim;
			char *tmp = NULL;
			char *p, *q;
			char *result[3];
			struct addrinfo hints;
			struct addrinfo *res;
			int i;

			if (epsvall) {
				reply(501, "No EPRT allowed after EPSV ALL.");
				goto eprt_done;
			}
			if (!yyvsp[-3].u.i)
				goto eprt_done;

			memset(&data_dest, 0, sizeof(data_dest));
			tmp = strdup(yyvsp[-1].s);
			if (ftpdebug)
				syslog(LOG_DEBUG, "%s", tmp);
			if (!tmp) {
				fatalerror("not enough core");
				/*NOTREACHED*/
			}
			p = tmp;
			delim = p[0];
			p++;
			memset(result, 0, sizeof(result));
			for (i = 0; i < 3; i++) {
				q = strchr(p, delim);
				if (!q || *q != delim) {
		parsefail:
					reply(500,
						"Invalid argument, rejected.");
					if (tmp)
						free(tmp);
					usedefault = 1;
					goto eprt_done;
				}
				*q++ = '\0';
				result[i] = p;
				if (ftpdebug)
					syslog(LOG_DEBUG, "%d: %s", i, p);
				p = q;
			}

			/* some more sanity check */
			p = result[0];
			while (*p) {
				if (!isdigit(*p))
					goto parsefail;
				p++;
			}
			p = result[2];
			while (*p) {
				if (!isdigit(*p))
					goto parsefail;
				p++;
			}

			/* grab address */
			memset(&hints, 0, sizeof(hints));
			if (atoi(result[0]) == 1)
				hints.ai_family = PF_INET;
#ifdef INET6
			else if (atoi(result[0]) == 2)
				hints.ai_family = PF_INET6;
#endif
			else
				hints.ai_family = PF_UNSPEC;	/*XXX*/
			hints.ai_socktype = SOCK_STREAM;
			i = getaddrinfo(result[1], result[2], &hints, &res);
			if (i)
				goto parsefail;
			memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
#ifdef INET6
			if (his_addr.su_family == AF_INET6
			    && data_dest.su_family == AF_INET6) {
				/* XXX more sanity checks! */
				data_dest.su_sin6.sin6_scope_id =
					his_addr.su_sin6.sin6_scope_id;
			}
#endif
			free(tmp);
			tmp = NULL;

			if (port_check("EPRT") == 1)
				goto eprt_done;
#ifdef INET6
			if (his_addr.su_family != AF_INET6) {
				usedefault = 1;
				reply(500, "Invalid address rejected.");
				goto eprt_done;
			}
			if (port_check_v6("EPRT") == 1)
				goto eprt_done;
#endif
		eprt_done:
			free(yyvsp[-1].s);
		}
break;
case 13:
#line 463 "ftpcmd.y"
{
			if (epsvall)
				reply(501, "No PASV allowed after EPSV ALL.");
			else if (yyvsp[-1].u.i)
				passive();
		}
break;
case 14:
#line 470 "ftpcmd.y"
{
			if (epsvall)
				reply(501, "No LPSV allowed after EPSV ALL.");
			else if (yyvsp[-1].u.i)
				long_passive("LPSV", PF_UNSPEC);
		}
break;
case 15:
#line 477 "ftpcmd.y"
{
			if (yyvsp[-3].u.i) {
				int pf;
				switch (yyvsp[-1].u.i) {
				case 1:
					pf = PF_INET;
					break;
#ifdef INET6
				case 2:
					pf = PF_INET6;
					break;
#endif
				default:
					pf = -1;	/*junk value*/
					break;
				}
				long_passive("EPSV", pf);
			}
		}
break;
case 16:
#line 497 "ftpcmd.y"
{
			if (yyvsp[-3].u.i) {
				reply(200, "EPSV ALL command successful.");
				epsvall++;
			}
		}
break;
case 17:
#line 504 "ftpcmd.y"
{
			if (yyvsp[-1].u.i)
				long_passive("EPSV", PF_UNSPEC);
		}
break;
case 18:
#line 509 "ftpcmd.y"
{
			if (yyvsp[-3].u.i) {
				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 CHAR_BIT == 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 /* CHAR_BIT == 8 */
					UNIMPLEMENTED for CHAR_BIT != 8
#endif /* CHAR_BIT == 8 */
				}
			}
		}
break;
case 19:
#line 546 "ftpcmd.y"
{
			if (yyvsp[-3].u.i) {
				switch (yyvsp[-1].u.i) {

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

				default:
					reply(504, "Unimplemented STRU type.");
				}
			}
		}
break;
case 20:
#line 560 "ftpcmd.y"
{
			if (yyvsp[-3].u.i) {
				switch (yyvsp[-1].u.i) {

				case MODE_S:
					reply(200, "MODE S accepted.");
					break;
	
				default:
					reply(502, "Unimplemented MODE type.");
				}
			}
		}
break;
case 21:
#line 574 "ftpcmd.y"
{
			if (yyvsp[-3].u.i) {
				reply(202, "ALLO command ignored.");
			}
		}
break;
case 22:
#line 580 "ftpcmd.y"
{
			if (yyvsp[-7].u.i) {
				reply(202, "ALLO command ignored.");
			}
		}
break;
case 23:
#line 586 "ftpcmd.y"
{
			if (noretr || (guest && noguestretr))
				reply(500, "RETR command disabled.");
			else if (yyvsp[-3].u.i && yyvsp[-1].s != NULL)
				retrieve(NULL, yyvsp[-1].s);

			if (yyvsp[-1].s != NULL)
				free(yyvsp[-1].s);
		}
break;
case 24:
#line 596 "ftpcmd.y"
{
			if (yyvsp[-3].u.i && yyvsp[-1].s != NULL)
				store(yyvsp[-1].s, "w", 0);
			if (yyvsp[-1].s != NULL)
				free(yyvsp[-1].s);
		}
break;
case 25:
#line 603 "ftpcmd.y"
{
			if (yyvsp[-3].u.i && yyvsp[-1].s != NULL)
				store(yyvsp[-1].s, "a", 0);
			if (yyvsp[-1].s != NULL)
				free(yyvsp[-1].s);
		}
break;
case 26:
#line 610 "ftpcmd.y"
{
			if (yyvsp[-1].u.i)
				send_file_list(".");
		}
break;
case 27:
#line 615 "ftpcmd.y"
{
			if (yyvsp[-3].u.i)
				send_file_list(yyvsp[-1].s);
			free(yyvsp[-1].s);
		}
break;
case 28:
#line 621 "ftpcmd.y"
{
			if (yyvsp[-1].u.i)
				retrieve(_PATH_LS " -lgA", "");
		}
break;
case 29:
#line 626 "ftpcmd.y"
{
			if (yyvsp[-3].u.i)
				retrieve(_PATH_LS " -lgA %s", yyvsp[-1].s);
			free(yyvsp[-1].s);
		}
break;
case 30:
#line 632 "ftpcmd.y"
{
			if (yyvsp[-3].u.i && yyvsp[-1].s != NULL)
				statfilecmd(yyvsp[-1].s);
			if (yyvsp[-1].s != NULL)
				free(yyvsp[-1].s);
		}
break;
case 31:
#line 639 "ftpcmd.y"
{
			if (yyvsp[-1].u.i) {
				statcmd();
			}
		}
break;
case 32:
#line 645 "ftpcmd.y"
{
			if (yyvsp[-3].u.i && yyvsp[-1].s != NULL)
				delete(yyvsp[-1].s);
			if (yyvsp[-1].s != NULL)
				free(yyvsp[-1].s);
		}
break;
case 33:
#line 652 "ftpcmd.y"
{
			if (yyvsp[-3].u.i && yyvsp[-1].s != NULL) {
				if (fromname) {
					renamecmd(fromname, yyvsp[-1].s);
					free(fromname);
					fromname = NULL;
				} else {
					reply(503, "Bad sequence of commands.");
				}
			}
			if (yyvsp[-1].s != NULL)
				free(yyvsp[-1].s);
		}
break;
case 34:
#line 666 "ftpcmd.y"
{
			if (yyvsp[-1].u.i)
				reply(225, "ABOR command successful.");
		}
break;
case 35:
#line 671 "ftpcmd.y"
{
			if (yyvsp[-1].u.i) {
				cwd(homedir);
			}
		}
break;
case 36:
#line 677 "ftpcmd.y"
{
			if (yyvsp[-3].u.i && yyvsp[-1].s != NULL)
				cwd(yyvsp[-1].s);
			if (yyvsp[-1].s != NULL)
				free(yyvsp[-1].s);
		}
break;
case 37:
#line 684 "ftpcmd.y"
{
			help(cmdtab, NULL);
		}
break;
case 38:
#line 688 "ftpcmd.y"
{
			char *cp = yyvsp[-1].s;

			if (strncasecmp(cp, "SITE", 4) == 0) {
				cp = yyvsp[-1].s + 4;
				if (*cp == ' ')
					cp++;
				if (*cp)
					help(sitetab, cp);
				else
					help(sitetab, NULL);
			} else
				help(cmdtab, yyvsp[-1].s);
			free(yyvsp[-1].s);
		}
break;
case 39:
#line 704 "ftpcmd.y"
{
			reply(200, "NOOP command successful.");
		}
break;
case 40:
#line 708 "ftpcmd.y"
{
			if (yyvsp[-3].u.i && yyvsp[-1].s != NULL)
				makedir(yyvsp[-1].s);
			if (yyvsp[-1].s != NULL)
				free(yyvsp[-1].s);
		}
break;
case 41:
#line 715 "ftpcmd.y"
{
			if (yyvsp[-3].u.i && yyvsp[-1].s != NULL)
				removedir(yyvsp[-1].s);
			if (yyvsp[-1].s != NULL)
				free(yyvsp[-1].s);
		}
break;
case 42:
#line 722 "ftpcmd.y"
{
			if (yyvsp[-1].u.i)
				pwd();
		}
break;
case 43:
#line 727 "ftpcmd.y"
{
			if (yyvsp[-1].u.i)
				cwd("..");
		}
break;
case 44:
#line 732 "ftpcmd.y"
{
			help(sitetab, NULL);
		}
break;
case 45:
#line 736 "ftpcmd.y"
{
			help(sitetab, yyvsp[-1].s);
			free(yyvsp[-1].s);
		}
break;
case 46:
#line 741 "ftpcmd.y"
{
#ifdef USE_MD5
			char p[64], *q;

			if (yyvsp[-3].u.i && yyvsp[-1].s) {
				q = MD5File(yyvsp[-1].s, p);
				if (q != NULL)
					reply(200, "MD5(%s) = %s", yyvsp[-1].s, p);
				else
					perror_reply(550, yyvsp[-1].s);
			}
			if (yyvsp[-1].s)
				free(yyvsp[-1].s);
#endif /* USE_MD5 */
		}
break;
case 47:
#line 757 "ftpcmd.y"
{
			int oldmask;

			if (yyvsp[-1].u.i) {
				oldmask = umask(0);
				(void) umask(oldmask);
				reply(200, "Current UMASK is %03o.", oldmask);
			}
		}
break;
case 48:
#line 767 "ftpcmd.y"
{
			int oldmask;

			if (yyvsp[-3].u.i) {
				if ((yyvsp[-1].u.i == -1) || (yyvsp[-1].u.i > 0777)) {
					reply(501, "Bad UMASK value.");
				} else {
					oldmask = umask(yyvsp[-1].u.i);
					reply(200,
					    "UMASK set to %03o (was %03o).",
					    yyvsp[-1].u.i, oldmask);
				}
			}
		}
break;
case 49:
#line 782 "ftpcmd.y"
{
			if (yyvsp[-5].u.i && (yyvsp[-1].s != NULL)) {
				if ((yyvsp[-3].u.i == -1 ) || (yyvsp[-3].u.i > 0777))
					reply(501, "Bad mode value.");
				else if (chmod(yyvsp[-1].s, yyvsp[-3].u.i) < 0)
					perror_reply(550, yyvsp[-1].s);
				else
					reply(200, "CHMOD command successful.");
			}
			if (yyvsp[-1].s != NULL)
				free(yyvsp[-1].s);
		}
break;
case 50:
#line 795 "ftpcmd.y"
{
			if (yyvsp[-2].u.i)
				reply(200,
			    	    "Current IDLE time limit is %d seconds; max %d.",
				    timeout, maxtimeout);
		}
break;
case 51:
#line 802 "ftpcmd.y"
{
			if (yyvsp[-4].u.i) {
				if (yyvsp[-1].u.i < 30 || yyvsp[-1].u.i > maxtimeout) {
					reply(501,
					    "Maximum IDLE time must be between 30 and %d seconds.",
					    maxtimeout);
				} else {
					timeout = yyvsp[-1].u.i;
					(void) alarm(timeout);
					reply(200,
					    "Maximum IDLE time set to %d seconds.",
					    timeout);
				}
			}
		}
break;
case 52:
#line 818 "ftpcmd.y"
{
			if (yyvsp[-3].u.i && yyvsp[-1].s != NULL)
				store(yyvsp[-1].s, "w", 1);
			if (yyvsp[-1].s != NULL)
				free(yyvsp[-1].s);
		}
break;
case 53:
#line 825 "ftpcmd.y"
{
			if (yyvsp[-1].u.i) {
				if (hostinfo)
#ifdef BSD
					reply(215, "UNIX Type: L%d Version: BSD-%d",
					      CHAR_BIT, BSD);
#else /* BSD */
					reply(215, "UNIX Type: L%d", CHAR_BIT);
#endif /* BSD */
				else
					reply(215, "UNKNOWN Type: L%d", CHAR_BIT);
			}
		}
break;
case 54:
#line 847 "ftpcmd.y"
{
			if (yyvsp[-3].u.i && yyvsp[-1].s != NULL)
				sizecmd(yyvsp[-1].s);
			if (yyvsp[-1].s != NULL)
				free(yyvsp[-1].s);
		}
break;
case 55:
#line 864 "ftpcmd.y"
{
			if (yyvsp[-3].u.i && yyvsp[-1].s != NULL) {
				struct stat stbuf;
				if (stat(yyvsp[-1].s, &stbuf) < 0)
					perror_reply(550, yyvsp[-1].s);
				else if (!S_ISREG(stbuf.st_mode)) {
					reply(550, "%s: not a plain file.", yyvsp[-1].s);
				} else {
					struct tm *t;
					t = gmtime(&stbuf.st_mtime);
					reply(213,
					    "%04d%02d%02d%02d%02d%02d",
					    1900 + t->tm_year,
					    t->tm_mon+1, t->tm_mday,
					    t->tm_hour, t->tm_min, t->tm_sec);
				}
			}
			if (yyvsp[-1].s != NULL)
				free(yyvsp[-1].s);
		}
break;
case 56:
#line 885 "ftpcmd.y"
{
			feat();
		}
break;
case 57:
#line 889 "ftpcmd.y"
{
			opts(yyvsp[-1].s);
			free(yyvsp[-1].s);
		}
break;
case 58:
#line 894 "ftpcmd.y"
{
			reply(221, "Goodbye.");
			dologout(0);
		}
break;
case 59:
#line 899 "ftpcmd.y"
{
			nack(yyvsp[0].s);
		}
break;
case 60:
#line 903 "ftpcmd.y"
{
			char buf[64];
			snprintf(buf, sizeof(buf), "SITE %s", yyvsp[0].s);
			nack(buf);
		}
break;
case 61:
#line 909 "ftpcmd.y"
{
			synterr(cbuf);
		}
break;
case 62:
#line 913 "ftpcmd.y"
{
			synterr(cbuf);
		}
break;
case 63:
#line 917 "ftpcmd.y"
{
			yyclearin;		/* discard lookahead data */
			yyerrok;		/* clear error condition */
			state = CMD;		/* reset lexer state */
		}
break;
case 64:
#line 925 "ftpcmd.y"
{
			restart_point = 0;
			if (yyvsp[-3].u.i && yyvsp[-1].s) {
				if (fromname)
					free(fromname);
				fromname = NULL;
				if (renamefrom(yyvsp[-1].s))
					fromname = yyvsp[-1].s;
				else
					free(yyvsp[-1].s);
			} else if (yyvsp[-1].s) {
				free(yyvsp[-1].s);
			}
		}
break;
case 65:
#line 940 "ftpcmd.y"
{
			if (yyvsp[-3].u.i) {
				if (fromname)
					free(fromname);
				fromname = NULL;
				restart_point = yyvsp[-1].u.o;
				reply(350, "Restarting at %jd. %s",
				    (intmax_t)restart_point,
				    "Send STORE or RETRIEVE to initiate transfer.");
			}
		}
break;
case 67:
#line 959 "ftpcmd.y"
{
			yyval.s = (char *)calloc(1, sizeof(char));
		}
break;
case 71:
#line 976 "ftpcmd.y"
{
			yyval.u.i = yyvsp[0].u.i;
		}
break;
case 72:
#line 983 "ftpcmd.y"
{
			yyval.u.i = yyvsp[0].u.i;
		}
break;
case 73:
#line 991 "ftpcmd.y"
{
			char *a, *p;

#ifndef LINUX /* BSD source */
			data_dest.su_len = sizeof(struct sockaddr_in);
#endif
			data_dest.su_family = AF_INET;
			p = (char *)&data_dest.su_sin.sin_port;
			p[0] = yyvsp[-2].u.i; p[1] = yyvsp[0].u.i;
			a = (char *)&data_dest.su_sin.sin_addr;
			a[0] = yyvsp[-10].u.i; a[1] = yyvsp[-8].u.i; a[2] = yyvsp[-6].u.i; a[3] = yyvsp[-4].u.i;
		}
break;
case 74:
#line 1012 "ftpcmd.y"
{
#ifdef INET6
			char *a, *p;

			memset(&data_dest, 0, sizeof(data_dest));
#ifndef LINUX /* BSD source */
			data_dest.su_len = sizeof(struct sockaddr_in6);
#endif
			data_dest.su_family = AF_INET6;
			p = (char *)&data_dest.su_port;
			p[0] = yyvsp[-2].u.i; p[1] = yyvsp[0].u.i;
			a = (char *)&data_dest.su_sin6.sin6_addr;
			a[0] = yyvsp[-36].u.i; a[1] = yyvsp[-34].u.i; a[2] = yyvsp[-32].u.i; a[3] = yyvsp[-30].u.i;
			a[4] = yyvsp[-28].u.i; a[5] = yyvsp[-26].u.i; a[6] = yyvsp[-24].u.i; a[7] = yyvsp[-22].u.i;
			a[8] = yyvsp[-20].u.i; a[9] = yyvsp[-18].u.i; a[10] = yyvsp[-16].u.i; a[11] = yyvsp[-14].u.i;
			a[12] = yyvsp[-12].u.i; a[13] = yyvsp[-10].u.i; a[14] = yyvsp[-8].u.i; a[15] = yyvsp[-6].u.i;
			if (his_addr.su_family == AF_INET6) {
				/* XXX more sanity checks! */
				data_dest.su_sin6.sin6_scope_id =
					his_addr.su_sin6.sin6_scope_id;
			}
			if (yyvsp[-40].u.i != 6 || yyvsp[-38].u.i != 16 || yyvsp[-4].u.i != 2)
				memset(&data_dest, 0, sizeof(data_dest));
#endif /* INET6 */
		}
break;
case 75:
#line 1040 "ftpcmd.y"
{
			char *a, *p;

			memset(&data_dest, 0, sizeof(data_dest));
#ifndef LINUX /* BSD source */
			data_dest.su_sin.sin_len = sizeof(struct sockaddr_in);
#endif
			data_dest.su_family = AF_INET;
			p = (char *)&data_dest.su_port;
			p[0] = yyvsp[-2].u.i; p[1] = yyvsp[0].u.i;
			a = (char *)&data_dest.su_sin.sin_addr;
			a[0] =  yyvsp[-12].u.i; a[1] = yyvsp[-10].u.i; a[2] = yyvsp[-8].u.i; a[3] = yyvsp[-6].u.i;
			if (yyvsp[-16].u.i != 4 || yyvsp[-14].u.i != 4 || yyvsp[-4].u.i != 2)
				memset(&data_dest, 0, sizeof(data_dest));
		}
break;
case 76:
#line 1059 "ftpcmd.y"
{
			yyval.u.i = FORM_N;
		}
break;
case 77:
#line 1063 "ftpcmd.y"
{
			yyval.u.i = FORM_T;
		}
break;
case 78:
#line 1067 "ftpcmd.y"
{
			yyval.u.i = FORM_C;
		}
break;
case 79:
#line 1074 "ftpcmd.y"
{
			cmd_type = TYPE_A;
			cmd_form = FORM_N;
		}
break;
case 80:
#line 1079 "ftpcmd.y"
{
			cmd_type = TYPE_A;
			cmd_form = yyvsp[0].u.i;
		}
break;
case 81:
#line 1084 "ftpcmd.y"
{
			cmd_type = TYPE_E;
			cmd_form = FORM_N;
		}
break;
case 82:
#line 1089 "ftpcmd.y"
{
			cmd_type = TYPE_E;
			cmd_form = yyvsp[0].u.i;
		}
break;
case 83:
#line 1094 "ftpcmd.y"
{
			cmd_type = TYPE_I;
		}
break;
case 84:
#line 1098 "ftpcmd.y"
{
			cmd_type = TYPE_L;
			cmd_bytesz = CHAR_BIT;
		}
break;
case 85:
#line 1103 "ftpcmd.y"
{
			cmd_type = TYPE_L;
			cmd_bytesz = yyvsp[0].u.i;
		}
break;
case 86:
#line 1109 "ftpcmd.y"
{
			cmd_type = TYPE_L;
			cmd_bytesz = yyvsp[0].u.i;
		}
break;
case 87:
#line 1117 "ftpcmd.y"
{
			yyval.u.i = STRU_F;
		}
break;
case 88:
#line 1121 "ftpcmd.y"
{
			yyval.u.i = STRU_R;
		}
break;
case 89:
#line 1125 "ftpcmd.y"
{
			yyval.u.i = STRU_P;
		}
break;
case 90:
#line 1132 "ftpcmd.y"
{
			yyval.u.i = MODE_S;
		}
break;
case 91:
#line 1136 "ftpcmd.y"
{
			yyval.u.i = MODE_B;
		}
break;
case 92:
#line 1140 "ftpcmd.y"
{
			yyval.u.i = MODE_C;
		}
break;
case 93:
#line 1147 "ftpcmd.y"
{
			if (logged_in && yyvsp[0].s) {
				char *p;

				/*
				 * Expand ~user manually since glob(3)
				 * will return the unexpanded pathname
				 * if the corresponding file/directory
				 * doesn't exist yet.  Using sole glob(3)
				 * would break natural commands like
				 * MKD ~user/newdir
				 * or
				 * RNTO ~/newfile
				 */
				if ((p = exptilde(yyvsp[0].s)) != NULL) {
					yyval.s = expglob(p);
					free(p);
				} else
					yyval.s = NULL;
				free(yyvsp[0].s);
			} else
				yyval.s = yyvsp[0].s;
		}
break;
case 95:
#line 1178 "ftpcmd.y"
{
			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 = yyvsp[0].u.i;
			multby = 1;
			ret = 0;
			while (dec) {
				digit = dec%10;
				if (digit > 7) {
					ret = -1;
					break;
				}
				ret += digit * multby;
				multby *= 8;
				dec /= 10;
			}
			yyval.u.i = ret;
		}
break;
case 96:
#line 1205 "ftpcmd.y"
{
		yyval.u.i = check_login1();
		}
break;
case 97:
#line 1212 "ftpcmd.y"
{
		if (noepsv) {
			reply(500, "EPSV and EPRT commands disabled.");
			yyval.u.i = 0;
		}
		else
			yyval.u.i = check_login1();
		}
break;
case 98:
#line 1224 "ftpcmd.y"
{
		if (readonly) {
			reply(550, "Permission denied.");
			yyval.u.i = 0;
		}
		else
			yyval.u.i = check_login1();
		}
break;
case 99:
#line 1236 "ftpcmd.y"
{
#ifdef USE_SSL
			if (logged_in || ssl_apbu_flag)
				yyval.u.i = 1;
			else {
				reply(534, "Please login with USER and PASS.");
				yyval.u.i = 0;
			}
#else /* !USE_SSL */
			/* do nothing */
			yyval.u.i = 1;
#endif /* USE_SSL */
		}
break;
#line 2754 "ftpcmd.c"
    }
    yyssp -= yym;
    yystate = *yyssp;
    yyvsp -= yym;
    yym = yylhs[yyn];
    if (yystate == 0 && yym == 0)
    {
#if YYDEBUG
        if (yydebug)
            printf("%sdebug: after reduction, shifting from state 0 to\
 state %d\n", YYPREFIX, YYFINAL);
#endif
        yystate = YYFINAL;
        *++yyssp = YYFINAL;
        *++yyvsp = yyval;
        if (yychar < 0)
        {
            if ((yychar = yylex()) < 0) yychar = 0;
#if YYDEBUG
            if (yydebug)
            {
                yys = 0;
                if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
                if (!yys) yys = "illegal-symbol";
                printf("%sdebug: state %d, reading %d (%s)\n",
                        YYPREFIX, YYFINAL, yychar, yys);
            }
#endif
        }
        if (yychar == 0) goto yyaccept;
        goto yyloop;
    }
    if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
            yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
        yystate = yytable[yyn];
    else
        yystate = yydgoto[yym];
#if YYDEBUG
    if (yydebug)
        printf("%sdebug: after reduction, shifting from state %d \
to state %d\n", YYPREFIX, *yyssp, yystate);
#endif
    if (yyssp >= yysslim && yygrowstack())
    {
        goto yyoverflow;
    }
    *++yyssp = yystate;
    *++yyvsp = yyval;
    goto yyloop;
yyoverflow:
    yyerror("yacc stack overflow");
yyabort:
    return (1);
yyaccept:
    return (0);
}


syntax highlighted by Code2HTML, v. 0.9.1