1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*0Sstevel@tonic-gate 
8*0Sstevel@tonic-gate /****************************************************************************
9*0Sstevel@tonic-gate   Copyright (c) 1999,2000 WU-FTPD Development Group.
10*0Sstevel@tonic-gate   All rights reserved.
11*0Sstevel@tonic-gate 
12*0Sstevel@tonic-gate   Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994
13*0Sstevel@tonic-gate     The Regents of the University of California.
14*0Sstevel@tonic-gate   Portions Copyright (c) 1993, 1994 Washington University in Saint Louis.
15*0Sstevel@tonic-gate   Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc.
16*0Sstevel@tonic-gate   Portions Copyright (c) 1989 Massachusetts Institute of Technology.
17*0Sstevel@tonic-gate   Portions Copyright (c) 1998 Sendmail, Inc.
18*0Sstevel@tonic-gate   Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P.  Allman.
19*0Sstevel@tonic-gate   Portions Copyright (c) 1997 by Stan Barber.
20*0Sstevel@tonic-gate   Portions Copyright (c) 1997 by Kent Landfield.
21*0Sstevel@tonic-gate   Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997
22*0Sstevel@tonic-gate     Free Software Foundation, Inc.
23*0Sstevel@tonic-gate 
24*0Sstevel@tonic-gate   Use and distribution of this software and its source code are governed
25*0Sstevel@tonic-gate   by the terms and conditions of the WU-FTPD Software License ("LICENSE").
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate   If you did not receive a copy of the license, it may be obtained online
28*0Sstevel@tonic-gate   at http://www.wu-ftpd.org/license.html.
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate   $Id: routevector.c,v 1.13 2000/07/01 18:17:39 wuftpd Exp $
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate ****************************************************************************/
33*0Sstevel@tonic-gate /*
34*0Sstevel@tonic-gate  * Parse the entire ftpaccess file looking for:
35*0Sstevel@tonic-gate  *
36*0Sstevel@tonic-gate  * passive address <externalip> <address/CIDR>
37*0Sstevel@tonic-gate  * passive ports <address/CIDR> <min> <max>
38*0Sstevel@tonic-gate  *
39*0Sstevel@tonic-gate  * vect_addr, passive_port_min and passive_port_max store the external IP
40*0Sstevel@tonic-gate  * address, min and max ports found whose associated address is the most
41*0Sstevel@tonic-gate  * specific match of the address the client connected from.
42*0Sstevel@tonic-gate  *
43*0Sstevel@tonic-gate  * The optional CIDR denotes the number of significant bits in the address,
44*0Sstevel@tonic-gate  * the higher the CIDR the more specific the address. If no CIDR is specified,
45*0Sstevel@tonic-gate  * the whole address is significant.
46*0Sstevel@tonic-gate  *
47*0Sstevel@tonic-gate  * When a passive data connection is requested the server listens on a port
48*0Sstevel@tonic-gate  * randomly selected between passive_port_min and passive_port_max
49*0Sstevel@tonic-gate  * (inclusive), if vect_addr is set its address is reported (if not the
50*0Sstevel@tonic-gate  * local address of the control connection is reported). Note this does not
51*0Sstevel@tonic-gate  * change the address the server actually listens on, only the address
52*0Sstevel@tonic-gate  * reported to the client.
53*0Sstevel@tonic-gate  *
54*0Sstevel@tonic-gate  * For example if the ftpaccess file includes:
55*0Sstevel@tonic-gate  * passive address 194.80.17.14  0.0.0.0/0
56*0Sstevel@tonic-gate  * passive address 10.0.1.15     10.0.0.0/8
57*0Sstevel@tonic-gate  *
58*0Sstevel@tonic-gate  * Clients connecting from the class-A network 10 will be told the passive
59*0Sstevel@tonic-gate  * connection is listening on IP address 10.0.1.15, while clients connecting
60*0Sstevel@tonic-gate  * from all other addresses will be told the connection is listening on
61*0Sstevel@tonic-gate  * 194.80.17.14 (a CIDR of /0 matches all addresses of the same address
62*0Sstevel@tonic-gate  * family, if IPv6 support is enabled then IPv4 and IPv6 addresses are
63*0Sstevel@tonic-gate  * supported).
64*0Sstevel@tonic-gate  */
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate #include "config.h"
67*0Sstevel@tonic-gate #include <sys/socket.h>
68*0Sstevel@tonic-gate #include <netinet/in.h>
69*0Sstevel@tonic-gate #include <arpa/inet.h>
70*0Sstevel@tonic-gate #include <string.h>
71*0Sstevel@tonic-gate #ifdef HAVE_SYS_SYSLOG_H
72*0Sstevel@tonic-gate #include <sys/syslog.h>
73*0Sstevel@tonic-gate #endif
74*0Sstevel@tonic-gate #if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H))
75*0Sstevel@tonic-gate #include <syslog.h>
76*0Sstevel@tonic-gate #endif
77*0Sstevel@tonic-gate #include "extensions.h"
78*0Sstevel@tonic-gate #include "proto.h"
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate extern struct SOCKSTORAGE his_addr;
81*0Sstevel@tonic-gate extern struct SOCKSTORAGE vect_addr; /* best matching external IP address */
82*0Sstevel@tonic-gate extern int passive_port_min;
83*0Sstevel@tonic-gate extern int passive_port_max;
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate /* significance of the external IP address and port entries */
86*0Sstevel@tonic-gate static int vect_sig = -1;
87*0Sstevel@tonic-gate static int port_sig = -1;
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate #ifdef INET6
90*0Sstevel@tonic-gate static int his_addr_family = AF_INET;
91*0Sstevel@tonic-gate static int his_v4mapped = 0;
92*0Sstevel@tonic-gate #endif
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate /*
95*0Sstevel@tonic-gate  * Compares the address the client connected from (in his_addr) with the
96*0Sstevel@tonic-gate  * supplied address, with the specified number of bits being significant
97*0Sstevel@tonic-gate  * in the comparison. Returns 0 if the addresses match, non-zero otherwise.
98*0Sstevel@tonic-gate  */
addr_cmp(void * addr,int sig)99*0Sstevel@tonic-gate static int addr_cmp(void *addr, int sig)
100*0Sstevel@tonic-gate {
101*0Sstevel@tonic-gate     uint32_t addr32[4], rem32[4];
102*0Sstevel@tonic-gate     int bitstozero, i, start = 0, len = sizeof(uint32_t);
103*0Sstevel@tonic-gate     char *ptr;
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate #ifdef INET6
106*0Sstevel@tonic-gate     if (his_addr_family == AF_INET) {
107*0Sstevel@tonic-gate 	if (his_v4mapped) {
108*0Sstevel@tonic-gate 	    ptr = (char *)&((struct sockaddr_in6 *)&his_addr)->sin6_addr;
109*0Sstevel@tonic-gate 	    /* move to the IPv4 part of an IPv4-mapped IPv6 address */
110*0Sstevel@tonic-gate 	    ptr += 12;
111*0Sstevel@tonic-gate 	}
112*0Sstevel@tonic-gate 	else
113*0Sstevel@tonic-gate #endif
114*0Sstevel@tonic-gate 	    ptr = (char *)&((struct sockaddr_in *)&his_addr)->sin_addr;
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate 	/* IPv4 addresses are 32-bits long */
117*0Sstevel@tonic-gate 	bitstozero = 32 - sig;
118*0Sstevel@tonic-gate 	memcpy(addr32, addr, sizeof(uint32_t));
119*0Sstevel@tonic-gate 	memcpy(rem32, ptr, sizeof(uint32_t));
120*0Sstevel@tonic-gate #ifdef INET6
121*0Sstevel@tonic-gate     }
122*0Sstevel@tonic-gate     else {
123*0Sstevel@tonic-gate 	/* IPv6 addresses are 128-bits long */
124*0Sstevel@tonic-gate 	bitstozero = 128 - sig;
125*0Sstevel@tonic-gate 	start = 3;
126*0Sstevel@tonic-gate 	len = sizeof(addr32);
127*0Sstevel@tonic-gate 	memcpy(addr32, addr, sizeof(addr32));
128*0Sstevel@tonic-gate 	memcpy(rem32, &((struct sockaddr_in6 *)&his_addr)->sin6_addr, sizeof(rem32));
129*0Sstevel@tonic-gate     }
130*0Sstevel@tonic-gate #endif
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate     /* zero bits starting with the least significant */
133*0Sstevel@tonic-gate     for (i = start; (bitstozero > 0) && (i >= 0); i--, bitstozero -= 32) {
134*0Sstevel@tonic-gate 	if (bitstozero >= 32)
135*0Sstevel@tonic-gate 	    addr32[i] = rem32[i] = 0;
136*0Sstevel@tonic-gate 	else {
137*0Sstevel@tonic-gate 	    addr32[i] = (ntohl(addr32[i]) >> bitstozero) << bitstozero;
138*0Sstevel@tonic-gate 	    rem32[i] = (ntohl(rem32[i]) >> bitstozero) << bitstozero;
139*0Sstevel@tonic-gate 	}
140*0Sstevel@tonic-gate     }
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate     /* compare the IP addresses */
143*0Sstevel@tonic-gate     return memcmp(addr32, rem32, len);
144*0Sstevel@tonic-gate }
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate /*
147*0Sstevel@tonic-gate  * Matches a supplied IP address string against the address the client
148*0Sstevel@tonic-gate  * connected from (in his_addr). Returns 1 and updates sig if the addresses
149*0Sstevel@tonic-gate  * match and there hasn't already been a more specific match, zero otherwise.
150*0Sstevel@tonic-gate  */
better_match(char * addrstr,int * sig)151*0Sstevel@tonic-gate static int better_match(char *addrstr, int *sig)
152*0Sstevel@tonic-gate {
153*0Sstevel@tonic-gate     int addr_sig, max_sig = 32;
154*0Sstevel@tonic-gate     char *ptr;
155*0Sstevel@tonic-gate     void *addr;
156*0Sstevel@tonic-gate #ifdef INET6
157*0Sstevel@tonic-gate     int rval;
158*0Sstevel@tonic-gate     struct in6_addr in6;
159*0Sstevel@tonic-gate #else
160*0Sstevel@tonic-gate     struct in_addr in;
161*0Sstevel@tonic-gate #endif
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate     /* look for the optional significance (/CIDR) */
164*0Sstevel@tonic-gate     if ((ptr = strstr(addrstr, "/")))
165*0Sstevel@tonic-gate 	*ptr = '\0';
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate #ifdef INET6
168*0Sstevel@tonic-gate     if (his_addr_family == AF_INET6)
169*0Sstevel@tonic-gate 	max_sig = 128;
170*0Sstevel@tonic-gate #endif
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate     if (ptr) {
173*0Sstevel@tonic-gate 	addr_sig = atoi(++ptr);
174*0Sstevel@tonic-gate 	if (addr_sig < 0)
175*0Sstevel@tonic-gate 	    addr_sig = 0;
176*0Sstevel@tonic-gate 	else if (addr_sig > max_sig)
177*0Sstevel@tonic-gate 	    addr_sig = max_sig;
178*0Sstevel@tonic-gate     }
179*0Sstevel@tonic-gate     else
180*0Sstevel@tonic-gate 	addr_sig = max_sig;
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate     /* return if we already have a more specific match */
183*0Sstevel@tonic-gate     if (addr_sig < *sig) {
184*0Sstevel@tonic-gate 	if (ptr)
185*0Sstevel@tonic-gate 	    *--ptr = '/';
186*0Sstevel@tonic-gate 	return 0;
187*0Sstevel@tonic-gate     }
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate #ifdef INET6
190*0Sstevel@tonic-gate     rval = inet_pton6(addrstr, &in6);
191*0Sstevel@tonic-gate     if (ptr)
192*0Sstevel@tonic-gate 	*--ptr = '/';
193*0Sstevel@tonic-gate     if (rval != 1)
194*0Sstevel@tonic-gate 	return 0;
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate     if (his_addr_family == AF_INET) {
197*0Sstevel@tonic-gate 	/* convert IPv4-mapped IPv6 addresses to IPv4 addresses */
198*0Sstevel@tonic-gate 	if (IN6_IS_ADDR_V4MAPPED(&in6))
199*0Sstevel@tonic-gate 	    addr = &in6.s6_addr[12];
200*0Sstevel@tonic-gate 	else
201*0Sstevel@tonic-gate 	    return 0;
202*0Sstevel@tonic-gate     }
203*0Sstevel@tonic-gate     else
204*0Sstevel@tonic-gate 	addr = &in6.s6_addr;
205*0Sstevel@tonic-gate #else
206*0Sstevel@tonic-gate     in.s_addr = inet_addr(addrstr);
207*0Sstevel@tonic-gate     if (ptr)
208*0Sstevel@tonic-gate 	*--ptr = '/';
209*0Sstevel@tonic-gate     if ((int)in.s_addr == -1)
210*0Sstevel@tonic-gate 	return 0;
211*0Sstevel@tonic-gate     addr = &in.s_addr;
212*0Sstevel@tonic-gate #endif
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate     if (addr_cmp(addr, addr_sig) == 0) {
215*0Sstevel@tonic-gate 	*sig = addr_sig;
216*0Sstevel@tonic-gate 	return 1;
217*0Sstevel@tonic-gate     }
218*0Sstevel@tonic-gate     return 0;
219*0Sstevel@tonic-gate }
220*0Sstevel@tonic-gate 
update_address(char * externalip,char * addrstr)221*0Sstevel@tonic-gate static void update_address(char *externalip, char *addrstr)
222*0Sstevel@tonic-gate {
223*0Sstevel@tonic-gate     struct SOCKSTORAGE ext_addr;
224*0Sstevel@tonic-gate #ifndef INET6
225*0Sstevel@tonic-gate     struct in_addr in;
226*0Sstevel@tonic-gate #endif
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate     /* validate the external IP address string */
229*0Sstevel@tonic-gate #ifdef INET6
230*0Sstevel@tonic-gate     SET_SOCK_FAMILY(ext_addr, AF_INET6);
231*0Sstevel@tonic-gate     if (inet_pton6(externalip, SOCK_ADDR(ext_addr)) != 1)
232*0Sstevel@tonic-gate 	return;
233*0Sstevel@tonic-gate     if ((his_addr_family == AF_INET) &&
234*0Sstevel@tonic-gate 	!IN6_IS_ADDR_V4MAPPED((struct in6_addr *)SOCK_ADDR(ext_addr)))
235*0Sstevel@tonic-gate 	return;
236*0Sstevel@tonic-gate #else
237*0Sstevel@tonic-gate     if ((int)(in.s_addr = inet_addr(externalip)) == -1)
238*0Sstevel@tonic-gate 	return;
239*0Sstevel@tonic-gate     SET_SOCK_FAMILY(ext_addr, AF_INET);
240*0Sstevel@tonic-gate     SET_SOCK_ADDR4(ext_addr, in);
241*0Sstevel@tonic-gate #endif
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate     if (better_match(addrstr, &vect_sig))
244*0Sstevel@tonic-gate 	vect_addr = ext_addr;
245*0Sstevel@tonic-gate }
246*0Sstevel@tonic-gate 
update_ports(char * addrstr,char * minport,char * maxport)247*0Sstevel@tonic-gate static void update_ports(char *addrstr, char *minport, char *maxport)
248*0Sstevel@tonic-gate {
249*0Sstevel@tonic-gate     int min, max;
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate     min = atoi(minport);
252*0Sstevel@tonic-gate     max = atoi(maxport);
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate     /* validate the ports supplied */
255*0Sstevel@tonic-gate     if ((min > max) || (min < 0) || (max > 65535) || (min == 0 && max != 0)) {
256*0Sstevel@tonic-gate 	syslog(LOG_WARNING, "ftpaccess passive ports entry invalid: %s %s %s", addrstr, minport, maxport);
257*0Sstevel@tonic-gate 	return;
258*0Sstevel@tonic-gate     }
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate     if (better_match(addrstr, &port_sig)) {
261*0Sstevel@tonic-gate 	passive_port_min = min;
262*0Sstevel@tonic-gate 	passive_port_max = max;
263*0Sstevel@tonic-gate     }
264*0Sstevel@tonic-gate }
265*0Sstevel@tonic-gate 
routevector(void)266*0Sstevel@tonic-gate int routevector(void)
267*0Sstevel@tonic-gate {
268*0Sstevel@tonic-gate     struct aclmember *entry = NULL;
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate #ifdef INET6
271*0Sstevel@tonic-gate     if (SOCK_FAMILY(his_addr) == AF_INET6) {
272*0Sstevel@tonic-gate 	if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&(his_addr))->sin6_addr))
273*0Sstevel@tonic-gate 	    his_v4mapped = 1;
274*0Sstevel@tonic-gate 	else
275*0Sstevel@tonic-gate 	    his_addr_family = AF_INET6;
276*0Sstevel@tonic-gate     }
277*0Sstevel@tonic-gate #endif
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate     while (getaclentry("passive", &entry)) {
280*0Sstevel@tonic-gate 	if (!strcasecmp(ARG0, "address")) {
281*0Sstevel@tonic-gate 	    if (!ARG1 || !ARG2)
282*0Sstevel@tonic-gate 		continue;
283*0Sstevel@tonic-gate 	    update_address(ARG1, ARG2);
284*0Sstevel@tonic-gate 	}
285*0Sstevel@tonic-gate 	if (!strcasecmp(ARG0, "ports")) {
286*0Sstevel@tonic-gate 	    if (!ARG1 || !ARG2 || !ARG3)
287*0Sstevel@tonic-gate 		continue;
288*0Sstevel@tonic-gate 	    update_ports(ARG1, ARG2, ARG3);
289*0Sstevel@tonic-gate 	}
290*0Sstevel@tonic-gate     }
291*0Sstevel@tonic-gate     return vect_sig != -1;
292*0Sstevel@tonic-gate }
293