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.
23*2830Sdjl  * Use is subject to license terms.
24*2830Sdjl  */
25*2830Sdjl 
26*2830Sdjl #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*2830Sdjl 
28*2830Sdjl /*
290Sstevel@tonic-gate  *	dns_common.c
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
32*2830Sdjl #include "dns_common.h"
330Sstevel@tonic-gate 
34*2830Sdjl #pragma weak	dn_expand
35*2830Sdjl #pragma weak	res_ninit
36*2830Sdjl #pragma weak	res_nsearch
37*2830Sdjl #pragma weak	res_nclose
38*2830Sdjl #pragma weak	ns_get16
39*2830Sdjl #pragma weak	ns_get32
40*2830Sdjl #pragma weak	__ns_get16
41*2830Sdjl #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) {
71*2830Sdjl 			/* LINTED: E_BAD_PTR_CAST_ALIGN */
72*2830Sdjl 			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;
110*2830Sdjl 	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) {
128*2830Sdjl 		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 
166*2830Sdjl /*
167*2830Sdjl  * Convert the hostent structure into string in the following
168*2830Sdjl  * format:
169*2830Sdjl  *
170*2830Sdjl  * IP-address official-host-name nicknames ...
171*2830Sdjl  *
172*2830Sdjl  * If more than one IP-addresses matches the official-host-name,
173*2830Sdjl  * the above line will be followed by:
174*2830Sdjl  * IP-address-1 official-host-name
175*2830Sdjl  * IP-address-2 official-host-name
176*2830Sdjl  * ...
177*2830Sdjl  *
178*2830Sdjl  * This is so that the str2hostent function in libnsl
179*2830Sdjl  * can convert the string back to the original hostent
180*2830Sdjl  * data.
181*2830Sdjl  */
182*2830Sdjl int
183*2830Sdjl ent2str(
184*2830Sdjl 	struct hostent	*hp,
185*2830Sdjl 	nss_XbyY_args_t *ap,
186*2830Sdjl 	int		af_type)
187*2830Sdjl {
188*2830Sdjl 	char		**p;
189*2830Sdjl 	char		obuf[INET6_ADDRSTRLEN];
190*2830Sdjl 	void		*addr;
191*2830Sdjl 	struct in_addr	in4;
192*2830Sdjl 	int		af;
193*2830Sdjl 	int		n;
194*2830Sdjl 	const char	*res;
195*2830Sdjl 	char		**q;
196*2830Sdjl 	int		l = ap->buf.buflen;
197*2830Sdjl 	char		*s = ap->buf.buffer;
198*2830Sdjl 
199*2830Sdjl 	/*
200*2830Sdjl 	 * for "hosts" lookup, we only want address type of
201*2830Sdjl 	 * AF_INET. For "ipnodes", we can have both AF_INET
202*2830Sdjl 	 * and AF_INET6.
203*2830Sdjl 	 */
204*2830Sdjl 	if (af_type == AF_INET && hp->h_addrtype != AF_INET)
205*2830Sdjl 		return (NSS_STR_PARSE_PARSE);
206*2830Sdjl 
207*2830Sdjl 	for (p = hp->h_addr_list; *p != 0; p++) {
208*2830Sdjl 
209*2830Sdjl 		if (p != hp->h_addr_list) {
210*2830Sdjl 			*s = '\n';
211*2830Sdjl 			s++;
212*2830Sdjl 			l--;
213*2830Sdjl 		}
214*2830Sdjl 
215*2830Sdjl 		if (hp->h_addrtype == AF_INET6) {
216*2830Sdjl 			/* LINTED: E_BAD_PTR_CAST_ALIGN */
217*2830Sdjl 			if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)*p)) {
218*2830Sdjl 				/* LINTED: E_BAD_PTR_CAST_ALIGN */
219*2830Sdjl 				IN6_V4MAPPED_TO_INADDR((struct in6_addr *)*p,
220*2830Sdjl 							&in4);
221*2830Sdjl 				af = AF_INET;
222*2830Sdjl 				addr = &in4;
223*2830Sdjl 			} else {
224*2830Sdjl 				af = AF_INET6;
225*2830Sdjl 				addr = *p;
226*2830Sdjl 			}
227*2830Sdjl 		} else {
228*2830Sdjl 			af = AF_INET;
229*2830Sdjl 			addr = *p;
230*2830Sdjl 		}
231*2830Sdjl 		res = inet_ntop(af, addr, obuf, sizeof (obuf));
232*2830Sdjl 		if (res == NULL)
233*2830Sdjl 			return (NSS_STR_PARSE_PARSE);
234*2830Sdjl 
235*2830Sdjl 		if ((n = snprintf(s, l, "%s %s", res, hp->h_name)) >= l)
236*2830Sdjl 			return (NSS_STR_PARSE_ERANGE);
237*2830Sdjl 		l -= n;
238*2830Sdjl 		s += n;
239*2830Sdjl 		if (p == hp->h_addr_list) {
240*2830Sdjl 			for (q = hp->h_aliases; q && *q; q++) {
241*2830Sdjl 				if ((n = snprintf(s, l, " %s", *q)) >= l)
242*2830Sdjl 					return (NSS_STR_PARSE_ERANGE);
243*2830Sdjl 				l -= n;
244*2830Sdjl 				s += n;
245*2830Sdjl 			}
246*2830Sdjl 		}
247*2830Sdjl 	}
248*2830Sdjl 
249*2830Sdjl 	ap->returnlen = s - ap->buf.buffer;
250*2830Sdjl 	return (NSS_STR_PARSE_SUCCESS);
251*2830Sdjl }
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 
258*2830Sdjl 	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;
263*2830Sdjl 	return ((nss_backend_t *)be);
264*2830Sdjl }
265*2830Sdjl 
266*2830Sdjl 
267*2830Sdjl /*
268*2830Sdjl  * nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode)
269*2830Sdjl  *      nss2 get hosts/ipnodes with ttl backend DNS search engine.
270*2830Sdjl  *
271*2830Sdjl  * This API is given a pointer to a packed buffer, and the buffer size
272*2830Sdjl  * It's job is to perform the appropriate res_nsearch, extract the
273*2830Sdjl  * results and build a unmarshalled hosts/ipnodes result buffer.
274*2830Sdjl  * Additionally in the extended results a nssuint_t ttl is placed.
275*2830Sdjl  * This ttl is the lessor of the ttl's extracted from the result.
276*2830Sdjl  *
277*2830Sdjl  * ***Currently the first version of this API only performs simple
278*2830Sdjl  *    single res_nsearch lookups for with T_A or T_AAAA results.
279*2830Sdjl  *    Other searches are deferred to the generic API w/t ttls.
280*2830Sdjl  *
281*2830Sdjl  *    This function is not a generic res_* operation.  It only performs
282*2830Sdjl  *    a single T_A or T_AAAA lookups***
283*2830Sdjl  *
284*2830Sdjl  * RETURNS:  NSS_SUCCESS or NSS_ERROR
285*2830Sdjl  *	If an NSS_ERROR result is returned, nscd is expected
286*2830Sdjl  *	to resubmit the gethosts request using the old style
287*2830Sdjl  *	nsswitch lookup format.
288*2830Sdjl  */
289*2830Sdjl 
290*2830Sdjl struct tsd_priv {
291*2830Sdjl 	struct __res_state *statp;	/* dns state block */
292*2830Sdjl 	union msg {
293*2830Sdjl 		uchar_t	buf[NS_MAXMSG];	/* max legal DNS answer size */
294*2830Sdjl 		HEADER	h;
295*2830Sdjl 	} resbuf;
296*2830Sdjl 	char aliases[NS_MAXMSG];	/* set of aliases */
297*2830Sdjl };
298*2830Sdjl 
299*2830Sdjl static void ghttlcleanup(void *ptr)
300*2830Sdjl {
301*2830Sdjl 	struct tsd_priv	*priv = (struct tsd_priv *)ptr;
302*2830Sdjl 
303*2830Sdjl 	if (priv) {
304*2830Sdjl 		if (priv->statp != NULL) {
305*2830Sdjl 			res_nclose(priv->statp);
306*2830Sdjl 			free((void *)priv->statp);
307*2830Sdjl 		}
308*2830Sdjl 		free(ptr);
309*2830Sdjl 	}
3100Sstevel@tonic-gate }
311*2830Sdjl 
312*2830Sdjl nss_status_t
313*2830Sdjl _nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode)
314*2830Sdjl {
315*2830Sdjl 	/* nss buffer variables */
316*2830Sdjl 	nss_pheader_t	*pbuf = (nss_pheader_t *)buffer;
317*2830Sdjl 	nss_XbyY_args_t	arg;
318*2830Sdjl 	char		*dbname;
319*2830Sdjl 	int		dbop;
320*2830Sdjl 	nss_status_t	sret;
321*2830Sdjl 	size_t		bsize, blen;
322*2830Sdjl 	char		*bptr;
323*2830Sdjl 	/* resolver query variables */
324*2830Sdjl 	static mutex_t		keylock;
325*2830Sdjl 	static thread_key_t	key;
326*2830Sdjl 	static int		once_per_keyname = 0;
327*2830Sdjl 	struct tsd_priv		*tsd = NULL;
328*2830Sdjl 	const char	*name;
329*2830Sdjl 	int		qtype;
330*2830Sdjl 	/* answer parsing variables */
331*2830Sdjl 	HEADER		*hp;
332*2830Sdjl 	uchar_t		*cp;	/* current location in message */
333*2830Sdjl 	uchar_t		*bom;	/* start of message */
334*2830Sdjl 	uchar_t		*eom;	/* end of message */
335*2830Sdjl 	uchar_t		*eor;	/* end of record */
336*2830Sdjl 	int		ancount, qdcount;
337*2830Sdjl 	int		type, class;
338*2830Sdjl 	nssuint_t	nttl, ttl, *pttl;	/* The purpose of this API */
339*2830Sdjl 	int		n, ret;
340*2830Sdjl 	const char	*np;
341*2830Sdjl 	/* temporary buffers */
342*2830Sdjl 	char		nbuf[INET6_ADDRSTRLEN];	/* address parser */
343*2830Sdjl 	char		host[MAXHOSTNAMELEN];	/* result host name */
344*2830Sdjl 	char		ans[MAXHOSTNAMELEN];	/* record name */
345*2830Sdjl 	char		aname[MAXHOSTNAMELEN];	/* alias result (C_NAME) */
346*2830Sdjl 	/* misc variables */
347*2830Sdjl 	int		af;
348*2830Sdjl 	char		*ap, *apc;
349*2830Sdjl 	int		hlen, alen, iplen, len;
350*2830Sdjl 
351*2830Sdjl 	if (!once_per_keyname) {
352*2830Sdjl 		(void) mutex_lock(&keylock);
353*2830Sdjl 		if (!once_per_keyname) {
354*2830Sdjl 			(void) thr_keycreate(&key, ghttlcleanup);
355*2830Sdjl 			once_per_keyname++;
356*2830Sdjl 		}
357*2830Sdjl 		(void) mutex_unlock(&keylock);
358*2830Sdjl 	}
359*2830Sdjl 	(void) thr_getspecific(key, (void **)&tsd);
360*2830Sdjl 	if (tsd == NULL) {
361*2830Sdjl 		tsd = (struct tsd_priv *)calloc(1, sizeof (struct tsd_priv));
362*2830Sdjl 		(void) thr_setspecific(key, (void *)tsd);
363*2830Sdjl 		(void) thr_getspecific(key, (void **)&tsd);
364*2830Sdjl 		tsd->statp = (struct __res_state *)
365*2830Sdjl 				calloc(1, sizeof (struct __res_state));
366*2830Sdjl 		if (tsd->statp == NULL)
367*2830Sdjl 			return (NSS_ERROR);
368*2830Sdjl 		if (res_ninit(tsd->statp) == -1) {
369*2830Sdjl 			free(tsd->statp);
370*2830Sdjl 			return (NSS_ERROR);
371*2830Sdjl 		}
372*2830Sdjl 	}
373*2830Sdjl 	ap = apc = (char *)tsd->aliases;
374*2830Sdjl 	alen = 0;
375*2830Sdjl 	ttl = (nssuint_t)0xFFFFFFF;		/* start w/max, find smaller */
376*2830Sdjl 
377*2830Sdjl 	/* save space for ttl otherwise, why bother... */
378*2830Sdjl 	bsize = pbuf->data_len - sizeof (nssuint_t);
379*2830Sdjl 	bptr = (char *)buffer + pbuf->data_off;
380*2830Sdjl 	blen = 0;
381*2830Sdjl 	sret = nss_packed_getkey(buffer, bufsize, &dbname, &dbop, &arg);
382*2830Sdjl 	if (sret != NSS_SUCCESS) {
383*2830Sdjl 		return (NSS_ERROR);
384*2830Sdjl 	}
385*2830Sdjl 
386*2830Sdjl 	if (ipnode) {
387*2830Sdjl 		/* initially only handle the simple cases */
388*2830Sdjl 		if (arg.key.ipnode.flags != 0)
389*2830Sdjl 			return (NSS_ERROR);
390*2830Sdjl 		name = arg.key.ipnode.name;
391*2830Sdjl 		if (arg.key.ipnode.af_family == AF_INET6)
392*2830Sdjl 			qtype = T_AAAA;
393*2830Sdjl 		else
394*2830Sdjl 			qtype = T_A;
395*2830Sdjl 	} else {
396*2830Sdjl 		name = arg.key.name;
397*2830Sdjl 		qtype = T_A;
398*2830Sdjl 	}
399*2830Sdjl 	ret = res_nsearch(tsd->statp, name, C_IN, qtype,
400*2830Sdjl 				tsd->resbuf.buf, NS_MAXMSG);
401*2830Sdjl 	if (ret == -1) {
402*2830Sdjl 		if (tsd->statp->res_h_errno == HOST_NOT_FOUND) {
403*2830Sdjl 			pbuf->p_herrno = HOST_NOT_FOUND;
404*2830Sdjl 			pbuf->p_status = NSS_NOTFOUND;
405*2830Sdjl 			pbuf->data_len = 0;
406*2830Sdjl 			return (NSS_NOTFOUND);
407*2830Sdjl 		}
408*2830Sdjl 		/* else lookup error - handle in general code */
409*2830Sdjl 		return (NSS_ERROR);
410*2830Sdjl 	}
411*2830Sdjl 
412*2830Sdjl 	cp = tsd->resbuf.buf;
413*2830Sdjl 	hp = (HEADER *)&tsd->resbuf.h;
414*2830Sdjl 	bom = cp;
415*2830Sdjl 	eom = cp + ret;
416*2830Sdjl 
417*2830Sdjl 	ancount = ntohs(hp->ancount);
418*2830Sdjl 	qdcount = ntohs(hp->qdcount);
419*2830Sdjl 	cp += HFIXEDSZ;
420*2830Sdjl 	if (qdcount != 1)
421*2830Sdjl 		return (NSS_ERROR);
422*2830Sdjl 	n = dn_expand(bom, eom, cp, host, MAXHOSTNAMELEN);
423*2830Sdjl 	if (n < 0) {
424*2830Sdjl 		return (NSS_ERROR);
425*2830Sdjl 	} else
426*2830Sdjl 		hlen = strlen(host);
427*2830Sdjl 	cp += n + QFIXEDSZ;
428*2830Sdjl 	if (cp > eom)
429*2830Sdjl 		return (NSS_ERROR);
430*2830Sdjl 	while (ancount-- > 0 && cp < eom && blen < bsize) {
431*2830Sdjl 		n = dn_expand(bom, eom, cp, ans, MAXHOSTNAMELEN);
432*2830Sdjl 		if (n > 0) {
433*2830Sdjl 			if (strncasecmp(host, ans, hlen) != 0)
434*2830Sdjl 				return (NSS_ERROR);	/* spoof? */
435*2830Sdjl 		}
436*2830Sdjl 		cp += n;
437*2830Sdjl 		/* bounds check */
438*2830Sdjl 		type = ns_get16(cp);			/* type */
439*2830Sdjl 		cp += INT16SZ;
440*2830Sdjl 		class = ns_get16(cp);			/* class */
441*2830Sdjl 		cp += INT16SZ;
442*2830Sdjl 		nttl = (nssuint_t)ns_get32(cp);	/* ttl in sec */
443*2830Sdjl 		if (nttl < ttl)
444*2830Sdjl 			ttl = nttl;
445*2830Sdjl 		cp += INT32SZ;
446*2830Sdjl 		n = ns_get16(cp);			/* len */
447*2830Sdjl 		cp += INT16SZ;
448*2830Sdjl 		if (class != C_IN) {
449*2830Sdjl 			cp += n;
450*2830Sdjl 			continue;
451*2830Sdjl 		}
452*2830Sdjl 		eor = cp + n;
453*2830Sdjl 		if (type == T_CNAME) {
454*2830Sdjl 			/* add an alias to the alias list */
455*2830Sdjl 			n = dn_expand(bom, eor, cp, aname, MAXHOSTNAMELEN);
456*2830Sdjl 			if (n > 0) {
457*2830Sdjl 				len = strlen(aname);
458*2830Sdjl 				if (len > 0) {
459*2830Sdjl 					/*
460*2830Sdjl 					 * Just error out if there is an
461*2830Sdjl 					 * attempted buffer overflow exploit
462*2830Sdjl 					 * generic code will do a syslog
463*2830Sdjl 					 */
464*2830Sdjl 					if (alen + len + 2 > NS_MAXMSG)
465*2830Sdjl 						return (NSS_ERROR);
466*2830Sdjl 					*apc++ = ' ';
467*2830Sdjl 					alen++;
468*2830Sdjl 					(void) strlcpy(apc, aname, len + 1);
469*2830Sdjl 					alen += len;
470*2830Sdjl 					apc += len;
471*2830Sdjl 				}
472*2830Sdjl 			}
473*2830Sdjl 			cp += n;
474*2830Sdjl 			continue;
475*2830Sdjl 		}
476*2830Sdjl 		if (type != qtype) {
477*2830Sdjl 			cp += n;
478*2830Sdjl 			continue;
479*2830Sdjl 		}
480*2830Sdjl 		/* check data size */
481*2830Sdjl 		if ((type == T_A && n != INADDRSZ) ||
482*2830Sdjl 		    (type == T_AAAA && n != IN6ADDRSZ)) {
483*2830Sdjl 			cp += n;
484*2830Sdjl 			continue;
485*2830Sdjl 		}
486*2830Sdjl 		af = (type == T_A ? AF_INET : AF_INET6);
487*2830Sdjl 		np = inet_ntop(af, (void *)cp, nbuf, INET6_ADDRSTRLEN);
488*2830Sdjl 		if (np == NULL)
489*2830Sdjl 			return (NSS_ERROR);
490*2830Sdjl 		cp += n;
491*2830Sdjl 		/* append IP host aliases to results */
492*2830Sdjl 		iplen = strlen(np);
493*2830Sdjl 		/* ip <SP> hostname [<SP>][aliases] */
494*2830Sdjl 		len = iplen + 2 + hlen + alen;
495*2830Sdjl 		if (alen > 0)
496*2830Sdjl 			len++;
497*2830Sdjl 		if (blen + len > bsize)
498*2830Sdjl 			return (NSS_ERROR);
499*2830Sdjl 		(void) strlcpy(bptr, np, bsize - blen);
500*2830Sdjl 		blen += iplen;
501*2830Sdjl 		bptr += iplen;
502*2830Sdjl 		*bptr++ = ' ';
503*2830Sdjl 		blen++;
504*2830Sdjl 		(void) strlcpy(bptr, host, bsize - blen);
505*2830Sdjl 		blen += hlen;
506*2830Sdjl 		bptr += hlen;
507*2830Sdjl 		if (alen > 0) {
508*2830Sdjl 			*bptr++ = ' ';
509*2830Sdjl 			blen++;
510*2830Sdjl 			(void) strlcpy(bptr, ap, bsize - blen);
511*2830Sdjl 			blen += alen;
512*2830Sdjl 			bptr += alen;
513*2830Sdjl 		}
514*2830Sdjl 		*bptr++ = '\n';
515*2830Sdjl 		blen++;
516*2830Sdjl 	}
517*2830Sdjl 	/* Presumably the buffer is now filled. */
518*2830Sdjl 	len = ROUND_UP(blen, sizeof (nssuint_t));
519*2830Sdjl 	/* still room? */
520*2830Sdjl 	if (len + sizeof (nssuint_t) > pbuf->data_len) {
521*2830Sdjl 		/* sigh, no, what happened? */
522*2830Sdjl 		return (NSS_ERROR);
523*2830Sdjl 	}
524*2830Sdjl 	pbuf->ext_off = pbuf->data_off + len;
525*2830Sdjl 	pbuf->ext_len = sizeof (nssuint_t);
526*2830Sdjl 	pbuf->data_len = blen;
527*2830Sdjl 	pttl = (nssuint_t *)((void *)((char *)pbuf + pbuf->ext_off));
528*2830Sdjl 	*pttl = ttl;
529*2830Sdjl 	return (NSS_SUCCESS);
530*2830Sdjl }
531