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
52830Sdjl  * Common Development and Distribution License (the "License").
62830Sdjl  * 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  */
21*6812Sraf 
220Sstevel@tonic-gate /*
23*6812Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <netdb.h>
300Sstevel@tonic-gate #include "files_common.h"
310Sstevel@tonic-gate #include <string.h>
320Sstevel@tonic-gate #include <strings.h>
330Sstevel@tonic-gate #include <stddef.h>
340Sstevel@tonic-gate #include <stdlib.h>
350Sstevel@tonic-gate #include <sys/types.h>
360Sstevel@tonic-gate #include <sys/socket.h>
370Sstevel@tonic-gate #include <netinet/in.h>
380Sstevel@tonic-gate #include <arpa/nameser.h>
392830Sdjl #include <arpa/inet.h>
400Sstevel@tonic-gate #include <ctype.h>
410Sstevel@tonic-gate 
422830Sdjl static int	check_name(nss_XbyY_args_t *, const char *, int,
432830Sdjl 			int, const char **, int *, void *, int *);
440Sstevel@tonic-gate static char *do_aliases();
452830Sdjl static char *strcasestr(const char *as1, const char *as2);
460Sstevel@tonic-gate nss_status_t __nss_files_XY_hostbyname();
470Sstevel@tonic-gate int __nss_files_2herrno();
482830Sdjl static int	__nss_files_get_addr(int, const char *, int,
492830Sdjl 			void *, int, int *);
500Sstevel@tonic-gate 
510Sstevel@tonic-gate static int
522830Sdjl check_name(nss_XbyY_args_t *argp, const char *line, int linelen,
532830Sdjl 	int type, const char **namep, int *namelen,
542830Sdjl 	void *addrp, int *addrsize)
550Sstevel@tonic-gate {
562830Sdjl 	const char	*limit, *linep, *keyp, *addrstart;
572830Sdjl 	int		v6flag = 0, addrlen;
582830Sdjl 
592830Sdjl 	linep = line;
602830Sdjl 	limit = line + linelen;
610Sstevel@tonic-gate 
622830Sdjl 	/* Address */
632830Sdjl 	addrstart = linep;
642830Sdjl 	while (linep < limit && !isspace(*linep)) {
652830Sdjl 		if (*linep == ':')
662830Sdjl 			v6flag++;
672830Sdjl 		linep++;
680Sstevel@tonic-gate 	}
692830Sdjl 	addrlen = linep - addrstart;
702830Sdjl 
712830Sdjl 	/* skip the delimiting spaces */
722830Sdjl 	while (linep < limit && isspace(*linep))
732830Sdjl 		linep++;
742830Sdjl 
752830Sdjl 	/* Canonical name */
762830Sdjl 	keyp = argp->key.name;
772830Sdjl 	*namep = linep;
782830Sdjl 	while (*keyp && linep < limit && !isspace(*linep) &&
79*6812Sraf 	    tolower(*keyp) == tolower(*linep)) {
802830Sdjl 		keyp++;
812830Sdjl 		linep++;
822830Sdjl 	}
832830Sdjl 	if (*keyp == '\0' && (linep == limit || isspace(*linep))) {
842830Sdjl 		if (__nss_files_get_addr(type, addrstart, addrlen,
85*6812Sraf 		    addrp, v6flag, addrsize)) {
862830Sdjl 			*namelen = linep - *namep;
870Sstevel@tonic-gate 			return (1);
880Sstevel@tonic-gate 		}
890Sstevel@tonic-gate 	}
902830Sdjl 	while (linep < limit && !isspace(*linep))
912830Sdjl 		linep++;
922830Sdjl 	*namelen = linep - *namep;
932830Sdjl 
942830Sdjl 	/* Aliases */
952830Sdjl 	while (linep < limit) {
962830Sdjl 		/* skip the delimiting spaces */
972830Sdjl 		while (linep < limit && isspace(*linep))
982830Sdjl 			linep++;
992830Sdjl 
1002830Sdjl 		/* compare name (case insensitive) */
1012830Sdjl 		keyp = argp->key.name;
1022830Sdjl 		while (*keyp && linep < limit && !isspace(*linep) &&
103*6812Sraf 		    tolower(*keyp) == tolower(*linep)) {
1042830Sdjl 			keyp++;
1052830Sdjl 			linep++;
1062830Sdjl 		}
1072830Sdjl 		if (*keyp == '\0' && (linep == limit || isspace(*linep)))
1082830Sdjl 			return (__nss_files_get_addr(type, addrstart, addrlen,
109*6812Sraf 			    addrp, v6flag, addrsize));
1102830Sdjl 
1112830Sdjl 		/* skip remainder of alias, if any */
1122830Sdjl 		while (linep < limit && !isspace(*linep))
1132830Sdjl 			linep++;
1142830Sdjl 	}
1150Sstevel@tonic-gate 	return (0);
1162830Sdjl 
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate static nss_status_t
1200Sstevel@tonic-gate getbyname(be, a)
1210Sstevel@tonic-gate 	files_backend_ptr_t	be;
1220Sstevel@tonic-gate 	void			*a;
1230Sstevel@tonic-gate {
1240Sstevel@tonic-gate 	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
1250Sstevel@tonic-gate 	nss_status_t		res;
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	res = __nss_files_XY_hostbyname(be, argp, argp->key.name, AF_INET);
1280Sstevel@tonic-gate 	if (res != NSS_SUCCESS)
1290Sstevel@tonic-gate 		argp->h_errno = __nss_files_2herrno(res);
1300Sstevel@tonic-gate 	return (res);
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate 
1332830Sdjl static int
1342830Sdjl __nss_files_get_addr(int af, const char *addrstart, int addrlen,
1352830Sdjl 	void *addrp, int v6flag, int *h_length)
1362830Sdjl {
1372830Sdjl 	struct in_addr	addr_ipv4;
1382830Sdjl 	struct in6_addr	*addrpv6;
1392830Sdjl 	in_addr_t	*addrpv4;
1402830Sdjl 	char		addrbuf[INET6_ADDRSTRLEN + 1];
1412830Sdjl 
1422830Sdjl 	if (addrlen >= sizeof (addrbuf))
1432830Sdjl 		return (0);
1442830Sdjl 	(void) memcpy(addrbuf, addrstart, addrlen);
1452830Sdjl 	addrbuf[addrlen] = '\0';
1462830Sdjl 
1472830Sdjl 	if (af == AF_INET) {
1482830Sdjl 		addrpv4 = (in_addr_t *)addrp;
1492830Sdjl 		if ((*addrpv4 = inet_addr(addrbuf)) == 0xffffffffU)
1502830Sdjl 			return (0);
1512830Sdjl 		*h_length = sizeof (in_addr_t);
1522830Sdjl 	} else if (af == AF_INET6) {
1532830Sdjl 		addrpv6 = (struct in6_addr *)addrp;
1542830Sdjl 		if (v6flag) {
1552830Sdjl 			if (inet_pton(af, addrbuf, addrpv6) != 1)
1562830Sdjl 				return (0);
1572830Sdjl 		} else {
1582830Sdjl 			if ((addr_ipv4.s_addr = inet_addr(addrbuf)) ==
159*6812Sraf 			    0xffffffffU)
1602830Sdjl 				return (0);
1612830Sdjl 			IN6_INADDR_TO_V4MAPPED(&addr_ipv4, addrpv6);
1622830Sdjl 		}
1632830Sdjl 		*h_length = sizeof (struct in6_addr);
1642830Sdjl 	} else {
1652830Sdjl 		return (0);
1662830Sdjl 	}
1672830Sdjl 	return (1);
1682830Sdjl }
1692830Sdjl 
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate int
1722830Sdjl __nss_files_check_addr(int af, nss_XbyY_args_t *argp, const char *line,
1732830Sdjl 		int linelen)
1740Sstevel@tonic-gate {
1752830Sdjl 	const char	*limit, *linep, *addrstart;
1762830Sdjl 	int		v6flag = 0, addrlen, h_length;
1772830Sdjl 	in_addr_t	addr_ipv4;
1782830Sdjl 	struct in6_addr	addr_ipv6;
1792830Sdjl 	char		*h_addrp;
1802830Sdjl 
1812830Sdjl 	/* Compare the address type */
1822830Sdjl 	if (argp->key.hostaddr.type != af)
1832830Sdjl 		return (0);
1840Sstevel@tonic-gate 
1852830Sdjl 	/* Retrieve the address */
1862830Sdjl 	if (af == AF_INET)
1872830Sdjl 		h_addrp = (char *)&addr_ipv4;
1882830Sdjl 	else
1892830Sdjl 		h_addrp = (char *)&addr_ipv6;
1902830Sdjl 	linep = line;
1912830Sdjl 	limit = line + linelen;
1922830Sdjl 	addrstart = linep;
1932830Sdjl 	while (linep < limit && !isspace(*linep)) {
1942830Sdjl 		if (*linep == ':')
1952830Sdjl 			v6flag++;
1962830Sdjl 		linep++;
1972830Sdjl 	}
1982830Sdjl 	addrlen = linep - addrstart;
1992830Sdjl 	if (__nss_files_get_addr(af, addrstart, addrlen, h_addrp,
200*6812Sraf 	    v6flag, &h_length) == 0)
2012830Sdjl 		return (0);
2022830Sdjl 
2032830Sdjl 	/* Compare the address */
2042830Sdjl 	return (h_length == argp->key.hostaddr.len &&
205*6812Sraf 	    memcmp(h_addrp, argp->key.hostaddr.addr,
206*6812Sraf 	    argp->key.hostaddr.len) == 0);
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate 
2092830Sdjl static int
2102830Sdjl check_addr(nss_XbyY_args_t *argp, const char *line, int linelen)
2112830Sdjl {
2122830Sdjl 	return (__nss_files_check_addr(AF_INET, argp, line, linelen));
2132830Sdjl }
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate static nss_status_t
2160Sstevel@tonic-gate getbyaddr(be, a)
2170Sstevel@tonic-gate 	files_backend_ptr_t	be;
2180Sstevel@tonic-gate 	void			*a;
2190Sstevel@tonic-gate {
2200Sstevel@tonic-gate 	nss_XbyY_args_t		*argp	= (nss_XbyY_args_t *)a;
2210Sstevel@tonic-gate 	nss_status_t		res;
2220Sstevel@tonic-gate 
2232830Sdjl 	res = _nss_files_XY_all(be, argp, 1, 0, check_addr);
2240Sstevel@tonic-gate 	if (res != NSS_SUCCESS)
2250Sstevel@tonic-gate 		argp->h_errno = __nss_files_2herrno(res);
2260Sstevel@tonic-gate 	return (res);
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate 
2292883Schinlong /*
2302883Schinlong  * filter_ipv6
2312883Schinlong  *
2322883Schinlong  * Return - NSS_STR_PARSE_SUCCESS: An IPv4 address
2332883Schinlong  *          NSS_STR_PARSE_PARSE: An IPv6 address or other errors
2342883Schinlong  */
2352883Schinlong static int
2362883Schinlong filter_ipv6(char *instr, int lenstr) {
2372883Schinlong 	char	*p, *addrstart, *limit, c;
2382883Schinlong 	int	rc;
2392883Schinlong 	struct in_addr	addr;
2402883Schinlong 
2412883Schinlong 	p = instr;
2422883Schinlong 	limit = p + lenstr;
2432883Schinlong 
2442883Schinlong 	addrstart = p;
2452883Schinlong 
2462883Schinlong 	/* parse IP address */
2472883Schinlong 	while (p < limit && !isspace(*p)) {
2482883Schinlong 		if (*p == ':')
2492883Schinlong 			/* IPv6 */
2502883Schinlong 			return (NSS_STR_PARSE_PARSE);
2512883Schinlong 		else
2522883Schinlong 			p++;
2532883Schinlong 	}
2542883Schinlong 
2552883Schinlong 	if (p >= limit)
2562883Schinlong 		/* invalid IP */
2572883Schinlong 		return (NSS_STR_PARSE_PARSE);
2582883Schinlong 
2592883Schinlong 	/* extract IP address */
2602883Schinlong 	c = *p;
2612883Schinlong 	*p = '\0';
262*6812Sraf 	rc = inet_aton(addrstart, &addr);
2632883Schinlong 	*p = c;
2642883Schinlong 
2652883Schinlong 	if (rc == 0)
2662883Schinlong 		/* invalid IP */
2672883Schinlong 		return (NSS_STR_PARSE_PARSE);
2682883Schinlong 	else
2692883Schinlong 		/* IPv4 */
2702883Schinlong 		return (NSS_STR_PARSE_SUCCESS);
2712883Schinlong 
2722883Schinlong 
2732883Schinlong }
2742883Schinlong static nss_status_t
2752883Schinlong getent_hosts(files_backend_ptr_t be, void *a)
2762883Schinlong {
2772883Schinlong 	nss_XbyY_args_t	*args = (nss_XbyY_args_t *)a;
2782883Schinlong 	nss_status_t	rc = NSS_SUCCESS;
2792883Schinlong 
2802883Schinlong 	if (args->buf.result != NULL) {
2812883Schinlong 		return (_nss_files_XY_all(be, args, 1, 0, 0));
2822883Schinlong 	} else {
2832883Schinlong 		/*
2842883Schinlong 		 * Called by nscd
2852883Schinlong 		 */
2862883Schinlong 		/*CONSTCOND*/
2872883Schinlong 		while (1) {
2882883Schinlong 			rc = _nss_files_XY_all(be, args, 1, 0, 0);
2892883Schinlong 			/*
2902883Schinlong 			 * NSS_NOTFOUND, end of file or other errors.
2912883Schinlong 			 */
2922883Schinlong 			if (rc != NSS_SUCCESS)
2932883Schinlong 				break;
2942883Schinlong 			/*
2952883Schinlong 			 * /etc/hosts and /etc/ipnodes are merged and
2962883Schinlong 			 * /etc/hosts can contain IPv6 addresses.
2972883Schinlong 			 * These addresses have to be filtered.
2982883Schinlong 			 */
2992883Schinlong 			if (filter_ipv6(args->returnval, args->returnlen)
300*6812Sraf 			    == NSS_STR_PARSE_SUCCESS)
3012883Schinlong 				break;
3022883Schinlong 			/*
3032883Schinlong 			 * The entry is an IPv6 address or other errors.
3042883Schinlong 			 * Skip it and continue to find next one.
3052883Schinlong 			 */
3062883Schinlong 			args->returnval = NULL;
3072883Schinlong 			args->returnlen = 0;
3082883Schinlong 
3092883Schinlong 		}
3102883Schinlong 		return (rc);
3112883Schinlong 	}
3122883Schinlong 
3132883Schinlong }
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate static files_backend_op_t host_ops[] = {
3160Sstevel@tonic-gate 	_nss_files_destr,
3170Sstevel@tonic-gate 	_nss_files_endent,
3180Sstevel@tonic-gate 	_nss_files_setent,
3192883Schinlong 	getent_hosts,
3200Sstevel@tonic-gate 	getbyname,
3210Sstevel@tonic-gate 	getbyaddr,
3220Sstevel@tonic-gate };
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate /*ARGSUSED*/
3250Sstevel@tonic-gate nss_backend_t *
3260Sstevel@tonic-gate _nss_files_hosts_constr(dummy1, dummy2, dummy3)
3270Sstevel@tonic-gate 	const char	*dummy1, *dummy2, *dummy3;
3280Sstevel@tonic-gate {
3290Sstevel@tonic-gate 	return (_nss_files_constr(host_ops,
3300Sstevel@tonic-gate 				sizeof (host_ops) / sizeof (host_ops[0]),
3310Sstevel@tonic-gate 				_PATH_HOSTS,
3320Sstevel@tonic-gate 				NSS_LINELEN_HOSTS,
3330Sstevel@tonic-gate 				NULL));
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate /*
3380Sstevel@tonic-gate  * XXX - this duplicates code from files_common.c because we need to keep
3390Sstevel@tonic-gate  * going after we've found a match to satisfy the multihomed host case.
3400Sstevel@tonic-gate  */
3410Sstevel@tonic-gate nss_status_t
3420Sstevel@tonic-gate __nss_files_XY_hostbyname(be, args, filter, type)
3430Sstevel@tonic-gate 	files_backend_ptr_t be;
3440Sstevel@tonic-gate 	nss_XbyY_args_t *args;
3450Sstevel@tonic-gate 	const char *filter;		/* hint for name string */
3460Sstevel@tonic-gate 	int type;
3470Sstevel@tonic-gate {
3482830Sdjl 	nss_status_t	res;
3492830Sdjl 	char		*abuf = NULL, *abuf_start = NULL, *abuf_end;
3502830Sdjl 	char		*first, *last, *buffer;
3512830Sdjl 	int		parsestat, i, nhosts = 0, buflen;
3522830Sdjl 	const char	*namep;
3532830Sdjl 	char		*h_name;
3542830Sdjl 	int		h_namelen, namelen;
3552830Sdjl 	struct hostent	*hp;
3562830Sdjl 	in_addr_t	*taddr = NULL;
3572830Sdjl 	struct in6_addr	*taddr6 = NULL;
3582830Sdjl 	size_t		ntaddr;
3592830Sdjl 	void		*addrp;
3602830Sdjl 	char		*alias_end = NULL;
3610Sstevel@tonic-gate 
3622830Sdjl 	if (be->buf == 0 && (be->buf = malloc(be->minbuf)) == 0) {
3630Sstevel@tonic-gate 		return (NSS_UNAVAIL);
3640Sstevel@tonic-gate 	}
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	if (be->f == 0) {
3670Sstevel@tonic-gate 		if ((res = _nss_files_setent(be, 0)) != NSS_SUCCESS)
3680Sstevel@tonic-gate 			return (res);
3690Sstevel@tonic-gate 	}
3700Sstevel@tonic-gate 
3712830Sdjl 	ntaddr = MAXADDRS;
3722830Sdjl 	if (type == AF_INET) {
3732830Sdjl 		taddr = (in_addr_t *)calloc(ntaddr, sizeof (*taddr));
3742830Sdjl 		if (taddr == NULL)
3752830Sdjl 			return (NSS_UNAVAIL);
3762830Sdjl 	} else {
3772830Sdjl 		taddr6 = (struct in6_addr *)calloc(ntaddr, sizeof (*taddr6));
3782830Sdjl 		if (taddr6 == NULL)
3792830Sdjl 			return (NSS_UNAVAIL);
3802830Sdjl 	}
3812830Sdjl 
3820Sstevel@tonic-gate 	res = NSS_NOTFOUND;
3830Sstevel@tonic-gate 	args->returnval = (char *)0;
3842830Sdjl 	args->returnlen = 0;
3852830Sdjl 	hp = (struct hostent *)args->buf.result;
3862830Sdjl 	buffer = args->buf.buffer;
3872830Sdjl 	buflen = args->buf.buflen;
3882830Sdjl 	h_namelen = 0;
3892830Sdjl 	h_name = NULL;
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	for (;;) {
3920Sstevel@tonic-gate 		char *instr = be->buf;
3930Sstevel@tonic-gate 		int linelen;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 		if ((linelen = _nss_files_read_line(be->f,
3960Sstevel@tonic-gate 		    instr, be->minbuf)) < 0) {
3970Sstevel@tonic-gate 			break;		/* EOF */
3980Sstevel@tonic-gate 		}
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 		/*
4010Sstevel@tonic-gate 		 * This check avoids a malloc()/free() for the common
4020Sstevel@tonic-gate 		 * case. Also, if we're trying to match an alias and an
4030Sstevel@tonic-gate 		 * already matched entry doesn't share a canonical name
4040Sstevel@tonic-gate 		 * with the current one, bail.
4050Sstevel@tonic-gate 		 */
4060Sstevel@tonic-gate 		if (nhosts == 0 && strcasestr(instr, filter) == 0) {
4070Sstevel@tonic-gate 			continue;
4080Sstevel@tonic-gate 		}
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 		if ((last = strchr(instr, '#')) == 0)
4110Sstevel@tonic-gate 			last = instr + linelen;
4120Sstevel@tonic-gate 		*last-- = '\0';
4130Sstevel@tonic-gate 		for (first = instr;  isspace(*first);  first++)
4140Sstevel@tonic-gate 			;
4150Sstevel@tonic-gate 		/* Ignore blank and comment lines */
4160Sstevel@tonic-gate 		if (*first == '\0')
4170Sstevel@tonic-gate 			continue;
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 		while (isspace(*last))
4200Sstevel@tonic-gate 			--last;
4210Sstevel@tonic-gate 		linelen = last - first + 1;
4220Sstevel@tonic-gate 		if (first != instr)
4230Sstevel@tonic-gate 			instr = first;
4240Sstevel@tonic-gate 
4252830Sdjl 		/* Bail out if the canonical name does not match */
4262830Sdjl 		if (nhosts && strcasestr(instr, h_name) == 0) {
4270Sstevel@tonic-gate 			continue;
4280Sstevel@tonic-gate 		}
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 		/*
4310Sstevel@tonic-gate 		 * Still need to check, strcasestr() above is just a hint.
4320Sstevel@tonic-gate 		 */
4332830Sdjl 		addrp = (type == AF_INET)?
4342830Sdjl 				(void *)&taddr[nhosts]:
4352830Sdjl 				(void *)&taddr6[nhosts];
4360Sstevel@tonic-gate 
4372830Sdjl 		if (check_name(args, instr, linelen,
4382830Sdjl 				type, &namep, &namelen,
4392830Sdjl 				addrp, &i)) {
4402830Sdjl 
4412830Sdjl 			/*
4422830Sdjl 			 * If we've already matched once and have a possible
4432830Sdjl 			 * match on this line, copy the aliases where they're
4442830Sdjl 			 * safe from being overwritten when we look at the
4452830Sdjl 			 * next entry. They're saved as a string of blank
4462830Sdjl 			 * separated names for the alias parser. On errors,
4472830Sdjl 			 * we return failure whether or not we have already
4482830Sdjl 			 * obtained a valid address.
4492830Sdjl 			 */
4502830Sdjl 			if (nhosts == 1 && hp) {
4512830Sdjl 				if (h_namelen + 1 > args->buf.buflen) {
4522830Sdjl 					args->erange = 1;
4532830Sdjl 					res = NSS_NOTFOUND;
4542830Sdjl 					break;
4552830Sdjl 				}
4562830Sdjl 				abuf = (char *)malloc(args->buf.buflen);
4572830Sdjl 				if (abuf == NULL) {
4582830Sdjl 					res = NSS_UNAVAIL;
4592830Sdjl 					break;
4602830Sdjl 				}
4612830Sdjl 				abuf_start = abuf;
4622830Sdjl 				abuf_end = abuf_start + args->buf.buflen;
4632830Sdjl 				(void) memcpy(abuf, h_name, h_namelen);
4642830Sdjl 				abuf += h_namelen;
4652830Sdjl 				*abuf = '\0';
4662830Sdjl 				abuf = do_aliases(hp, abuf, abuf_end);
4672830Sdjl 				if (abuf == NULL) {
4682830Sdjl 					args->erange = 1;
4692830Sdjl 					res = NSS_NOTFOUND;
4702830Sdjl 					break;
4712830Sdjl 				}
4722830Sdjl 			}
4732830Sdjl 
4742830Sdjl 			if (hp != NULL) {
4752830Sdjl 				/* inside the application */
4762830Sdjl 				parsestat = (*args->str2ent)(instr, linelen,
4772830Sdjl 						hp, buffer, buflen);
4782830Sdjl 				if (parsestat != NSS_STR_PARSE_SUCCESS) {
4792830Sdjl 					if (parsestat == NSS_STR_PARSE_ERANGE)
4802830Sdjl 						args->erange = 1;
4812830Sdjl 					(void) memset(buffer, 0, buflen);
4822830Sdjl 					continue;
4832830Sdjl 				}
4842830Sdjl 			} else {
4852830Sdjl 				/* inside nscd */
4862830Sdjl 				int	alen, cplen, erange = 0;
4872830Sdjl 				char	*ap;
4882830Sdjl 
4892830Sdjl 				/* Add alias to the first line if any */
4902830Sdjl 				if (nhosts > 0) {
4912830Sdjl 
4922830Sdjl 					/* get to the start of alias */
4932830Sdjl 					ap = (char *)namep + namelen;
4942830Sdjl 					/* see if there's any alias */
4952830Sdjl 					if (ap == instr + linelen)
4962830Sdjl 						alen = 0;
4972830Sdjl 					else
4982830Sdjl 						alen = linelen - (ap - instr);
4992830Sdjl 					if (alen + 1 >= buflen)
5002830Sdjl 						erange  = 1;
5012830Sdjl 					if (erange == 0 && alen != 0) {
5022830Sdjl 						/* make room for the alias */
5032830Sdjl 						if (alias_end != NULL)
5042830Sdjl 						(void) memmove(alias_end +
5052830Sdjl 						alen, alias_end, buffer -
5062830Sdjl 						alias_end);
5072830Sdjl 						/* copy in the alias */
5082830Sdjl 						(void) memmove(alias_end,
5092830Sdjl 							ap, alen);
5102830Sdjl 						buffer += alen;
5112830Sdjl 						buflen -= alen;
5122924Smichen 						args->returnlen += alen;
5132830Sdjl 						alias_end += alen;
5142830Sdjl 					}
5152830Sdjl 
5162830Sdjl 					/* Add delimiter to the buffer */
5172830Sdjl 					*buffer++ = '\n';
5182830Sdjl 					buflen--;
5192830Sdjl 					args->returnlen++;
5202830Sdjl 				}
5212830Sdjl 
5222830Sdjl 				/* copy just the addr if not first one */
5232830Sdjl 				if (alias_end == NULL)
5242830Sdjl 					cplen = linelen;
5252830Sdjl 				else
5262830Sdjl 					cplen = namep - instr;
5272830Sdjl 
5282830Sdjl 				if (cplen >= buflen || erange == 1) {
5292830Sdjl 					args->erange = 1;
5302830Sdjl 					if (nhosts > 0) {
5312830Sdjl 						*(--buffer) = '\0';
5322830Sdjl 						buflen++;
5332830Sdjl 						args->returnlen--;
5342830Sdjl 					}
5352830Sdjl 					continue;
5362830Sdjl 				}
5372830Sdjl 
5382830Sdjl 				(void) memcpy(buffer, instr, cplen);
5392830Sdjl 				/* Adjust buffer */
5402830Sdjl 				buffer += cplen;
5412830Sdjl 				*buffer = '\0';
5422830Sdjl 				buflen -= cplen;
5432924Smichen 				args->returnlen += cplen;
5442830Sdjl 				if (alias_end == NULL)
5452830Sdjl 					alias_end = buffer;
5462830Sdjl 			}
5472830Sdjl 
5482830Sdjl 			/*
5492830Sdjl 			 * If this is the first one, save the canonical
5502830Sdjl 			 * name for future matches and continue.
5512830Sdjl 			 */
5522830Sdjl 			if (++nhosts == 1) {
5532830Sdjl 				h_name = malloc(namelen + 1);
5542830Sdjl 				if (h_name == NULL) {
5552830Sdjl 					res = NSS_UNAVAIL;
5562830Sdjl 					break;
5572830Sdjl 				}
5582830Sdjl 				res = NSS_SUCCESS;
5592830Sdjl 				(void) memcpy(h_name, namep, namelen);
5602830Sdjl 				h_name[namelen] = '\0';
5612830Sdjl 				h_namelen = namelen;
5622830Sdjl 				if (hp)
5632830Sdjl 					args->returnval = hp;
5642830Sdjl 				else
5652830Sdjl 					args->returnval = args->buf.buffer;
5662830Sdjl 				continue;
5670Sstevel@tonic-gate 			}
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 
5702830Sdjl 			/* Extend the array */
5712830Sdjl 			if (nhosts >= ntaddr) {
5722830Sdjl 				ntaddr *= 2;
5732830Sdjl 				if (type == AF_INET) {
5742830Sdjl 					addrp = realloc(taddr,
5752830Sdjl 						sizeof (*taddr) * ntaddr);
5762830Sdjl 					if (addrp == NULL) {
5772830Sdjl 						res = NSS_UNAVAIL;
5782830Sdjl 						break;
5792830Sdjl 					}
5802830Sdjl 					taddr = (in_addr_t *)addrp;
5812830Sdjl 				} else {
5822830Sdjl 					addrp = realloc(taddr6,
5832830Sdjl 						sizeof (*taddr6) * ntaddr);
5842830Sdjl 					if (addrp == NULL) {
5852830Sdjl 						res = NSS_UNAVAIL;
5862830Sdjl 						break;
5872830Sdjl 					}
5882830Sdjl 					taddr6 = (struct in6_addr *)addrp;
5892830Sdjl 				}
5900Sstevel@tonic-gate 			}
5912830Sdjl 
5922830Sdjl 			/*
5932830Sdjl 			 * For non-nscd, save aliases in a temporary buffer
5942830Sdjl 			 * Don't have to do this for nscd as 'buffer' already
5952830Sdjl 			 * contains the required data in the appropriate
5962830Sdjl 			 * format
5972830Sdjl 			 */
5982830Sdjl 			if (hp) {
5992830Sdjl 				abuf = do_aliases(hp, abuf, abuf_end);
6002830Sdjl 				if (abuf == NULL) {
6012830Sdjl 					args->erange = 1;
6022830Sdjl 					res = NSS_NOTFOUND;
6032830Sdjl 					break;
6042830Sdjl 				}
6050Sstevel@tonic-gate 			}
6062830Sdjl 		} else if (namep && h_namelen == namelen &&
6072830Sdjl 		    strncasecmp(h_name, namep, namelen) == 0) {
6080Sstevel@tonic-gate 			/*
6090Sstevel@tonic-gate 			 * This line didn't have the requested name but
6100Sstevel@tonic-gate 			 * is part of the same multihomed host (i.e. it
6110Sstevel@tonic-gate 			 * has the same canonical name as the previous
6120Sstevel@tonic-gate 			 * line), so march on...
6130Sstevel@tonic-gate 			 */
6140Sstevel@tonic-gate 			continue;
6150Sstevel@tonic-gate 		} else if (nhosts) {
6163099Smichen 			continue;
6170Sstevel@tonic-gate 		}
6180Sstevel@tonic-gate 	}
6190Sstevel@tonic-gate 
6202830Sdjl 	if (abuf && res == NSS_SUCCESS) {
6212830Sdjl 
6222830Sdjl 		/* abuf != NULL implies hp and abuf_start != NULL */
6232830Sdjl 
6240Sstevel@tonic-gate 		struct in_addr *addrp;
6250Sstevel@tonic-gate 		struct in6_addr *addrp6;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 		if (type == AF_INET) {
6280Sstevel@tonic-gate 			addrp = (struct in_addr *)(ROUND_DOWN(args->buf.buffer +
6290Sstevel@tonic-gate 			    args->buf.buflen, sizeof (*addrp)));
6300Sstevel@tonic-gate 			hp->h_addr_list = (char **)(ROUND_DOWN(addrp -
6310Sstevel@tonic-gate 			    ((nhosts + 1) * sizeof (char *) +
6320Sstevel@tonic-gate 			    (nhosts * sizeof (*addrp))), sizeof (char *)));
6330Sstevel@tonic-gate 			for (i = 0, --addrp; i < nhosts; i++, --addrp) {
6340Sstevel@tonic-gate 				(*(in_addr_t *)addrp) = taddr[i];
6350Sstevel@tonic-gate 				hp->h_addr_list[i] = (char *)addrp;
6360Sstevel@tonic-gate 			}
6370Sstevel@tonic-gate 		} else {
6380Sstevel@tonic-gate 			addrp6 = (struct in6_addr *)
6390Sstevel@tonic-gate 			(ROUND_DOWN(args->buf.buffer + args->buf.buflen,
6400Sstevel@tonic-gate 			sizeof (*addrp6)));
6410Sstevel@tonic-gate 			hp->h_addr_list = (char **)(ROUND_DOWN(addrp6 -
6420Sstevel@tonic-gate 			    ((nhosts + 1) * sizeof (char *) +
6430Sstevel@tonic-gate 			    (nhosts * sizeof (*addrp6))), sizeof (char *)));
6440Sstevel@tonic-gate 			for (i = 0, --addrp6; i < nhosts; i++, --addrp6) {
6452830Sdjl 				(void) memcpy(addrp6, &taddr6[i],
6462830Sdjl 						sizeof (struct in6_addr));
6470Sstevel@tonic-gate 				hp->h_addr_list[i] = (char *)addrp6;
6480Sstevel@tonic-gate 			}
6490Sstevel@tonic-gate 		}
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 		hp->h_addr_list[nhosts] = 0;
6520Sstevel@tonic-gate 		hp->h_aliases = _nss_netdb_aliases(abuf_start,
6530Sstevel@tonic-gate 		    abuf - abuf_start, args->buf.buffer,
6540Sstevel@tonic-gate 		    (char *)hp->h_addr_list - args->buf.buffer);
6550Sstevel@tonic-gate 		if (hp->h_aliases == 0) {
6560Sstevel@tonic-gate 			args->erange = 1;
6572830Sdjl 			res = NSS_NOTFOUND;
6580Sstevel@tonic-gate 		} else {
6590Sstevel@tonic-gate 			hp->h_name = hp->h_aliases[0];
6600Sstevel@tonic-gate 			hp->h_aliases++;
6610Sstevel@tonic-gate 		}
6620Sstevel@tonic-gate 	}
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	/*
6650Sstevel@tonic-gate 	 * stayopen is set to 0 by default in order to close the opened
6660Sstevel@tonic-gate 	 * file.  Some applications may break if it is set to 1.
6670Sstevel@tonic-gate 	 */
6680Sstevel@tonic-gate 	if (!args->stayopen)
6690Sstevel@tonic-gate 		(void) _nss_files_endent(be, 0);
6700Sstevel@tonic-gate 
6712830Sdjl 	if (taddr)
6722830Sdjl 		free(taddr);
6732830Sdjl 	if (taddr6)
6742830Sdjl 		free(taddr6);
6752830Sdjl 	if (h_name)
6762830Sdjl 		free(h_name);
6772830Sdjl 	if (abuf_start)
6782830Sdjl 		free(abuf_start);
6792830Sdjl 
6800Sstevel@tonic-gate 	return (res);
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate /*
6840Sstevel@tonic-gate  * A case-insensitive version of strstr().
6850Sstevel@tonic-gate  */
6860Sstevel@tonic-gate static char *
6872830Sdjl strcasestr(const char *as1, const char *as2)
6880Sstevel@tonic-gate {
6890Sstevel@tonic-gate 	int c2;
6902830Sdjl 	register const char *tptr;
6912830Sdjl 	register const char *s1, *s2;
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	s1 = as1;
6940Sstevel@tonic-gate 	s2 = as2;
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	if (s2 == NULL || *s2 == '\0')
6970Sstevel@tonic-gate 		return (0);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	while (*s1) {
7000Sstevel@tonic-gate 		if (tolower(*s1++) == tolower(c2 = *s2)) {
7010Sstevel@tonic-gate 			tptr = s1;
7020Sstevel@tonic-gate 			while ((tolower(c2 = *++s2) ==
7030Sstevel@tonic-gate 			    tolower(*s1++)) && c2 != 0)
7040Sstevel@tonic-gate 				;
7050Sstevel@tonic-gate 			if (c2 == 0)
7060Sstevel@tonic-gate 				return ((char *)tptr - 1);
7070Sstevel@tonic-gate 			s1 = tptr;
7080Sstevel@tonic-gate 			s2 = as2;
7090Sstevel@tonic-gate 		}
7100Sstevel@tonic-gate 	}
7110Sstevel@tonic-gate 	return (0);
7120Sstevel@tonic-gate }
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate static char *
7162830Sdjl do_aliases(struct hostent *hp, char *abuf, char *end)
7170Sstevel@tonic-gate {
7182830Sdjl 	char	**cp;
7192830Sdjl 	size_t	len;
7200Sstevel@tonic-gate 
7212830Sdjl 	if ((cp = hp->h_aliases) == NULL)
7222830Sdjl 		return (abuf);
7230Sstevel@tonic-gate 
7242830Sdjl 	for (; *cp; cp++) {
7250Sstevel@tonic-gate 		len = strlen(*cp);
7260Sstevel@tonic-gate 		if (abuf+len+1 >= end) {
7272830Sdjl 			return (NULL);
7280Sstevel@tonic-gate 		}
7292830Sdjl 		*abuf++ = ' ';
7302830Sdjl 		(void) memcpy(abuf, *cp, len);
7310Sstevel@tonic-gate 		abuf += len;
7320Sstevel@tonic-gate 	}
7330Sstevel@tonic-gate 	*abuf = '\0';
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	return (abuf);
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate /*
7400Sstevel@tonic-gate  * This is a copy of a routine in libnsl/nss/netdir_inet.c.  It is
7410Sstevel@tonic-gate  * here because /etc/lib/nss_files.so.1 cannot call routines
7420Sstevel@tonic-gate  * in libnsl.  Care should be taken to keep the two copies in sync.
7430Sstevel@tonic-gate  */
7440Sstevel@tonic-gate int
7450Sstevel@tonic-gate __nss_files_2herrno(nsstat)
7460Sstevel@tonic-gate 	nss_status_t nsstat;
7470Sstevel@tonic-gate {
7480Sstevel@tonic-gate 	switch (nsstat) {
7490Sstevel@tonic-gate 	case NSS_SUCCESS:
7500Sstevel@tonic-gate 		/* no macro-defined success code for h_errno */
7510Sstevel@tonic-gate 		return (0);
7520Sstevel@tonic-gate 	case NSS_NOTFOUND:
7530Sstevel@tonic-gate 		return (HOST_NOT_FOUND);
7540Sstevel@tonic-gate 	case NSS_TRYAGAIN:
7550Sstevel@tonic-gate 		return (TRY_AGAIN);
7560Sstevel@tonic-gate 	case NSS_UNAVAIL:
7570Sstevel@tonic-gate 		return (NO_RECOVERY);
7580Sstevel@tonic-gate 	}
7590Sstevel@tonic-gate 	/* anything else */
7600Sstevel@tonic-gate 	return (NO_RECOVERY);
7610Sstevel@tonic-gate }
762