xref: /onnv-gate/usr/src/lib/nsswitch/files/common/gethostent.c (revision 13093:48f2dbca79a2)
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  */
216812Sraf 
220Sstevel@tonic-gate /*
23*13093SRoger.Faulkner@Oracle.COM  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <netdb.h>
270Sstevel@tonic-gate #include "files_common.h"
280Sstevel@tonic-gate #include <string.h>
290Sstevel@tonic-gate #include <strings.h>
300Sstevel@tonic-gate #include <stddef.h>
310Sstevel@tonic-gate #include <stdlib.h>
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/socket.h>
340Sstevel@tonic-gate #include <netinet/in.h>
350Sstevel@tonic-gate #include <arpa/nameser.h>
362830Sdjl #include <arpa/inet.h>
370Sstevel@tonic-gate #include <ctype.h>
380Sstevel@tonic-gate 
392830Sdjl static int	check_name(nss_XbyY_args_t *, const char *, int,
402830Sdjl 			int, const char **, int *, void *, int *);
410Sstevel@tonic-gate static char *do_aliases();
420Sstevel@tonic-gate nss_status_t __nss_files_XY_hostbyname();
430Sstevel@tonic-gate int __nss_files_2herrno();
442830Sdjl static int	__nss_files_get_addr(int, const char *, int,
452830Sdjl 			void *, int, int *);
460Sstevel@tonic-gate 
470Sstevel@tonic-gate static int
check_name(nss_XbyY_args_t * argp,const char * line,int linelen,int type,const char ** namep,int * namelen,void * addrp,int * addrsize)482830Sdjl check_name(nss_XbyY_args_t *argp, const char *line, int linelen,
492830Sdjl 	int type, const char **namep, int *namelen,
502830Sdjl 	void *addrp, int *addrsize)
510Sstevel@tonic-gate {
522830Sdjl 	const char	*limit, *linep, *keyp, *addrstart;
532830Sdjl 	int		v6flag = 0, addrlen;
542830Sdjl 
552830Sdjl 	linep = line;
562830Sdjl 	limit = line + linelen;
570Sstevel@tonic-gate 
582830Sdjl 	/* Address */
592830Sdjl 	addrstart = linep;
602830Sdjl 	while (linep < limit && !isspace(*linep)) {
612830Sdjl 		if (*linep == ':')
622830Sdjl 			v6flag++;
632830Sdjl 		linep++;
640Sstevel@tonic-gate 	}
652830Sdjl 	addrlen = linep - addrstart;
662830Sdjl 
672830Sdjl 	/* skip the delimiting spaces */
682830Sdjl 	while (linep < limit && isspace(*linep))
692830Sdjl 		linep++;
702830Sdjl 
712830Sdjl 	/* Canonical name */
722830Sdjl 	keyp = argp->key.name;
732830Sdjl 	*namep = linep;
742830Sdjl 	while (*keyp && linep < limit && !isspace(*linep) &&
756812Sraf 	    tolower(*keyp) == tolower(*linep)) {
762830Sdjl 		keyp++;
772830Sdjl 		linep++;
782830Sdjl 	}
792830Sdjl 	if (*keyp == '\0' && (linep == limit || isspace(*linep))) {
802830Sdjl 		if (__nss_files_get_addr(type, addrstart, addrlen,
816812Sraf 		    addrp, v6flag, addrsize)) {
822830Sdjl 			*namelen = linep - *namep;
830Sstevel@tonic-gate 			return (1);
840Sstevel@tonic-gate 		}
850Sstevel@tonic-gate 	}
862830Sdjl 	while (linep < limit && !isspace(*linep))
872830Sdjl 		linep++;
882830Sdjl 	*namelen = linep - *namep;
892830Sdjl 
902830Sdjl 	/* Aliases */
912830Sdjl 	while (linep < limit) {
922830Sdjl 		/* skip the delimiting spaces */
932830Sdjl 		while (linep < limit && isspace(*linep))
942830Sdjl 			linep++;
952830Sdjl 
962830Sdjl 		/* compare name (case insensitive) */
972830Sdjl 		keyp = argp->key.name;
982830Sdjl 		while (*keyp && linep < limit && !isspace(*linep) &&
996812Sraf 		    tolower(*keyp) == tolower(*linep)) {
1002830Sdjl 			keyp++;
1012830Sdjl 			linep++;
1022830Sdjl 		}
1032830Sdjl 		if (*keyp == '\0' && (linep == limit || isspace(*linep)))
1042830Sdjl 			return (__nss_files_get_addr(type, addrstart, addrlen,
1056812Sraf 			    addrp, v6flag, addrsize));
1062830Sdjl 
1072830Sdjl 		/* skip remainder of alias, if any */
1082830Sdjl 		while (linep < limit && !isspace(*linep))
1092830Sdjl 			linep++;
1102830Sdjl 	}
1110Sstevel@tonic-gate 	return (0);
1122830Sdjl 
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate static nss_status_t
getbyname(be,a)1160Sstevel@tonic-gate getbyname(be, a)
1170Sstevel@tonic-gate 	files_backend_ptr_t	be;
1180Sstevel@tonic-gate 	void			*a;
1190Sstevel@tonic-gate {
1200Sstevel@tonic-gate 	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
1210Sstevel@tonic-gate 	nss_status_t		res;
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	res = __nss_files_XY_hostbyname(be, argp, argp->key.name, AF_INET);
1240Sstevel@tonic-gate 	if (res != NSS_SUCCESS)
1250Sstevel@tonic-gate 		argp->h_errno = __nss_files_2herrno(res);
1260Sstevel@tonic-gate 	return (res);
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate 
1292830Sdjl static int
__nss_files_get_addr(int af,const char * addrstart,int addrlen,void * addrp,int v6flag,int * h_length)1302830Sdjl __nss_files_get_addr(int af, const char *addrstart, int addrlen,
1312830Sdjl 	void *addrp, int v6flag, int *h_length)
1322830Sdjl {
1332830Sdjl 	struct in_addr	addr_ipv4;
1342830Sdjl 	struct in6_addr	*addrpv6;
1352830Sdjl 	in_addr_t	*addrpv4;
1362830Sdjl 	char		addrbuf[INET6_ADDRSTRLEN + 1];
1372830Sdjl 
1382830Sdjl 	if (addrlen >= sizeof (addrbuf))
1392830Sdjl 		return (0);
1402830Sdjl 	(void) memcpy(addrbuf, addrstart, addrlen);
1412830Sdjl 	addrbuf[addrlen] = '\0';
1422830Sdjl 
1432830Sdjl 	if (af == AF_INET) {
1442830Sdjl 		addrpv4 = (in_addr_t *)addrp;
1452830Sdjl 		if ((*addrpv4 = inet_addr(addrbuf)) == 0xffffffffU)
1462830Sdjl 			return (0);
1472830Sdjl 		*h_length = sizeof (in_addr_t);
1482830Sdjl 	} else if (af == AF_INET6) {
1492830Sdjl 		addrpv6 = (struct in6_addr *)addrp;
1502830Sdjl 		if (v6flag) {
1512830Sdjl 			if (inet_pton(af, addrbuf, addrpv6) != 1)
1522830Sdjl 				return (0);
1532830Sdjl 		} else {
1542830Sdjl 			if ((addr_ipv4.s_addr = inet_addr(addrbuf)) ==
1556812Sraf 			    0xffffffffU)
1562830Sdjl 				return (0);
1572830Sdjl 			IN6_INADDR_TO_V4MAPPED(&addr_ipv4, addrpv6);
1582830Sdjl 		}
1592830Sdjl 		*h_length = sizeof (struct in6_addr);
1602830Sdjl 	} else {
1612830Sdjl 		return (0);
1622830Sdjl 	}
1632830Sdjl 	return (1);
1642830Sdjl }
1652830Sdjl 
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate int
__nss_files_check_addr(int af,nss_XbyY_args_t * argp,const char * line,int linelen)1682830Sdjl __nss_files_check_addr(int af, nss_XbyY_args_t *argp, const char *line,
1692830Sdjl 		int linelen)
1700Sstevel@tonic-gate {
1712830Sdjl 	const char	*limit, *linep, *addrstart;
1722830Sdjl 	int		v6flag = 0, addrlen, h_length;
1732830Sdjl 	in_addr_t	addr_ipv4;
1742830Sdjl 	struct in6_addr	addr_ipv6;
1752830Sdjl 	char		*h_addrp;
1762830Sdjl 
1772830Sdjl 	/* Compare the address type */
1782830Sdjl 	if (argp->key.hostaddr.type != af)
1792830Sdjl 		return (0);
1800Sstevel@tonic-gate 
1812830Sdjl 	/* Retrieve the address */
1822830Sdjl 	if (af == AF_INET)
1832830Sdjl 		h_addrp = (char *)&addr_ipv4;
1842830Sdjl 	else
1852830Sdjl 		h_addrp = (char *)&addr_ipv6;
1862830Sdjl 	linep = line;
1872830Sdjl 	limit = line + linelen;
1882830Sdjl 	addrstart = linep;
1892830Sdjl 	while (linep < limit && !isspace(*linep)) {
1902830Sdjl 		if (*linep == ':')
1912830Sdjl 			v6flag++;
1922830Sdjl 		linep++;
1932830Sdjl 	}
1942830Sdjl 	addrlen = linep - addrstart;
1952830Sdjl 	if (__nss_files_get_addr(af, addrstart, addrlen, h_addrp,
1966812Sraf 	    v6flag, &h_length) == 0)
1972830Sdjl 		return (0);
1982830Sdjl 
1992830Sdjl 	/* Compare the address */
2002830Sdjl 	return (h_length == argp->key.hostaddr.len &&
2016812Sraf 	    memcmp(h_addrp, argp->key.hostaddr.addr,
2026812Sraf 	    argp->key.hostaddr.len) == 0);
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate 
2052830Sdjl static int
check_addr(nss_XbyY_args_t * argp,const char * line,int linelen)2062830Sdjl check_addr(nss_XbyY_args_t *argp, const char *line, int linelen)
2072830Sdjl {
2082830Sdjl 	return (__nss_files_check_addr(AF_INET, argp, line, linelen));
2092830Sdjl }
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate static nss_status_t
getbyaddr(be,a)2120Sstevel@tonic-gate getbyaddr(be, a)
2130Sstevel@tonic-gate 	files_backend_ptr_t	be;
2140Sstevel@tonic-gate 	void			*a;
2150Sstevel@tonic-gate {
2160Sstevel@tonic-gate 	nss_XbyY_args_t		*argp	= (nss_XbyY_args_t *)a;
2170Sstevel@tonic-gate 	nss_status_t		res;
2180Sstevel@tonic-gate 
2192830Sdjl 	res = _nss_files_XY_all(be, argp, 1, 0, check_addr);
2200Sstevel@tonic-gate 	if (res != NSS_SUCCESS)
2210Sstevel@tonic-gate 		argp->h_errno = __nss_files_2herrno(res);
2220Sstevel@tonic-gate 	return (res);
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate 
2252883Schinlong /*
2262883Schinlong  * filter_ipv6
2272883Schinlong  *
2282883Schinlong  * Return - NSS_STR_PARSE_SUCCESS: An IPv4 address
2292883Schinlong  *          NSS_STR_PARSE_PARSE: An IPv6 address or other errors
2302883Schinlong  */
2312883Schinlong static int
filter_ipv6(char * instr,int lenstr)2322883Schinlong filter_ipv6(char *instr, int lenstr) {
2332883Schinlong 	char	*p, *addrstart, *limit, c;
2342883Schinlong 	int	rc;
2352883Schinlong 	struct in_addr	addr;
2362883Schinlong 
2372883Schinlong 	p = instr;
2382883Schinlong 	limit = p + lenstr;
2392883Schinlong 
2402883Schinlong 	addrstart = p;
2412883Schinlong 
2422883Schinlong 	/* parse IP address */
2432883Schinlong 	while (p < limit && !isspace(*p)) {
2442883Schinlong 		if (*p == ':')
2452883Schinlong 			/* IPv6 */
2462883Schinlong 			return (NSS_STR_PARSE_PARSE);
2472883Schinlong 		else
2482883Schinlong 			p++;
2492883Schinlong 	}
2502883Schinlong 
2512883Schinlong 	if (p >= limit)
2522883Schinlong 		/* invalid IP */
2532883Schinlong 		return (NSS_STR_PARSE_PARSE);
2542883Schinlong 
2552883Schinlong 	/* extract IP address */
2562883Schinlong 	c = *p;
2572883Schinlong 	*p = '\0';
2586812Sraf 	rc = inet_aton(addrstart, &addr);
2592883Schinlong 	*p = c;
2602883Schinlong 
2612883Schinlong 	if (rc == 0)
2622883Schinlong 		/* invalid IP */
2632883Schinlong 		return (NSS_STR_PARSE_PARSE);
2642883Schinlong 	else
2652883Schinlong 		/* IPv4 */
2662883Schinlong 		return (NSS_STR_PARSE_SUCCESS);
2672883Schinlong 
2682883Schinlong 
2692883Schinlong }
2702883Schinlong static nss_status_t
getent_hosts(files_backend_ptr_t be,void * a)2712883Schinlong getent_hosts(files_backend_ptr_t be, void *a)
2722883Schinlong {
2732883Schinlong 	nss_XbyY_args_t	*args = (nss_XbyY_args_t *)a;
2742883Schinlong 	nss_status_t	rc = NSS_SUCCESS;
2752883Schinlong 
2762883Schinlong 	if (args->buf.result != NULL) {
2772883Schinlong 		return (_nss_files_XY_all(be, args, 1, 0, 0));
2782883Schinlong 	} else {
2792883Schinlong 		/*
2802883Schinlong 		 * Called by nscd
2812883Schinlong 		 */
2822883Schinlong 		/*CONSTCOND*/
2832883Schinlong 		while (1) {
2842883Schinlong 			rc = _nss_files_XY_all(be, args, 1, 0, 0);
2852883Schinlong 			/*
2862883Schinlong 			 * NSS_NOTFOUND, end of file or other errors.
2872883Schinlong 			 */
2882883Schinlong 			if (rc != NSS_SUCCESS)
2892883Schinlong 				break;
2902883Schinlong 			/*
2912883Schinlong 			 * /etc/hosts and /etc/ipnodes are merged and
2922883Schinlong 			 * /etc/hosts can contain IPv6 addresses.
2932883Schinlong 			 * These addresses have to be filtered.
2942883Schinlong 			 */
2952883Schinlong 			if (filter_ipv6(args->returnval, args->returnlen)
2966812Sraf 			    == NSS_STR_PARSE_SUCCESS)
2972883Schinlong 				break;
2982883Schinlong 			/*
2992883Schinlong 			 * The entry is an IPv6 address or other errors.
3002883Schinlong 			 * Skip it and continue to find next one.
3012883Schinlong 			 */
3022883Schinlong 			args->returnval = NULL;
3032883Schinlong 			args->returnlen = 0;
3042883Schinlong 
3052883Schinlong 		}
3062883Schinlong 		return (rc);
3072883Schinlong 	}
3082883Schinlong 
3092883Schinlong }
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate static files_backend_op_t host_ops[] = {
3120Sstevel@tonic-gate 	_nss_files_destr,
3130Sstevel@tonic-gate 	_nss_files_endent,
3140Sstevel@tonic-gate 	_nss_files_setent,
3152883Schinlong 	getent_hosts,
3160Sstevel@tonic-gate 	getbyname,
3170Sstevel@tonic-gate 	getbyaddr,
3180Sstevel@tonic-gate };
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate /*ARGSUSED*/
3210Sstevel@tonic-gate nss_backend_t *
_nss_files_hosts_constr(dummy1,dummy2,dummy3)3220Sstevel@tonic-gate _nss_files_hosts_constr(dummy1, dummy2, dummy3)
3230Sstevel@tonic-gate 	const char	*dummy1, *dummy2, *dummy3;
3240Sstevel@tonic-gate {
3250Sstevel@tonic-gate 	return (_nss_files_constr(host_ops,
3260Sstevel@tonic-gate 				sizeof (host_ops) / sizeof (host_ops[0]),
3270Sstevel@tonic-gate 				_PATH_HOSTS,
3280Sstevel@tonic-gate 				NSS_LINELEN_HOSTS,
3290Sstevel@tonic-gate 				NULL));
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate /*
3340Sstevel@tonic-gate  * XXX - this duplicates code from files_common.c because we need to keep
3350Sstevel@tonic-gate  * going after we've found a match to satisfy the multihomed host case.
3360Sstevel@tonic-gate  */
3370Sstevel@tonic-gate nss_status_t
__nss_files_XY_hostbyname(be,args,filter,type)3380Sstevel@tonic-gate __nss_files_XY_hostbyname(be, args, filter, type)
3390Sstevel@tonic-gate 	files_backend_ptr_t be;
3400Sstevel@tonic-gate 	nss_XbyY_args_t *args;
3410Sstevel@tonic-gate 	const char *filter;		/* hint for name string */
3420Sstevel@tonic-gate 	int type;
3430Sstevel@tonic-gate {
3442830Sdjl 	nss_status_t	res;
3452830Sdjl 	char		*abuf = NULL, *abuf_start = NULL, *abuf_end;
3462830Sdjl 	char		*first, *last, *buffer;
3472830Sdjl 	int		parsestat, i, nhosts = 0, buflen;
3482830Sdjl 	const char	*namep;
3492830Sdjl 	char		*h_name;
3502830Sdjl 	int		h_namelen, namelen;
3512830Sdjl 	struct hostent	*hp;
3522830Sdjl 	in_addr_t	*taddr = NULL;
3532830Sdjl 	struct in6_addr	*taddr6 = NULL;
3542830Sdjl 	size_t		ntaddr;
3552830Sdjl 	void		*addrp;
3562830Sdjl 	char		*alias_end = NULL;
3570Sstevel@tonic-gate 
3582830Sdjl 	if (be->buf == 0 && (be->buf = malloc(be->minbuf)) == 0) {
3590Sstevel@tonic-gate 		return (NSS_UNAVAIL);
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	if (be->f == 0) {
3630Sstevel@tonic-gate 		if ((res = _nss_files_setent(be, 0)) != NSS_SUCCESS)
3640Sstevel@tonic-gate 			return (res);
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 
3672830Sdjl 	ntaddr = MAXADDRS;
3682830Sdjl 	if (type == AF_INET) {
3692830Sdjl 		taddr = (in_addr_t *)calloc(ntaddr, sizeof (*taddr));
3702830Sdjl 		if (taddr == NULL)
3712830Sdjl 			return (NSS_UNAVAIL);
3722830Sdjl 	} else {
3732830Sdjl 		taddr6 = (struct in6_addr *)calloc(ntaddr, sizeof (*taddr6));
3742830Sdjl 		if (taddr6 == NULL)
3752830Sdjl 			return (NSS_UNAVAIL);
3762830Sdjl 	}
3772830Sdjl 
3780Sstevel@tonic-gate 	res = NSS_NOTFOUND;
3790Sstevel@tonic-gate 	args->returnval = (char *)0;
3802830Sdjl 	args->returnlen = 0;
3812830Sdjl 	hp = (struct hostent *)args->buf.result;
3822830Sdjl 	buffer = args->buf.buffer;
3832830Sdjl 	buflen = args->buf.buflen;
3842830Sdjl 	h_namelen = 0;
3852830Sdjl 	h_name = NULL;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	for (;;) {
3880Sstevel@tonic-gate 		char *instr = be->buf;
3890Sstevel@tonic-gate 		int linelen;
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 		if ((linelen = _nss_files_read_line(be->f,
3920Sstevel@tonic-gate 		    instr, be->minbuf)) < 0) {
3930Sstevel@tonic-gate 			break;		/* EOF */
3940Sstevel@tonic-gate 		}
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 		/*
3970Sstevel@tonic-gate 		 * This check avoids a malloc()/free() for the common
3980Sstevel@tonic-gate 		 * case. Also, if we're trying to match an alias and an
3990Sstevel@tonic-gate 		 * already matched entry doesn't share a canonical name
4000Sstevel@tonic-gate 		 * with the current one, bail.
4010Sstevel@tonic-gate 		 */
4020Sstevel@tonic-gate 		if (nhosts == 0 && strcasestr(instr, filter) == 0) {
4030Sstevel@tonic-gate 			continue;
4040Sstevel@tonic-gate 		}
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 		if ((last = strchr(instr, '#')) == 0)
4070Sstevel@tonic-gate 			last = instr + linelen;
4080Sstevel@tonic-gate 		*last-- = '\0';
4090Sstevel@tonic-gate 		for (first = instr;  isspace(*first);  first++)
4100Sstevel@tonic-gate 			;
4110Sstevel@tonic-gate 		/* Ignore blank and comment lines */
4120Sstevel@tonic-gate 		if (*first == '\0')
4130Sstevel@tonic-gate 			continue;
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 		while (isspace(*last))
4160Sstevel@tonic-gate 			--last;
4170Sstevel@tonic-gate 		linelen = last - first + 1;
4180Sstevel@tonic-gate 		if (first != instr)
4190Sstevel@tonic-gate 			instr = first;
4200Sstevel@tonic-gate 
4212830Sdjl 		/* Bail out if the canonical name does not match */
4222830Sdjl 		if (nhosts && strcasestr(instr, h_name) == 0) {
4230Sstevel@tonic-gate 			continue;
4240Sstevel@tonic-gate 		}
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 		/*
4270Sstevel@tonic-gate 		 * Still need to check, strcasestr() above is just a hint.
4280Sstevel@tonic-gate 		 */
4292830Sdjl 		addrp = (type == AF_INET)?
4302830Sdjl 				(void *)&taddr[nhosts]:
4312830Sdjl 				(void *)&taddr6[nhosts];
4320Sstevel@tonic-gate 
4332830Sdjl 		if (check_name(args, instr, linelen,
4342830Sdjl 				type, &namep, &namelen,
4352830Sdjl 				addrp, &i)) {
4362830Sdjl 
4372830Sdjl 			/*
4382830Sdjl 			 * If we've already matched once and have a possible
4392830Sdjl 			 * match on this line, copy the aliases where they're
4402830Sdjl 			 * safe from being overwritten when we look at the
4412830Sdjl 			 * next entry. They're saved as a string of blank
4422830Sdjl 			 * separated names for the alias parser. On errors,
4432830Sdjl 			 * we return failure whether or not we have already
4442830Sdjl 			 * obtained a valid address.
4452830Sdjl 			 */
4462830Sdjl 			if (nhosts == 1 && hp) {
4472830Sdjl 				if (h_namelen + 1 > args->buf.buflen) {
4482830Sdjl 					args->erange = 1;
4492830Sdjl 					res = NSS_NOTFOUND;
4502830Sdjl 					break;
4512830Sdjl 				}
4522830Sdjl 				abuf = (char *)malloc(args->buf.buflen);
4532830Sdjl 				if (abuf == NULL) {
4542830Sdjl 					res = NSS_UNAVAIL;
4552830Sdjl 					break;
4562830Sdjl 				}
4572830Sdjl 				abuf_start = abuf;
4582830Sdjl 				abuf_end = abuf_start + args->buf.buflen;
4592830Sdjl 				(void) memcpy(abuf, h_name, h_namelen);
4602830Sdjl 				abuf += h_namelen;
4612830Sdjl 				*abuf = '\0';
4622830Sdjl 				abuf = do_aliases(hp, abuf, abuf_end);
4632830Sdjl 				if (abuf == NULL) {
4642830Sdjl 					args->erange = 1;
4652830Sdjl 					res = NSS_NOTFOUND;
4662830Sdjl 					break;
4672830Sdjl 				}
4682830Sdjl 			}
4692830Sdjl 
4702830Sdjl 			if (hp != NULL) {
4712830Sdjl 				/* inside the application */
4722830Sdjl 				parsestat = (*args->str2ent)(instr, linelen,
4732830Sdjl 						hp, buffer, buflen);
4742830Sdjl 				if (parsestat != NSS_STR_PARSE_SUCCESS) {
4752830Sdjl 					if (parsestat == NSS_STR_PARSE_ERANGE)
4762830Sdjl 						args->erange = 1;
4772830Sdjl 					(void) memset(buffer, 0, buflen);
4782830Sdjl 					continue;
4792830Sdjl 				}
4802830Sdjl 			} else {
4812830Sdjl 				/* inside nscd */
4822830Sdjl 				int	alen, cplen, erange = 0;
4832830Sdjl 				char	*ap;
4842830Sdjl 
4852830Sdjl 				/* Add alias to the first line if any */
4862830Sdjl 				if (nhosts > 0) {
4872830Sdjl 
4882830Sdjl 					/* get to the start of alias */
4892830Sdjl 					ap = (char *)namep + namelen;
4902830Sdjl 					/* see if there's any alias */
4912830Sdjl 					if (ap == instr + linelen)
4922830Sdjl 						alen = 0;
4932830Sdjl 					else
4942830Sdjl 						alen = linelen - (ap - instr);
4952830Sdjl 					if (alen + 1 >= buflen)
4962830Sdjl 						erange  = 1;
4972830Sdjl 					if (erange == 0 && alen != 0) {
4982830Sdjl 						/* make room for the alias */
4992830Sdjl 						if (alias_end != NULL)
5002830Sdjl 						(void) memmove(alias_end +
5012830Sdjl 						alen, alias_end, buffer -
5022830Sdjl 						alias_end);
5032830Sdjl 						/* copy in the alias */
5042830Sdjl 						(void) memmove(alias_end,
5052830Sdjl 							ap, alen);
5062830Sdjl 						buffer += alen;
5072830Sdjl 						buflen -= alen;
5082924Smichen 						args->returnlen += alen;
5092830Sdjl 						alias_end += alen;
5102830Sdjl 					}
5112830Sdjl 
5122830Sdjl 					/* Add delimiter to the buffer */
5132830Sdjl 					*buffer++ = '\n';
5142830Sdjl 					buflen--;
5152830Sdjl 					args->returnlen++;
5162830Sdjl 				}
5172830Sdjl 
5182830Sdjl 				/* copy just the addr if not first one */
5192830Sdjl 				if (alias_end == NULL)
5202830Sdjl 					cplen = linelen;
5212830Sdjl 				else
5222830Sdjl 					cplen = namep - instr;
5232830Sdjl 
5242830Sdjl 				if (cplen >= buflen || erange == 1) {
5252830Sdjl 					args->erange = 1;
5262830Sdjl 					if (nhosts > 0) {
5272830Sdjl 						*(--buffer) = '\0';
5282830Sdjl 						buflen++;
5292830Sdjl 						args->returnlen--;
5302830Sdjl 					}
5312830Sdjl 					continue;
5322830Sdjl 				}
5332830Sdjl 
5342830Sdjl 				(void) memcpy(buffer, instr, cplen);
5352830Sdjl 				/* Adjust buffer */
5362830Sdjl 				buffer += cplen;
5372830Sdjl 				*buffer = '\0';
5382830Sdjl 				buflen -= cplen;
5392924Smichen 				args->returnlen += cplen;
5402830Sdjl 				if (alias_end == NULL)
5412830Sdjl 					alias_end = buffer;
5422830Sdjl 			}
5432830Sdjl 
5442830Sdjl 			/*
5452830Sdjl 			 * If this is the first one, save the canonical
5462830Sdjl 			 * name for future matches and continue.
5472830Sdjl 			 */
5482830Sdjl 			if (++nhosts == 1) {
5492830Sdjl 				h_name = malloc(namelen + 1);
5502830Sdjl 				if (h_name == NULL) {
5512830Sdjl 					res = NSS_UNAVAIL;
5522830Sdjl 					break;
5532830Sdjl 				}
5542830Sdjl 				res = NSS_SUCCESS;
5552830Sdjl 				(void) memcpy(h_name, namep, namelen);
5562830Sdjl 				h_name[namelen] = '\0';
5572830Sdjl 				h_namelen = namelen;
5582830Sdjl 				if (hp)
5592830Sdjl 					args->returnval = hp;
5602830Sdjl 				else
5612830Sdjl 					args->returnval = args->buf.buffer;
5622830Sdjl 				continue;
5630Sstevel@tonic-gate 			}
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 
5662830Sdjl 			/* Extend the array */
5672830Sdjl 			if (nhosts >= ntaddr) {
5682830Sdjl 				ntaddr *= 2;
5692830Sdjl 				if (type == AF_INET) {
5702830Sdjl 					addrp = realloc(taddr,
5712830Sdjl 						sizeof (*taddr) * ntaddr);
5722830Sdjl 					if (addrp == NULL) {
5732830Sdjl 						res = NSS_UNAVAIL;
5742830Sdjl 						break;
5752830Sdjl 					}
5762830Sdjl 					taddr = (in_addr_t *)addrp;
5772830Sdjl 				} else {
5782830Sdjl 					addrp = realloc(taddr6,
5792830Sdjl 						sizeof (*taddr6) * ntaddr);
5802830Sdjl 					if (addrp == NULL) {
5812830Sdjl 						res = NSS_UNAVAIL;
5822830Sdjl 						break;
5832830Sdjl 					}
5842830Sdjl 					taddr6 = (struct in6_addr *)addrp;
5852830Sdjl 				}
5860Sstevel@tonic-gate 			}
5872830Sdjl 
5882830Sdjl 			/*
5892830Sdjl 			 * For non-nscd, save aliases in a temporary buffer
5902830Sdjl 			 * Don't have to do this for nscd as 'buffer' already
5912830Sdjl 			 * contains the required data in the appropriate
5922830Sdjl 			 * format
5932830Sdjl 			 */
5942830Sdjl 			if (hp) {
5952830Sdjl 				abuf = do_aliases(hp, abuf, abuf_end);
5962830Sdjl 				if (abuf == NULL) {
5972830Sdjl 					args->erange = 1;
5982830Sdjl 					res = NSS_NOTFOUND;
5992830Sdjl 					break;
6002830Sdjl 				}
6010Sstevel@tonic-gate 			}
6022830Sdjl 		} else if (namep && h_namelen == namelen &&
6032830Sdjl 		    strncasecmp(h_name, namep, namelen) == 0) {
6040Sstevel@tonic-gate 			/*
6050Sstevel@tonic-gate 			 * This line didn't have the requested name but
6060Sstevel@tonic-gate 			 * is part of the same multihomed host (i.e. it
6070Sstevel@tonic-gate 			 * has the same canonical name as the previous
6080Sstevel@tonic-gate 			 * line), so march on...
6090Sstevel@tonic-gate 			 */
6100Sstevel@tonic-gate 			continue;
6110Sstevel@tonic-gate 		} else if (nhosts) {
6123099Smichen 			continue;
6130Sstevel@tonic-gate 		}
6140Sstevel@tonic-gate 	}
6150Sstevel@tonic-gate 
6162830Sdjl 	if (abuf && res == NSS_SUCCESS) {
6172830Sdjl 
6182830Sdjl 		/* abuf != NULL implies hp and abuf_start != NULL */
6192830Sdjl 
6200Sstevel@tonic-gate 		struct in_addr *addrp;
6210Sstevel@tonic-gate 		struct in6_addr *addrp6;
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 		if (type == AF_INET) {
6240Sstevel@tonic-gate 			addrp = (struct in_addr *)(ROUND_DOWN(args->buf.buffer +
6250Sstevel@tonic-gate 			    args->buf.buflen, sizeof (*addrp)));
6260Sstevel@tonic-gate 			hp->h_addr_list = (char **)(ROUND_DOWN(addrp -
6270Sstevel@tonic-gate 			    ((nhosts + 1) * sizeof (char *) +
6280Sstevel@tonic-gate 			    (nhosts * sizeof (*addrp))), sizeof (char *)));
6290Sstevel@tonic-gate 			for (i = 0, --addrp; i < nhosts; i++, --addrp) {
6300Sstevel@tonic-gate 				(*(in_addr_t *)addrp) = taddr[i];
6310Sstevel@tonic-gate 				hp->h_addr_list[i] = (char *)addrp;
6320Sstevel@tonic-gate 			}
6330Sstevel@tonic-gate 		} else {
6340Sstevel@tonic-gate 			addrp6 = (struct in6_addr *)
6350Sstevel@tonic-gate 			(ROUND_DOWN(args->buf.buffer + args->buf.buflen,
6360Sstevel@tonic-gate 			sizeof (*addrp6)));
6370Sstevel@tonic-gate 			hp->h_addr_list = (char **)(ROUND_DOWN(addrp6 -
6380Sstevel@tonic-gate 			    ((nhosts + 1) * sizeof (char *) +
6390Sstevel@tonic-gate 			    (nhosts * sizeof (*addrp6))), sizeof (char *)));
6400Sstevel@tonic-gate 			for (i = 0, --addrp6; i < nhosts; i++, --addrp6) {
6412830Sdjl 				(void) memcpy(addrp6, &taddr6[i],
6422830Sdjl 						sizeof (struct in6_addr));
6430Sstevel@tonic-gate 				hp->h_addr_list[i] = (char *)addrp6;
6440Sstevel@tonic-gate 			}
6450Sstevel@tonic-gate 		}
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 		hp->h_addr_list[nhosts] = 0;
6480Sstevel@tonic-gate 		hp->h_aliases = _nss_netdb_aliases(abuf_start,
6490Sstevel@tonic-gate 		    abuf - abuf_start, args->buf.buffer,
6500Sstevel@tonic-gate 		    (char *)hp->h_addr_list - args->buf.buffer);
6510Sstevel@tonic-gate 		if (hp->h_aliases == 0) {
6520Sstevel@tonic-gate 			args->erange = 1;
6532830Sdjl 			res = NSS_NOTFOUND;
6540Sstevel@tonic-gate 		} else {
6550Sstevel@tonic-gate 			hp->h_name = hp->h_aliases[0];
6560Sstevel@tonic-gate 			hp->h_aliases++;
6570Sstevel@tonic-gate 		}
6580Sstevel@tonic-gate 	}
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	/*
6610Sstevel@tonic-gate 	 * stayopen is set to 0 by default in order to close the opened
6620Sstevel@tonic-gate 	 * file.  Some applications may break if it is set to 1.
6630Sstevel@tonic-gate 	 */
6640Sstevel@tonic-gate 	if (!args->stayopen)
6650Sstevel@tonic-gate 		(void) _nss_files_endent(be, 0);
6660Sstevel@tonic-gate 
6672830Sdjl 	if (taddr)
6682830Sdjl 		free(taddr);
6692830Sdjl 	if (taddr6)
6702830Sdjl 		free(taddr6);
6712830Sdjl 	if (h_name)
6722830Sdjl 		free(h_name);
6732830Sdjl 	if (abuf_start)
6742830Sdjl 		free(abuf_start);
6752830Sdjl 
6760Sstevel@tonic-gate 	return (res);
6770Sstevel@tonic-gate }
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate static char *
do_aliases(struct hostent * hp,char * abuf,char * end)6812830Sdjl do_aliases(struct hostent *hp, char *abuf, char *end)
6820Sstevel@tonic-gate {
6832830Sdjl 	char	**cp;
6842830Sdjl 	size_t	len;
6850Sstevel@tonic-gate 
6862830Sdjl 	if ((cp = hp->h_aliases) == NULL)
6872830Sdjl 		return (abuf);
6880Sstevel@tonic-gate 
6892830Sdjl 	for (; *cp; cp++) {
6900Sstevel@tonic-gate 		len = strlen(*cp);
6910Sstevel@tonic-gate 		if (abuf+len+1 >= end) {
6922830Sdjl 			return (NULL);
6930Sstevel@tonic-gate 		}
6942830Sdjl 		*abuf++ = ' ';
6952830Sdjl 		(void) memcpy(abuf, *cp, len);
6960Sstevel@tonic-gate 		abuf += len;
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate 	*abuf = '\0';
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 	return (abuf);
7010Sstevel@tonic-gate }
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate /*
7050Sstevel@tonic-gate  * This is a copy of a routine in libnsl/nss/netdir_inet.c.  It is
7060Sstevel@tonic-gate  * here because /etc/lib/nss_files.so.1 cannot call routines
7070Sstevel@tonic-gate  * in libnsl.  Care should be taken to keep the two copies in sync.
7080Sstevel@tonic-gate  */
7090Sstevel@tonic-gate int
__nss_files_2herrno(nsstat)7100Sstevel@tonic-gate __nss_files_2herrno(nsstat)
7110Sstevel@tonic-gate 	nss_status_t nsstat;
7120Sstevel@tonic-gate {
7130Sstevel@tonic-gate 	switch (nsstat) {
7140Sstevel@tonic-gate 	case NSS_SUCCESS:
7150Sstevel@tonic-gate 		/* no macro-defined success code for h_errno */
7160Sstevel@tonic-gate 		return (0);
7170Sstevel@tonic-gate 	case NSS_NOTFOUND:
7180Sstevel@tonic-gate 		return (HOST_NOT_FOUND);
7190Sstevel@tonic-gate 	case NSS_TRYAGAIN:
7200Sstevel@tonic-gate 		return (TRY_AGAIN);
7210Sstevel@tonic-gate 	case NSS_UNAVAIL:
7220Sstevel@tonic-gate 		return (NO_RECOVERY);
7230Sstevel@tonic-gate 	}
7240Sstevel@tonic-gate 	/* anything else */
7250Sstevel@tonic-gate 	return (NO_RECOVERY);
7260Sstevel@tonic-gate }
727