17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (C) 1997-2003 by Darren Reed
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * See the IPFILTER.LICENCE file for details on licencing.
57c478bd9Sstevel@tonic-gate  *
6ab25eeb5Syz  * $Id: ip_ftp_pxy.c,v 2.88.2.15 2005/03/19 19:38:10 darrenr Exp $
7ab25eeb5Syz  *
833f2fefdSDarren Reed  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
97c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
107c478bd9Sstevel@tonic-gate  *
117c478bd9Sstevel@tonic-gate  * Simple FTP transparent proxy for in-kernel use.  For use with the NAT
127c478bd9Sstevel@tonic-gate  * code.
13ab25eeb5Syz */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #define	IPF_FTP_PROXY
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate #define	IPF_MINPORTLEN	18
187c478bd9Sstevel@tonic-gate #define	IPF_MAXPORTLEN	30
197c478bd9Sstevel@tonic-gate #define	IPF_MIN227LEN	39
207c478bd9Sstevel@tonic-gate #define	IPF_MAX227LEN	51
217c478bd9Sstevel@tonic-gate #define	IPF_MIN229LEN	47
227c478bd9Sstevel@tonic-gate #define	IPF_MAX229LEN	51
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate #define	FTPXY_GO	0
257c478bd9Sstevel@tonic-gate #define	FTPXY_INIT	1
267c478bd9Sstevel@tonic-gate #define	FTPXY_USER_1	2
277c478bd9Sstevel@tonic-gate #define	FTPXY_USOK_1	3
287c478bd9Sstevel@tonic-gate #define	FTPXY_PASS_1	4
297c478bd9Sstevel@tonic-gate #define	FTPXY_PAOK_1	5
307c478bd9Sstevel@tonic-gate #define	FTPXY_AUTH_1	6
317c478bd9Sstevel@tonic-gate #define	FTPXY_AUOK_1	7
327c478bd9Sstevel@tonic-gate #define	FTPXY_ADAT_1	8
337c478bd9Sstevel@tonic-gate #define	FTPXY_ADOK_1	9
347c478bd9Sstevel@tonic-gate #define	FTPXY_ACCT_1	10
357c478bd9Sstevel@tonic-gate #define	FTPXY_ACOK_1	11
367c478bd9Sstevel@tonic-gate #define	FTPXY_USER_2	12
377c478bd9Sstevel@tonic-gate #define	FTPXY_USOK_2	13
387c478bd9Sstevel@tonic-gate #define	FTPXY_PASS_2	14
397c478bd9Sstevel@tonic-gate #define	FTPXY_PAOK_2	15
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate  * Values for FTP commands.  Numerics cover 0-999
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate #define	FTPXY_C_PASV	1000
457c478bd9Sstevel@tonic-gate 
46f4b3ec61Sdh typedef struct ifs_ftppxy {
47f4b3ec61Sdh 	frentry_t		ftppxyfr;
48f4b3ec61Sdh 	int			ftp_proxy_init;
49f4b3ec61Sdh 	int			ippr_ftp_pasvonly;
50f4b3ec61Sdh 	int			ippr_ftp_insecure;
51f4b3ec61Sdh 				/* Do not require logins before transfers */
52f4b3ec61Sdh 	int			ippr_ftp_pasvrdr;
53f4b3ec61Sdh 	int			ippr_ftp_forcepasv;
54f4b3ec61Sdh 				/* PASV must be last command prior to 227 */
55f4b3ec61Sdh 	/*
56f4b3ec61Sdh 	 * 1 - security
57f4b3ec61Sdh 	 * 2 - errors
58f4b3ec61Sdh 	 * 3 - error debugging
59f4b3ec61Sdh 	 * 4 - parsing errors
60f4b3ec61Sdh 	 * 5 - parsing info
61f4b3ec61Sdh 	 * 6 - parsing debug
62f4b3ec61Sdh 	 */
63f4b3ec61Sdh 	int			ippr_ftp_debug;
64f4b3ec61Sdh 	ipftuneable_t		ftptune;
65f4b3ec61Sdh } ifs_ftppxy_t;
66f4b3ec61Sdh 
67f4b3ec61Sdh int ippr_ftp_client __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int,
68f4b3ec61Sdh     ifs_ftppxy_t *));
697c478bd9Sstevel@tonic-gate int ippr_ftp_complete __P((char *, size_t));
70f4b3ec61Sdh int ippr_ftp_in __P((fr_info_t *, ap_session_t *, nat_t *, void *));
71f4b3ec61Sdh int ippr_ftp_init __P((void **, ipf_stack_t *));
72f4b3ec61Sdh void ippr_ftp_fini __P((void **, ipf_stack_t *));
73f4b3ec61Sdh int ippr_ftp_new __P((fr_info_t *, ap_session_t *, nat_t *, void *));
74f4b3ec61Sdh int ippr_ftp_out __P((fr_info_t *, ap_session_t *, nat_t *, void *));
75f4b3ec61Sdh int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int,
76f4b3ec61Sdh     ifs_ftppxy_t *));
77f4b3ec61Sdh int ippr_ftp_epsv __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int,
78f4b3ec61Sdh     ifs_ftppxy_t *));
79f4b3ec61Sdh int ippr_ftp_port __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int,
80f4b3ec61Sdh     ifs_ftppxy_t *));
81f4b3ec61Sdh int ippr_ftp_process __P((fr_info_t *, nat_t *, ftpinfo_t *, int,
82f4b3ec61Sdh     ifs_ftppxy_t *));
83f4b3ec61Sdh int ippr_ftp_server __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int,
84f4b3ec61Sdh     ifs_ftppxy_t *));
85f4b3ec61Sdh int ippr_ftp_valid __P((ftpinfo_t *, int, char *, size_t, ifs_ftppxy_t *));
86f4b3ec61Sdh int ippr_ftp_server_valid __P((ftpside_t *, char *, size_t, ifs_ftppxy_t *));
87f4b3ec61Sdh int ippr_ftp_client_valid __P((ftpside_t *, char *, size_t, ifs_ftppxy_t *));
887c478bd9Sstevel@tonic-gate u_short ippr_ftp_atoi __P((char **));
897c478bd9Sstevel@tonic-gate int ippr_ftp_pasvreply __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *,
90f4b3ec61Sdh 			    u_int, char *, char *, u_int, ifs_ftppxy_t *));
91f4b3ec61Sdh 
92f4b3ec61Sdh /*
93f4b3ec61Sdh  * Initialize local structures.
94f4b3ec61Sdh  */
ippr_ftp_init(private,ifs)95f4b3ec61Sdh int ippr_ftp_init(private, ifs)
96f4b3ec61Sdh void **private;
97f4b3ec61Sdh ipf_stack_t *ifs;
98f4b3ec61Sdh {
99f4b3ec61Sdh 	ifs_ftppxy_t *ifsftp;
1007c478bd9Sstevel@tonic-gate 
101f4b3ec61Sdh 	KMALLOC(ifsftp, ifs_ftppxy_t *);
102f4b3ec61Sdh 	if (ifsftp == NULL)
103f4b3ec61Sdh 		return -1;
1047c478bd9Sstevel@tonic-gate 
105f4b3ec61Sdh 	bzero((char *)&ifsftp->ftppxyfr, sizeof(ifsftp->ftppxyfr));
106f4b3ec61Sdh 	ifsftp->ftppxyfr.fr_ref = 1;
107f4b3ec61Sdh 	ifsftp->ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
108f4b3ec61Sdh 	MUTEX_INIT(&ifsftp->ftppxyfr.fr_lock, "FTP Proxy Mutex");
109f4b3ec61Sdh 	ifsftp->ftp_proxy_init = 1;
110f4b3ec61Sdh 	ifsftp->ippr_ftp_pasvonly = 0;
111f4b3ec61Sdh 	ifsftp->ippr_ftp_insecure = 0;
112f4b3ec61Sdh 	ifsftp->ippr_ftp_pasvrdr = 0;
113f4b3ec61Sdh 	ifsftp->ippr_ftp_forcepasv = 0;
114ab25eeb5Syz #if defined(_KERNEL)
115f4b3ec61Sdh 	ifsftp->ippr_ftp_debug = 0;
116ab25eeb5Syz #else
117f4b3ec61Sdh 	ifsftp->ippr_ftp_debug = 2;
118ab25eeb5Syz #endif
119f4b3ec61Sdh 	bzero((char *)&ifsftp->ftptune, sizeof(ifsftp->ftptune));
120f4b3ec61Sdh 	ifsftp->ftptune.ipft_pint = (uint_t *)&ifsftp->ippr_ftp_debug;
121f4b3ec61Sdh 	ifsftp->ftptune.ipft_name = "ippr_ftp_debug";
122f4b3ec61Sdh 	ifsftp->ftptune.ipft_max = 10;
123f4b3ec61Sdh 	ifsftp->ftptune.ipft_sz = sizeof(ifsftp->ippr_ftp_debug);
124f4b3ec61Sdh 	ifsftp->ftptune.ipft_next = NULL;
125ab25eeb5Syz 
126f4b3ec61Sdh 	(void) fr_addipftune(&ifsftp->ftptune, ifs);
1277c478bd9Sstevel@tonic-gate 
128f4b3ec61Sdh 	*private = (void *)ifsftp;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	return 0;
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 
ippr_ftp_fini(private,ifs)134f4b3ec61Sdh void ippr_ftp_fini(private, ifs)
135f4b3ec61Sdh void **private;
136f4b3ec61Sdh ipf_stack_t *ifs;
1377c478bd9Sstevel@tonic-gate {
138f4b3ec61Sdh 	ifs_ftppxy_t *ifsftp = *((ifs_ftppxy_t **)private);
139ab25eeb5Syz 
140f4b3ec61Sdh 	(void) fr_delipftune(&ifsftp->ftptune, ifs);
141f4b3ec61Sdh 
142f4b3ec61Sdh 	if (ifsftp->ftp_proxy_init == 1) {
143f4b3ec61Sdh 		MUTEX_DESTROY(&ifsftp->ftppxyfr.fr_lock);
144f4b3ec61Sdh 		ifsftp->ftp_proxy_init = 0;
1457c478bd9Sstevel@tonic-gate 	}
146f4b3ec61Sdh 
147f4b3ec61Sdh 	KFREE(ifsftp);
148f4b3ec61Sdh 	*private = NULL;
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 
152f4b3ec61Sdh /*ARGSUSED*/
ippr_ftp_new(fin,aps,nat,private)153f4b3ec61Sdh int ippr_ftp_new(fin, aps, nat, private)
1547c478bd9Sstevel@tonic-gate fr_info_t *fin;
1557c478bd9Sstevel@tonic-gate ap_session_t *aps;
1567c478bd9Sstevel@tonic-gate nat_t *nat;
157f4b3ec61Sdh void *private;
1587c478bd9Sstevel@tonic-gate {
1597c478bd9Sstevel@tonic-gate 	ftpinfo_t *ftp;
1607c478bd9Sstevel@tonic-gate 	ftpside_t *f;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	KMALLOC(ftp, ftpinfo_t *);
1637c478bd9Sstevel@tonic-gate 	if (ftp == NULL)
1647c478bd9Sstevel@tonic-gate 		return -1;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	fin = fin;	/* LINT */
1677c478bd9Sstevel@tonic-gate 	nat = nat;	/* LINT */
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	aps->aps_data = ftp;
1707c478bd9Sstevel@tonic-gate 	aps->aps_psiz = sizeof(ftpinfo_t);
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	bzero((char *)ftp, sizeof(*ftp));
1737c478bd9Sstevel@tonic-gate 	f = &ftp->ftp_side[0];
1747c478bd9Sstevel@tonic-gate 	f->ftps_rptr = f->ftps_buf;
1757c478bd9Sstevel@tonic-gate 	f->ftps_wptr = f->ftps_buf;
1767c478bd9Sstevel@tonic-gate 	f = &ftp->ftp_side[1];
1777c478bd9Sstevel@tonic-gate 	f->ftps_rptr = f->ftps_buf;
1787c478bd9Sstevel@tonic-gate 	f->ftps_wptr = f->ftps_buf;
1797c478bd9Sstevel@tonic-gate 	ftp->ftp_passok = FTPXY_INIT;
1807c478bd9Sstevel@tonic-gate 	ftp->ftp_incok = 0;
1817c478bd9Sstevel@tonic-gate 	return 0;
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 
ippr_ftp_port(fin,ip,nat,f,dlen,ifsftp)185f4b3ec61Sdh int ippr_ftp_port(fin, ip, nat, f, dlen, ifsftp)
1867c478bd9Sstevel@tonic-gate fr_info_t *fin;
1877c478bd9Sstevel@tonic-gate ip_t *ip;
1887c478bd9Sstevel@tonic-gate nat_t *nat;
1897c478bd9Sstevel@tonic-gate ftpside_t *f;
1907c478bd9Sstevel@tonic-gate int dlen;
191f4b3ec61Sdh ifs_ftppxy_t *ifsftp;
1927c478bd9Sstevel@tonic-gate {
1937c478bd9Sstevel@tonic-gate 	tcphdr_t *tcp, tcph, *tcp2 = &tcph;
1947c478bd9Sstevel@tonic-gate 	char newbuf[IPF_FTPBUFSZ], *s;
1957c478bd9Sstevel@tonic-gate 	struct in_addr swip, swip2;
1967c478bd9Sstevel@tonic-gate 	u_int a1, a2, a3, a4;
197ab25eeb5Syz 	int inc, off, flags;
1987c478bd9Sstevel@tonic-gate 	u_short a5, a6, sp;
1997c478bd9Sstevel@tonic-gate 	size_t nlen, olen;
2007c478bd9Sstevel@tonic-gate 	fr_info_t fi;
2017c478bd9Sstevel@tonic-gate 	nat_t *nat2;
2027c478bd9Sstevel@tonic-gate 	mb_t *m;
203f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	m = fin->fin_m;
2067c478bd9Sstevel@tonic-gate 	tcp = (tcphdr_t *)fin->fin_dp;
207ab25eeb5Syz 	off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	/*
2107c478bd9Sstevel@tonic-gate 	 * Check for client sending out PORT message.
2117c478bd9Sstevel@tonic-gate 	 */
2127c478bd9Sstevel@tonic-gate 	if (dlen < IPF_MINPORTLEN) {
213f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1)
214ab25eeb5Syz 			printf("ippr_ftp_port:dlen(%d) < IPF_MINPORTLEN\n",
215ab25eeb5Syz 			       dlen);
2167c478bd9Sstevel@tonic-gate 		return 0;
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate 	/*
2197c478bd9Sstevel@tonic-gate 	 * Skip the PORT command + space
2207c478bd9Sstevel@tonic-gate 	 */
2217c478bd9Sstevel@tonic-gate 	s = f->ftps_rptr + 5;
2227c478bd9Sstevel@tonic-gate 	/*
2237c478bd9Sstevel@tonic-gate 	 * Pick out the address components, two at a time.
2247c478bd9Sstevel@tonic-gate 	 */
2257c478bd9Sstevel@tonic-gate 	a1 = ippr_ftp_atoi(&s);
2267c478bd9Sstevel@tonic-gate 	if (s == NULL) {
227f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1)
228ab25eeb5Syz 			printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 1);
2297c478bd9Sstevel@tonic-gate 		return 0;
2307c478bd9Sstevel@tonic-gate 	}
2317c478bd9Sstevel@tonic-gate 	a2 = ippr_ftp_atoi(&s);
2327c478bd9Sstevel@tonic-gate 	if (s == NULL) {
233f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1)
234ab25eeb5Syz 			printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 2);
2357c478bd9Sstevel@tonic-gate 		return 0;
2367c478bd9Sstevel@tonic-gate 	}
237ab25eeb5Syz 
2387c478bd9Sstevel@tonic-gate 	/*
2397c478bd9Sstevel@tonic-gate 	 * Check that IP address in the PORT/PASV reply is the same as the
2407c478bd9Sstevel@tonic-gate 	 * sender of the command - prevents using PORT for port scanning.
2417c478bd9Sstevel@tonic-gate 	 */
2427c478bd9Sstevel@tonic-gate 	a1 <<= 16;
2437c478bd9Sstevel@tonic-gate 	a1 |= a2;
2447c478bd9Sstevel@tonic-gate 	if (((nat->nat_dir == NAT_OUTBOUND) &&
2457c478bd9Sstevel@tonic-gate 	     (a1 != ntohl(nat->nat_inip.s_addr))) ||
2467c478bd9Sstevel@tonic-gate 	    ((nat->nat_dir == NAT_INBOUND) &&
2477c478bd9Sstevel@tonic-gate 	     (a1 != ntohl(nat->nat_oip.s_addr)))) {
248f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 0)
249ab25eeb5Syz 			printf("ippr_ftp_port:%s != nat->nat_inip\n", "a1");
2507c478bd9Sstevel@tonic-gate 		return APR_ERR(1);
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	a5 = ippr_ftp_atoi(&s);
2547c478bd9Sstevel@tonic-gate 	if (s == NULL) {
255f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1)
256ab25eeb5Syz 			printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 3);
2577c478bd9Sstevel@tonic-gate 		return 0;
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 	if (*s == ')')
2607c478bd9Sstevel@tonic-gate 		s++;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	/*
2637c478bd9Sstevel@tonic-gate 	 * check for CR-LF at the end.
2647c478bd9Sstevel@tonic-gate 	 */
2657c478bd9Sstevel@tonic-gate 	if (*s == '\n')
2667c478bd9Sstevel@tonic-gate 		s--;
2677c478bd9Sstevel@tonic-gate 	if ((*s == '\r') && (*(s + 1) == '\n')) {
2687c478bd9Sstevel@tonic-gate 		s += 2;
2697c478bd9Sstevel@tonic-gate 		a6 = a5 & 0xff;
2707c478bd9Sstevel@tonic-gate 	} else {
271f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1)
272ab25eeb5Syz 			printf("ippr_ftp_port:missing %s\n", "cr-lf");
2737c478bd9Sstevel@tonic-gate 		return 0;
2747c478bd9Sstevel@tonic-gate 	}
275ab25eeb5Syz 
2767c478bd9Sstevel@tonic-gate 	a5 >>= 8;
2777c478bd9Sstevel@tonic-gate 	a5 &= 0xff;
278ab25eeb5Syz 	sp = a5 << 8 | a6;
279ab25eeb5Syz 	/*
280ab25eeb5Syz 	 * Don't allow the PORT command to specify a port < 1024 due to
281ab25eeb5Syz 	 * security crap.
282ab25eeb5Syz 	 */
283ab25eeb5Syz 	if (sp < 1024) {
284f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 0)
285ab25eeb5Syz 			printf("ippr_ftp_port:sp(%d) < 1024\n", sp);
286ab25eeb5Syz 		return 0;
287ab25eeb5Syz 	}
2887c478bd9Sstevel@tonic-gate 	/*
2897c478bd9Sstevel@tonic-gate 	 * Calculate new address parts for PORT command
2907c478bd9Sstevel@tonic-gate 	 */
2917c478bd9Sstevel@tonic-gate 	if (nat->nat_dir == NAT_INBOUND)
2927c478bd9Sstevel@tonic-gate 		a1 = ntohl(nat->nat_oip.s_addr);
2937c478bd9Sstevel@tonic-gate 	else
2947c478bd9Sstevel@tonic-gate 		a1 = ntohl(ip->ip_src.s_addr);
2957c478bd9Sstevel@tonic-gate 	a2 = (a1 >> 16) & 0xff;
2967c478bd9Sstevel@tonic-gate 	a3 = (a1 >> 8) & 0xff;
2977c478bd9Sstevel@tonic-gate 	a4 = a1 & 0xff;
2987c478bd9Sstevel@tonic-gate 	a1 >>= 24;
2997c478bd9Sstevel@tonic-gate 	olen = s - f->ftps_rptr;
3007c478bd9Sstevel@tonic-gate 	/* DO NOT change this to snprintf! */
301ab25eeb5Syz #if defined(SNPRINTF) && defined(_KERNEL)
302ab25eeb5Syz 	(void) SNPRINTF(newbuf, sizeof(newbuf), "%s %u,%u,%u,%u,%u,%u\r\n",
303ab25eeb5Syz 		 "PORT", a1, a2, a3, a4, a5, a6);
3047c478bd9Sstevel@tonic-gate #else
3057c478bd9Sstevel@tonic-gate 	(void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n",
3067c478bd9Sstevel@tonic-gate 		       "PORT", a1, a2, a3, a4, a5, a6);
3077c478bd9Sstevel@tonic-gate #endif
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	nlen = strlen(newbuf);
3107c478bd9Sstevel@tonic-gate 	inc = nlen - olen;
3117c478bd9Sstevel@tonic-gate 	if ((inc + ip->ip_len) > 65535) {
312f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 0)
313ab25eeb5Syz 			printf("ippr_ftp_port:inc(%d) + ip->ip_len > 65535\n",
314ab25eeb5Syz 			       inc);
3157c478bd9Sstevel@tonic-gate 		return 0;
3167c478bd9Sstevel@tonic-gate 	}
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate #if !defined(_KERNEL)
3197c478bd9Sstevel@tonic-gate 	bcopy(newbuf, MTOD(m, char *) + off, nlen);
3207c478bd9Sstevel@tonic-gate #else
3217c478bd9Sstevel@tonic-gate # if defined(MENTAT)
3227c478bd9Sstevel@tonic-gate 	if (inc < 0)
3237c478bd9Sstevel@tonic-gate 		(void)adjmsg(m, inc);
324ab25eeb5Syz # else /* defined(MENTAT) */
325ab25eeb5Syz 	/*
326ab25eeb5Syz 	 * m_adj takes care of pkthdr.len, if required and treats inc<0 to
327ab25eeb5Syz 	 * mean remove -len bytes from the end of the packet.
328ab25eeb5Syz 	 * The mbuf chain will be extended if necessary by m_copyback().
329ab25eeb5Syz 	 */
3307c478bd9Sstevel@tonic-gate 	if (inc < 0)
3317c478bd9Sstevel@tonic-gate 		m_adj(m, inc);
332ab25eeb5Syz # endif /* defined(MENTAT) */
333ab25eeb5Syz #endif /* !defined(_KERNEL) */
3347c478bd9Sstevel@tonic-gate 	COPYBACK(m, off, nlen, newbuf);
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	if (inc != 0) {
3377c478bd9Sstevel@tonic-gate 		ip->ip_len += inc;
3387c478bd9Sstevel@tonic-gate 		fin->fin_dlen += inc;
3397c478bd9Sstevel@tonic-gate 		fin->fin_plen += inc;
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	/*
3437c478bd9Sstevel@tonic-gate 	 * The server may not make the connection back from port 20, but
3447c478bd9Sstevel@tonic-gate 	 * it is the most likely so use it here to check for a conflicting
3457c478bd9Sstevel@tonic-gate 	 * mapping.
3467c478bd9Sstevel@tonic-gate 	 */
3477c478bd9Sstevel@tonic-gate 	bcopy((char *)fin, (char *)&fi, sizeof(fi));
3487c478bd9Sstevel@tonic-gate 	fi.fin_flx |= FI_IGNORE;
3497c478bd9Sstevel@tonic-gate 	fi.fin_data[0] = sp;
3507c478bd9Sstevel@tonic-gate 	fi.fin_data[1] = fin->fin_data[1] - 1;
351ab25eeb5Syz 	/*
352ab25eeb5Syz 	 * Add skeleton NAT entry for connection which will come back the
353ab25eeb5Syz 	 * other way.
354ab25eeb5Syz 	 */
3557c478bd9Sstevel@tonic-gate 	if (nat->nat_dir == NAT_OUTBOUND)
3567c478bd9Sstevel@tonic-gate 		nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p,
3577c478bd9Sstevel@tonic-gate 				     nat->nat_inip, nat->nat_oip);
3587c478bd9Sstevel@tonic-gate 	else
3597c478bd9Sstevel@tonic-gate 		nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p,
3607c478bd9Sstevel@tonic-gate 				    nat->nat_inip, nat->nat_oip);
3617c478bd9Sstevel@tonic-gate 	if (nat2 == NULL) {
3627c478bd9Sstevel@tonic-gate 		int slen;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 		slen = ip->ip_len;
3657c478bd9Sstevel@tonic-gate 		ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
3667c478bd9Sstevel@tonic-gate 		bzero((char *)tcp2, sizeof(*tcp2));
3677c478bd9Sstevel@tonic-gate 		tcp2->th_win = htons(8192);
3687c478bd9Sstevel@tonic-gate 		tcp2->th_sport = htons(sp);
3697c478bd9Sstevel@tonic-gate 		TCP_OFF_A(tcp2, 5);
3707c478bd9Sstevel@tonic-gate 		tcp2->th_flags = TH_SYN;
3717c478bd9Sstevel@tonic-gate 		tcp2->th_dport = 0; /* XXX - don't specify remote port */
3727c478bd9Sstevel@tonic-gate 		fi.fin_data[1] = 0;
3737c478bd9Sstevel@tonic-gate 		fi.fin_dlen = sizeof(*tcp2);
3747c478bd9Sstevel@tonic-gate 		fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
3757c478bd9Sstevel@tonic-gate 		fi.fin_dp = (char *)tcp2;
376f4b3ec61Sdh 		fi.fin_fr = &ifsftp->ftppxyfr;
3777c478bd9Sstevel@tonic-gate 		fi.fin_out = nat->nat_dir;
3787c478bd9Sstevel@tonic-gate 		fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
3797c478bd9Sstevel@tonic-gate 		swip = ip->ip_src;
3807c478bd9Sstevel@tonic-gate 		swip2 = ip->ip_dst;
3817c478bd9Sstevel@tonic-gate 		if (nat->nat_dir == NAT_OUTBOUND) {
3827c478bd9Sstevel@tonic-gate 			fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
3837c478bd9Sstevel@tonic-gate 			ip->ip_src = nat->nat_inip;
3847c478bd9Sstevel@tonic-gate 		} else if (nat->nat_dir == NAT_INBOUND) {
3857c478bd9Sstevel@tonic-gate 			fi.fin_fi.fi_saddr = nat->nat_oip.s_addr;
3867c478bd9Sstevel@tonic-gate 			ip->ip_src = nat->nat_oip;
3877c478bd9Sstevel@tonic-gate 		}
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 		flags = NAT_SLAVE|IPN_TCP|SI_W_DPORT;
3907c478bd9Sstevel@tonic-gate 		if (nat->nat_dir == NAT_INBOUND)
3917c478bd9Sstevel@tonic-gate 			flags |= NAT_NOTRULEPORT;
3927c478bd9Sstevel@tonic-gate 		nat2 = nat_new(&fi, nat->nat_ptr, NULL, flags, nat->nat_dir);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 		if (nat2 != NULL) {
3957c478bd9Sstevel@tonic-gate 			(void) nat_proto(&fi, nat2, IPN_TCP);
3967c478bd9Sstevel@tonic-gate 			nat_update(&fi, nat2, nat->nat_ptr);
3977c478bd9Sstevel@tonic-gate 			fi.fin_ifp = NULL;
3987c478bd9Sstevel@tonic-gate 			if (nat->nat_dir == NAT_INBOUND) {
3997c478bd9Sstevel@tonic-gate 				fi.fin_fi.fi_daddr = nat->nat_inip.s_addr;
4007c478bd9Sstevel@tonic-gate 				ip->ip_dst = nat->nat_inip;
4017c478bd9Sstevel@tonic-gate 			}
4027c478bd9Sstevel@tonic-gate 			(void) fr_addstate(&fi, &nat2->nat_state, SI_W_DPORT);
4037c478bd9Sstevel@tonic-gate 		}
4047c478bd9Sstevel@tonic-gate 		ip->ip_len = slen;
4057c478bd9Sstevel@tonic-gate 		ip->ip_src = swip;
4067c478bd9Sstevel@tonic-gate 		ip->ip_dst = swip2;
4077c478bd9Sstevel@tonic-gate 	} else {
4087c478bd9Sstevel@tonic-gate 		ipstate_t *is;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 		nat_update(&fi, nat2, nat->nat_ptr);
411f4b3ec61Sdh 		READ_ENTER(&ifs->ifs_ipf_state);
4127c478bd9Sstevel@tonic-gate 		is = nat2->nat_state;
4137c478bd9Sstevel@tonic-gate 		if (is != NULL) {
4147c478bd9Sstevel@tonic-gate 			MUTEX_ENTER(&is->is_lock);
415*55fea89dSDan Cross 			(void)fr_tcp_age(&is->is_sti, &fi, ifs->ifs_ips_tqtqb,
416f4b3ec61Sdh 				         is->is_flags);
4177c478bd9Sstevel@tonic-gate 			MUTEX_EXIT(&is->is_lock);
4187c478bd9Sstevel@tonic-gate 		}
419f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_state);
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 	return APR_INC(inc);
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 
ippr_ftp_client(fin,ip,nat,ftp,dlen,ifsftp)425f4b3ec61Sdh int ippr_ftp_client(fin, ip, nat, ftp, dlen, ifsftp)
4267c478bd9Sstevel@tonic-gate fr_info_t *fin;
4277c478bd9Sstevel@tonic-gate nat_t *nat;
4287c478bd9Sstevel@tonic-gate ftpinfo_t *ftp;
4297c478bd9Sstevel@tonic-gate ip_t *ip;
4307c478bd9Sstevel@tonic-gate int dlen;
431f4b3ec61Sdh ifs_ftppxy_t *ifsftp;
4327c478bd9Sstevel@tonic-gate {
4337c478bd9Sstevel@tonic-gate 	char *rptr, *wptr, cmd[6], c;
4347c478bd9Sstevel@tonic-gate 	ftpside_t *f;
4357c478bd9Sstevel@tonic-gate 	int inc, i;
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	inc = 0;
4387c478bd9Sstevel@tonic-gate 	f = &ftp->ftp_side[0];
4397c478bd9Sstevel@tonic-gate 	rptr = f->ftps_rptr;
4407c478bd9Sstevel@tonic-gate 	wptr = f->ftps_wptr;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	for (i = 0; (i < 5) && (i < dlen); i++) {
4437c478bd9Sstevel@tonic-gate 		c = rptr[i];
444ab25eeb5Syz 		if (ISALPHA(c)) {
445ab25eeb5Syz 			cmd[i] = TOUPPER(c);
4467c478bd9Sstevel@tonic-gate 		} else {
4477c478bd9Sstevel@tonic-gate 			cmd[i] = c;
4487c478bd9Sstevel@tonic-gate 		}
4497c478bd9Sstevel@tonic-gate 	}
4507c478bd9Sstevel@tonic-gate 	cmd[i] = '\0';
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	ftp->ftp_incok = 0;
4537c478bd9Sstevel@tonic-gate 	if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) {
4547c478bd9Sstevel@tonic-gate 		if (ftp->ftp_passok == FTPXY_ADOK_1 ||
4557c478bd9Sstevel@tonic-gate 		    ftp->ftp_passok == FTPXY_AUOK_1) {
4567c478bd9Sstevel@tonic-gate 			ftp->ftp_passok = FTPXY_USER_2;
4577c478bd9Sstevel@tonic-gate 			ftp->ftp_incok = 1;
4587c478bd9Sstevel@tonic-gate 		} else {
4597c478bd9Sstevel@tonic-gate 			ftp->ftp_passok = FTPXY_USER_1;
4607c478bd9Sstevel@tonic-gate 			ftp->ftp_incok = 1;
4617c478bd9Sstevel@tonic-gate 		}
4627c478bd9Sstevel@tonic-gate 	} else if (!strncmp(cmd, "AUTH ", 5)) {
4637c478bd9Sstevel@tonic-gate 		ftp->ftp_passok = FTPXY_AUTH_1;
4647c478bd9Sstevel@tonic-gate 		ftp->ftp_incok = 1;
4657c478bd9Sstevel@tonic-gate 	} else if (!strncmp(cmd, "PASS ", 5)) {
4667c478bd9Sstevel@tonic-gate 		if (ftp->ftp_passok == FTPXY_USOK_1) {
4677c478bd9Sstevel@tonic-gate 			ftp->ftp_passok = FTPXY_PASS_1;
4687c478bd9Sstevel@tonic-gate 			ftp->ftp_incok = 1;
4697c478bd9Sstevel@tonic-gate 		} else if (ftp->ftp_passok == FTPXY_USOK_2) {
4707c478bd9Sstevel@tonic-gate 			ftp->ftp_passok = FTPXY_PASS_2;
4717c478bd9Sstevel@tonic-gate 			ftp->ftp_incok = 1;
4727c478bd9Sstevel@tonic-gate 		}
4737c478bd9Sstevel@tonic-gate 	} else if ((ftp->ftp_passok == FTPXY_AUOK_1) &&
4747c478bd9Sstevel@tonic-gate 		   !strncmp(cmd, "ADAT ", 5)) {
4757c478bd9Sstevel@tonic-gate 		ftp->ftp_passok = FTPXY_ADAT_1;
4767c478bd9Sstevel@tonic-gate 		ftp->ftp_incok = 1;
4777c478bd9Sstevel@tonic-gate 	} else if ((ftp->ftp_passok == FTPXY_PAOK_1 ||
4787c478bd9Sstevel@tonic-gate 		    ftp->ftp_passok == FTPXY_PAOK_2) &&
4797c478bd9Sstevel@tonic-gate 		 !strncmp(cmd, "ACCT ", 5)) {
4807c478bd9Sstevel@tonic-gate 		ftp->ftp_passok = FTPXY_ACCT_1;
4817c478bd9Sstevel@tonic-gate 		ftp->ftp_incok = 1;
482f4b3ec61Sdh 	} else if ((ftp->ftp_passok == FTPXY_GO) &&
483f4b3ec61Sdh 		 !ifsftp->ippr_ftp_pasvonly &&
4847c478bd9Sstevel@tonic-gate 		 !strncmp(cmd, "PORT ", 5)) {
485f4b3ec61Sdh 		inc = ippr_ftp_port(fin, ip, nat, f, dlen, ifsftp);
486f4b3ec61Sdh 	} else if (ifsftp->ippr_ftp_insecure && !ifsftp->ippr_ftp_pasvonly &&
4877c478bd9Sstevel@tonic-gate 		   !strncmp(cmd, "PORT ", 5)) {
488f4b3ec61Sdh 		inc = ippr_ftp_port(fin, ip, nat, f, dlen, ifsftp);
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	while ((*rptr++ != '\n') && (rptr < wptr))
4927c478bd9Sstevel@tonic-gate 		;
4937c478bd9Sstevel@tonic-gate 	f->ftps_rptr = rptr;
4947c478bd9Sstevel@tonic-gate 	return inc;
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 
ippr_ftp_pasv(fin,ip,nat,ftp,dlen,ifsftp)498f4b3ec61Sdh int ippr_ftp_pasv(fin, ip, nat, ftp, dlen, ifsftp)
4997c478bd9Sstevel@tonic-gate fr_info_t *fin;
5007c478bd9Sstevel@tonic-gate ip_t *ip;
5017c478bd9Sstevel@tonic-gate nat_t *nat;
5027c478bd9Sstevel@tonic-gate ftpinfo_t *ftp;
5037c478bd9Sstevel@tonic-gate int dlen;
504f4b3ec61Sdh ifs_ftppxy_t *ifsftp;
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate 	u_int a1, a2, a3, a4, data_ip;
5077c478bd9Sstevel@tonic-gate 	char newbuf[IPF_FTPBUFSZ];
508ab25eeb5Syz 	char *s, *brackets[2];
5097c478bd9Sstevel@tonic-gate 	u_short a5, a6;
5107c478bd9Sstevel@tonic-gate 	ftpside_t *f;
5117c478bd9Sstevel@tonic-gate 
512f4b3ec61Sdh 	if (ifsftp->ippr_ftp_forcepasv != 0 &&
5137c478bd9Sstevel@tonic-gate 	    ftp->ftp_side[0].ftps_cmds != FTPXY_C_PASV) {
514f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 0)
515ab25eeb5Syz 			printf("ippr_ftp_pasv:ftps_cmds(%d) != FTPXY_C_PASV\n",
516ab25eeb5Syz 			       ftp->ftp_side[0].ftps_cmds);
5177c478bd9Sstevel@tonic-gate 		return 0;
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	f = &ftp->ftp_side[1];
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate #define	PASV_REPLEN	24
5237c478bd9Sstevel@tonic-gate 	/*
5247c478bd9Sstevel@tonic-gate 	 * Check for PASV reply message.
5257c478bd9Sstevel@tonic-gate 	 */
5267c478bd9Sstevel@tonic-gate 	if (dlen < IPF_MIN227LEN) {
527f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1)
528ab25eeb5Syz 			printf("ippr_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n",
529ab25eeb5Syz 			       dlen);
5307c478bd9Sstevel@tonic-gate 		return 0;
5317c478bd9Sstevel@tonic-gate 	} else if (strncmp(f->ftps_rptr,
5327c478bd9Sstevel@tonic-gate 			   "227 Entering Passive Mod", PASV_REPLEN)) {
533f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 0)
534ab25eeb5Syz 			printf("ippr_ftp_pasv:%d reply wrong\n", 227);
5357c478bd9Sstevel@tonic-gate 		return 0;
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 
538ab25eeb5Syz 	brackets[0] = "";
539ab25eeb5Syz 	brackets[1] = "";
5407c478bd9Sstevel@tonic-gate 	/*
5417c478bd9Sstevel@tonic-gate 	 * Skip the PASV reply + space
5427c478bd9Sstevel@tonic-gate 	 */
5437c478bd9Sstevel@tonic-gate 	s = f->ftps_rptr + PASV_REPLEN;
544ab25eeb5Syz 	while (*s && !ISDIGIT(*s)) {
545ab25eeb5Syz 		if (*s == '(') {
546ab25eeb5Syz 			brackets[0] = "(";
547ab25eeb5Syz 			brackets[1] = ")";
548ab25eeb5Syz 		}
5497c478bd9Sstevel@tonic-gate 		s++;
550ab25eeb5Syz 	}
551ab25eeb5Syz 
5527c478bd9Sstevel@tonic-gate 	/*
5537c478bd9Sstevel@tonic-gate 	 * Pick out the address components, two at a time.
5547c478bd9Sstevel@tonic-gate 	 */
5557c478bd9Sstevel@tonic-gate 	a1 = ippr_ftp_atoi(&s);
5567c478bd9Sstevel@tonic-gate 	if (s == NULL) {
557f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1)
558ab25eeb5Syz 			printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 1);
5597c478bd9Sstevel@tonic-gate 		return 0;
5607c478bd9Sstevel@tonic-gate 	}
5617c478bd9Sstevel@tonic-gate 	a2 = ippr_ftp_atoi(&s);
5627c478bd9Sstevel@tonic-gate 	if (s == NULL) {
563f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1)
564ab25eeb5Syz 			printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 2);
5657c478bd9Sstevel@tonic-gate 		return 0;
5667c478bd9Sstevel@tonic-gate 	}
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	/*
5697c478bd9Sstevel@tonic-gate 	 * check that IP address in the PASV reply is the same as the
5707c478bd9Sstevel@tonic-gate 	 * sender of the command - prevents using PASV for port scanning.
5717c478bd9Sstevel@tonic-gate 	 */
5727c478bd9Sstevel@tonic-gate 	a1 <<= 16;
5737c478bd9Sstevel@tonic-gate 	a1 |= a2;
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	if (((nat->nat_dir == NAT_INBOUND) &&
5767c478bd9Sstevel@tonic-gate 	     (a1 != ntohl(nat->nat_inip.s_addr))) ||
5777c478bd9Sstevel@tonic-gate 	    ((nat->nat_dir == NAT_OUTBOUND) &&
5787c478bd9Sstevel@tonic-gate 	     (a1 != ntohl(nat->nat_oip.s_addr)))) {
579f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 0)
580ab25eeb5Syz 			printf("ippr_ftp_pasv:%s != nat->nat_oip\n", "a1");
5817c478bd9Sstevel@tonic-gate 		return 0;
5827c478bd9Sstevel@tonic-gate 	}
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	a5 = ippr_ftp_atoi(&s);
5857c478bd9Sstevel@tonic-gate 	if (s == NULL) {
586f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1)
587ab25eeb5Syz 			printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 3);
5887c478bd9Sstevel@tonic-gate 		return 0;
5897c478bd9Sstevel@tonic-gate 	}
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	if (*s == ')')
5927c478bd9Sstevel@tonic-gate 		s++;
5937c478bd9Sstevel@tonic-gate 	if (*s == '.')
5947c478bd9Sstevel@tonic-gate 		s++;
5957c478bd9Sstevel@tonic-gate 	if (*s == '\n')
5967c478bd9Sstevel@tonic-gate 		s--;
5977c478bd9Sstevel@tonic-gate 	/*
5987c478bd9Sstevel@tonic-gate 	 * check for CR-LF at the end.
5997c478bd9Sstevel@tonic-gate 	 */
6007c478bd9Sstevel@tonic-gate 	if ((*s == '\r') && (*(s + 1) == '\n')) {
6017c478bd9Sstevel@tonic-gate 		s += 2;
6027c478bd9Sstevel@tonic-gate 	} else {
603f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1)
604ab25eeb5Syz 			printf("ippr_ftp_pasv:missing %s", "cr-lf\n");
6057c478bd9Sstevel@tonic-gate 		return 0;
6067c478bd9Sstevel@tonic-gate 	}
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	a6 = a5 & 0xff;
6097c478bd9Sstevel@tonic-gate 	a5 >>= 8;
6107c478bd9Sstevel@tonic-gate 	/*
6117c478bd9Sstevel@tonic-gate 	 * Calculate new address parts for 227 reply
6127c478bd9Sstevel@tonic-gate 	 */
6137c478bd9Sstevel@tonic-gate 	if (nat->nat_dir == NAT_INBOUND) {
6147c478bd9Sstevel@tonic-gate 		data_ip = nat->nat_outip.s_addr;
6157c478bd9Sstevel@tonic-gate 		a1 = ntohl(data_ip);
6167c478bd9Sstevel@tonic-gate 	} else
6177c478bd9Sstevel@tonic-gate 		data_ip = htonl(a1);
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	a2 = (a1 >> 16) & 0xff;
6207c478bd9Sstevel@tonic-gate 	a3 = (a1 >> 8) & 0xff;
6217c478bd9Sstevel@tonic-gate 	a4 = a1 & 0xff;
6227c478bd9Sstevel@tonic-gate 	a1 >>= 24;
6237c478bd9Sstevel@tonic-gate 
624ab25eeb5Syz #if defined(SNPRINTF) && defined(_KERNEL)
625ab25eeb5Syz 	(void) SNPRINTF(newbuf, sizeof(newbuf), "%s %s%u,%u,%u,%u,%u,%u%s\r\n",
626ab25eeb5Syz 		"227 Entering Passive Mode", brackets[0], a1, a2, a3, a4,
627ab25eeb5Syz 		a5, a6, brackets[1]);
6287c478bd9Sstevel@tonic-gate #else
629ab25eeb5Syz 	(void) sprintf(newbuf, "%s %s%u,%u,%u,%u,%u,%u%s\r\n",
630ab25eeb5Syz 		"227 Entering Passive Mode", brackets[0], a1, a2, a3, a4,
631ab25eeb5Syz 		a5, a6, brackets[1]);
6327c478bd9Sstevel@tonic-gate #endif
6337c478bd9Sstevel@tonic-gate 	return ippr_ftp_pasvreply(fin, ip, nat, f, (a5 << 8 | a6),
634f4b3ec61Sdh 				  newbuf, s, data_ip, ifsftp);
6357c478bd9Sstevel@tonic-gate }
6367c478bd9Sstevel@tonic-gate 
ippr_ftp_pasvreply(fin,ip,nat,f,port,newmsg,s,data_ip,ifsftp)637f4b3ec61Sdh int ippr_ftp_pasvreply(fin, ip, nat, f, port, newmsg, s, data_ip, ifsftp)
6387c478bd9Sstevel@tonic-gate fr_info_t *fin;
6397c478bd9Sstevel@tonic-gate ip_t *ip;
6407c478bd9Sstevel@tonic-gate nat_t *nat;
6417c478bd9Sstevel@tonic-gate ftpside_t *f;
6427c478bd9Sstevel@tonic-gate u_int port;
6437c478bd9Sstevel@tonic-gate char *newmsg;
6447c478bd9Sstevel@tonic-gate char *s;
6457c478bd9Sstevel@tonic-gate u_int data_ip;
646f4b3ec61Sdh ifs_ftppxy_t *ifsftp;
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate 	int inc, off, nflags, sflags;
6497c478bd9Sstevel@tonic-gate 	tcphdr_t *tcp, tcph, *tcp2;
6507c478bd9Sstevel@tonic-gate 	struct in_addr swip, swip2;
6517c478bd9Sstevel@tonic-gate 	struct in_addr data_addr;
6527c478bd9Sstevel@tonic-gate 	size_t nlen, olen;
6537c478bd9Sstevel@tonic-gate 	fr_info_t fi;
6547c478bd9Sstevel@tonic-gate 	nat_t *nat2;
6557c478bd9Sstevel@tonic-gate 	mb_t *m;
656f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	m = fin->fin_m;
6597c478bd9Sstevel@tonic-gate 	tcp = (tcphdr_t *)fin->fin_dp;
660ab25eeb5Syz 	off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	data_addr.s_addr = data_ip;
6637c478bd9Sstevel@tonic-gate 	tcp2 = &tcph;
6647c478bd9Sstevel@tonic-gate 	inc = 0;
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	olen = s - f->ftps_rptr;
6687c478bd9Sstevel@tonic-gate 	nlen = strlen(newmsg);
6697c478bd9Sstevel@tonic-gate 	inc = nlen - olen;
6707c478bd9Sstevel@tonic-gate 	if ((inc + ip->ip_len) > 65535) {
671f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 0)
672ab25eeb5Syz 			printf("ippr_ftp_pasv:inc(%d) + ip->ip_len > 65535\n",
673ab25eeb5Syz 			       inc);
6747c478bd9Sstevel@tonic-gate 		return 0;
6757c478bd9Sstevel@tonic-gate 	}
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate #if !defined(_KERNEL)
678ab25eeb5Syz 	bcopy(newmsg, MTOD(m, char *) + off, nlen);
6797c478bd9Sstevel@tonic-gate #else
6807c478bd9Sstevel@tonic-gate # if defined(MENTAT)
6817c478bd9Sstevel@tonic-gate 	if (inc < 0)
6827c478bd9Sstevel@tonic-gate 		(void)adjmsg(m, inc);
6837c478bd9Sstevel@tonic-gate # else /* defined(MENTAT) */
684ab25eeb5Syz 	/*
685ab25eeb5Syz 	 * m_adj takes care of pkthdr.len, if required and treats inc<0 to
686ab25eeb5Syz 	 * mean remove -len bytes from the end of the packet.
687ab25eeb5Syz 	 * The mbuf chain will be extended if necessary by m_copyback().
688ab25eeb5Syz 	 */
6897c478bd9Sstevel@tonic-gate 	if (inc < 0)
6907c478bd9Sstevel@tonic-gate 		m_adj(m, inc);
6917c478bd9Sstevel@tonic-gate # endif /* defined(MENTAT) */
6927c478bd9Sstevel@tonic-gate #endif /* !defined(_KERNEL) */
6937c478bd9Sstevel@tonic-gate 	COPYBACK(m, off, nlen, newmsg);
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	if (inc != 0) {
6967c478bd9Sstevel@tonic-gate 		ip->ip_len += inc;
6977c478bd9Sstevel@tonic-gate 		fin->fin_dlen += inc;
6987c478bd9Sstevel@tonic-gate 		fin->fin_plen += inc;
6997c478bd9Sstevel@tonic-gate 	}
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	/*
7027c478bd9Sstevel@tonic-gate 	 * Add skeleton NAT entry for connection which will come back the
7037c478bd9Sstevel@tonic-gate 	 * other way.
7047c478bd9Sstevel@tonic-gate 	 */
7057c478bd9Sstevel@tonic-gate 	bcopy((char *)fin, (char *)&fi, sizeof(fi));
7067c478bd9Sstevel@tonic-gate 	fi.fin_flx |= FI_IGNORE;
7077c478bd9Sstevel@tonic-gate 	fi.fin_data[0] = 0;
7087c478bd9Sstevel@tonic-gate 	fi.fin_data[1] = port;
7097c478bd9Sstevel@tonic-gate 	nflags = IPN_TCP|SI_W_SPORT;
710f4b3ec61Sdh 	if (ifsftp->ippr_ftp_pasvrdr && f->ftps_ifp)
7117c478bd9Sstevel@tonic-gate 		nflags |= SI_W_DPORT;
7127c478bd9Sstevel@tonic-gate 	if (nat->nat_dir == NAT_OUTBOUND)
7137c478bd9Sstevel@tonic-gate 		nat2 = nat_outlookup(&fi, nflags|NAT_SEARCH,
7147c478bd9Sstevel@tonic-gate 				     nat->nat_p, nat->nat_inip, nat->nat_oip);
7157c478bd9Sstevel@tonic-gate 	else
7167c478bd9Sstevel@tonic-gate 		nat2 = nat_inlookup(&fi, nflags|NAT_SEARCH,
7177c478bd9Sstevel@tonic-gate 				    nat->nat_p, nat->nat_inip, nat->nat_oip);
7187c478bd9Sstevel@tonic-gate 	if (nat2 == NULL) {
7197c478bd9Sstevel@tonic-gate 		int slen;
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 		slen = ip->ip_len;
7227c478bd9Sstevel@tonic-gate 		ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
7237c478bd9Sstevel@tonic-gate 		bzero((char *)tcp2, sizeof(*tcp2));
7247c478bd9Sstevel@tonic-gate 		tcp2->th_win = htons(8192);
7257c478bd9Sstevel@tonic-gate 		tcp2->th_sport = 0;		/* XXX - fake it for nat_new */
7267c478bd9Sstevel@tonic-gate 		TCP_OFF_A(tcp2, 5);
7277c478bd9Sstevel@tonic-gate 		tcp2->th_flags = TH_SYN;
7287c478bd9Sstevel@tonic-gate 		fi.fin_data[1] = port;
7297c478bd9Sstevel@tonic-gate 		fi.fin_dlen = sizeof(*tcp2);
7307c478bd9Sstevel@tonic-gate 		tcp2->th_dport = htons(port);
7317c478bd9Sstevel@tonic-gate 		fi.fin_data[0] = 0;
7327c478bd9Sstevel@tonic-gate 		fi.fin_dp = (char *)tcp2;
7337c478bd9Sstevel@tonic-gate 		fi.fin_plen = fi.fin_hlen + sizeof(*tcp);
734f4b3ec61Sdh 		fi.fin_fr = &ifsftp->ftppxyfr;
7357c478bd9Sstevel@tonic-gate 		fi.fin_out = nat->nat_dir;
7367c478bd9Sstevel@tonic-gate 		fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
7377c478bd9Sstevel@tonic-gate 		swip = ip->ip_src;
7387c478bd9Sstevel@tonic-gate 		swip2 = ip->ip_dst;
7397c478bd9Sstevel@tonic-gate 		if (nat->nat_dir == NAT_OUTBOUND) {
7407c478bd9Sstevel@tonic-gate 			fi.fin_fi.fi_daddr = data_addr.s_addr;
7417c478bd9Sstevel@tonic-gate 			fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
7427c478bd9Sstevel@tonic-gate 			ip->ip_dst = data_addr;
7437c478bd9Sstevel@tonic-gate 			ip->ip_src = nat->nat_inip;
7447c478bd9Sstevel@tonic-gate 		} else if (nat->nat_dir == NAT_INBOUND) {
7457c478bd9Sstevel@tonic-gate 			fi.fin_fi.fi_saddr = nat->nat_oip.s_addr;
7467c478bd9Sstevel@tonic-gate 			fi.fin_fi.fi_daddr = nat->nat_outip.s_addr;
7477c478bd9Sstevel@tonic-gate 			ip->ip_src = nat->nat_oip;
7487c478bd9Sstevel@tonic-gate 			ip->ip_dst = nat->nat_outip;
7497c478bd9Sstevel@tonic-gate 		}
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 		sflags = nflags;
7527c478bd9Sstevel@tonic-gate 		nflags |= NAT_SLAVE;
7537c478bd9Sstevel@tonic-gate 		if (nat->nat_dir == NAT_INBOUND)
7547c478bd9Sstevel@tonic-gate 			nflags |= NAT_NOTRULEPORT;
7557c478bd9Sstevel@tonic-gate 		nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir);
7567c478bd9Sstevel@tonic-gate 		if (nat2 != NULL) {
7577c478bd9Sstevel@tonic-gate 			(void) nat_proto(&fi, nat2, IPN_TCP);
7587c478bd9Sstevel@tonic-gate 			nat_update(&fi, nat2, nat->nat_ptr);
7597c478bd9Sstevel@tonic-gate 			fi.fin_ifp = NULL;
7607c478bd9Sstevel@tonic-gate 			if (nat->nat_dir == NAT_INBOUND) {
7617c478bd9Sstevel@tonic-gate 				fi.fin_fi.fi_daddr = nat->nat_inip.s_addr;
7627c478bd9Sstevel@tonic-gate 				ip->ip_dst = nat->nat_inip;
7637c478bd9Sstevel@tonic-gate 			}
7647c478bd9Sstevel@tonic-gate 			(void) fr_addstate(&fi, &nat2->nat_state, sflags);
7657c478bd9Sstevel@tonic-gate 		}
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 		ip->ip_len = slen;
7687c478bd9Sstevel@tonic-gate 		ip->ip_src = swip;
7697c478bd9Sstevel@tonic-gate 		ip->ip_dst = swip2;
7707c478bd9Sstevel@tonic-gate 	} else {
7717c478bd9Sstevel@tonic-gate 		ipstate_t *is;
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 		nat_update(&fi, nat2, nat->nat_ptr);
774f4b3ec61Sdh 		READ_ENTER(&ifs->ifs_ipf_state);
7757c478bd9Sstevel@tonic-gate 		is = nat2->nat_state;
7767c478bd9Sstevel@tonic-gate 		if (is != NULL) {
7777c478bd9Sstevel@tonic-gate 			MUTEX_ENTER(&is->is_lock);
778f4b3ec61Sdh 			(void) fr_tcp_age(&is->is_sti, &fi, ifs->ifs_ips_tqtqb,
779f4b3ec61Sdh 					  is->is_flags);
7807c478bd9Sstevel@tonic-gate 			MUTEX_EXIT(&is->is_lock);
7817c478bd9Sstevel@tonic-gate 		}
782f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_state);
7837c478bd9Sstevel@tonic-gate 	}
7847c478bd9Sstevel@tonic-gate 	return inc;
7857c478bd9Sstevel@tonic-gate }
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 
ippr_ftp_server(fin,ip,nat,ftp,dlen,ifsftp)788f4b3ec61Sdh int ippr_ftp_server(fin, ip, nat, ftp, dlen, ifsftp)
7897c478bd9Sstevel@tonic-gate fr_info_t *fin;
7907c478bd9Sstevel@tonic-gate ip_t *ip;
7917c478bd9Sstevel@tonic-gate nat_t *nat;
7927c478bd9Sstevel@tonic-gate ftpinfo_t *ftp;
7937c478bd9Sstevel@tonic-gate int dlen;
794f4b3ec61Sdh ifs_ftppxy_t *ifsftp;
7957c478bd9Sstevel@tonic-gate {
7967c478bd9Sstevel@tonic-gate 	char *rptr, *wptr;
7977c478bd9Sstevel@tonic-gate 	ftpside_t *f;
7987c478bd9Sstevel@tonic-gate 	int inc;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	inc = 0;
8017c478bd9Sstevel@tonic-gate 	f = &ftp->ftp_side[1];
8027c478bd9Sstevel@tonic-gate 	rptr = f->ftps_rptr;
8037c478bd9Sstevel@tonic-gate 	wptr = f->ftps_wptr;
8047c478bd9Sstevel@tonic-gate 
805ab25eeb5Syz 	if (*rptr == ' ')
806ab25eeb5Syz 		goto server_cmd_ok;
807ab25eeb5Syz 	if (!ISDIGIT(*rptr) || !ISDIGIT(*(rptr + 1)) || !ISDIGIT(*(rptr + 2)))
8087c478bd9Sstevel@tonic-gate 		return 0;
8097c478bd9Sstevel@tonic-gate 	if (ftp->ftp_passok == FTPXY_GO) {
8107c478bd9Sstevel@tonic-gate 		if (!strncmp(rptr, "227 ", 4))
811f4b3ec61Sdh 			inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen, ifsftp);
8127c478bd9Sstevel@tonic-gate 		else if (!strncmp(rptr, "229 ", 4))
813f4b3ec61Sdh 			inc = ippr_ftp_epsv(fin, ip, nat, f, dlen, ifsftp);
814f4b3ec61Sdh 	} else if (ifsftp->ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) {
815f4b3ec61Sdh 		inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen, ifsftp);
816f4b3ec61Sdh 	} else if (ifsftp->ippr_ftp_insecure && !strncmp(rptr, "229 ", 4)) {
817f4b3ec61Sdh 		inc = ippr_ftp_epsv(fin, ip, nat, f, dlen, ifsftp);
8187c478bd9Sstevel@tonic-gate 	} else if (*rptr == '5' || *rptr == '4')
8197c478bd9Sstevel@tonic-gate 		ftp->ftp_passok = FTPXY_INIT;
8207c478bd9Sstevel@tonic-gate 	else if (ftp->ftp_incok) {
8217c478bd9Sstevel@tonic-gate 		if (*rptr == '3') {
8227c478bd9Sstevel@tonic-gate 			if (ftp->ftp_passok == FTPXY_ACCT_1)
8237c478bd9Sstevel@tonic-gate 				ftp->ftp_passok = FTPXY_GO;
8247c478bd9Sstevel@tonic-gate 			else
8257c478bd9Sstevel@tonic-gate 				ftp->ftp_passok++;
8267c478bd9Sstevel@tonic-gate 		} else if (*rptr == '2') {
8277c478bd9Sstevel@tonic-gate 			switch (ftp->ftp_passok)
8287c478bd9Sstevel@tonic-gate 			{
8297c478bd9Sstevel@tonic-gate 			case FTPXY_USER_1 :
8307c478bd9Sstevel@tonic-gate 			case FTPXY_USER_2 :
8317c478bd9Sstevel@tonic-gate 			case FTPXY_PASS_1 :
8327c478bd9Sstevel@tonic-gate 			case FTPXY_PASS_2 :
8337c478bd9Sstevel@tonic-gate 			case FTPXY_ACCT_1 :
8347c478bd9Sstevel@tonic-gate 				ftp->ftp_passok = FTPXY_GO;
8357c478bd9Sstevel@tonic-gate 				break;
8367c478bd9Sstevel@tonic-gate 			default :
8377c478bd9Sstevel@tonic-gate 				ftp->ftp_passok += 3;
8387c478bd9Sstevel@tonic-gate 				break;
8397c478bd9Sstevel@tonic-gate 			}
8407c478bd9Sstevel@tonic-gate 		}
8417c478bd9Sstevel@tonic-gate 	}
842ab25eeb5Syz server_cmd_ok:
8437c478bd9Sstevel@tonic-gate 	ftp->ftp_incok = 0;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	while ((*rptr++ != '\n') && (rptr < wptr))
8467c478bd9Sstevel@tonic-gate 		;
8477c478bd9Sstevel@tonic-gate 	f->ftps_rptr = rptr;
8487c478bd9Sstevel@tonic-gate 	return inc;
8497c478bd9Sstevel@tonic-gate }
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate /*
8537c478bd9Sstevel@tonic-gate  * Look to see if the buffer starts with something which we recognise as
8547c478bd9Sstevel@tonic-gate  * being the correct syntax for the FTP protocol.
8557c478bd9Sstevel@tonic-gate  */
ippr_ftp_client_valid(ftps,buf,len,ifsftp)856f4b3ec61Sdh int ippr_ftp_client_valid(ftps, buf, len, ifsftp)
8577c478bd9Sstevel@tonic-gate ftpside_t *ftps;
8587c478bd9Sstevel@tonic-gate char *buf;
8597c478bd9Sstevel@tonic-gate size_t len;
860f4b3ec61Sdh ifs_ftppxy_t *ifsftp;
8617c478bd9Sstevel@tonic-gate {
862ab25eeb5Syz 	register char *s, c, pc;
8637c478bd9Sstevel@tonic-gate 	register size_t i = len;
8647c478bd9Sstevel@tonic-gate 	char cmd[5];
8657c478bd9Sstevel@tonic-gate 
866ab25eeb5Syz 	s = buf;
867ab25eeb5Syz 
868ab25eeb5Syz 	if (ftps->ftps_junk == 1)
869ab25eeb5Syz 		return 1;
870ab25eeb5Syz 
8717c478bd9Sstevel@tonic-gate 	if (i < 5) {
872f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 3)
873ab25eeb5Syz 			printf("ippr_ftp_client_valid:i(%d) < 5\n", (int)i);
8747c478bd9Sstevel@tonic-gate 		return 2;
8757c478bd9Sstevel@tonic-gate 	}
876ab25eeb5Syz 
8777c478bd9Sstevel@tonic-gate 	i--;
878ab25eeb5Syz 	c = *s++;
8797c478bd9Sstevel@tonic-gate 
880ab25eeb5Syz 	if (ISALPHA(c)) {
881ab25eeb5Syz 		cmd[0] = TOUPPER(c);
8827c478bd9Sstevel@tonic-gate 		c = *s++;
8837c478bd9Sstevel@tonic-gate 		i--;
884ab25eeb5Syz 		if (ISALPHA(c)) {
885ab25eeb5Syz 			cmd[1] = TOUPPER(c);
8867c478bd9Sstevel@tonic-gate 			c = *s++;
8877c478bd9Sstevel@tonic-gate 			i--;
888ab25eeb5Syz 			if (ISALPHA(c)) {
889ab25eeb5Syz 				cmd[2] = TOUPPER(c);
8907c478bd9Sstevel@tonic-gate 				c = *s++;
8917c478bd9Sstevel@tonic-gate 				i--;
892ab25eeb5Syz 				if (ISALPHA(c)) {
893ab25eeb5Syz 					cmd[3] = TOUPPER(c);
8947c478bd9Sstevel@tonic-gate 					c = *s++;
8957c478bd9Sstevel@tonic-gate 					i--;
8967c478bd9Sstevel@tonic-gate 					if ((c != ' ') && (c != '\r'))
8977c478bd9Sstevel@tonic-gate 						goto bad_client_command;
8987c478bd9Sstevel@tonic-gate 				} else if ((c != ' ') && (c != '\r'))
8997c478bd9Sstevel@tonic-gate 					goto bad_client_command;
9007c478bd9Sstevel@tonic-gate 			} else
9017c478bd9Sstevel@tonic-gate 				goto bad_client_command;
9027c478bd9Sstevel@tonic-gate 		} else
9037c478bd9Sstevel@tonic-gate 			goto bad_client_command;
9047c478bd9Sstevel@tonic-gate 	} else {
9057c478bd9Sstevel@tonic-gate bad_client_command:
906f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 3)
907ab25eeb5Syz 			printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*s]\n",
908ab25eeb5Syz 			       "ippr_ftp_client_valid",
909ab25eeb5Syz 			       ftps->ftps_junk, (int)len, (int)i, c,
910ab25eeb5Syz 			       (int)len, buf);
9117c478bd9Sstevel@tonic-gate 		return 1;
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	for (; i; i--) {
915ab25eeb5Syz 		pc = c;
9167c478bd9Sstevel@tonic-gate 		c = *s++;
917ab25eeb5Syz 		if ((pc == '\r') && (c == '\n')) {
9187c478bd9Sstevel@tonic-gate 			cmd[4] = '\0';
9197c478bd9Sstevel@tonic-gate 			if (!strcmp(cmd, "PASV"))
9207c478bd9Sstevel@tonic-gate 				ftps->ftps_cmds = FTPXY_C_PASV;
9217c478bd9Sstevel@tonic-gate 			else
9227c478bd9Sstevel@tonic-gate 				ftps->ftps_cmds = 0;
9237c478bd9Sstevel@tonic-gate 			return 0;
9247c478bd9Sstevel@tonic-gate 		}
9257c478bd9Sstevel@tonic-gate 	}
9267c478bd9Sstevel@tonic-gate #if !defined(_KERNEL)
927ab25eeb5Syz 	printf("ippr_ftp_client_valid:junk after cmd[%*.*s]\n",
928ab25eeb5Syz 	       (int)len, (int)len, buf);
9297c478bd9Sstevel@tonic-gate #endif
9307c478bd9Sstevel@tonic-gate 	return 2;
9317c478bd9Sstevel@tonic-gate }
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 
ippr_ftp_server_valid(ftps,buf,len,ifsftp)934f4b3ec61Sdh int ippr_ftp_server_valid(ftps, buf, len, ifsftp)
9357c478bd9Sstevel@tonic-gate ftpside_t *ftps;
9367c478bd9Sstevel@tonic-gate char *buf;
9377c478bd9Sstevel@tonic-gate size_t len;
938f4b3ec61Sdh ifs_ftppxy_t *ifsftp;
9397c478bd9Sstevel@tonic-gate {
940ab25eeb5Syz 	register char *s, c, pc;
9417c478bd9Sstevel@tonic-gate 	register size_t i = len;
9427c478bd9Sstevel@tonic-gate 	int cmd;
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 	s = buf;
9457c478bd9Sstevel@tonic-gate 	cmd = 0;
946ab25eeb5Syz 
947ab25eeb5Syz 	if (ftps->ftps_junk == 1)
948ab25eeb5Syz 		return 1;
949ab25eeb5Syz 
950ab25eeb5Syz 	if (i < 5) {
951f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 3)
952ab25eeb5Syz 			printf("ippr_ftp_servert_valid:i(%d) < 5\n", (int)i);
953ab25eeb5Syz 		return 2;
954ab25eeb5Syz 	}
955ab25eeb5Syz 
956ab25eeb5Syz 	c = *s++;
9577c478bd9Sstevel@tonic-gate 	i--;
958ab25eeb5Syz 	if (c == ' ')
959ab25eeb5Syz 		goto search_eol;
9607c478bd9Sstevel@tonic-gate 
961ab25eeb5Syz 	if (ISDIGIT(c)) {
9627c478bd9Sstevel@tonic-gate 		cmd = (c - '0') * 100;
9637c478bd9Sstevel@tonic-gate 		c = *s++;
9647c478bd9Sstevel@tonic-gate 		i--;
965ab25eeb5Syz 		if (ISDIGIT(c)) {
9667c478bd9Sstevel@tonic-gate 			cmd += (c - '0') * 10;
9677c478bd9Sstevel@tonic-gate 			c = *s++;
9687c478bd9Sstevel@tonic-gate 			i--;
969ab25eeb5Syz 			if (ISDIGIT(c)) {
9707c478bd9Sstevel@tonic-gate 				cmd += (c - '0');
9717c478bd9Sstevel@tonic-gate 				c = *s++;
9727c478bd9Sstevel@tonic-gate 				i--;
9737c478bd9Sstevel@tonic-gate 				if ((c != '-') && (c != ' '))
9747c478bd9Sstevel@tonic-gate 					goto bad_server_command;
9757c478bd9Sstevel@tonic-gate 			} else
9767c478bd9Sstevel@tonic-gate 				goto bad_server_command;
9777c478bd9Sstevel@tonic-gate 		} else
9787c478bd9Sstevel@tonic-gate 			goto bad_server_command;
9797c478bd9Sstevel@tonic-gate 	} else {
9807c478bd9Sstevel@tonic-gate bad_server_command:
981f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 3)
982ab25eeb5Syz 			printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*s]\n",
983ab25eeb5Syz 			       "ippr_ftp_server_valid",
984ab25eeb5Syz 			       ftps->ftps_junk, (int)len, (int)i,
985ab25eeb5Syz 			       c, (int)len, buf);
9867c478bd9Sstevel@tonic-gate 		return 1;
9877c478bd9Sstevel@tonic-gate 	}
988ab25eeb5Syz search_eol:
9897c478bd9Sstevel@tonic-gate 	for (; i; i--) {
990ab25eeb5Syz 		pc = c;
9917c478bd9Sstevel@tonic-gate 		c = *s++;
992ab25eeb5Syz 		if ((pc == '\r') && (c == '\n')) {
9937c478bd9Sstevel@tonic-gate 			ftps->ftps_cmds = cmd;
9947c478bd9Sstevel@tonic-gate 			return 0;
9957c478bd9Sstevel@tonic-gate 		}
9967c478bd9Sstevel@tonic-gate 	}
997f4b3ec61Sdh 	if (ifsftp->ippr_ftp_debug > 3)
998ab25eeb5Syz 		printf("ippr_ftp_server_valid:junk after cmd[%*s]\n",
999ab25eeb5Syz 		       (int)len, buf);
10007c478bd9Sstevel@tonic-gate 	return 2;
10017c478bd9Sstevel@tonic-gate }
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 
ippr_ftp_valid(ftp,side,buf,len,ifsftp)1004f4b3ec61Sdh int ippr_ftp_valid(ftp, side, buf, len, ifsftp)
10057c478bd9Sstevel@tonic-gate ftpinfo_t *ftp;
10067c478bd9Sstevel@tonic-gate int side;
10077c478bd9Sstevel@tonic-gate char *buf;
10087c478bd9Sstevel@tonic-gate size_t len;
1009f4b3ec61Sdh ifs_ftppxy_t *ifsftp;
10107c478bd9Sstevel@tonic-gate {
10117c478bd9Sstevel@tonic-gate 	ftpside_t *ftps;
10127c478bd9Sstevel@tonic-gate 	int ret;
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 	ftps = &ftp->ftp_side[side];
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 	if (side == 0)
1017f4b3ec61Sdh 		ret = ippr_ftp_client_valid(ftps, buf, len, ifsftp);
10187c478bd9Sstevel@tonic-gate 	else
1019f4b3ec61Sdh 		ret = ippr_ftp_server_valid(ftps, buf, len, ifsftp);
10207c478bd9Sstevel@tonic-gate 	return ret;
10217c478bd9Sstevel@tonic-gate }
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate /*
10257c478bd9Sstevel@tonic-gate  * For map rules, the following applies:
10267c478bd9Sstevel@tonic-gate  * rv == 0 for outbound processing,
10277c478bd9Sstevel@tonic-gate  * rv == 1 for inbound processing.
10287c478bd9Sstevel@tonic-gate  * For rdr rules, the following applies:
10297c478bd9Sstevel@tonic-gate  * rv == 0 for inbound processing,
10307c478bd9Sstevel@tonic-gate  * rv == 1 for outbound processing.
10317c478bd9Sstevel@tonic-gate  */
ippr_ftp_process(fin,nat,ftp,rv,ifsftp)1032f4b3ec61Sdh int ippr_ftp_process(fin, nat, ftp, rv, ifsftp)
10337c478bd9Sstevel@tonic-gate fr_info_t *fin;
10347c478bd9Sstevel@tonic-gate nat_t *nat;
10357c478bd9Sstevel@tonic-gate ftpinfo_t *ftp;
10367c478bd9Sstevel@tonic-gate int rv;
1037f4b3ec61Sdh ifs_ftppxy_t *ifsftp;
10387c478bd9Sstevel@tonic-gate {
10397c478bd9Sstevel@tonic-gate 	int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff;
1040ab25eeb5Syz 	char *rptr, *wptr, *s;
10417c478bd9Sstevel@tonic-gate 	u_32_t thseq, thack;
10427c478bd9Sstevel@tonic-gate 	ap_session_t *aps;
10437c478bd9Sstevel@tonic-gate 	ftpside_t *f, *t;
10447c478bd9Sstevel@tonic-gate 	tcphdr_t *tcp;
10457c478bd9Sstevel@tonic-gate 	ip_t *ip;
10467c478bd9Sstevel@tonic-gate 	mb_t *m;
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 	m = fin->fin_m;
10497c478bd9Sstevel@tonic-gate 	ip = fin->fin_ip;
10507c478bd9Sstevel@tonic-gate 	tcp = (tcphdr_t *)fin->fin_dp;
1051ab25eeb5Syz 	off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	f = &ftp->ftp_side[rv];
10547c478bd9Sstevel@tonic-gate 	t = &ftp->ftp_side[1 - rv];
10557c478bd9Sstevel@tonic-gate 	thseq = ntohl(tcp->th_seq);
10567c478bd9Sstevel@tonic-gate 	thack = ntohl(tcp->th_ack);
10577c478bd9Sstevel@tonic-gate 
1058ab25eeb5Syz #ifdef __sgi
1059ab25eeb5Syz 	mlen = fin->fin_plen - off;
1060ab25eeb5Syz #else
10617c478bd9Sstevel@tonic-gate 	mlen = MSGDSIZE(m) - off;
1062ab25eeb5Syz #endif
1063f4b3ec61Sdh 	if (ifsftp->ippr_ftp_debug > 4)
1064ab25eeb5Syz 		printf("ippr_ftp_process: mlen %d\n", mlen);
1065ab25eeb5Syz 
10667c478bd9Sstevel@tonic-gate 	if (mlen <= 0) {
10677c478bd9Sstevel@tonic-gate 		if ((tcp->th_flags & TH_OPENING) == TH_OPENING) {
10687c478bd9Sstevel@tonic-gate 			f->ftps_seq[0] = thseq + 1;
10697c478bd9Sstevel@tonic-gate 			t->ftps_seq[0] = thack;
10707c478bd9Sstevel@tonic-gate 		}
10717c478bd9Sstevel@tonic-gate 		return 0;
10727c478bd9Sstevel@tonic-gate 	}
10737c478bd9Sstevel@tonic-gate 	aps = nat->nat_aps;
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	sel = aps->aps_sel[1 - rv];
10767c478bd9Sstevel@tonic-gate 	sel2 = aps->aps_sel[rv];
10777c478bd9Sstevel@tonic-gate 	if (rv == 0) {
10787c478bd9Sstevel@tonic-gate 		seqoff = aps->aps_seqoff[sel];
10797c478bd9Sstevel@tonic-gate 		if (aps->aps_seqmin[sel] > seqoff + thseq)
10807c478bd9Sstevel@tonic-gate 			seqoff = aps->aps_seqoff[!sel];
10817c478bd9Sstevel@tonic-gate 		ackoff = aps->aps_ackoff[sel2];
10827c478bd9Sstevel@tonic-gate 		if (aps->aps_ackmin[sel2] > ackoff + thack)
10837c478bd9Sstevel@tonic-gate 			ackoff = aps->aps_ackoff[!sel2];
10847c478bd9Sstevel@tonic-gate 	} else {
10857c478bd9Sstevel@tonic-gate 		seqoff = aps->aps_ackoff[sel];
1086f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 2)
1087ab25eeb5Syz 			printf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq,
1088ab25eeb5Syz 			       aps->aps_ackmin[sel]);
10897c478bd9Sstevel@tonic-gate 		if (aps->aps_ackmin[sel] > seqoff + thseq)
10907c478bd9Sstevel@tonic-gate 			seqoff = aps->aps_ackoff[!sel];
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 		ackoff = aps->aps_seqoff[sel2];
1093f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 2)
1094ab25eeb5Syz 			printf("ackoff %d thack %x seqmin %x\n", ackoff, thack,
1095ab25eeb5Syz 			       aps->aps_seqmin[sel2]);
10967c478bd9Sstevel@tonic-gate 		if (ackoff > 0) {
10977c478bd9Sstevel@tonic-gate 			if (aps->aps_seqmin[sel2] > ackoff + thack)
10987c478bd9Sstevel@tonic-gate 				ackoff = aps->aps_seqoff[!sel2];
10997c478bd9Sstevel@tonic-gate 		} else {
11007c478bd9Sstevel@tonic-gate 			if (aps->aps_seqmin[sel2] > thack)
11017c478bd9Sstevel@tonic-gate 				ackoff = aps->aps_seqoff[!sel2];
11027c478bd9Sstevel@tonic-gate 		}
11037c478bd9Sstevel@tonic-gate 	}
1104f4b3ec61Sdh 	if (ifsftp->ippr_ftp_debug > 2) {
1105ab25eeb5Syz 		printf("%s: %x seq %x/%d ack %x/%d len %d/%d off %d\n",
1106ab25eeb5Syz 		       rv ? "IN" : "OUT", tcp->th_flags, thseq, seqoff,
1107ab25eeb5Syz 		       thack, ackoff, mlen, fin->fin_plen, off);
1108ab25eeb5Syz 		printf("sel %d seqmin %x/%x offset %d/%d\n", sel,
1109ab25eeb5Syz 		       aps->aps_seqmin[sel], aps->aps_seqmin[sel2],
1110ab25eeb5Syz 		       aps->aps_seqoff[sel], aps->aps_seqoff[sel2]);
1111ab25eeb5Syz 		printf("sel %d ackmin %x/%x offset %d/%d\n", sel2,
1112ab25eeb5Syz 		       aps->aps_ackmin[sel], aps->aps_ackmin[sel2],
1113ab25eeb5Syz 		       aps->aps_ackoff[sel], aps->aps_ackoff[sel2]);
1114ab25eeb5Syz 	}
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 	/*
11177c478bd9Sstevel@tonic-gate 	 * XXX - Ideally, this packet should get dropped because we now know
11187c478bd9Sstevel@tonic-gate 	 * that it is out of order (and there is no real danger in doing so
11197c478bd9Sstevel@tonic-gate 	 * apart from causing packets to go through here ordered).
11207c478bd9Sstevel@tonic-gate 	 */
1121f4b3ec61Sdh 	if (ifsftp->ippr_ftp_debug > 2) {
1122ab25eeb5Syz 		printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n",
1123ab25eeb5Syz 		       rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff);
1124ab25eeb5Syz 	}
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	ok = 0;
11277c478bd9Sstevel@tonic-gate 	if (t->ftps_seq[0] == 0) {
11287c478bd9Sstevel@tonic-gate 		t->ftps_seq[0] = thack;
11297c478bd9Sstevel@tonic-gate 		ok = 1;
11307c478bd9Sstevel@tonic-gate 	} else {
11317c478bd9Sstevel@tonic-gate 		if (ackoff == 0) {
11327c478bd9Sstevel@tonic-gate 			if (t->ftps_seq[0] == thack)
11337c478bd9Sstevel@tonic-gate 				ok = 1;
11347c478bd9Sstevel@tonic-gate 			else if (t->ftps_seq[1] == thack) {
11357c478bd9Sstevel@tonic-gate 				t->ftps_seq[0] = thack;
11367c478bd9Sstevel@tonic-gate 				ok = 1;
11377c478bd9Sstevel@tonic-gate 			}
11387c478bd9Sstevel@tonic-gate 		} else {
11397c478bd9Sstevel@tonic-gate 			if (t->ftps_seq[0] + ackoff == thack)
11407c478bd9Sstevel@tonic-gate 				ok = 1;
11417c478bd9Sstevel@tonic-gate 			else if (t->ftps_seq[0] == thack + ackoff)
11427c478bd9Sstevel@tonic-gate 				ok = 1;
11437c478bd9Sstevel@tonic-gate 			else if (t->ftps_seq[1] + ackoff == thack) {
11447c478bd9Sstevel@tonic-gate 				t->ftps_seq[0] = thack - ackoff;
11457c478bd9Sstevel@tonic-gate 				ok = 1;
11467c478bd9Sstevel@tonic-gate 			} else if (t->ftps_seq[1] == thack + ackoff) {
11477c478bd9Sstevel@tonic-gate 				t->ftps_seq[0] = thack - ackoff;
11487c478bd9Sstevel@tonic-gate 				ok = 1;
11497c478bd9Sstevel@tonic-gate 			}
11507c478bd9Sstevel@tonic-gate 		}
11517c478bd9Sstevel@tonic-gate 	}
11527c478bd9Sstevel@tonic-gate 
1153f4b3ec61Sdh 	if (ifsftp->ippr_ftp_debug > 2) {
1154ab25eeb5Syz 		if (!ok)
1155ab25eeb5Syz 			printf("%s ok\n", "not");
1156ab25eeb5Syz 	}
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 	if (!mlen) {
11597c478bd9Sstevel@tonic-gate 		if (t->ftps_seq[0] + ackoff != thack) {
1160f4b3ec61Sdh 			if (ifsftp->ippr_ftp_debug > 1) {
1161ab25eeb5Syz 				printf("%s:seq[0](%x) + (%x) != (%x)\n",
1162ab25eeb5Syz 				       "ippr_ftp_process", t->ftps_seq[0],
1163ab25eeb5Syz 				       ackoff, thack);
1164ab25eeb5Syz 			}
11657c478bd9Sstevel@tonic-gate 			return APR_ERR(1);
11667c478bd9Sstevel@tonic-gate 		}
11677c478bd9Sstevel@tonic-gate 
1168f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 2) {
1169ab25eeb5Syz 			printf("ippr_ftp_process:f:seq[0] %x seq[1] %x\n",
1170ab25eeb5Syz 				f->ftps_seq[0], f->ftps_seq[1]);
1171ab25eeb5Syz 		}
1172ab25eeb5Syz 
11737c478bd9Sstevel@tonic-gate 		if (tcp->th_flags & TH_FIN) {
11747c478bd9Sstevel@tonic-gate 			if (thseq == f->ftps_seq[1]) {
11757c478bd9Sstevel@tonic-gate 				f->ftps_seq[0] = f->ftps_seq[1] - seqoff;
11767c478bd9Sstevel@tonic-gate 				f->ftps_seq[1] = thseq + 1 - seqoff;
11777c478bd9Sstevel@tonic-gate 			} else {
1178f4b3ec61Sdh 				if (ifsftp->ippr_ftp_debug > 1) {
1179ab25eeb5Syz 					printf("FIN: thseq %x seqoff %d ftps_seq %x\n",
1180ab25eeb5Syz 					       thseq, seqoff, f->ftps_seq[0]);
1181ab25eeb5Syz 				}
11827c478bd9Sstevel@tonic-gate 				return APR_ERR(1);
11837c478bd9Sstevel@tonic-gate 			}
11847c478bd9Sstevel@tonic-gate 		}
11857c478bd9Sstevel@tonic-gate 		f->ftps_len = 0;
11867c478bd9Sstevel@tonic-gate 		return 0;
11877c478bd9Sstevel@tonic-gate 	}
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	ok = 0;
11907c478bd9Sstevel@tonic-gate 	if ((thseq == f->ftps_seq[0]) || (thseq == f->ftps_seq[1])) {
11917c478bd9Sstevel@tonic-gate 		ok = 1;
11927c478bd9Sstevel@tonic-gate 	/*
11937c478bd9Sstevel@tonic-gate 	 * Retransmitted data packet.
11947c478bd9Sstevel@tonic-gate 	 */
11957c478bd9Sstevel@tonic-gate 	} else if ((thseq + mlen == f->ftps_seq[0]) ||
11967c478bd9Sstevel@tonic-gate 		   (thseq + mlen == f->ftps_seq[1])) {
11977c478bd9Sstevel@tonic-gate 		ok = 1;
11987c478bd9Sstevel@tonic-gate 	}
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate 	if (ok == 0) {
12017c478bd9Sstevel@tonic-gate 		inc = thseq - f->ftps_seq[0];
1202f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1) {
1203ab25eeb5Syz 			printf("inc %d sel %d rv %d\n", inc, sel, rv);
1204ab25eeb5Syz 			printf("th_seq %x ftps_seq %x/%x\n",
1205ab25eeb5Syz 			       thseq, f->ftps_seq[0], f->ftps_seq[1]);
1206ab25eeb5Syz 			printf("ackmin %x ackoff %d\n", aps->aps_ackmin[sel],
1207ab25eeb5Syz 			       aps->aps_ackoff[sel]);
1208ab25eeb5Syz 			printf("seqmin %x seqoff %d\n", aps->aps_seqmin[sel],
1209ab25eeb5Syz 			       aps->aps_seqoff[sel]);
1210ab25eeb5Syz 		}
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 		return APR_ERR(1);
12137c478bd9Sstevel@tonic-gate 	}
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	inc = 0;
12167c478bd9Sstevel@tonic-gate 	rptr = f->ftps_rptr;
12177c478bd9Sstevel@tonic-gate 	wptr = f->ftps_wptr;
12187c478bd9Sstevel@tonic-gate 	f->ftps_seq[0] = thseq;
12197c478bd9Sstevel@tonic-gate 	f->ftps_seq[1] = f->ftps_seq[0] + mlen;
12207c478bd9Sstevel@tonic-gate 	f->ftps_len = mlen;
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	while (mlen > 0) {
1223ab25eeb5Syz 		len = MIN(mlen, sizeof(f->ftps_buf) - (wptr - rptr));
12247c478bd9Sstevel@tonic-gate 		COPYDATA(m, off, len, wptr);
12257c478bd9Sstevel@tonic-gate 		mlen -= len;
12267c478bd9Sstevel@tonic-gate 		off += len;
12277c478bd9Sstevel@tonic-gate 		wptr += len;
1228ab25eeb5Syz 
1229f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 3)
1230ab25eeb5Syz 			printf("%s:len %d/%d off %d wptr %lx junk %d [%*s]\n",
1231ab25eeb5Syz 			       "ippr_ftp_process",
1232ab25eeb5Syz 			       len, mlen, off, (u_long)wptr, f->ftps_junk,
1233ab25eeb5Syz 			       len, rptr);
1234ab25eeb5Syz 
12357c478bd9Sstevel@tonic-gate 		f->ftps_wptr = wptr;
1236ab25eeb5Syz 		if (f->ftps_junk != 0) {
1237ab25eeb5Syz 			i = f->ftps_junk;
12387c478bd9Sstevel@tonic-gate 			f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr,
1239f4b3ec61Sdh 						      wptr - rptr, ifsftp);
12407c478bd9Sstevel@tonic-gate 
1241f4b3ec61Sdh 			if (ifsftp->ippr_ftp_debug > 5)
1242ab25eeb5Syz 				printf("%s:junk %d -> %d\n",
1243ab25eeb5Syz 				       "ippr_ftp_process", i, f->ftps_junk);
1244ab25eeb5Syz 
1245ab25eeb5Syz 			if (f->ftps_junk != 0) {
1246ab25eeb5Syz 				if (wptr - rptr == sizeof(f->ftps_buf)) {
1247f4b3ec61Sdh 					if (ifsftp->ippr_ftp_debug > 4)
1248ab25eeb5Syz 						printf("%s:full buffer\n",
1249ab25eeb5Syz 						       "ippr_ftp_process");
1250ab25eeb5Syz 					f->ftps_rptr = f->ftps_buf;
1251ab25eeb5Syz 					f->ftps_wptr = f->ftps_buf;
1252ab25eeb5Syz 					rptr = f->ftps_rptr;
1253ab25eeb5Syz 					wptr = f->ftps_wptr;
1254ab25eeb5Syz 					/*
1255ab25eeb5Syz 					 * Because we throw away data here that
1256ab25eeb5Syz 					 * we would otherwise parse, set the
1257ab25eeb5Syz 					 * junk flag to indicate just ignore
1258ab25eeb5Syz 					 * any data upto the next CRLF.
1259ab25eeb5Syz 					 */
1260ab25eeb5Syz 					f->ftps_junk = 1;
1261ab25eeb5Syz 					continue;
1262ab25eeb5Syz 				}
1263ab25eeb5Syz 			}
1264ab25eeb5Syz 		}
1265ab25eeb5Syz 
12667c478bd9Sstevel@tonic-gate 		while ((f->ftps_junk == 0) && (wptr > rptr)) {
1267ab25eeb5Syz 			len = wptr - rptr;
1268f4b3ec61Sdh 			f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, len, ifsftp);
1269ab25eeb5Syz 
1270f4b3ec61Sdh 			if (ifsftp->ippr_ftp_debug > 3) {
1271ab25eeb5Syz 				printf("%s=%d len %d rv %d ptr %lx/%lx ",
1272ab25eeb5Syz 				       "ippr_ftp_valid",
1273ab25eeb5Syz 				       f->ftps_junk, len, rv, (u_long)rptr,
1274ab25eeb5Syz 				       (u_long)wptr);
1275ab25eeb5Syz 				printf("buf [%*s]\n", len, rptr);
1276ab25eeb5Syz 			}
1277ab25eeb5Syz 
12787c478bd9Sstevel@tonic-gate 			if (f->ftps_junk == 0) {
12797c478bd9Sstevel@tonic-gate 				f->ftps_rptr = rptr;
12807c478bd9Sstevel@tonic-gate 				if (rv)
12817c478bd9Sstevel@tonic-gate 					inc += ippr_ftp_server(fin, ip, nat,
1282f4b3ec61Sdh 							       ftp, len, ifsftp);
12837c478bd9Sstevel@tonic-gate 				else
12847c478bd9Sstevel@tonic-gate 					inc += ippr_ftp_client(fin, ip, nat,
1285f4b3ec61Sdh 							       ftp, len, ifsftp);
12867c478bd9Sstevel@tonic-gate 				rptr = f->ftps_rptr;
12877c478bd9Sstevel@tonic-gate 				wptr = f->ftps_wptr;
12887c478bd9Sstevel@tonic-gate 			}
12897c478bd9Sstevel@tonic-gate 		}
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 		/*
12927c478bd9Sstevel@tonic-gate 		 * Off to a bad start so lets just forget about using the
12937c478bd9Sstevel@tonic-gate 		 * ftp proxy for this connection.
12947c478bd9Sstevel@tonic-gate 		 */
12957c478bd9Sstevel@tonic-gate 		if ((f->ftps_cmds == 0) && (f->ftps_junk == 1)) {
12967c478bd9Sstevel@tonic-gate 			/* f->ftps_seq[1] += inc; */
1297ab25eeb5Syz 
1298f4b3ec61Sdh 			if (ifsftp->ippr_ftp_debug > 1)
1299ab25eeb5Syz 				printf("%s:cmds == 0 junk == 1\n",
1300ab25eeb5Syz 				       "ippr_ftp_process");
13017c478bd9Sstevel@tonic-gate 			return APR_ERR(2);
13027c478bd9Sstevel@tonic-gate 		}
13037c478bd9Sstevel@tonic-gate 
1304ab25eeb5Syz 		if ((f->ftps_junk != 0) && (rptr < wptr)) {
1305ab25eeb5Syz 			for (s = rptr; s < wptr; s++) {
1306ab25eeb5Syz 				if ((*s == '\r') && (s + 1 < wptr) &&
1307ab25eeb5Syz 				    (*(s + 1) == '\n')) {
1308ab25eeb5Syz 					rptr = s + 2;
1309ab25eeb5Syz 					f->ftps_junk = 0;
13107c478bd9Sstevel@tonic-gate 					break;
1311ab25eeb5Syz 				}
13127c478bd9Sstevel@tonic-gate 			}
13137c478bd9Sstevel@tonic-gate 		}
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 		if (rptr == wptr) {
13167c478bd9Sstevel@tonic-gate 			rptr = wptr = f->ftps_buf;
13177c478bd9Sstevel@tonic-gate 		} else {
1318ab25eeb5Syz 			/*
1319ab25eeb5Syz 			 * Compact the buffer back to the start.  The junk
1320ab25eeb5Syz 			 * flag should already be set and because we're not
1321ab25eeb5Syz 			 * throwing away any data, it is preserved from its
1322ab25eeb5Syz 			 * current state.
1323ab25eeb5Syz 			 */
1324ab25eeb5Syz 			if (rptr > f->ftps_buf) {
1325ab25eeb5Syz 				bcopy(rptr, f->ftps_buf, len);
1326ab25eeb5Syz 				wptr -= rptr - f->ftps_buf;
1327ab25eeb5Syz 				rptr = f->ftps_buf;
13287c478bd9Sstevel@tonic-gate 			}
13297c478bd9Sstevel@tonic-gate 		}
1330ab25eeb5Syz 		f->ftps_rptr = rptr;
1331ab25eeb5Syz 		f->ftps_wptr = wptr;
13327c478bd9Sstevel@tonic-gate 	}
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 	/* f->ftps_seq[1] += inc; */
13357c478bd9Sstevel@tonic-gate 	if (tcp->th_flags & TH_FIN)
13367c478bd9Sstevel@tonic-gate 		f->ftps_seq[1]++;
1337f4b3ec61Sdh 	if (ifsftp->ippr_ftp_debug > 3) {
1338ab25eeb5Syz #ifdef __sgi
1339ab25eeb5Syz 		mlen = fin->fin_plen;
1340ab25eeb5Syz #else
1341ab25eeb5Syz 		mlen = MSGDSIZE(m);
13427c478bd9Sstevel@tonic-gate #endif
1343ab25eeb5Syz 		mlen -= off;
1344ab25eeb5Syz 		printf("ftps_seq[1] = %x inc %d len %d\n",
1345ab25eeb5Syz 		       f->ftps_seq[1], inc, mlen);
1346ab25eeb5Syz 	}
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	f->ftps_rptr = rptr;
13497c478bd9Sstevel@tonic-gate 	f->ftps_wptr = wptr;
13507c478bd9Sstevel@tonic-gate 	return APR_INC(inc);
13517c478bd9Sstevel@tonic-gate }
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 
ippr_ftp_out(fin,aps,nat,private)1354f4b3ec61Sdh int ippr_ftp_out(fin, aps, nat, private)
13557c478bd9Sstevel@tonic-gate fr_info_t *fin;
13567c478bd9Sstevel@tonic-gate ap_session_t *aps;
13577c478bd9Sstevel@tonic-gate nat_t *nat;
1358f4b3ec61Sdh void *private;
13597c478bd9Sstevel@tonic-gate {
13607c478bd9Sstevel@tonic-gate 	ftpinfo_t *ftp;
13617c478bd9Sstevel@tonic-gate 	int rev;
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 	ftp = aps->aps_data;
13647c478bd9Sstevel@tonic-gate 	if (ftp == NULL)
13657c478bd9Sstevel@tonic-gate 		return 0;
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 	rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1;
13687c478bd9Sstevel@tonic-gate 	if (ftp->ftp_side[1 - rev].ftps_ifp == NULL)
13697c478bd9Sstevel@tonic-gate 		ftp->ftp_side[1 - rev].ftps_ifp = fin->fin_ifp;
13707c478bd9Sstevel@tonic-gate 
1371f4b3ec61Sdh 	return ippr_ftp_process(fin, nat, ftp, rev, (ifs_ftppxy_t *)private);
13727c478bd9Sstevel@tonic-gate }
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 
ippr_ftp_in(fin,aps,nat,private)1375f4b3ec61Sdh int ippr_ftp_in(fin, aps, nat, private)
13767c478bd9Sstevel@tonic-gate fr_info_t *fin;
13777c478bd9Sstevel@tonic-gate ap_session_t *aps;
13787c478bd9Sstevel@tonic-gate nat_t *nat;
1379f4b3ec61Sdh void *private;
13807c478bd9Sstevel@tonic-gate {
13817c478bd9Sstevel@tonic-gate 	ftpinfo_t *ftp;
13827c478bd9Sstevel@tonic-gate 	int rev;
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 	ftp = aps->aps_data;
13857c478bd9Sstevel@tonic-gate 	if (ftp == NULL)
13867c478bd9Sstevel@tonic-gate 		return 0;
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate 	rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1;
13897c478bd9Sstevel@tonic-gate 	if (ftp->ftp_side[rev].ftps_ifp == NULL)
13907c478bd9Sstevel@tonic-gate 		ftp->ftp_side[rev].ftps_ifp = fin->fin_ifp;
13917c478bd9Sstevel@tonic-gate 
1392f4b3ec61Sdh 	return ippr_ftp_process(fin, nat, ftp, 1 - rev, (ifs_ftppxy_t *)private);
13937c478bd9Sstevel@tonic-gate }
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate /*
13977c478bd9Sstevel@tonic-gate  * ippr_ftp_atoi - implement a version of atoi which processes numbers in
13987c478bd9Sstevel@tonic-gate  * pairs separated by commas (which are expected to be in the range 0 - 255),
13997c478bd9Sstevel@tonic-gate  * returning a 16 bit number combining either side of the , as the MSB and
14007c478bd9Sstevel@tonic-gate  * LSB.
14017c478bd9Sstevel@tonic-gate  */
ippr_ftp_atoi(ptr)14027c478bd9Sstevel@tonic-gate u_short ippr_ftp_atoi(ptr)
14037c478bd9Sstevel@tonic-gate char **ptr;
14047c478bd9Sstevel@tonic-gate {
14057c478bd9Sstevel@tonic-gate 	register char *s = *ptr, c;
14067c478bd9Sstevel@tonic-gate 	register u_char i = 0, j = 0;
14077c478bd9Sstevel@tonic-gate 
1408ab25eeb5Syz 	while (((c = *s++) != '\0') && ISDIGIT(c)) {
14097c478bd9Sstevel@tonic-gate 		i *= 10;
14107c478bd9Sstevel@tonic-gate 		i += c - '0';
14117c478bd9Sstevel@tonic-gate 	}
14127c478bd9Sstevel@tonic-gate 	if (c != ',') {
14137c478bd9Sstevel@tonic-gate 		*ptr = NULL;
14147c478bd9Sstevel@tonic-gate 		return 0;
14157c478bd9Sstevel@tonic-gate 	}
1416ab25eeb5Syz 	while (((c = *s++) != '\0') && ISDIGIT(c)) {
14177c478bd9Sstevel@tonic-gate 		j *= 10;
14187c478bd9Sstevel@tonic-gate 		j += c - '0';
14197c478bd9Sstevel@tonic-gate 	}
14207c478bd9Sstevel@tonic-gate 	*ptr = s;
14217c478bd9Sstevel@tonic-gate 	i &= 0xff;
14227c478bd9Sstevel@tonic-gate 	j &= 0xff;
14237c478bd9Sstevel@tonic-gate 	return (i << 8) | j;
14247c478bd9Sstevel@tonic-gate }
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate 
ippr_ftp_epsv(fin,ip,nat,f,dlen,ifsftp)1427f4b3ec61Sdh int ippr_ftp_epsv(fin, ip, nat, f, dlen, ifsftp)
14287c478bd9Sstevel@tonic-gate fr_info_t *fin;
14297c478bd9Sstevel@tonic-gate ip_t *ip;
14307c478bd9Sstevel@tonic-gate nat_t *nat;
14317c478bd9Sstevel@tonic-gate ftpside_t *f;
14327c478bd9Sstevel@tonic-gate int dlen;
1433f4b3ec61Sdh ifs_ftppxy_t *ifsftp;
14347c478bd9Sstevel@tonic-gate {
14357c478bd9Sstevel@tonic-gate 	char newbuf[IPF_FTPBUFSZ];
14367c478bd9Sstevel@tonic-gate 	char *s;
14377c478bd9Sstevel@tonic-gate 	u_short ap = 0;
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate #define EPSV_REPLEN	33
14407c478bd9Sstevel@tonic-gate 	/*
14417c478bd9Sstevel@tonic-gate 	 * Check for EPSV reply message.
14427c478bd9Sstevel@tonic-gate 	 */
14437c478bd9Sstevel@tonic-gate 	if (dlen < IPF_MIN229LEN)
14447c478bd9Sstevel@tonic-gate 		return (0);
14457c478bd9Sstevel@tonic-gate 	else if (strncmp(f->ftps_rptr,
14467c478bd9Sstevel@tonic-gate 			 "229 Entering Extended Passive Mode", EPSV_REPLEN))
14477c478bd9Sstevel@tonic-gate 		return (0);
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 	/*
14507c478bd9Sstevel@tonic-gate 	 * Skip the EPSV command + space
14517c478bd9Sstevel@tonic-gate 	 */
14527c478bd9Sstevel@tonic-gate 	s = f->ftps_rptr + 33;
1453ab25eeb5Syz 	while (*s && !ISDIGIT(*s))
14547c478bd9Sstevel@tonic-gate 		s++;
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 	/*
14577c478bd9Sstevel@tonic-gate 	 * As per RFC 2428, there are no addres components in the EPSV
14587c478bd9Sstevel@tonic-gate 	 * response.  So we'll go straight to getting the port.
14597c478bd9Sstevel@tonic-gate 	 */
1460ab25eeb5Syz 	while (*s && ISDIGIT(*s)) {
14617c478bd9Sstevel@tonic-gate 		ap *= 10;
14627c478bd9Sstevel@tonic-gate 		ap += *s++ - '0';
14637c478bd9Sstevel@tonic-gate 	}
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 	if (!s)
14667c478bd9Sstevel@tonic-gate 		return 0;
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 	if (*s == '|')
14697c478bd9Sstevel@tonic-gate 		s++;
14707c478bd9Sstevel@tonic-gate 	if (*s == ')')
14717c478bd9Sstevel@tonic-gate 		s++;
14727c478bd9Sstevel@tonic-gate 	if (*s == '\n')
14737c478bd9Sstevel@tonic-gate 		s--;
14747c478bd9Sstevel@tonic-gate 	/*
14757c478bd9Sstevel@tonic-gate 	 * check for CR-LF at the end.
14767c478bd9Sstevel@tonic-gate 	 */
14777c478bd9Sstevel@tonic-gate 	if ((*s == '\r') && (*(s + 1) == '\n')) {
14787c478bd9Sstevel@tonic-gate 		s += 2;
14797c478bd9Sstevel@tonic-gate 	} else
14807c478bd9Sstevel@tonic-gate 		return 0;
14817c478bd9Sstevel@tonic-gate 
1482ab25eeb5Syz #if defined(SNPRINTF) && defined(_KERNEL)
1483ab25eeb5Syz 	(void) SNPRINTF(newbuf, sizeof(newbuf), "%s (|||%u|)\r\n",
1484ab25eeb5Syz 		 "229 Entering Extended Passive Mode", ap);
14857c478bd9Sstevel@tonic-gate #else
14867c478bd9Sstevel@tonic-gate 	(void) sprintf(newbuf, "%s (|||%u|)\r\n",
14877c478bd9Sstevel@tonic-gate 		       "229 Entering Extended Passive Mode", ap);
14887c478bd9Sstevel@tonic-gate #endif
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 	return ippr_ftp_pasvreply(fin, ip, nat, f, (u_int)ap, newbuf, s,
1491f4b3ec61Sdh 				  ip->ip_src.s_addr, ifsftp);
14927c478bd9Sstevel@tonic-gate }
1493