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