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