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 /*
22*10544SStacey.Marshall@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
232830Sdjl  * Use is subject to license terms.
242830Sdjl  */
252830Sdjl 
262830Sdjl /*
270Sstevel@tonic-gate  *	dns_common.c
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
302830Sdjl #include "dns_common.h"
310Sstevel@tonic-gate 
322830Sdjl #pragma weak	dn_expand
332830Sdjl #pragma weak	res_ninit
342830Sdjl #pragma weak	res_nsearch
352830Sdjl #pragma weak	res_nclose
362830Sdjl #pragma weak	ns_get16
372830Sdjl #pragma weak	ns_get32
382830Sdjl #pragma weak	__ns_get16
392830Sdjl #pragma weak	__ns_get32
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #define	DNS_ALIASES	0
420Sstevel@tonic-gate #define	DNS_ADDRLIST	1
430Sstevel@tonic-gate #define	DNS_MAPDLIST	2
440Sstevel@tonic-gate 
456666Ssm26363 #ifndef	tolower
466666Ssm26363 #define	tolower(c) ((c) >= 'A' && (c) <= 'Z' ? (c) | 0x20 : (c))
476666Ssm26363 #endif
486666Ssm26363 
490Sstevel@tonic-gate static int
500Sstevel@tonic-gate dns_netdb_aliases(from_list, to_list, aliaspp, type, count, af_type)
510Sstevel@tonic-gate 	char	**from_list, **to_list,	**aliaspp;
520Sstevel@tonic-gate 	int	type, *count, af_type;
530Sstevel@tonic-gate {
540Sstevel@tonic-gate 	char		*fstr;
550Sstevel@tonic-gate 	int		cnt = 0;
560Sstevel@tonic-gate 	size_t		len;
570Sstevel@tonic-gate 
580Sstevel@tonic-gate 	*count = 0;
590Sstevel@tonic-gate 	if ((char *)to_list >= *aliaspp)
600Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
610Sstevel@tonic-gate 
620Sstevel@tonic-gate 	for (fstr = from_list[cnt]; fstr != NULL; fstr = from_list[cnt]) {
630Sstevel@tonic-gate 		if (type == DNS_ALIASES)
640Sstevel@tonic-gate 			len = strlen(fstr) + 1;
650Sstevel@tonic-gate 		else
660Sstevel@tonic-gate 			len = (af_type == AF_INET) ? sizeof (struct in_addr)
670Sstevel@tonic-gate 						: sizeof (struct in6_addr);
680Sstevel@tonic-gate 		*aliaspp -= len;
690Sstevel@tonic-gate 		to_list[cnt] = *aliaspp;
700Sstevel@tonic-gate 		if (*aliaspp <= (char *)&to_list[cnt+1])
710Sstevel@tonic-gate 			return (NSS_STR_PARSE_ERANGE);
720Sstevel@tonic-gate 		if (type == DNS_MAPDLIST) {
732830Sdjl 			/* LINTED: E_BAD_PTR_CAST_ALIGN */
742830Sdjl 			struct in6_addr *addr6p = (struct in6_addr *)*aliaspp;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 			(void) memset(addr6p, '\0', sizeof (struct in6_addr));
770Sstevel@tonic-gate 			(void) memcpy(&addr6p->s6_addr[12], fstr,
780Sstevel@tonic-gate 					sizeof (struct in_addr));
790Sstevel@tonic-gate 			addr6p->s6_addr[10] = 0xffU;
800Sstevel@tonic-gate 			addr6p->s6_addr[11] = 0xffU;
810Sstevel@tonic-gate 			++cnt;
820Sstevel@tonic-gate 		} else {
830Sstevel@tonic-gate 			(void) memcpy (*aliaspp, fstr, len);
840Sstevel@tonic-gate 			++cnt;
850Sstevel@tonic-gate 		}
860Sstevel@tonic-gate 	}
870Sstevel@tonic-gate 	to_list[cnt] = NULL;
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 	*count = cnt;
900Sstevel@tonic-gate 	if (cnt == 0)
910Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	return (NSS_STR_PARSE_SUCCESS);
940Sstevel@tonic-gate }
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 
970Sstevel@tonic-gate int
980Sstevel@tonic-gate ent2result(he, argp, af_type)
990Sstevel@tonic-gate 	struct hostent		*he;
1000Sstevel@tonic-gate 	nss_XbyY_args_t		*argp;
1010Sstevel@tonic-gate 	int			af_type;
1020Sstevel@tonic-gate {
1030Sstevel@tonic-gate 	char		*buffer, *limit;
1040Sstevel@tonic-gate 	int		buflen = argp->buf.buflen;
1050Sstevel@tonic-gate 	int		ret, count;
1060Sstevel@tonic-gate 	size_t len;
1070Sstevel@tonic-gate 	struct hostent 	*host;
1080Sstevel@tonic-gate 	struct in_addr	*addrp;
1090Sstevel@tonic-gate 	struct in6_addr	*addrp6;
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 	limit = argp->buf.buffer + buflen;
1122830Sdjl 	host = (struct hostent *)argp->buf.result;
1130Sstevel@tonic-gate 	buffer = argp->buf.buffer;
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	/* h_addrtype and h_length */
1160Sstevel@tonic-gate 	host->h_addrtype = af_type;
1170Sstevel@tonic-gate 	host->h_length = (af_type == AF_INET) ? sizeof (struct in_addr)
1180Sstevel@tonic-gate 					: sizeof (struct in6_addr);
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	/* h_name */
1210Sstevel@tonic-gate 	len = strlen(he->h_name) + 1;
1220Sstevel@tonic-gate 	host->h_name = buffer;
1230Sstevel@tonic-gate 	if (host->h_name + len >= limit)
1240Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
1250Sstevel@tonic-gate 	(void) memcpy(host->h_name, he->h_name, len);
1260Sstevel@tonic-gate 	buffer += len;
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	/* h_addr_list */
1290Sstevel@tonic-gate 	if (af_type == AF_INET) {
1302830Sdjl 		addrp = (struct in_addr *)ROUND_DOWN(limit, sizeof (*addrp));
1310Sstevel@tonic-gate 		host->h_addr_list = (char **)
1320Sstevel@tonic-gate 				ROUND_UP(buffer, sizeof (char **));
1330Sstevel@tonic-gate 		ret = dns_netdb_aliases(he->h_addr_list, host->h_addr_list,
1340Sstevel@tonic-gate 			(char **)&addrp, DNS_ADDRLIST, &count, af_type);
1350Sstevel@tonic-gate 		if (ret != NSS_STR_PARSE_SUCCESS)
1360Sstevel@tonic-gate 			return (ret);
1370Sstevel@tonic-gate 		/* h_aliases */
1380Sstevel@tonic-gate 		host->h_aliases = host->h_addr_list + count + 1;
1390Sstevel@tonic-gate 		ret = dns_netdb_aliases(he->h_aliases, host->h_aliases,
1400Sstevel@tonic-gate 			(char **)&addrp, DNS_ALIASES, &count, af_type);
1410Sstevel@tonic-gate 	} else {
1420Sstevel@tonic-gate 		addrp6 = (struct in6_addr *)
1430Sstevel@tonic-gate 			ROUND_DOWN(limit, sizeof (*addrp6));
1440Sstevel@tonic-gate 		host->h_addr_list = (char **)
1450Sstevel@tonic-gate 			ROUND_UP(buffer, sizeof (char **));
1460Sstevel@tonic-gate 		if (he->h_addrtype == AF_INET && af_type == AF_INET6) {
1470Sstevel@tonic-gate 			ret = dns_netdb_aliases(he->h_addr_list,
1480Sstevel@tonic-gate 				host->h_addr_list, (char **)&addrp6,
1490Sstevel@tonic-gate 				DNS_MAPDLIST, &count, af_type);
1500Sstevel@tonic-gate 		} else {
1510Sstevel@tonic-gate 			ret = dns_netdb_aliases(he->h_addr_list,
1520Sstevel@tonic-gate 				host->h_addr_list, (char **)&addrp6,
1530Sstevel@tonic-gate 				DNS_ADDRLIST, &count, af_type);
1540Sstevel@tonic-gate 		}
1550Sstevel@tonic-gate 		if (ret != NSS_STR_PARSE_SUCCESS)
1560Sstevel@tonic-gate 			return (ret);
1570Sstevel@tonic-gate 		/* h_aliases */
1580Sstevel@tonic-gate 		host->h_aliases = host->h_addr_list + count + 1;
1590Sstevel@tonic-gate 		ret = dns_netdb_aliases(he->h_aliases, host->h_aliases,
1600Sstevel@tonic-gate 			(char **)&addrp6, DNS_ALIASES, &count, af_type);
1610Sstevel@tonic-gate 	}
1620Sstevel@tonic-gate 	if (ret == NSS_STR_PARSE_PARSE)
1630Sstevel@tonic-gate 		ret = NSS_STR_PARSE_SUCCESS;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	return (ret);
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate 
1682830Sdjl /*
1692830Sdjl  * Convert the hostent structure into string in the following
1702830Sdjl  * format:
1712830Sdjl  *
1722830Sdjl  * IP-address official-host-name nicknames ...
1732830Sdjl  *
1742830Sdjl  * If more than one IP-addresses matches the official-host-name,
1752830Sdjl  * the above line will be followed by:
1762830Sdjl  * IP-address-1 official-host-name
1772830Sdjl  * IP-address-2 official-host-name
1782830Sdjl  * ...
1792830Sdjl  *
1802830Sdjl  * This is so that the str2hostent function in libnsl
1812830Sdjl  * can convert the string back to the original hostent
1822830Sdjl  * data.
1832830Sdjl  */
1842830Sdjl int
1852830Sdjl ent2str(
1862830Sdjl 	struct hostent	*hp,
1872830Sdjl 	nss_XbyY_args_t *ap,
1882830Sdjl 	int		af_type)
1892830Sdjl {
1902830Sdjl 	char		**p;
1912830Sdjl 	char		obuf[INET6_ADDRSTRLEN];
1922830Sdjl 	void		*addr;
1932830Sdjl 	struct in_addr	in4;
1942830Sdjl 	int		af;
1952830Sdjl 	int		n;
1962830Sdjl 	const char	*res;
1972830Sdjl 	char		**q;
1982830Sdjl 	int		l = ap->buf.buflen;
1992830Sdjl 	char		*s = ap->buf.buffer;
2002830Sdjl 
2012830Sdjl 	/*
2022830Sdjl 	 * for "hosts" lookup, we only want address type of
2032830Sdjl 	 * AF_INET. For "ipnodes", we can have both AF_INET
2042830Sdjl 	 * and AF_INET6.
2052830Sdjl 	 */
2062830Sdjl 	if (af_type == AF_INET && hp->h_addrtype != AF_INET)
2072830Sdjl 		return (NSS_STR_PARSE_PARSE);
2082830Sdjl 
2092830Sdjl 	for (p = hp->h_addr_list; *p != 0; p++) {
2102830Sdjl 
2112830Sdjl 		if (p != hp->h_addr_list) {
2122830Sdjl 			*s = '\n';
2132830Sdjl 			s++;
2142830Sdjl 			l--;
2152830Sdjl 		}
2162830Sdjl 
2172830Sdjl 		if (hp->h_addrtype == AF_INET6) {
2182830Sdjl 			/* LINTED: E_BAD_PTR_CAST_ALIGN */
2192830Sdjl 			if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)*p)) {
2202830Sdjl 				/* LINTED: E_BAD_PTR_CAST_ALIGN */
2212830Sdjl 				IN6_V4MAPPED_TO_INADDR((struct in6_addr *)*p,
2225161Smichen 				    &in4);
2232830Sdjl 				af = AF_INET;
2242830Sdjl 				addr = &in4;
2252830Sdjl 			} else {
2262830Sdjl 				af = AF_INET6;
2272830Sdjl 				addr = *p;
2282830Sdjl 			}
2292830Sdjl 		} else {
2302830Sdjl 			af = AF_INET;
2312830Sdjl 			addr = *p;
2322830Sdjl 		}
2332830Sdjl 		res = inet_ntop(af, addr, obuf, sizeof (obuf));
2342830Sdjl 		if (res == NULL)
2352830Sdjl 			return (NSS_STR_PARSE_PARSE);
2362830Sdjl 
2375161Smichen 		if ((n = snprintf(s, l, "%s", res)) >= l)
2382830Sdjl 			return (NSS_STR_PARSE_ERANGE);
2392830Sdjl 		l -= n;
2402830Sdjl 		s += n;
2415161Smichen 		if (hp->h_name != NULL && *hp->h_name != '\0') {
2425161Smichen 			if ((n = snprintf(s, l, " %s", hp->h_name)) >= l)
2435161Smichen 				return (NSS_STR_PARSE_ERANGE);
2445161Smichen 			l -= n;
2455161Smichen 			s += n;
2465161Smichen 		}
2472830Sdjl 		if (p == hp->h_addr_list) {
2482830Sdjl 			for (q = hp->h_aliases; q && *q; q++) {
2492830Sdjl 				if ((n = snprintf(s, l, " %s", *q)) >= l)
2502830Sdjl 					return (NSS_STR_PARSE_ERANGE);
2512830Sdjl 				l -= n;
2522830Sdjl 				s += n;
2532830Sdjl 			}
2542830Sdjl 		}
2552830Sdjl 	}
2562830Sdjl 
2572830Sdjl 	ap->returnlen = s - ap->buf.buffer;
2582830Sdjl 	return (NSS_STR_PARSE_SUCCESS);
2592830Sdjl }
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate nss_backend_t *
2620Sstevel@tonic-gate _nss_dns_constr(dns_backend_op_t ops[], int n_ops)
2630Sstevel@tonic-gate {
2640Sstevel@tonic-gate 	dns_backend_ptr_t	be;
2650Sstevel@tonic-gate 
2662830Sdjl 	if ((be = (dns_backend_ptr_t)malloc(sizeof (*be))) == 0)
2670Sstevel@tonic-gate 		return (0);
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	be->ops = ops;
2700Sstevel@tonic-gate 	be->n_ops = n_ops;
2712830Sdjl 	return ((nss_backend_t *)be);
2722830Sdjl }
2732830Sdjl 
2743176Smichen /*
2753176Smichen  * __res_ndestroy is a simplified version of the non-public function
2763176Smichen  * res_ndestroy in libresolv.so.2. Before res_ndestroy can be made
2773176Smichen  * public, __res_ndestroy will be used to make sure the memory pointed
2783176Smichen  * by statp->_u._ext.ext is freed after res_nclose() is called.
2793176Smichen  */
2803176Smichen static void
2813176Smichen __res_ndestroy(res_state statp) {
2823176Smichen 	res_nclose(statp);
2833176Smichen 	if (statp->_u._ext.ext != NULL)
2843176Smichen 		free(statp->_u._ext.ext);
2853176Smichen }
2862830Sdjl 
2872830Sdjl /*
2886666Ssm26363  * name_is_alias(aliases_ptr, name_ptr)
2896666Ssm26363  * Verify name matches an alias in the provided aliases list.
2906666Ssm26363  *
2916666Ssm26363  * Within DNS there should be only one canonical name, aliases should
2926666Ssm26363  * all refer to the one canonical.  However alias chains do occur and
2936666Ssm26363  * pre BIND 9 servers may also respond with multiple CNAMEs.  This
2946666Ssm26363  * routine checks if a given name has been provided as a CNAME in the
2956666Ssm26363  * response.  This assumes that the chains have been sent in-order.
2966666Ssm26363  *
2976666Ssm26363  * INPUT:
2986666Ssm26363  *  aliases_ptr: space separated list of alias names.
2996666Ssm26363  *  name_ptr: name to look for in aliases_ptr list.
300*10544SStacey.Marshall@Sun.COM  * RETURNS: NSS_SUCCESS or NSS_NOTFOUND
3016666Ssm26363  *  NSS_SUCCESS indicates that the name is listed in the collected aliases.
3026666Ssm26363  */
3036666Ssm26363 static nss_status_t
3046666Ssm26363 name_is_alias(char *aliases_ptr, char *name_ptr) {
3056666Ssm26363 	char *host_ptr;
3066666Ssm26363 	/* Loop through alias string and compare it against host string. */
3076666Ssm26363 	while (*aliases_ptr != '\0') {
3086666Ssm26363 		host_ptr = name_ptr;
3096666Ssm26363 
3106666Ssm26363 		/* Compare name with alias. */
3116666Ssm26363 		while (tolower(*host_ptr) == tolower(*aliases_ptr) &&
3126666Ssm26363 		    *host_ptr != '\0') {
3136666Ssm26363 			host_ptr++;
3146666Ssm26363 			aliases_ptr++;
3156666Ssm26363 		}
3166666Ssm26363 
3176666Ssm26363 		/*
3186666Ssm26363 		 * If name was exhausted and the next character in the
3196666Ssm26363 		 * alias is either the end-of-string or space
3206666Ssm26363 		 * character then we have a match.
3216666Ssm26363 		 */
3226666Ssm26363 		if (*host_ptr == '\0' &&
3236666Ssm26363 		    (*aliases_ptr == '\0' || *aliases_ptr == ' ')) {
3246666Ssm26363 			return (NSS_SUCCESS);
3256666Ssm26363 		}
3266666Ssm26363 
3276666Ssm26363 		/* Alias did not match, step over remainder of alias. */
3286666Ssm26363 		while (*aliases_ptr != ' ' && *aliases_ptr != '\0')
3296666Ssm26363 			aliases_ptr++;
3306666Ssm26363 		/* Step over separator character. */
3316666Ssm26363 		while (*aliases_ptr == ' ') aliases_ptr++;
3326666Ssm26363 	}
333*10544SStacey.Marshall@Sun.COM 	return (NSS_NOTFOUND);
3346666Ssm26363 }
3356666Ssm26363 
3366666Ssm26363 /*
3372830Sdjl  * nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode)
3382830Sdjl  *      nss2 get hosts/ipnodes with ttl backend DNS search engine.
3392830Sdjl  *
3402830Sdjl  * This API is given a pointer to a packed buffer, and the buffer size
3412830Sdjl  * It's job is to perform the appropriate res_nsearch, extract the
3422830Sdjl  * results and build a unmarshalled hosts/ipnodes result buffer.
3432830Sdjl  * Additionally in the extended results a nssuint_t ttl is placed.
3442830Sdjl  * This ttl is the lessor of the ttl's extracted from the result.
3452830Sdjl  *
3462830Sdjl  * ***Currently the first version of this API only performs simple
3472830Sdjl  *    single res_nsearch lookups for with T_A or T_AAAA results.
3482830Sdjl  *    Other searches are deferred to the generic API w/t ttls.
3492830Sdjl  *
3502830Sdjl  *    This function is not a generic res_* operation.  It only performs
3512830Sdjl  *    a single T_A or T_AAAA lookups***
3522830Sdjl  *
3532830Sdjl  * RETURNS:  NSS_SUCCESS or NSS_ERROR
3542830Sdjl  *	If an NSS_ERROR result is returned, nscd is expected
3552830Sdjl  *	to resubmit the gethosts request using the old style
3562830Sdjl  *	nsswitch lookup format.
3572830Sdjl  */
3582830Sdjl 
3592830Sdjl nss_status_t
3602830Sdjl _nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode)
3612830Sdjl {
3622830Sdjl 	/* nss buffer variables */
3632830Sdjl 	nss_pheader_t	*pbuf = (nss_pheader_t *)buffer;
3642830Sdjl 	nss_XbyY_args_t	arg;
3652830Sdjl 	char		*dbname;
3662830Sdjl 	int		dbop;
3672830Sdjl 	nss_status_t	sret;
3682830Sdjl 	size_t		bsize, blen;
3692830Sdjl 	char		*bptr;
3702830Sdjl 	/* resolver query variables */
3712924Smichen 	struct __res_state stat, *statp;	/* dns state block */
3722924Smichen 	union msg {
3732924Smichen 		uchar_t	buf[NS_MAXMSG];		/* max legal DNS answer size */
3742924Smichen 		HEADER	h;
3752924Smichen 	} resbuf;
3762924Smichen 	char aliases[NS_MAXMSG];		/* set of aliases */
3772830Sdjl 	const char	*name;
3782830Sdjl 	int		qtype;
3792830Sdjl 	/* answer parsing variables */
3802830Sdjl 	HEADER		*hp;
3812830Sdjl 	uchar_t		*cp;	/* current location in message */
3822830Sdjl 	uchar_t		*bom;	/* start of message */
3832830Sdjl 	uchar_t		*eom;	/* end of message */
3842830Sdjl 	uchar_t		*eor;	/* end of record */
3852830Sdjl 	int		ancount, qdcount;
3862830Sdjl 	int		type, class;
3872830Sdjl 	nssuint_t	nttl, ttl, *pttl;	/* The purpose of this API */
3882830Sdjl 	int		n, ret;
3892830Sdjl 	const char	*np;
3902830Sdjl 	/* temporary buffers */
3912830Sdjl 	char		nbuf[INET6_ADDRSTRLEN];	/* address parser */
3922830Sdjl 	char		host[MAXHOSTNAMELEN];	/* result host name */
3932830Sdjl 	char		ans[MAXHOSTNAMELEN];	/* record name */
3942830Sdjl 	char		aname[MAXHOSTNAMELEN];	/* alias result (C_NAME) */
3952830Sdjl 	/* misc variables */
3962830Sdjl 	int		af;
3972830Sdjl 	char		*ap, *apc;
398*10544SStacey.Marshall@Sun.COM 	int		hlen = 0, alen, iplen, len, isans;
3992830Sdjl 
4002924Smichen 	statp = &stat;
4012924Smichen 	(void) memset(statp, '\0', sizeof (struct __res_state));
4022924Smichen 	if (res_ninit(statp) == -1)
4032924Smichen 		return (NSS_ERROR);
4042924Smichen 
4052924Smichen 	ap = apc = (char *)aliases;
4062830Sdjl 	alen = 0;
4072830Sdjl 	ttl = (nssuint_t)0xFFFFFFF;		/* start w/max, find smaller */
4082830Sdjl 
4092830Sdjl 	/* save space for ttl otherwise, why bother... */
4102830Sdjl 	bsize = pbuf->data_len - sizeof (nssuint_t);
4112830Sdjl 	bptr = (char *)buffer + pbuf->data_off;
4122830Sdjl 	blen = 0;
4132830Sdjl 	sret = nss_packed_getkey(buffer, bufsize, &dbname, &dbop, &arg);
4142830Sdjl 	if (sret != NSS_SUCCESS) {
4153176Smichen 		__res_ndestroy(statp);
4162830Sdjl 		return (NSS_ERROR);
4172830Sdjl 	}
4182830Sdjl 
4192830Sdjl 	if (ipnode) {
4202830Sdjl 		/* initially only handle the simple cases */
4212924Smichen 		if (arg.key.ipnode.flags != 0) {
4223176Smichen 			__res_ndestroy(statp);
4232830Sdjl 			return (NSS_ERROR);
4242924Smichen 		}
4252830Sdjl 		name = arg.key.ipnode.name;
4262830Sdjl 		if (arg.key.ipnode.af_family == AF_INET6)
4272830Sdjl 			qtype = T_AAAA;
4282830Sdjl 		else
4292830Sdjl 			qtype = T_A;
4302830Sdjl 	} else {
4312830Sdjl 		name = arg.key.name;
4322830Sdjl 		qtype = T_A;
4332830Sdjl 	}
4342924Smichen 	ret = res_nsearch(statp, name, C_IN, qtype, resbuf.buf, NS_MAXMSG);
4352830Sdjl 	if (ret == -1) {
4362924Smichen 		if (statp->res_h_errno == HOST_NOT_FOUND) {
4372830Sdjl 			pbuf->p_herrno = HOST_NOT_FOUND;
4382830Sdjl 			pbuf->p_status = NSS_NOTFOUND;
4392830Sdjl 			pbuf->data_len = 0;
4403176Smichen 			__res_ndestroy(statp);
4412830Sdjl 			return (NSS_NOTFOUND);
4422830Sdjl 		}
4432830Sdjl 		/* else lookup error - handle in general code */
4443176Smichen 		__res_ndestroy(statp);
4452830Sdjl 		return (NSS_ERROR);
4462830Sdjl 	}
4472830Sdjl 
4482924Smichen 	cp = resbuf.buf;
4492924Smichen 	hp = (HEADER *)&resbuf.h;
4502830Sdjl 	bom = cp;
4512830Sdjl 	eom = cp + ret;
4522830Sdjl 
4532830Sdjl 	ancount = ntohs(hp->ancount);
4542830Sdjl 	qdcount = ntohs(hp->qdcount);
4552830Sdjl 	cp += HFIXEDSZ;
4562924Smichen 	if (qdcount != 1) {
4573176Smichen 		__res_ndestroy(statp);
4582830Sdjl 		return (NSS_ERROR);
4592924Smichen 	}
4602830Sdjl 	n = dn_expand(bom, eom, cp, host, MAXHOSTNAMELEN);
4612830Sdjl 	if (n < 0) {
4623176Smichen 		__res_ndestroy(statp);
4632830Sdjl 		return (NSS_ERROR);
4642830Sdjl 	} else
4652830Sdjl 		hlen = strlen(host);
4665161Smichen 	/* no host name is an error, return */
4675161Smichen 	if (hlen <= 0) {
4685161Smichen 		__res_ndestroy(statp);
4695161Smichen 		return (NSS_ERROR);
4705161Smichen 	}
4712830Sdjl 	cp += n + QFIXEDSZ;
4722924Smichen 	if (cp > eom) {
4733176Smichen 		__res_ndestroy(statp);
4742830Sdjl 		return (NSS_ERROR);
4752924Smichen 	}
4762830Sdjl 	while (ancount-- > 0 && cp < eom && blen < bsize) {
4772830Sdjl 		n = dn_expand(bom, eom, cp, ans, MAXHOSTNAMELEN);
4782830Sdjl 		if (n > 0) {
4796666Ssm26363 			/*
4806666Ssm26363 			 * Check that the expanded name is either the
4816666Ssm26363 			 * name we asked for or a learned alias.
4826666Ssm26363 			 */
483*10544SStacey.Marshall@Sun.COM 			if ((isans = strncasecmp(host, ans, hlen)) != 0 &&
484*10544SStacey.Marshall@Sun.COM 			    (alen == 0 || name_is_alias(aliases, ans)
485*10544SStacey.Marshall@Sun.COM 			    == NSS_NOTFOUND)) {
4863176Smichen 				__res_ndestroy(statp);
4872830Sdjl 				return (NSS_ERROR);	/* spoof? */
4882924Smichen 			}
4892830Sdjl 		}
4902830Sdjl 		cp += n;
4912830Sdjl 		/* bounds check */
4922830Sdjl 		type = ns_get16(cp);			/* type */
4932830Sdjl 		cp += INT16SZ;
4942830Sdjl 		class = ns_get16(cp);			/* class */
4952830Sdjl 		cp += INT16SZ;
496*10544SStacey.Marshall@Sun.COM 		nttl = (nssuint_t)ns_get32(cp);		/* ttl in sec */
4972830Sdjl 		if (nttl < ttl)
4982830Sdjl 			ttl = nttl;
4992830Sdjl 		cp += INT32SZ;
5002830Sdjl 		n = ns_get16(cp);			/* len */
5012830Sdjl 		cp += INT16SZ;
5022830Sdjl 		if (class != C_IN) {
5032830Sdjl 			cp += n;
5042830Sdjl 			continue;
5052830Sdjl 		}
5062830Sdjl 		eor = cp + n;
5072830Sdjl 		if (type == T_CNAME) {
5086666Ssm26363 			/*
509*10544SStacey.Marshall@Sun.COM 			 * The name looked up is really an alias and the
510*10544SStacey.Marshall@Sun.COM 			 * canonical name should be in the RDATA.
511*10544SStacey.Marshall@Sun.COM 			 * A canonical name may have several aliases but an
512*10544SStacey.Marshall@Sun.COM 			 * alias should only have one canonical name.
513*10544SStacey.Marshall@Sun.COM 			 * However multiple CNAMEs and CNAME chains do exist!
514*10544SStacey.Marshall@Sun.COM 			 *
515*10544SStacey.Marshall@Sun.COM 			 * Just error out on attempted buffer overflow exploit,
516*10544SStacey.Marshall@Sun.COM 			 * generic code will syslog.
517*10544SStacey.Marshall@Sun.COM 			 *
5186666Ssm26363 			 */
5192830Sdjl 			n = dn_expand(bom, eor, cp, aname, MAXHOSTNAMELEN);
520*10544SStacey.Marshall@Sun.COM 			if (n > 0 && (len = strlen(aname)) > 0) {
521*10544SStacey.Marshall@Sun.COM 				if (isans == 0) { /* host matched ans. */
5222830Sdjl 					/*
523*10544SStacey.Marshall@Sun.COM 					 * Append host to alias list.
5242830Sdjl 					 */
525*10544SStacey.Marshall@Sun.COM 					if (alen + hlen + 2 > NS_MAXMSG) {
5263176Smichen 						__res_ndestroy(statp);
5272830Sdjl 						return (NSS_ERROR);
5283176Smichen 					}
5292830Sdjl 					*apc++ = ' ';
5302830Sdjl 					alen++;
531*10544SStacey.Marshall@Sun.COM 					(void) strlcpy(apc, host,
532*10544SStacey.Marshall@Sun.COM 					    NS_MAXMSG - alen);
533*10544SStacey.Marshall@Sun.COM 					alen += hlen;
534*10544SStacey.Marshall@Sun.COM 					apc += hlen;
5352830Sdjl 				}
536*10544SStacey.Marshall@Sun.COM 				/*
537*10544SStacey.Marshall@Sun.COM 				 * Overwrite host with canonical name.
538*10544SStacey.Marshall@Sun.COM 				 */
539*10544SStacey.Marshall@Sun.COM 				if (strlcpy(host, aname, MAXHOSTNAMELEN) >=
540*10544SStacey.Marshall@Sun.COM 				    MAXHOSTNAMELEN) {
541*10544SStacey.Marshall@Sun.COM 					__res_ndestroy(statp);
542*10544SStacey.Marshall@Sun.COM 					return (NSS_ERROR);
543*10544SStacey.Marshall@Sun.COM 				}
544*10544SStacey.Marshall@Sun.COM 				hlen = len;
5452830Sdjl 			}
5462830Sdjl 			cp += n;
5472830Sdjl 			continue;
5482830Sdjl 		}
5492830Sdjl 		if (type != qtype) {
5502830Sdjl 			cp += n;
5512830Sdjl 			continue;
5522830Sdjl 		}
5532830Sdjl 		/* check data size */
5542830Sdjl 		if ((type == T_A && n != INADDRSZ) ||
5552830Sdjl 		    (type == T_AAAA && n != IN6ADDRSZ)) {
5562830Sdjl 			cp += n;
5572830Sdjl 			continue;
5582830Sdjl 		}
5592830Sdjl 		af = (type == T_A ? AF_INET : AF_INET6);
5602830Sdjl 		np = inet_ntop(af, (void *)cp, nbuf, INET6_ADDRSTRLEN);
5612924Smichen 		if (np == NULL) {
5623176Smichen 			__res_ndestroy(statp);
5632830Sdjl 			return (NSS_ERROR);
5642924Smichen 		}
5652830Sdjl 		cp += n;
5662830Sdjl 		/* append IP host aliases to results */
5672830Sdjl 		iplen = strlen(np);
5682830Sdjl 		/* ip <SP> hostname [<SP>][aliases] */
5692830Sdjl 		len = iplen + 2 + hlen + alen;
5702830Sdjl 		if (alen > 0)
5712830Sdjl 			len++;
5723176Smichen 		if (blen + len > bsize) {
5733176Smichen 			__res_ndestroy(statp);
5742830Sdjl 			return (NSS_ERROR);
5753176Smichen 		}
5762830Sdjl 		(void) strlcpy(bptr, np, bsize - blen);
5772830Sdjl 		blen += iplen;
5782830Sdjl 		bptr += iplen;
5792830Sdjl 		*bptr++ = ' ';
5802830Sdjl 		blen++;
5812830Sdjl 		(void) strlcpy(bptr, host, bsize - blen);
5822830Sdjl 		blen += hlen;
5832830Sdjl 		bptr += hlen;
5842830Sdjl 		if (alen > 0) {
5852830Sdjl 			*bptr++ = ' ';
5862830Sdjl 			blen++;
5872830Sdjl 			(void) strlcpy(bptr, ap, bsize - blen);
5882830Sdjl 			blen += alen;
5892830Sdjl 			bptr += alen;
5902830Sdjl 		}
5912830Sdjl 		*bptr++ = '\n';
5922830Sdjl 		blen++;
5932830Sdjl 	}
5942830Sdjl 	/* Presumably the buffer is now filled. */
5952830Sdjl 	len = ROUND_UP(blen, sizeof (nssuint_t));
5962830Sdjl 	/* still room? */
5972830Sdjl 	if (len + sizeof (nssuint_t) > pbuf->data_len) {
5982830Sdjl 		/* sigh, no, what happened? */
5993176Smichen 		__res_ndestroy(statp);
6002830Sdjl 		return (NSS_ERROR);
6012830Sdjl 	}
6022830Sdjl 	pbuf->ext_off = pbuf->data_off + len;
6032830Sdjl 	pbuf->ext_len = sizeof (nssuint_t);
6042830Sdjl 	pbuf->data_len = blen;
6052830Sdjl 	pttl = (nssuint_t *)((void *)((char *)pbuf + pbuf->ext_off));
6062830Sdjl 	*pttl = ttl;
6073176Smichen 	__res_ndestroy(statp);
6082830Sdjl 	return (NSS_SUCCESS);
6092830Sdjl }
610