xref: /onnv-gate/usr/src/lib/nsswitch/dns/common/dns_common.c (revision 3176:a38e922f22b0)
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  */
210Sstevel@tonic-gate /*
222830Sdjl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
232830Sdjl  * Use is subject to license terms.
242830Sdjl  */
252830Sdjl 
262830Sdjl #pragma ident	"%Z%%M%	%I%	%E% SMI"
272830Sdjl 
282830Sdjl /*
290Sstevel@tonic-gate  *	dns_common.c
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
322830Sdjl #include "dns_common.h"
330Sstevel@tonic-gate 
342830Sdjl #pragma weak	dn_expand
352830Sdjl #pragma weak	res_ninit
362830Sdjl #pragma weak	res_nsearch
372830Sdjl #pragma weak	res_nclose
382830Sdjl #pragma weak	ns_get16
392830Sdjl #pragma weak	ns_get32
402830Sdjl #pragma weak	__ns_get16
412830Sdjl #pragma weak	__ns_get32
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #define	DNS_ALIASES	0
440Sstevel@tonic-gate #define	DNS_ADDRLIST	1
450Sstevel@tonic-gate #define	DNS_MAPDLIST	2
460Sstevel@tonic-gate 
470Sstevel@tonic-gate static int
480Sstevel@tonic-gate dns_netdb_aliases(from_list, to_list, aliaspp, type, count, af_type)
490Sstevel@tonic-gate 	char	**from_list, **to_list,	**aliaspp;
500Sstevel@tonic-gate 	int	type, *count, af_type;
510Sstevel@tonic-gate {
520Sstevel@tonic-gate 	char		*fstr;
530Sstevel@tonic-gate 	int		cnt = 0;
540Sstevel@tonic-gate 	size_t		len;
550Sstevel@tonic-gate 
560Sstevel@tonic-gate 	*count = 0;
570Sstevel@tonic-gate 	if ((char *)to_list >= *aliaspp)
580Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
590Sstevel@tonic-gate 
600Sstevel@tonic-gate 	for (fstr = from_list[cnt]; fstr != NULL; fstr = from_list[cnt]) {
610Sstevel@tonic-gate 		if (type == DNS_ALIASES)
620Sstevel@tonic-gate 			len = strlen(fstr) + 1;
630Sstevel@tonic-gate 		else
640Sstevel@tonic-gate 			len = (af_type == AF_INET) ? sizeof (struct in_addr)
650Sstevel@tonic-gate 						: sizeof (struct in6_addr);
660Sstevel@tonic-gate 		*aliaspp -= len;
670Sstevel@tonic-gate 		to_list[cnt] = *aliaspp;
680Sstevel@tonic-gate 		if (*aliaspp <= (char *)&to_list[cnt+1])
690Sstevel@tonic-gate 			return (NSS_STR_PARSE_ERANGE);
700Sstevel@tonic-gate 		if (type == DNS_MAPDLIST) {
712830Sdjl 			/* LINTED: E_BAD_PTR_CAST_ALIGN */
722830Sdjl 			struct in6_addr *addr6p = (struct in6_addr *)*aliaspp;
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 			(void) memset(addr6p, '\0', sizeof (struct in6_addr));
750Sstevel@tonic-gate 			(void) memcpy(&addr6p->s6_addr[12], fstr,
760Sstevel@tonic-gate 					sizeof (struct in_addr));
770Sstevel@tonic-gate 			addr6p->s6_addr[10] = 0xffU;
780Sstevel@tonic-gate 			addr6p->s6_addr[11] = 0xffU;
790Sstevel@tonic-gate 			++cnt;
800Sstevel@tonic-gate 		} else {
810Sstevel@tonic-gate 			(void) memcpy (*aliaspp, fstr, len);
820Sstevel@tonic-gate 			++cnt;
830Sstevel@tonic-gate 		}
840Sstevel@tonic-gate 	}
850Sstevel@tonic-gate 	to_list[cnt] = NULL;
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	*count = cnt;
880Sstevel@tonic-gate 	if (cnt == 0)
890Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	return (NSS_STR_PARSE_SUCCESS);
920Sstevel@tonic-gate }
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 
950Sstevel@tonic-gate int
960Sstevel@tonic-gate ent2result(he, argp, af_type)
970Sstevel@tonic-gate 	struct hostent		*he;
980Sstevel@tonic-gate 	nss_XbyY_args_t		*argp;
990Sstevel@tonic-gate 	int			af_type;
1000Sstevel@tonic-gate {
1010Sstevel@tonic-gate 	char		*buffer, *limit;
1020Sstevel@tonic-gate 	int		buflen = argp->buf.buflen;
1030Sstevel@tonic-gate 	int		ret, count;
1040Sstevel@tonic-gate 	size_t len;
1050Sstevel@tonic-gate 	struct hostent 	*host;
1060Sstevel@tonic-gate 	struct in_addr	*addrp;
1070Sstevel@tonic-gate 	struct in6_addr	*addrp6;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	limit = argp->buf.buffer + buflen;
1102830Sdjl 	host = (struct hostent *)argp->buf.result;
1110Sstevel@tonic-gate 	buffer = argp->buf.buffer;
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	/* h_addrtype and h_length */
1140Sstevel@tonic-gate 	host->h_addrtype = af_type;
1150Sstevel@tonic-gate 	host->h_length = (af_type == AF_INET) ? sizeof (struct in_addr)
1160Sstevel@tonic-gate 					: sizeof (struct in6_addr);
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	/* h_name */
1190Sstevel@tonic-gate 	len = strlen(he->h_name) + 1;
1200Sstevel@tonic-gate 	host->h_name = buffer;
1210Sstevel@tonic-gate 	if (host->h_name + len >= limit)
1220Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
1230Sstevel@tonic-gate 	(void) memcpy(host->h_name, he->h_name, len);
1240Sstevel@tonic-gate 	buffer += len;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	/* h_addr_list */
1270Sstevel@tonic-gate 	if (af_type == AF_INET) {
1282830Sdjl 		addrp = (struct in_addr *)ROUND_DOWN(limit, sizeof (*addrp));
1290Sstevel@tonic-gate 		host->h_addr_list = (char **)
1300Sstevel@tonic-gate 				ROUND_UP(buffer, sizeof (char **));
1310Sstevel@tonic-gate 		ret = dns_netdb_aliases(he->h_addr_list, host->h_addr_list,
1320Sstevel@tonic-gate 			(char **)&addrp, DNS_ADDRLIST, &count, af_type);
1330Sstevel@tonic-gate 		if (ret != NSS_STR_PARSE_SUCCESS)
1340Sstevel@tonic-gate 			return (ret);
1350Sstevel@tonic-gate 		/* h_aliases */
1360Sstevel@tonic-gate 		host->h_aliases = host->h_addr_list + count + 1;
1370Sstevel@tonic-gate 		ret = dns_netdb_aliases(he->h_aliases, host->h_aliases,
1380Sstevel@tonic-gate 			(char **)&addrp, DNS_ALIASES, &count, af_type);
1390Sstevel@tonic-gate 	} else {
1400Sstevel@tonic-gate 		addrp6 = (struct in6_addr *)
1410Sstevel@tonic-gate 			ROUND_DOWN(limit, sizeof (*addrp6));
1420Sstevel@tonic-gate 		host->h_addr_list = (char **)
1430Sstevel@tonic-gate 			ROUND_UP(buffer, sizeof (char **));
1440Sstevel@tonic-gate 		if (he->h_addrtype == AF_INET && af_type == AF_INET6) {
1450Sstevel@tonic-gate 			ret = dns_netdb_aliases(he->h_addr_list,
1460Sstevel@tonic-gate 				host->h_addr_list, (char **)&addrp6,
1470Sstevel@tonic-gate 				DNS_MAPDLIST, &count, af_type);
1480Sstevel@tonic-gate 		} else {
1490Sstevel@tonic-gate 			ret = dns_netdb_aliases(he->h_addr_list,
1500Sstevel@tonic-gate 				host->h_addr_list, (char **)&addrp6,
1510Sstevel@tonic-gate 				DNS_ADDRLIST, &count, af_type);
1520Sstevel@tonic-gate 		}
1530Sstevel@tonic-gate 		if (ret != NSS_STR_PARSE_SUCCESS)
1540Sstevel@tonic-gate 			return (ret);
1550Sstevel@tonic-gate 		/* h_aliases */
1560Sstevel@tonic-gate 		host->h_aliases = host->h_addr_list + count + 1;
1570Sstevel@tonic-gate 		ret = dns_netdb_aliases(he->h_aliases, host->h_aliases,
1580Sstevel@tonic-gate 			(char **)&addrp6, DNS_ALIASES, &count, af_type);
1590Sstevel@tonic-gate 	}
1600Sstevel@tonic-gate 	if (ret == NSS_STR_PARSE_PARSE)
1610Sstevel@tonic-gate 		ret = NSS_STR_PARSE_SUCCESS;
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	return (ret);
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate 
1662830Sdjl /*
1672830Sdjl  * Convert the hostent structure into string in the following
1682830Sdjl  * format:
1692830Sdjl  *
1702830Sdjl  * IP-address official-host-name nicknames ...
1712830Sdjl  *
1722830Sdjl  * If more than one IP-addresses matches the official-host-name,
1732830Sdjl  * the above line will be followed by:
1742830Sdjl  * IP-address-1 official-host-name
1752830Sdjl  * IP-address-2 official-host-name
1762830Sdjl  * ...
1772830Sdjl  *
1782830Sdjl  * This is so that the str2hostent function in libnsl
1792830Sdjl  * can convert the string back to the original hostent
1802830Sdjl  * data.
1812830Sdjl  */
1822830Sdjl int
1832830Sdjl ent2str(
1842830Sdjl 	struct hostent	*hp,
1852830Sdjl 	nss_XbyY_args_t *ap,
1862830Sdjl 	int		af_type)
1872830Sdjl {
1882830Sdjl 	char		**p;
1892830Sdjl 	char		obuf[INET6_ADDRSTRLEN];
1902830Sdjl 	void		*addr;
1912830Sdjl 	struct in_addr	in4;
1922830Sdjl 	int		af;
1932830Sdjl 	int		n;
1942830Sdjl 	const char	*res;
1952830Sdjl 	char		**q;
1962830Sdjl 	int		l = ap->buf.buflen;
1972830Sdjl 	char		*s = ap->buf.buffer;
1982830Sdjl 
1992830Sdjl 	/*
2002830Sdjl 	 * for "hosts" lookup, we only want address type of
2012830Sdjl 	 * AF_INET. For "ipnodes", we can have both AF_INET
2022830Sdjl 	 * and AF_INET6.
2032830Sdjl 	 */
2042830Sdjl 	if (af_type == AF_INET && hp->h_addrtype != AF_INET)
2052830Sdjl 		return (NSS_STR_PARSE_PARSE);
2062830Sdjl 
2072830Sdjl 	for (p = hp->h_addr_list; *p != 0; p++) {
2082830Sdjl 
2092830Sdjl 		if (p != hp->h_addr_list) {
2102830Sdjl 			*s = '\n';
2112830Sdjl 			s++;
2122830Sdjl 			l--;
2132830Sdjl 		}
2142830Sdjl 
2152830Sdjl 		if (hp->h_addrtype == AF_INET6) {
2162830Sdjl 			/* LINTED: E_BAD_PTR_CAST_ALIGN */
2172830Sdjl 			if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)*p)) {
2182830Sdjl 				/* LINTED: E_BAD_PTR_CAST_ALIGN */
2192830Sdjl 				IN6_V4MAPPED_TO_INADDR((struct in6_addr *)*p,
2202830Sdjl 							&in4);
2212830Sdjl 				af = AF_INET;
2222830Sdjl 				addr = &in4;
2232830Sdjl 			} else {
2242830Sdjl 				af = AF_INET6;
2252830Sdjl 				addr = *p;
2262830Sdjl 			}
2272830Sdjl 		} else {
2282830Sdjl 			af = AF_INET;
2292830Sdjl 			addr = *p;
2302830Sdjl 		}
2312830Sdjl 		res = inet_ntop(af, addr, obuf, sizeof (obuf));
2322830Sdjl 		if (res == NULL)
2332830Sdjl 			return (NSS_STR_PARSE_PARSE);
2342830Sdjl 
2352830Sdjl 		if ((n = snprintf(s, l, "%s %s", res, hp->h_name)) >= l)
2362830Sdjl 			return (NSS_STR_PARSE_ERANGE);
2372830Sdjl 		l -= n;
2382830Sdjl 		s += n;
2392830Sdjl 		if (p == hp->h_addr_list) {
2402830Sdjl 			for (q = hp->h_aliases; q && *q; q++) {
2412830Sdjl 				if ((n = snprintf(s, l, " %s", *q)) >= l)
2422830Sdjl 					return (NSS_STR_PARSE_ERANGE);
2432830Sdjl 				l -= n;
2442830Sdjl 				s += n;
2452830Sdjl 			}
2462830Sdjl 		}
2472830Sdjl 	}
2482830Sdjl 
2492830Sdjl 	ap->returnlen = s - ap->buf.buffer;
2502830Sdjl 	return (NSS_STR_PARSE_SUCCESS);
2512830Sdjl }
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate nss_backend_t *
2540Sstevel@tonic-gate _nss_dns_constr(dns_backend_op_t ops[], int n_ops)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate 	dns_backend_ptr_t	be;
2570Sstevel@tonic-gate 
2582830Sdjl 	if ((be = (dns_backend_ptr_t)malloc(sizeof (*be))) == 0)
2590Sstevel@tonic-gate 		return (0);
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	be->ops = ops;
2620Sstevel@tonic-gate 	be->n_ops = n_ops;
2632830Sdjl 	return ((nss_backend_t *)be);
2642830Sdjl }
2652830Sdjl 
266*3176Smichen /*
267*3176Smichen  * __res_ndestroy is a simplified version of the non-public function
268*3176Smichen  * res_ndestroy in libresolv.so.2. Before res_ndestroy can be made
269*3176Smichen  * public, __res_ndestroy will be used to make sure the memory pointed
270*3176Smichen  * by statp->_u._ext.ext is freed after res_nclose() is called.
271*3176Smichen  */
272*3176Smichen static void
273*3176Smichen __res_ndestroy(res_state statp) {
274*3176Smichen 	res_nclose(statp);
275*3176Smichen 	if (statp->_u._ext.ext != NULL)
276*3176Smichen 		free(statp->_u._ext.ext);
277*3176Smichen }
2782830Sdjl 
2792830Sdjl /*
2802830Sdjl  * nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode)
2812830Sdjl  *      nss2 get hosts/ipnodes with ttl backend DNS search engine.
2822830Sdjl  *
2832830Sdjl  * This API is given a pointer to a packed buffer, and the buffer size
2842830Sdjl  * It's job is to perform the appropriate res_nsearch, extract the
2852830Sdjl  * results and build a unmarshalled hosts/ipnodes result buffer.
2862830Sdjl  * Additionally in the extended results a nssuint_t ttl is placed.
2872830Sdjl  * This ttl is the lessor of the ttl's extracted from the result.
2882830Sdjl  *
2892830Sdjl  * ***Currently the first version of this API only performs simple
2902830Sdjl  *    single res_nsearch lookups for with T_A or T_AAAA results.
2912830Sdjl  *    Other searches are deferred to the generic API w/t ttls.
2922830Sdjl  *
2932830Sdjl  *    This function is not a generic res_* operation.  It only performs
2942830Sdjl  *    a single T_A or T_AAAA lookups***
2952830Sdjl  *
2962830Sdjl  * RETURNS:  NSS_SUCCESS or NSS_ERROR
2972830Sdjl  *	If an NSS_ERROR result is returned, nscd is expected
2982830Sdjl  *	to resubmit the gethosts request using the old style
2992830Sdjl  *	nsswitch lookup format.
3002830Sdjl  */
3012830Sdjl 
3022830Sdjl nss_status_t
3032830Sdjl _nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode)
3042830Sdjl {
3052830Sdjl 	/* nss buffer variables */
3062830Sdjl 	nss_pheader_t	*pbuf = (nss_pheader_t *)buffer;
3072830Sdjl 	nss_XbyY_args_t	arg;
3082830Sdjl 	char		*dbname;
3092830Sdjl 	int		dbop;
3102830Sdjl 	nss_status_t	sret;
3112830Sdjl 	size_t		bsize, blen;
3122830Sdjl 	char		*bptr;
3132830Sdjl 	/* resolver query variables */
3142924Smichen 	struct __res_state stat, *statp;	/* dns state block */
3152924Smichen 	union msg {
3162924Smichen 		uchar_t	buf[NS_MAXMSG];		/* max legal DNS answer size */
3172924Smichen 		HEADER	h;
3182924Smichen 	} resbuf;
3192924Smichen 	char aliases[NS_MAXMSG];		/* set of aliases */
3202830Sdjl 	const char	*name;
3212830Sdjl 	int		qtype;
3222830Sdjl 	/* answer parsing variables */
3232830Sdjl 	HEADER		*hp;
3242830Sdjl 	uchar_t		*cp;	/* current location in message */
3252830Sdjl 	uchar_t		*bom;	/* start of message */
3262830Sdjl 	uchar_t		*eom;	/* end of message */
3272830Sdjl 	uchar_t		*eor;	/* end of record */
3282830Sdjl 	int		ancount, qdcount;
3292830Sdjl 	int		type, class;
3302830Sdjl 	nssuint_t	nttl, ttl, *pttl;	/* The purpose of this API */
3312830Sdjl 	int		n, ret;
3322830Sdjl 	const char	*np;
3332830Sdjl 	/* temporary buffers */
3342830Sdjl 	char		nbuf[INET6_ADDRSTRLEN];	/* address parser */
3352830Sdjl 	char		host[MAXHOSTNAMELEN];	/* result host name */
3362830Sdjl 	char		ans[MAXHOSTNAMELEN];	/* record name */
3372830Sdjl 	char		aname[MAXHOSTNAMELEN];	/* alias result (C_NAME) */
3382830Sdjl 	/* misc variables */
3392830Sdjl 	int		af;
3402830Sdjl 	char		*ap, *apc;
3412830Sdjl 	int		hlen, alen, iplen, len;
3422830Sdjl 
3432924Smichen 	statp = &stat;
3442924Smichen 	(void) memset(statp, '\0', sizeof (struct __res_state));
3452924Smichen 	if (res_ninit(statp) == -1)
3462924Smichen 		return (NSS_ERROR);
3472924Smichen 
3482924Smichen 	ap = apc = (char *)aliases;
3492830Sdjl 	alen = 0;
3502830Sdjl 	ttl = (nssuint_t)0xFFFFFFF;		/* start w/max, find smaller */
3512830Sdjl 
3522830Sdjl 	/* save space for ttl otherwise, why bother... */
3532830Sdjl 	bsize = pbuf->data_len - sizeof (nssuint_t);
3542830Sdjl 	bptr = (char *)buffer + pbuf->data_off;
3552830Sdjl 	blen = 0;
3562830Sdjl 	sret = nss_packed_getkey(buffer, bufsize, &dbname, &dbop, &arg);
3572830Sdjl 	if (sret != NSS_SUCCESS) {
358*3176Smichen 		__res_ndestroy(statp);
3592830Sdjl 		return (NSS_ERROR);
3602830Sdjl 	}
3612830Sdjl 
3622830Sdjl 	if (ipnode) {
3632830Sdjl 		/* initially only handle the simple cases */
3642924Smichen 		if (arg.key.ipnode.flags != 0) {
365*3176Smichen 			__res_ndestroy(statp);
3662830Sdjl 			return (NSS_ERROR);
3672924Smichen 		}
3682830Sdjl 		name = arg.key.ipnode.name;
3692830Sdjl 		if (arg.key.ipnode.af_family == AF_INET6)
3702830Sdjl 			qtype = T_AAAA;
3712830Sdjl 		else
3722830Sdjl 			qtype = T_A;
3732830Sdjl 	} else {
3742830Sdjl 		name = arg.key.name;
3752830Sdjl 		qtype = T_A;
3762830Sdjl 	}
3772924Smichen 	ret = res_nsearch(statp, name, C_IN, qtype, resbuf.buf, NS_MAXMSG);
3782830Sdjl 	if (ret == -1) {
3792924Smichen 		if (statp->res_h_errno == HOST_NOT_FOUND) {
3802830Sdjl 			pbuf->p_herrno = HOST_NOT_FOUND;
3812830Sdjl 			pbuf->p_status = NSS_NOTFOUND;
3822830Sdjl 			pbuf->data_len = 0;
383*3176Smichen 			__res_ndestroy(statp);
3842830Sdjl 			return (NSS_NOTFOUND);
3852830Sdjl 		}
3862830Sdjl 		/* else lookup error - handle in general code */
387*3176Smichen 		__res_ndestroy(statp);
3882830Sdjl 		return (NSS_ERROR);
3892830Sdjl 	}
3902830Sdjl 
3912924Smichen 	cp = resbuf.buf;
3922924Smichen 	hp = (HEADER *)&resbuf.h;
3932830Sdjl 	bom = cp;
3942830Sdjl 	eom = cp + ret;
3952830Sdjl 
3962830Sdjl 	ancount = ntohs(hp->ancount);
3972830Sdjl 	qdcount = ntohs(hp->qdcount);
3982830Sdjl 	cp += HFIXEDSZ;
3992924Smichen 	if (qdcount != 1) {
400*3176Smichen 		__res_ndestroy(statp);
4012830Sdjl 		return (NSS_ERROR);
4022924Smichen 	}
4032830Sdjl 	n = dn_expand(bom, eom, cp, host, MAXHOSTNAMELEN);
4042830Sdjl 	if (n < 0) {
405*3176Smichen 		__res_ndestroy(statp);
4062830Sdjl 		return (NSS_ERROR);
4072830Sdjl 	} else
4082830Sdjl 		hlen = strlen(host);
4092830Sdjl 	cp += n + QFIXEDSZ;
4102924Smichen 	if (cp > eom) {
411*3176Smichen 		__res_ndestroy(statp);
4122830Sdjl 		return (NSS_ERROR);
4132924Smichen 	}
4142830Sdjl 	while (ancount-- > 0 && cp < eom && blen < bsize) {
4152830Sdjl 		n = dn_expand(bom, eom, cp, ans, MAXHOSTNAMELEN);
4162830Sdjl 		if (n > 0) {
4172924Smichen 			if (strncasecmp(host, ans, hlen) != 0) {
418*3176Smichen 				__res_ndestroy(statp);
4192830Sdjl 				return (NSS_ERROR);	/* spoof? */
4202924Smichen 			}
4212830Sdjl 		}
4222830Sdjl 		cp += n;
4232830Sdjl 		/* bounds check */
4242830Sdjl 		type = ns_get16(cp);			/* type */
4252830Sdjl 		cp += INT16SZ;
4262830Sdjl 		class = ns_get16(cp);			/* class */
4272830Sdjl 		cp += INT16SZ;
4282830Sdjl 		nttl = (nssuint_t)ns_get32(cp);	/* ttl in sec */
4292830Sdjl 		if (nttl < ttl)
4302830Sdjl 			ttl = nttl;
4312830Sdjl 		cp += INT32SZ;
4322830Sdjl 		n = ns_get16(cp);			/* len */
4332830Sdjl 		cp += INT16SZ;
4342830Sdjl 		if (class != C_IN) {
4352830Sdjl 			cp += n;
4362830Sdjl 			continue;
4372830Sdjl 		}
4382830Sdjl 		eor = cp + n;
4392830Sdjl 		if (type == T_CNAME) {
4402830Sdjl 			/* add an alias to the alias list */
4412830Sdjl 			n = dn_expand(bom, eor, cp, aname, MAXHOSTNAMELEN);
4422830Sdjl 			if (n > 0) {
4432830Sdjl 				len = strlen(aname);
4442830Sdjl 				if (len > 0) {
4452830Sdjl 					/*
4462830Sdjl 					 * Just error out if there is an
4472830Sdjl 					 * attempted buffer overflow exploit
4482830Sdjl 					 * generic code will do a syslog
4492830Sdjl 					 */
450*3176Smichen 					if (alen + len + 2 > NS_MAXMSG) {
451*3176Smichen 						__res_ndestroy(statp);
4522830Sdjl 						return (NSS_ERROR);
453*3176Smichen 					}
4542830Sdjl 					*apc++ = ' ';
4552830Sdjl 					alen++;
4562830Sdjl 					(void) strlcpy(apc, aname, len + 1);
4572830Sdjl 					alen += len;
4582830Sdjl 					apc += len;
4592830Sdjl 				}
4602830Sdjl 			}
4612830Sdjl 			cp += n;
4622830Sdjl 			continue;
4632830Sdjl 		}
4642830Sdjl 		if (type != qtype) {
4652830Sdjl 			cp += n;
4662830Sdjl 			continue;
4672830Sdjl 		}
4682830Sdjl 		/* check data size */
4692830Sdjl 		if ((type == T_A && n != INADDRSZ) ||
4702830Sdjl 		    (type == T_AAAA && n != IN6ADDRSZ)) {
4712830Sdjl 			cp += n;
4722830Sdjl 			continue;
4732830Sdjl 		}
4742830Sdjl 		af = (type == T_A ? AF_INET : AF_INET6);
4752830Sdjl 		np = inet_ntop(af, (void *)cp, nbuf, INET6_ADDRSTRLEN);
4762924Smichen 		if (np == NULL) {
477*3176Smichen 			__res_ndestroy(statp);
4782830Sdjl 			return (NSS_ERROR);
4792924Smichen 		}
4802830Sdjl 		cp += n;
4812830Sdjl 		/* append IP host aliases to results */
4822830Sdjl 		iplen = strlen(np);
4832830Sdjl 		/* ip <SP> hostname [<SP>][aliases] */
4842830Sdjl 		len = iplen + 2 + hlen + alen;
4852830Sdjl 		if (alen > 0)
4862830Sdjl 			len++;
487*3176Smichen 		if (blen + len > bsize) {
488*3176Smichen 			__res_ndestroy(statp);
4892830Sdjl 			return (NSS_ERROR);
490*3176Smichen 		}
4912830Sdjl 		(void) strlcpy(bptr, np, bsize - blen);
4922830Sdjl 		blen += iplen;
4932830Sdjl 		bptr += iplen;
4942830Sdjl 		*bptr++ = ' ';
4952830Sdjl 		blen++;
4962830Sdjl 		(void) strlcpy(bptr, host, bsize - blen);
4972830Sdjl 		blen += hlen;
4982830Sdjl 		bptr += hlen;
4992830Sdjl 		if (alen > 0) {
5002830Sdjl 			*bptr++ = ' ';
5012830Sdjl 			blen++;
5022830Sdjl 			(void) strlcpy(bptr, ap, bsize - blen);
5032830Sdjl 			blen += alen;
5042830Sdjl 			bptr += alen;
5052830Sdjl 		}
5062830Sdjl 		*bptr++ = '\n';
5072830Sdjl 		blen++;
5082830Sdjl 	}
5092830Sdjl 	/* Presumably the buffer is now filled. */
5102830Sdjl 	len = ROUND_UP(blen, sizeof (nssuint_t));
5112830Sdjl 	/* still room? */
5122830Sdjl 	if (len + sizeof (nssuint_t) > pbuf->data_len) {
5132830Sdjl 		/* sigh, no, what happened? */
514*3176Smichen 		__res_ndestroy(statp);
5152830Sdjl 		return (NSS_ERROR);
5162830Sdjl 	}
5172830Sdjl 	pbuf->ext_off = pbuf->data_off + len;
5182830Sdjl 	pbuf->ext_len = sizeof (nssuint_t);
5192830Sdjl 	pbuf->data_len = blen;
5202830Sdjl 	pttl = (nssuint_t *)((void *)((char *)pbuf + pbuf->ext_off));
5212830Sdjl 	*pttl = ttl;
522*3176Smichen 	__res_ndestroy(statp);
5232830Sdjl 	return (NSS_SUCCESS);
5242830Sdjl }
525