1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * All routines necessary to deal the "netmasks" database.  The sources
31*0Sstevel@tonic-gate  * contain mappings between 32 bit Internet addresses and corresponding
32*0Sstevel@tonic-gate  * 32 bit Internet address masks. The addresses are in dotted internet
33*0Sstevel@tonic-gate  * address notation.
34*0Sstevel@tonic-gate  */
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate #include <stdio.h>
37*0Sstevel@tonic-gate #include <ctype.h>
38*0Sstevel@tonic-gate #include <string.h>
39*0Sstevel@tonic-gate #include <stdlib.h>
40*0Sstevel@tonic-gate #include <sys/types.h>
41*0Sstevel@tonic-gate #include <sys/socket.h>
42*0Sstevel@tonic-gate #include <net/if.h>
43*0Sstevel@tonic-gate #include <netinet/in.h>
44*0Sstevel@tonic-gate #include <arpa/inet.h>
45*0Sstevel@tonic-gate #include <nss_dbdefs.h>
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate static int str2addr(const char *, int, void *, char *, int);
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root);
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate static void
52*0Sstevel@tonic-gate _nss_initf_netmasks(nss_db_params_t *p)
53*0Sstevel@tonic-gate {
54*0Sstevel@tonic-gate 	p->name = NSS_DBNAM_NETMASKS;
55*0Sstevel@tonic-gate 	p->default_config = NSS_DEFCONF_NETMASKS;
56*0Sstevel@tonic-gate }
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate /*
59*0Sstevel@tonic-gate  * Print a network number such as 129.144 as well as an IP address.
60*0Sstevel@tonic-gate  * Assumes network byte order for both IP addresses and network numbers
61*0Sstevel@tonic-gate  * (Network numbers are normally passed around in host byte order).
62*0Sstevel@tonic-gate  */
63*0Sstevel@tonic-gate static char *
64*0Sstevel@tonic-gate inet_nettoa(struct in_addr in)
65*0Sstevel@tonic-gate {
66*0Sstevel@tonic-gate 	uint32_t addr = in.s_addr;
67*0Sstevel@tonic-gate 	uchar_t *up = (uchar_t *)&addr;
68*0Sstevel@tonic-gate 	static char result[256];
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate 	/* Omit leading zeros */
71*0Sstevel@tonic-gate 	if (up[0]) {
72*0Sstevel@tonic-gate 		(void) sprintf(result, "%d.%d.%d.%d",
73*0Sstevel@tonic-gate 		    up[0], up[1], up[2], up[3]);
74*0Sstevel@tonic-gate 	} else if (up[1]) {
75*0Sstevel@tonic-gate 		(void) sprintf(result, "%d.%d.%d", up[1], up[2], up[3]);
76*0Sstevel@tonic-gate 	} else if (up[2]) {
77*0Sstevel@tonic-gate 		(void) sprintf(result, "%d.%d", up[2], up[3]);
78*0Sstevel@tonic-gate 	} else {
79*0Sstevel@tonic-gate 		(void) sprintf(result, "%d", up[3]);
80*0Sstevel@tonic-gate 	}
81*0Sstevel@tonic-gate 	return (result);
82*0Sstevel@tonic-gate }
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate /*
85*0Sstevel@tonic-gate  * Given a 32 bit key look it up in the netmasks database
86*0Sstevel@tonic-gate  * based on the "netmasks" policy in /etc/nsswitch.conf.
87*0Sstevel@tonic-gate  * If the key is a network number with the trailing zero's removed
88*0Sstevel@tonic-gate  * (e.g. "192.9.200") this routine can't use inet_ntoa to convert
89*0Sstevel@tonic-gate  * the address to the string key.
90*0Sstevel@tonic-gate  * Returns zero if successful, non-zero otherwise.
91*0Sstevel@tonic-gate  */
92*0Sstevel@tonic-gate static int
93*0Sstevel@tonic-gate getnetmaskbykey(const struct in_addr addr, struct in_addr *mask)
94*0Sstevel@tonic-gate {
95*0Sstevel@tonic-gate 	nss_XbyY_args_t arg;
96*0Sstevel@tonic-gate 	nss_status_t	res;
97*0Sstevel@tonic-gate 	char		tmp[NSS_LINELEN_NETMASKS];
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 	/*
100*0Sstevel@tonic-gate 	 * let the backend do the allocation to store stuff for parsing.
101*0Sstevel@tonic-gate 	 * To simplify things, we put the dotted internet address form of
102*0Sstevel@tonic-gate 	 * the network address in the 'name' field as a filter to speed
103*0Sstevel@tonic-gate 	 * up the lookup.
104*0Sstevel@tonic-gate 	 */
105*0Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, mask, NULL, 0, str2addr);
106*0Sstevel@tonic-gate 	(void) strcpy(tmp, inet_nettoa(addr));
107*0Sstevel@tonic-gate 	arg.key.name = tmp;
108*0Sstevel@tonic-gate 	res = nss_search(&db_root, _nss_initf_netmasks,
109*0Sstevel@tonic-gate 			NSS_DBOP_NETMASKS_BYNET, &arg);
110*0Sstevel@tonic-gate 	(void) NSS_XbyY_FINI(&arg);
111*0Sstevel@tonic-gate 	return (arg.status = res);
112*0Sstevel@tonic-gate }
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate /*
115*0Sstevel@tonic-gate  * Given a 32 bit internet network number, it finds the corresponding netmask
116*0Sstevel@tonic-gate  * address based on the "netmasks" policy in /etc/nsswitch.conf.
117*0Sstevel@tonic-gate  * Returns zero if successful, non-zero otherwise.
118*0Sstevel@tonic-gate  * Check both for the (masked) network number and the shifted network
119*0Sstevel@tonic-gate  * number (e.g., both "10.0.0.0" and "10").
120*0Sstevel@tonic-gate  * Assumes that the caller passes in an unshifted number (or an IP address).
121*0Sstevel@tonic-gate  */
122*0Sstevel@tonic-gate int
123*0Sstevel@tonic-gate getnetmaskbynet(const struct in_addr net, struct in_addr *mask)
124*0Sstevel@tonic-gate {
125*0Sstevel@tonic-gate 	struct in_addr net1, net2;
126*0Sstevel@tonic-gate 	uint32_t i;
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	i = ntohl(net.s_addr);
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	/*
131*0Sstevel@tonic-gate 	 * Try looking for the network number both with and without
132*0Sstevel@tonic-gate 	 * the trailing zeros.
133*0Sstevel@tonic-gate 	 */
134*0Sstevel@tonic-gate 	if ((i & IN_CLASSA_NET) == 0) {
135*0Sstevel@tonic-gate 		/* Assume already a right-shifted network number */
136*0Sstevel@tonic-gate 		net2.s_addr = htonl(i);
137*0Sstevel@tonic-gate 		if ((i & IN_CLASSB_NET) != 0) {
138*0Sstevel@tonic-gate 			net1.s_addr = htonl(i << IN_CLASSC_NSHIFT);
139*0Sstevel@tonic-gate 		} else if ((i & IN_CLASSC_NET) != 0) {
140*0Sstevel@tonic-gate 			net1.s_addr = htonl(i << IN_CLASSB_NSHIFT);
141*0Sstevel@tonic-gate 		} else {
142*0Sstevel@tonic-gate 			net1.s_addr = htonl(i << IN_CLASSA_NSHIFT);
143*0Sstevel@tonic-gate 		}
144*0Sstevel@tonic-gate 	} else if (IN_CLASSA(i)) {
145*0Sstevel@tonic-gate 		net1.s_addr = htonl(i & IN_CLASSA_NET);
146*0Sstevel@tonic-gate 		net2.s_addr = htonl(i >> IN_CLASSA_NSHIFT);
147*0Sstevel@tonic-gate 	} else if (IN_CLASSB(i)) {
148*0Sstevel@tonic-gate 		net1.s_addr = htonl(i & IN_CLASSB_NET);
149*0Sstevel@tonic-gate 		net2.s_addr = htonl(i >> IN_CLASSB_NSHIFT);
150*0Sstevel@tonic-gate 	} else {
151*0Sstevel@tonic-gate 		net1.s_addr = htonl(i & IN_CLASSC_NET);
152*0Sstevel@tonic-gate 		net2.s_addr = htonl(i >> IN_CLASSC_NSHIFT);
153*0Sstevel@tonic-gate 	}
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate 	if (getnetmaskbykey(net1, mask) == 0) {
156*0Sstevel@tonic-gate 		return (0);
157*0Sstevel@tonic-gate 	}
158*0Sstevel@tonic-gate 	if (getnetmaskbykey(net2, mask) == 0) {
159*0Sstevel@tonic-gate 		return (0);
160*0Sstevel@tonic-gate 	}
161*0Sstevel@tonic-gate 	return (-1);
162*0Sstevel@tonic-gate }
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate /*
165*0Sstevel@tonic-gate  * Find the netmask used for an IP address.
166*0Sstevel@tonic-gate  * Returns zero if successful, non-zero otherwise.
167*0Sstevel@tonic-gate  *
168*0Sstevel@tonic-gate  * Support Variable Length Subnetmasks by looking for the longest
169*0Sstevel@tonic-gate  * matching subnetmask in the database.
170*0Sstevel@tonic-gate  * Start by looking for a match for the full IP address and
171*0Sstevel@tonic-gate  * mask off one rightmost bit after another until we find a match.
172*0Sstevel@tonic-gate  * Note that for a match the found netmask must match what was used
173*0Sstevel@tonic-gate  * for the lookup masking.
174*0Sstevel@tonic-gate  * As a fallback for compatibility finally lookup the network
175*0Sstevel@tonic-gate  * number with and without the trailing zeros.
176*0Sstevel@tonic-gate  * In order to suppress redundant lookups in the name service
177*0Sstevel@tonic-gate  * we keep the previous lookup key and compare against it before
178*0Sstevel@tonic-gate  * doing the lookup.
179*0Sstevel@tonic-gate  */
180*0Sstevel@tonic-gate int
181*0Sstevel@tonic-gate getnetmaskbyaddr(const struct in_addr addr, struct in_addr *mask)
182*0Sstevel@tonic-gate {
183*0Sstevel@tonic-gate 	struct in_addr prevnet, net;
184*0Sstevel@tonic-gate 	uint32_t i, maskoff;
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 	i = ntohl(addr.s_addr);
187*0Sstevel@tonic-gate 	prevnet.s_addr = 0;
188*0Sstevel@tonic-gate 	mask->s_addr = 0;
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 	for (maskoff = 0xFFFFFFFF; maskoff != 0; maskoff = maskoff << 1) {
191*0Sstevel@tonic-gate 		net.s_addr = htonl(i & maskoff);
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 		if (net.s_addr != prevnet.s_addr) {
194*0Sstevel@tonic-gate 			if (getnetmaskbykey(net, mask) != 0) {
195*0Sstevel@tonic-gate 				mask->s_addr = 0;
196*0Sstevel@tonic-gate 			}
197*0Sstevel@tonic-gate 		}
198*0Sstevel@tonic-gate 		if (htonl(maskoff) == mask->s_addr)
199*0Sstevel@tonic-gate 			return (0);
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 		prevnet.s_addr = net.s_addr;
202*0Sstevel@tonic-gate 	}
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	/*
205*0Sstevel@tonic-gate 	 * Non-VLSM fallback.
206*0Sstevel@tonic-gate 	 * Try looking for the network number with and without the trailing
207*0Sstevel@tonic-gate 	 * zeros.
208*0Sstevel@tonic-gate 	 */
209*0Sstevel@tonic-gate 	return (getnetmaskbynet(addr, mask));
210*0Sstevel@tonic-gate }
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate /*
213*0Sstevel@tonic-gate  * Parse netmasks entry into its components. The network address is placed
214*0Sstevel@tonic-gate  * in buffer for use by check_addr for 'files' backend, to match the network
215*0Sstevel@tonic-gate  * address. The network address is placed in the buffer as a network order
216*0Sstevel@tonic-gate  * internet address, if buffer is non null. The network order form of the mask
217*0Sstevel@tonic-gate  * itself is placed in 'ent'.
218*0Sstevel@tonic-gate  */
219*0Sstevel@tonic-gate int
220*0Sstevel@tonic-gate str2addr(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
221*0Sstevel@tonic-gate {
222*0Sstevel@tonic-gate 	int	retval;
223*0Sstevel@tonic-gate 	struct in_addr	*mask = (struct in_addr *)ent;
224*0Sstevel@tonic-gate 	const char	*p, *limit, *start;
225*0Sstevel@tonic-gate 	struct in_addr	addr;
226*0Sstevel@tonic-gate 	int		i;
227*0Sstevel@tonic-gate 	char		tmp[NSS_LINELEN_NETMASKS];
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	p = instr;
230*0Sstevel@tonic-gate 	limit = p + lenstr;
231*0Sstevel@tonic-gate 	retval = NSS_STR_PARSE_PARSE;
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 	while (p < limit && isspace(*p))	/* skip leading whitespace */
234*0Sstevel@tonic-gate 		p++;
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 	if (buffer) {	/* for 'files' backend verification */
237*0Sstevel@tonic-gate 		for (start = p, i = 0; p < limit && !isspace(*p); p++)
238*0Sstevel@tonic-gate 			i++;
239*0Sstevel@tonic-gate 		if (p < limit && i < buflen) {
240*0Sstevel@tonic-gate 			(void) memcpy(tmp, start, i);
241*0Sstevel@tonic-gate 			tmp[i] = '\0';
242*0Sstevel@tonic-gate 			addr.s_addr = inet_addr(tmp);
243*0Sstevel@tonic-gate 			/* Addr will always be an ipv4 address (32bits) */
244*0Sstevel@tonic-gate 			if (addr.s_addr == 0xffffffffUL)
245*0Sstevel@tonic-gate 				return (NSS_STR_PARSE_PARSE);
246*0Sstevel@tonic-gate 			else {
247*0Sstevel@tonic-gate 				(void) memcpy(buffer, (char *)&addr,
248*0Sstevel@tonic-gate 				    sizeof (struct in_addr));
249*0Sstevel@tonic-gate 			}
250*0Sstevel@tonic-gate 		} else
251*0Sstevel@tonic-gate 			return (NSS_STR_PARSE_ERANGE);
252*0Sstevel@tonic-gate 	}
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	while (p < limit && isspace(*p))	/* skip intermediate */
255*0Sstevel@tonic-gate 		p++;
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	if (mask) {
258*0Sstevel@tonic-gate 		for (start = p, i = 0; p < limit && !isspace(*p); p++)
259*0Sstevel@tonic-gate 			i++;
260*0Sstevel@tonic-gate 		if (p <= limit) {
261*0Sstevel@tonic-gate 			if ((i + 1) > NSS_LINELEN_NETMASKS)
262*0Sstevel@tonic-gate 				return (NSS_STR_PARSE_ERANGE);
263*0Sstevel@tonic-gate 			(void) memcpy(tmp, start, i);
264*0Sstevel@tonic-gate 			tmp[i] = '\0';
265*0Sstevel@tonic-gate 			addr.s_addr = inet_addr(tmp);
266*0Sstevel@tonic-gate 			/* Addr will always be an ipv4 address (32bits) */
267*0Sstevel@tonic-gate 			if (addr.s_addr == 0xffffffffUL)
268*0Sstevel@tonic-gate 				retval = NSS_STR_PARSE_PARSE;
269*0Sstevel@tonic-gate 			else {
270*0Sstevel@tonic-gate 				mask->s_addr = addr.s_addr;
271*0Sstevel@tonic-gate 				retval = NSS_STR_PARSE_SUCCESS;
272*0Sstevel@tonic-gate 			}
273*0Sstevel@tonic-gate 		}
274*0Sstevel@tonic-gate 	}
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	return (retval);
277*0Sstevel@tonic-gate }
278