10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*2830Sdjl  * Common Development and Distribution License (the "License").
6*2830Sdjl  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*2830Sdjl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  * files/gethostent.c -- "files" backend for nsswitch "hosts" database
260Sstevel@tonic-gate  */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <netdb.h>
310Sstevel@tonic-gate #include "files_common.h"
320Sstevel@tonic-gate #include <string.h>
330Sstevel@tonic-gate #include <strings.h>
340Sstevel@tonic-gate #include <stddef.h>
350Sstevel@tonic-gate #include <stdlib.h>
360Sstevel@tonic-gate #include <sys/types.h>
370Sstevel@tonic-gate #include <sys/socket.h>
380Sstevel@tonic-gate #include <netinet/in.h>
390Sstevel@tonic-gate #include <arpa/nameser.h>
40*2830Sdjl #include <arpa/inet.h>
410Sstevel@tonic-gate #include <ctype.h>
420Sstevel@tonic-gate 
43*2830Sdjl static int	check_name(nss_XbyY_args_t *, const char *, int,
44*2830Sdjl 			int, const char **, int *, void *, int *);
450Sstevel@tonic-gate static char *do_aliases();
46*2830Sdjl static char *strcasestr(const char *as1, const char *as2);
470Sstevel@tonic-gate nss_status_t __nss_files_XY_hostbyname();
480Sstevel@tonic-gate int __nss_files_2herrno();
49*2830Sdjl static int	__nss_files_get_addr(int, const char *, int,
50*2830Sdjl 			void *, int, int *);
510Sstevel@tonic-gate 
520Sstevel@tonic-gate static int
53*2830Sdjl check_name(nss_XbyY_args_t *argp, const char *line, int linelen,
54*2830Sdjl 	int type, const char **namep, int *namelen,
55*2830Sdjl 	void *addrp, int *addrsize)
560Sstevel@tonic-gate {
57*2830Sdjl 	const char	*limit, *linep, *keyp, *addrstart;
58*2830Sdjl 	int		v6flag = 0, addrlen;
59*2830Sdjl 
60*2830Sdjl 	linep = line;
61*2830Sdjl 	limit = line + linelen;
620Sstevel@tonic-gate 
63*2830Sdjl 	/* Address */
64*2830Sdjl 	addrstart = linep;
65*2830Sdjl 	while (linep < limit && !isspace(*linep)) {
66*2830Sdjl 		if (*linep == ':')
67*2830Sdjl 			v6flag++;
68*2830Sdjl 		linep++;
690Sstevel@tonic-gate 	}
70*2830Sdjl 	addrlen = linep - addrstart;
71*2830Sdjl 
72*2830Sdjl 	/* skip the delimiting spaces */
73*2830Sdjl 	while (linep < limit && isspace(*linep))
74*2830Sdjl 		linep++;
75*2830Sdjl 
76*2830Sdjl 	/* Canonical name */
77*2830Sdjl 	keyp = argp->key.name;
78*2830Sdjl 	*namep = linep;
79*2830Sdjl 	while (*keyp && linep < limit && !isspace(*linep) &&
80*2830Sdjl 			tolower(*keyp) == tolower(*linep)) {
81*2830Sdjl 		keyp++;
82*2830Sdjl 		linep++;
83*2830Sdjl 	}
84*2830Sdjl 	if (*keyp == '\0' && (linep == limit || isspace(*linep))) {
85*2830Sdjl 		if (__nss_files_get_addr(type, addrstart, addrlen,
86*2830Sdjl 					addrp, v6flag, addrsize)) {
87*2830Sdjl 			*namelen = linep - *namep;
880Sstevel@tonic-gate 			return (1);
890Sstevel@tonic-gate 		}
900Sstevel@tonic-gate 	}
91*2830Sdjl 	while (linep < limit && !isspace(*linep))
92*2830Sdjl 		linep++;
93*2830Sdjl 	*namelen = linep - *namep;
94*2830Sdjl 
95*2830Sdjl 	/* Aliases */
96*2830Sdjl 	while (linep < limit) {
97*2830Sdjl 		/* skip the delimiting spaces */
98*2830Sdjl 		while (linep < limit && isspace(*linep))
99*2830Sdjl 			linep++;
100*2830Sdjl 
101*2830Sdjl 		/* compare name (case insensitive) */
102*2830Sdjl 		keyp = argp->key.name;
103*2830Sdjl 		while (*keyp && linep < limit && !isspace(*linep) &&
104*2830Sdjl 				tolower(*keyp) == tolower(*linep)) {
105*2830Sdjl 			keyp++;
106*2830Sdjl 			linep++;
107*2830Sdjl 		}
108*2830Sdjl 		if (*keyp == '\0' && (linep == limit || isspace(*linep)))
109*2830Sdjl 			return (__nss_files_get_addr(type, addrstart, addrlen,
110*2830Sdjl 					addrp, v6flag, addrsize));
111*2830Sdjl 
112*2830Sdjl 		/* skip remainder of alias, if any */
113*2830Sdjl 		while (linep < limit && !isspace(*linep))
114*2830Sdjl 			linep++;
115*2830Sdjl 	}
1160Sstevel@tonic-gate 	return (0);
117*2830Sdjl 
1180Sstevel@tonic-gate }
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate static nss_status_t
1210Sstevel@tonic-gate getbyname(be, a)
1220Sstevel@tonic-gate 	files_backend_ptr_t	be;
1230Sstevel@tonic-gate 	void			*a;
1240Sstevel@tonic-gate {
1250Sstevel@tonic-gate 	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
1260Sstevel@tonic-gate 	nss_status_t		res;
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	res = __nss_files_XY_hostbyname(be, argp, argp->key.name, AF_INET);
1290Sstevel@tonic-gate 	if (res != NSS_SUCCESS)
1300Sstevel@tonic-gate 		argp->h_errno = __nss_files_2herrno(res);
1310Sstevel@tonic-gate 	return (res);
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate 
134*2830Sdjl static int
135*2830Sdjl __nss_files_get_addr(int af, const char *addrstart, int addrlen,
136*2830Sdjl 	void *addrp, int v6flag, int *h_length)
137*2830Sdjl {
138*2830Sdjl 	struct in_addr	addr_ipv4;
139*2830Sdjl 	struct in6_addr	*addrpv6;
140*2830Sdjl 	in_addr_t	*addrpv4;
141*2830Sdjl 	char		addrbuf[INET6_ADDRSTRLEN + 1];
142*2830Sdjl 
143*2830Sdjl 	if (addrlen >= sizeof (addrbuf))
144*2830Sdjl 		return (0);
145*2830Sdjl 	(void) memcpy(addrbuf, addrstart, addrlen);
146*2830Sdjl 	addrbuf[addrlen] = '\0';
147*2830Sdjl 
148*2830Sdjl 	if (af == AF_INET) {
149*2830Sdjl 		addrpv4 = (in_addr_t *)addrp;
150*2830Sdjl 		if ((*addrpv4 = inet_addr(addrbuf)) == 0xffffffffU)
151*2830Sdjl 			return (0);
152*2830Sdjl 		*h_length = sizeof (in_addr_t);
153*2830Sdjl 	} else if (af == AF_INET6) {
154*2830Sdjl 		addrpv6 = (struct in6_addr *)addrp;
155*2830Sdjl 		if (v6flag) {
156*2830Sdjl 			if (inet_pton(af, addrbuf, addrpv6) != 1)
157*2830Sdjl 				return (0);
158*2830Sdjl 		} else {
159*2830Sdjl 			if ((addr_ipv4.s_addr = inet_addr(addrbuf)) ==
160*2830Sdjl 							0xffffffffU)
161*2830Sdjl 				return (0);
162*2830Sdjl 			IN6_INADDR_TO_V4MAPPED(&addr_ipv4, addrpv6);
163*2830Sdjl 		}
164*2830Sdjl 		*h_length = sizeof (struct in6_addr);
165*2830Sdjl 	} else {
166*2830Sdjl 		return (0);
167*2830Sdjl 	}
168*2830Sdjl 	return (1);
169*2830Sdjl }
170*2830Sdjl 
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate int
173*2830Sdjl __nss_files_check_addr(int af, nss_XbyY_args_t *argp, const char *line,
174*2830Sdjl 		int linelen)
1750Sstevel@tonic-gate {
176*2830Sdjl 	const char	*limit, *linep, *addrstart;
177*2830Sdjl 	int		v6flag = 0, addrlen, h_length;
178*2830Sdjl 	in_addr_t	addr_ipv4;
179*2830Sdjl 	struct in6_addr	addr_ipv6;
180*2830Sdjl 	char		*h_addrp;
181*2830Sdjl 
182*2830Sdjl 	/* Compare the address type */
183*2830Sdjl 	if (argp->key.hostaddr.type != af)
184*2830Sdjl 		return (0);
1850Sstevel@tonic-gate 
186*2830Sdjl 	/* Retrieve the address */
187*2830Sdjl 	if (af == AF_INET)
188*2830Sdjl 		h_addrp = (char *)&addr_ipv4;
189*2830Sdjl 	else
190*2830Sdjl 		h_addrp = (char *)&addr_ipv6;
191*2830Sdjl 	linep = line;
192*2830Sdjl 	limit = line + linelen;
193*2830Sdjl 	addrstart = linep;
194*2830Sdjl 	while (linep < limit && !isspace(*linep)) {
195*2830Sdjl 		if (*linep == ':')
196*2830Sdjl 			v6flag++;
197*2830Sdjl 		linep++;
198*2830Sdjl 	}
199*2830Sdjl 	addrlen = linep - addrstart;
200*2830Sdjl 	if (__nss_files_get_addr(af, addrstart, addrlen, h_addrp,
201*2830Sdjl 			v6flag, &h_length) == 0)
202*2830Sdjl 		return (0);
203*2830Sdjl 
204*2830Sdjl 	/* Compare the address */
205*2830Sdjl 	return (h_length == argp->key.hostaddr.len &&
206*2830Sdjl 		memcmp(h_addrp, argp->key.hostaddr.addr,
2070Sstevel@tonic-gate 			argp->key.hostaddr.len) == 0);
2080Sstevel@tonic-gate }
2090Sstevel@tonic-gate 
210*2830Sdjl static int
211*2830Sdjl check_addr(nss_XbyY_args_t *argp, const char *line, int linelen)
212*2830Sdjl {
213*2830Sdjl 	return (__nss_files_check_addr(AF_INET, argp, line, linelen));
214*2830Sdjl }
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate static nss_status_t
2170Sstevel@tonic-gate getbyaddr(be, a)
2180Sstevel@tonic-gate 	files_backend_ptr_t	be;
2190Sstevel@tonic-gate 	void			*a;
2200Sstevel@tonic-gate {
2210Sstevel@tonic-gate 	nss_XbyY_args_t		*argp	= (nss_XbyY_args_t *)a;
2220Sstevel@tonic-gate 	nss_status_t		res;
2230Sstevel@tonic-gate 
224*2830Sdjl 	res = _nss_files_XY_all(be, argp, 1, 0, check_addr);
2250Sstevel@tonic-gate 	if (res != NSS_SUCCESS)
2260Sstevel@tonic-gate 		argp->h_errno = __nss_files_2herrno(res);
2270Sstevel@tonic-gate 	return (res);
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate static files_backend_op_t host_ops[] = {
2320Sstevel@tonic-gate 	_nss_files_destr,
2330Sstevel@tonic-gate 	_nss_files_endent,
2340Sstevel@tonic-gate 	_nss_files_setent,
2350Sstevel@tonic-gate 	_nss_files_getent_netdb,
2360Sstevel@tonic-gate 	getbyname,
2370Sstevel@tonic-gate 	getbyaddr,
2380Sstevel@tonic-gate };
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate /*ARGSUSED*/
2410Sstevel@tonic-gate nss_backend_t *
2420Sstevel@tonic-gate _nss_files_hosts_constr(dummy1, dummy2, dummy3)
2430Sstevel@tonic-gate 	const char	*dummy1, *dummy2, *dummy3;
2440Sstevel@tonic-gate {
2450Sstevel@tonic-gate 	return (_nss_files_constr(host_ops,
2460Sstevel@tonic-gate 				sizeof (host_ops) / sizeof (host_ops[0]),
2470Sstevel@tonic-gate 				_PATH_HOSTS,
2480Sstevel@tonic-gate 				NSS_LINELEN_HOSTS,
2490Sstevel@tonic-gate 				NULL));
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate /*
2540Sstevel@tonic-gate  * XXX - this duplicates code from files_common.c because we need to keep
2550Sstevel@tonic-gate  * going after we've found a match to satisfy the multihomed host case.
2560Sstevel@tonic-gate  */
2570Sstevel@tonic-gate nss_status_t
2580Sstevel@tonic-gate __nss_files_XY_hostbyname(be, args, filter, type)
2590Sstevel@tonic-gate 	files_backend_ptr_t be;
2600Sstevel@tonic-gate 	nss_XbyY_args_t *args;
2610Sstevel@tonic-gate 	const char *filter;		/* hint for name string */
2620Sstevel@tonic-gate 	int type;
2630Sstevel@tonic-gate {
264*2830Sdjl 	nss_status_t	res;
265*2830Sdjl 	char		*abuf = NULL, *abuf_start = NULL, *abuf_end;
266*2830Sdjl 	char		*first, *last, *buffer;
267*2830Sdjl 	int		parsestat, i, nhosts = 0, buflen;
268*2830Sdjl 	const char	*namep;
269*2830Sdjl 	char		*h_name;
270*2830Sdjl 	int		h_namelen, namelen;
271*2830Sdjl 	struct hostent	*hp;
272*2830Sdjl 	in_addr_t	*taddr = NULL;
273*2830Sdjl 	struct in6_addr	*taddr6 = NULL;
274*2830Sdjl 	size_t		ntaddr;
275*2830Sdjl 	void		*addrp;
276*2830Sdjl 	char		*alias_end = NULL;
2770Sstevel@tonic-gate 
278*2830Sdjl 	if (be->buf == 0 && (be->buf = malloc(be->minbuf)) == 0) {
2790Sstevel@tonic-gate 		return (NSS_UNAVAIL);
2800Sstevel@tonic-gate 	}
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	if (be->f == 0) {
2830Sstevel@tonic-gate 		if ((res = _nss_files_setent(be, 0)) != NSS_SUCCESS)
2840Sstevel@tonic-gate 			return (res);
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate 
287*2830Sdjl 	ntaddr = MAXADDRS;
288*2830Sdjl 	if (type == AF_INET) {
289*2830Sdjl 		taddr = (in_addr_t *)calloc(ntaddr, sizeof (*taddr));
290*2830Sdjl 		if (taddr == NULL)
291*2830Sdjl 			return (NSS_UNAVAIL);
292*2830Sdjl 	} else {
293*2830Sdjl 		taddr6 = (struct in6_addr *)calloc(ntaddr, sizeof (*taddr6));
294*2830Sdjl 		if (taddr6 == NULL)
295*2830Sdjl 			return (NSS_UNAVAIL);
296*2830Sdjl 	}
297*2830Sdjl 
2980Sstevel@tonic-gate 	res = NSS_NOTFOUND;
2990Sstevel@tonic-gate 	args->returnval = (char *)0;
300*2830Sdjl 	args->returnlen = 0;
301*2830Sdjl 	hp = (struct hostent *)args->buf.result;
302*2830Sdjl 	buffer = args->buf.buffer;
303*2830Sdjl 	buflen = args->buf.buflen;
304*2830Sdjl 	h_namelen = 0;
305*2830Sdjl 	h_name = NULL;
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	for (;;) {
3080Sstevel@tonic-gate 		char *instr = be->buf;
3090Sstevel@tonic-gate 		int linelen;
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 		if ((linelen = _nss_files_read_line(be->f,
3120Sstevel@tonic-gate 		    instr, be->minbuf)) < 0) {
3130Sstevel@tonic-gate 			break;		/* EOF */
3140Sstevel@tonic-gate 		}
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 		/*
3170Sstevel@tonic-gate 		 * This check avoids a malloc()/free() for the common
3180Sstevel@tonic-gate 		 * case. Also, if we're trying to match an alias and an
3190Sstevel@tonic-gate 		 * already matched entry doesn't share a canonical name
3200Sstevel@tonic-gate 		 * with the current one, bail.
3210Sstevel@tonic-gate 		 */
3220Sstevel@tonic-gate 		if (nhosts == 0 && strcasestr(instr, filter) == 0) {
3230Sstevel@tonic-gate 			continue;
3240Sstevel@tonic-gate 		}
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 		if ((last = strchr(instr, '#')) == 0)
3270Sstevel@tonic-gate 			last = instr + linelen;
3280Sstevel@tonic-gate 		*last-- = '\0';
3290Sstevel@tonic-gate 		for (first = instr;  isspace(*first);  first++)
3300Sstevel@tonic-gate 			;
3310Sstevel@tonic-gate 		/* Ignore blank and comment lines */
3320Sstevel@tonic-gate 		if (*first == '\0')
3330Sstevel@tonic-gate 			continue;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 		while (isspace(*last))
3360Sstevel@tonic-gate 			--last;
3370Sstevel@tonic-gate 		linelen = last - first + 1;
3380Sstevel@tonic-gate 		if (first != instr)
3390Sstevel@tonic-gate 			instr = first;
3400Sstevel@tonic-gate 
341*2830Sdjl 		/* Bail out if the canonical name does not match */
342*2830Sdjl 		if (nhosts && strcasestr(instr, h_name) == 0) {
3430Sstevel@tonic-gate 			continue;
3440Sstevel@tonic-gate 		}
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 		/*
3470Sstevel@tonic-gate 		 * Still need to check, strcasestr() above is just a hint.
3480Sstevel@tonic-gate 		 */
349*2830Sdjl 		addrp = (type == AF_INET)?
350*2830Sdjl 				(void *)&taddr[nhosts]:
351*2830Sdjl 				(void *)&taddr6[nhosts];
3520Sstevel@tonic-gate 
353*2830Sdjl 		if (check_name(args, instr, linelen,
354*2830Sdjl 				type, &namep, &namelen,
355*2830Sdjl 				addrp, &i)) {
356*2830Sdjl 
357*2830Sdjl 			/*
358*2830Sdjl 			 * If we've already matched once and have a possible
359*2830Sdjl 			 * match on this line, copy the aliases where they're
360*2830Sdjl 			 * safe from being overwritten when we look at the
361*2830Sdjl 			 * next entry. They're saved as a string of blank
362*2830Sdjl 			 * separated names for the alias parser. On errors,
363*2830Sdjl 			 * we return failure whether or not we have already
364*2830Sdjl 			 * obtained a valid address.
365*2830Sdjl 			 */
366*2830Sdjl 			if (nhosts == 1 && hp) {
367*2830Sdjl 				if (h_namelen + 1 > args->buf.buflen) {
368*2830Sdjl 					args->erange = 1;
369*2830Sdjl 					res = NSS_NOTFOUND;
370*2830Sdjl 					break;
371*2830Sdjl 				}
372*2830Sdjl 				abuf = (char *)malloc(args->buf.buflen);
373*2830Sdjl 				if (abuf == NULL) {
374*2830Sdjl 					res = NSS_UNAVAIL;
375*2830Sdjl 					break;
376*2830Sdjl 				}
377*2830Sdjl 				abuf_start = abuf;
378*2830Sdjl 				abuf_end = abuf_start + args->buf.buflen;
379*2830Sdjl 				(void) memcpy(abuf, h_name, h_namelen);
380*2830Sdjl 				abuf += h_namelen;
381*2830Sdjl 				*abuf = '\0';
382*2830Sdjl 				abuf = do_aliases(hp, abuf, abuf_end);
383*2830Sdjl 				if (abuf == NULL) {
384*2830Sdjl 					args->erange = 1;
385*2830Sdjl 					res = NSS_NOTFOUND;
386*2830Sdjl 					break;
387*2830Sdjl 				}
388*2830Sdjl 			}
389*2830Sdjl 
390*2830Sdjl 			if (hp != NULL) {
391*2830Sdjl 				/* inside the application */
392*2830Sdjl 				parsestat = (*args->str2ent)(instr, linelen,
393*2830Sdjl 						hp, buffer, buflen);
394*2830Sdjl 				if (parsestat != NSS_STR_PARSE_SUCCESS) {
395*2830Sdjl 					if (parsestat == NSS_STR_PARSE_ERANGE)
396*2830Sdjl 						args->erange = 1;
397*2830Sdjl 					(void) memset(buffer, 0, buflen);
398*2830Sdjl 					continue;
399*2830Sdjl 				}
400*2830Sdjl 			} else {
401*2830Sdjl 				/* inside nscd */
402*2830Sdjl 				int	alen, cplen, erange = 0;
403*2830Sdjl 				char	*ap;
404*2830Sdjl 
405*2830Sdjl 				/* Add alias to the first line if any */
406*2830Sdjl 				if (nhosts > 0) {
407*2830Sdjl 
408*2830Sdjl 					/* get to the start of alias */
409*2830Sdjl 					ap = (char *)namep + namelen;
410*2830Sdjl 					/* see if there's any alias */
411*2830Sdjl 					if (ap == instr + linelen)
412*2830Sdjl 						alen = 0;
413*2830Sdjl 					else
414*2830Sdjl 						alen = linelen - (ap - instr);
415*2830Sdjl 					if (alen + 1 >= buflen)
416*2830Sdjl 						erange  = 1;
417*2830Sdjl 					if (erange == 0 && alen != 0) {
418*2830Sdjl 						/* make room for the alias */
419*2830Sdjl 						if (alias_end != NULL)
420*2830Sdjl 						(void) memmove(alias_end +
421*2830Sdjl 						alen, alias_end, buffer -
422*2830Sdjl 						alias_end);
423*2830Sdjl 						/* copy in the alias */
424*2830Sdjl 						(void) memmove(alias_end,
425*2830Sdjl 							ap, alen);
426*2830Sdjl 						buffer += alen;
427*2830Sdjl 						buflen -= alen;
428*2830Sdjl 						alias_end += alen;
429*2830Sdjl 					}
430*2830Sdjl 
431*2830Sdjl 					/* Add delimiter to the buffer */
432*2830Sdjl 					*buffer++ = '\n';
433*2830Sdjl 					buflen--;
434*2830Sdjl 					args->returnlen++;
435*2830Sdjl 				}
436*2830Sdjl 
437*2830Sdjl 				/* copy just the addr if not first one */
438*2830Sdjl 				if (alias_end == NULL)
439*2830Sdjl 					cplen = linelen;
440*2830Sdjl 				else
441*2830Sdjl 					cplen = namep - instr;
442*2830Sdjl 
443*2830Sdjl 				if (cplen >= buflen || erange == 1) {
444*2830Sdjl 					args->erange = 1;
445*2830Sdjl 					if (nhosts > 0) {
446*2830Sdjl 						*(--buffer) = '\0';
447*2830Sdjl 						buflen++;
448*2830Sdjl 						args->returnlen--;
449*2830Sdjl 					}
450*2830Sdjl 					continue;
451*2830Sdjl 				}
452*2830Sdjl 
453*2830Sdjl 				(void) memcpy(buffer, instr, cplen);
454*2830Sdjl 				/* Adjust buffer */
455*2830Sdjl 				buffer += cplen;
456*2830Sdjl 				*buffer = '\0';
457*2830Sdjl 				buflen -= cplen;
458*2830Sdjl 				if (alias_end == NULL)
459*2830Sdjl 					alias_end = buffer;
460*2830Sdjl 			}
461*2830Sdjl 
462*2830Sdjl 			args->returnlen += linelen;
463*2830Sdjl 
464*2830Sdjl 			/*
465*2830Sdjl 			 * If this is the first one, save the canonical
466*2830Sdjl 			 * name for future matches and continue.
467*2830Sdjl 			 */
468*2830Sdjl 			if (++nhosts == 1) {
469*2830Sdjl 				h_name = malloc(namelen + 1);
470*2830Sdjl 				if (h_name == NULL) {
471*2830Sdjl 					res = NSS_UNAVAIL;
472*2830Sdjl 					break;
473*2830Sdjl 				}
474*2830Sdjl 				res = NSS_SUCCESS;
475*2830Sdjl 				(void) memcpy(h_name, namep, namelen);
476*2830Sdjl 				h_name[namelen] = '\0';
477*2830Sdjl 				h_namelen = namelen;
478*2830Sdjl 				if (hp)
479*2830Sdjl 					args->returnval = hp;
480*2830Sdjl 				else
481*2830Sdjl 					args->returnval = args->buf.buffer;
482*2830Sdjl 				continue;
4830Sstevel@tonic-gate 			}
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 
486*2830Sdjl 			/* Extend the array */
487*2830Sdjl 			if (nhosts >= ntaddr) {
488*2830Sdjl 				ntaddr *= 2;
489*2830Sdjl 				if (type == AF_INET) {
490*2830Sdjl 					addrp = realloc(taddr,
491*2830Sdjl 						sizeof (*taddr) * ntaddr);
492*2830Sdjl 					if (addrp == NULL) {
493*2830Sdjl 						res = NSS_UNAVAIL;
494*2830Sdjl 						break;
495*2830Sdjl 					}
496*2830Sdjl 					taddr = (in_addr_t *)addrp;
497*2830Sdjl 				} else {
498*2830Sdjl 					addrp = realloc(taddr6,
499*2830Sdjl 						sizeof (*taddr6) * ntaddr);
500*2830Sdjl 					if (addrp == NULL) {
501*2830Sdjl 						res = NSS_UNAVAIL;
502*2830Sdjl 						break;
503*2830Sdjl 					}
504*2830Sdjl 					taddr6 = (struct in6_addr *)addrp;
505*2830Sdjl 				}
5060Sstevel@tonic-gate 			}
507*2830Sdjl 
508*2830Sdjl 			/*
509*2830Sdjl 			 * For non-nscd, save aliases in a temporary buffer
510*2830Sdjl 			 * Don't have to do this for nscd as 'buffer' already
511*2830Sdjl 			 * contains the required data in the appropriate
512*2830Sdjl 			 * format
513*2830Sdjl 			 */
514*2830Sdjl 			if (hp) {
515*2830Sdjl 				abuf = do_aliases(hp, abuf, abuf_end);
516*2830Sdjl 				if (abuf == NULL) {
517*2830Sdjl 					args->erange = 1;
518*2830Sdjl 					res = NSS_NOTFOUND;
519*2830Sdjl 					break;
520*2830Sdjl 				}
5210Sstevel@tonic-gate 			}
522*2830Sdjl 		} else if (namep && h_namelen == namelen &&
523*2830Sdjl 		    strncasecmp(h_name, namep, namelen) == 0) {
5240Sstevel@tonic-gate 			/*
5250Sstevel@tonic-gate 			 * This line didn't have the requested name but
5260Sstevel@tonic-gate 			 * is part of the same multihomed host (i.e. it
5270Sstevel@tonic-gate 			 * has the same canonical name as the previous
5280Sstevel@tonic-gate 			 * line), so march on...
5290Sstevel@tonic-gate 			 */
5300Sstevel@tonic-gate 			continue;
5310Sstevel@tonic-gate 		} else if (nhosts) {
5320Sstevel@tonic-gate 			break;
5330Sstevel@tonic-gate 		}
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 
536*2830Sdjl 	if (abuf && res == NSS_SUCCESS) {
537*2830Sdjl 
538*2830Sdjl 		/* abuf != NULL implies hp and abuf_start != NULL */
539*2830Sdjl 
5400Sstevel@tonic-gate 		struct in_addr *addrp;
5410Sstevel@tonic-gate 		struct in6_addr *addrp6;
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 		if (type == AF_INET) {
5440Sstevel@tonic-gate 			addrp = (struct in_addr *)(ROUND_DOWN(args->buf.buffer +
5450Sstevel@tonic-gate 			    args->buf.buflen, sizeof (*addrp)));
5460Sstevel@tonic-gate 			hp->h_addr_list = (char **)(ROUND_DOWN(addrp -
5470Sstevel@tonic-gate 			    ((nhosts + 1) * sizeof (char *) +
5480Sstevel@tonic-gate 			    (nhosts * sizeof (*addrp))), sizeof (char *)));
5490Sstevel@tonic-gate 			for (i = 0, --addrp; i < nhosts; i++, --addrp) {
5500Sstevel@tonic-gate 				(*(in_addr_t *)addrp) = taddr[i];
5510Sstevel@tonic-gate 				hp->h_addr_list[i] = (char *)addrp;
5520Sstevel@tonic-gate 			}
5530Sstevel@tonic-gate 		} else {
5540Sstevel@tonic-gate 			addrp6 = (struct in6_addr *)
5550Sstevel@tonic-gate 			(ROUND_DOWN(args->buf.buffer + args->buf.buflen,
5560Sstevel@tonic-gate 			sizeof (*addrp6)));
5570Sstevel@tonic-gate 			hp->h_addr_list = (char **)(ROUND_DOWN(addrp6 -
5580Sstevel@tonic-gate 			    ((nhosts + 1) * sizeof (char *) +
5590Sstevel@tonic-gate 			    (nhosts * sizeof (*addrp6))), sizeof (char *)));
5600Sstevel@tonic-gate 			for (i = 0, --addrp6; i < nhosts; i++, --addrp6) {
561*2830Sdjl 				(void) memcpy(addrp6, &taddr6[i],
562*2830Sdjl 						sizeof (struct in6_addr));
5630Sstevel@tonic-gate 				hp->h_addr_list[i] = (char *)addrp6;
5640Sstevel@tonic-gate 			}
5650Sstevel@tonic-gate 		}
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 		hp->h_addr_list[nhosts] = 0;
5680Sstevel@tonic-gate 		hp->h_aliases = _nss_netdb_aliases(abuf_start,
5690Sstevel@tonic-gate 		    abuf - abuf_start, args->buf.buffer,
5700Sstevel@tonic-gate 		    (char *)hp->h_addr_list - args->buf.buffer);
5710Sstevel@tonic-gate 		if (hp->h_aliases == 0) {
5720Sstevel@tonic-gate 			args->erange = 1;
573*2830Sdjl 			res = NSS_NOTFOUND;
5740Sstevel@tonic-gate 		} else {
5750Sstevel@tonic-gate 			hp->h_name = hp->h_aliases[0];
5760Sstevel@tonic-gate 			hp->h_aliases++;
5770Sstevel@tonic-gate 		}
5780Sstevel@tonic-gate 	}
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 	/*
5810Sstevel@tonic-gate 	 * stayopen is set to 0 by default in order to close the opened
5820Sstevel@tonic-gate 	 * file.  Some applications may break if it is set to 1.
5830Sstevel@tonic-gate 	 */
5840Sstevel@tonic-gate 	if (!args->stayopen)
5850Sstevel@tonic-gate 		(void) _nss_files_endent(be, 0);
5860Sstevel@tonic-gate 
587*2830Sdjl 	if (taddr)
588*2830Sdjl 		free(taddr);
589*2830Sdjl 	if (taddr6)
590*2830Sdjl 		free(taddr6);
591*2830Sdjl 	if (h_name)
592*2830Sdjl 		free(h_name);
593*2830Sdjl 	if (abuf_start)
594*2830Sdjl 		free(abuf_start);
595*2830Sdjl 
5960Sstevel@tonic-gate 	return (res);
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate /*
6000Sstevel@tonic-gate  * A case-insensitive version of strstr().
6010Sstevel@tonic-gate  */
6020Sstevel@tonic-gate static char *
603*2830Sdjl strcasestr(const char *as1, const char *as2)
6040Sstevel@tonic-gate {
6050Sstevel@tonic-gate 	int c2;
606*2830Sdjl 	register const char *tptr;
607*2830Sdjl 	register const char *s1, *s2;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	s1 = as1;
6100Sstevel@tonic-gate 	s2 = as2;
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	if (s2 == NULL || *s2 == '\0')
6130Sstevel@tonic-gate 		return (0);
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	while (*s1) {
6160Sstevel@tonic-gate 		if (tolower(*s1++) == tolower(c2 = *s2)) {
6170Sstevel@tonic-gate 			tptr = s1;
6180Sstevel@tonic-gate 			while ((tolower(c2 = *++s2) ==
6190Sstevel@tonic-gate 			    tolower(*s1++)) && c2 != 0)
6200Sstevel@tonic-gate 				;
6210Sstevel@tonic-gate 			if (c2 == 0)
6220Sstevel@tonic-gate 				return ((char *)tptr - 1);
6230Sstevel@tonic-gate 			s1 = tptr;
6240Sstevel@tonic-gate 			s2 = as2;
6250Sstevel@tonic-gate 		}
6260Sstevel@tonic-gate 	}
6270Sstevel@tonic-gate 	return (0);
6280Sstevel@tonic-gate }
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate static char *
632*2830Sdjl do_aliases(struct hostent *hp, char *abuf, char *end)
6330Sstevel@tonic-gate {
634*2830Sdjl 	char	**cp;
635*2830Sdjl 	size_t	len;
6360Sstevel@tonic-gate 
637*2830Sdjl 	if ((cp = hp->h_aliases) == NULL)
638*2830Sdjl 		return (abuf);
6390Sstevel@tonic-gate 
640*2830Sdjl 	for (; *cp; cp++) {
6410Sstevel@tonic-gate 		len = strlen(*cp);
6420Sstevel@tonic-gate 		if (abuf+len+1 >= end) {
643*2830Sdjl 			return (NULL);
6440Sstevel@tonic-gate 		}
645*2830Sdjl 		*abuf++ = ' ';
646*2830Sdjl 		(void) memcpy(abuf, *cp, len);
6470Sstevel@tonic-gate 		abuf += len;
6480Sstevel@tonic-gate 	}
6490Sstevel@tonic-gate 	*abuf = '\0';
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	return (abuf);
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate /*
6560Sstevel@tonic-gate  * This is a copy of a routine in libnsl/nss/netdir_inet.c.  It is
6570Sstevel@tonic-gate  * here because /etc/lib/nss_files.so.1 cannot call routines
6580Sstevel@tonic-gate  * in libnsl.  Care should be taken to keep the two copies in sync.
6590Sstevel@tonic-gate  */
6600Sstevel@tonic-gate int
6610Sstevel@tonic-gate __nss_files_2herrno(nsstat)
6620Sstevel@tonic-gate 	nss_status_t nsstat;
6630Sstevel@tonic-gate {
6640Sstevel@tonic-gate 	switch (nsstat) {
6650Sstevel@tonic-gate 	case NSS_SUCCESS:
6660Sstevel@tonic-gate 		/* no macro-defined success code for h_errno */
6670Sstevel@tonic-gate 		return (0);
6680Sstevel@tonic-gate 	case NSS_NOTFOUND:
6690Sstevel@tonic-gate 		return (HOST_NOT_FOUND);
6700Sstevel@tonic-gate 	case NSS_TRYAGAIN:
6710Sstevel@tonic-gate 		return (TRY_AGAIN);
6720Sstevel@tonic-gate 	case NSS_UNAVAIL:
6730Sstevel@tonic-gate 		return (NO_RECOVERY);
6740Sstevel@tonic-gate 	}
6750Sstevel@tonic-gate 	/* anything else */
6760Sstevel@tonic-gate 	return (NO_RECOVERY);
6770Sstevel@tonic-gate }
678