xref: /onnv-gate/usr/src/lib/nsswitch/dns/common/dns_common.c (revision 10545:a008c2e346a1)
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 /*
2210544SStacey.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
34*10545SStacey.Marshall@Sun.COM #pragma weak	res_ndestroy
352830Sdjl #pragma weak	res_nsearch
362830Sdjl #pragma weak	res_nclose
372830Sdjl #pragma weak	ns_get16
382830Sdjl #pragma weak	ns_get32
392830Sdjl #pragma weak	__ns_get16
402830Sdjl #pragma weak	__ns_get32
410Sstevel@tonic-gate 
420Sstevel@tonic-gate #define	DNS_ALIASES	0
430Sstevel@tonic-gate #define	DNS_ADDRLIST	1
440Sstevel@tonic-gate #define	DNS_MAPDLIST	2
450Sstevel@tonic-gate 
466666Ssm26363 #ifndef	tolower
476666Ssm26363 #define	tolower(c) ((c) >= 'A' && (c) <= 'Z' ? (c) | 0x20 : (c))
486666Ssm26363 #endif
496666Ssm26363 
500Sstevel@tonic-gate static int
dns_netdb_aliases(from_list,to_list,aliaspp,type,count,af_type)510Sstevel@tonic-gate dns_netdb_aliases(from_list, to_list, aliaspp, type, count, af_type)
520Sstevel@tonic-gate 	char	**from_list, **to_list,	**aliaspp;
530Sstevel@tonic-gate 	int	type, *count, af_type;
540Sstevel@tonic-gate {
550Sstevel@tonic-gate 	char		*fstr;
560Sstevel@tonic-gate 	int		cnt = 0;
570Sstevel@tonic-gate 	size_t		len;
580Sstevel@tonic-gate 
590Sstevel@tonic-gate 	*count = 0;
600Sstevel@tonic-gate 	if ((char *)to_list >= *aliaspp)
610Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
620Sstevel@tonic-gate 
630Sstevel@tonic-gate 	for (fstr = from_list[cnt]; fstr != NULL; fstr = from_list[cnt]) {
640Sstevel@tonic-gate 		if (type == DNS_ALIASES)
650Sstevel@tonic-gate 			len = strlen(fstr) + 1;
660Sstevel@tonic-gate 		else
670Sstevel@tonic-gate 			len = (af_type == AF_INET) ? sizeof (struct in_addr)
680Sstevel@tonic-gate 						: sizeof (struct in6_addr);
690Sstevel@tonic-gate 		*aliaspp -= len;
700Sstevel@tonic-gate 		to_list[cnt] = *aliaspp;
710Sstevel@tonic-gate 		if (*aliaspp <= (char *)&to_list[cnt+1])
720Sstevel@tonic-gate 			return (NSS_STR_PARSE_ERANGE);
730Sstevel@tonic-gate 		if (type == DNS_MAPDLIST) {
742830Sdjl 			/* LINTED: E_BAD_PTR_CAST_ALIGN */
752830Sdjl 			struct in6_addr *addr6p = (struct in6_addr *)*aliaspp;
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 			(void) memset(addr6p, '\0', sizeof (struct in6_addr));
780Sstevel@tonic-gate 			(void) memcpy(&addr6p->s6_addr[12], fstr,
790Sstevel@tonic-gate 					sizeof (struct in_addr));
800Sstevel@tonic-gate 			addr6p->s6_addr[10] = 0xffU;
810Sstevel@tonic-gate 			addr6p->s6_addr[11] = 0xffU;
820Sstevel@tonic-gate 			++cnt;
830Sstevel@tonic-gate 		} else {
840Sstevel@tonic-gate 			(void) memcpy (*aliaspp, fstr, len);
850Sstevel@tonic-gate 			++cnt;
860Sstevel@tonic-gate 		}
870Sstevel@tonic-gate 	}
880Sstevel@tonic-gate 	to_list[cnt] = NULL;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	*count = cnt;
910Sstevel@tonic-gate 	if (cnt == 0)
920Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	return (NSS_STR_PARSE_SUCCESS);
950Sstevel@tonic-gate }
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 
980Sstevel@tonic-gate int
ent2result(he,argp,af_type)990Sstevel@tonic-gate ent2result(he, argp, af_type)
1000Sstevel@tonic-gate 	struct hostent		*he;
1010Sstevel@tonic-gate 	nss_XbyY_args_t		*argp;
1020Sstevel@tonic-gate 	int			af_type;
1030Sstevel@tonic-gate {
1040Sstevel@tonic-gate 	char		*buffer, *limit;
1050Sstevel@tonic-gate 	int		buflen = argp->buf.buflen;
1060Sstevel@tonic-gate 	int		ret, count;
1070Sstevel@tonic-gate 	size_t len;
1080Sstevel@tonic-gate 	struct hostent 	*host;
1090Sstevel@tonic-gate 	struct in_addr	*addrp;
1100Sstevel@tonic-gate 	struct in6_addr	*addrp6;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	limit = argp->buf.buffer + buflen;
1132830Sdjl 	host = (struct hostent *)argp->buf.result;
1140Sstevel@tonic-gate 	buffer = argp->buf.buffer;
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	/* h_addrtype and h_length */
1170Sstevel@tonic-gate 	host->h_addrtype = af_type;
1180Sstevel@tonic-gate 	host->h_length = (af_type == AF_INET) ? sizeof (struct in_addr)
1190Sstevel@tonic-gate 					: sizeof (struct in6_addr);
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	/* h_name */
1220Sstevel@tonic-gate 	len = strlen(he->h_name) + 1;
1230Sstevel@tonic-gate 	host->h_name = buffer;
1240Sstevel@tonic-gate 	if (host->h_name + len >= limit)
1250Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
1260Sstevel@tonic-gate 	(void) memcpy(host->h_name, he->h_name, len);
1270Sstevel@tonic-gate 	buffer += len;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	/* h_addr_list */
1300Sstevel@tonic-gate 	if (af_type == AF_INET) {
1312830Sdjl 		addrp = (struct in_addr *)ROUND_DOWN(limit, sizeof (*addrp));
1320Sstevel@tonic-gate 		host->h_addr_list = (char **)
1330Sstevel@tonic-gate 				ROUND_UP(buffer, sizeof (char **));
1340Sstevel@tonic-gate 		ret = dns_netdb_aliases(he->h_addr_list, host->h_addr_list,
1350Sstevel@tonic-gate 			(char **)&addrp, DNS_ADDRLIST, &count, af_type);
1360Sstevel@tonic-gate 		if (ret != NSS_STR_PARSE_SUCCESS)
1370Sstevel@tonic-gate 			return (ret);
1380Sstevel@tonic-gate 		/* h_aliases */
1390Sstevel@tonic-gate 		host->h_aliases = host->h_addr_list + count + 1;
1400Sstevel@tonic-gate 		ret = dns_netdb_aliases(he->h_aliases, host->h_aliases,
1410Sstevel@tonic-gate 			(char **)&addrp, DNS_ALIASES, &count, af_type);
1420Sstevel@tonic-gate 	} else {
1430Sstevel@tonic-gate 		addrp6 = (struct in6_addr *)
1440Sstevel@tonic-gate 			ROUND_DOWN(limit, sizeof (*addrp6));
1450Sstevel@tonic-gate 		host->h_addr_list = (char **)
1460Sstevel@tonic-gate 			ROUND_UP(buffer, sizeof (char **));
1470Sstevel@tonic-gate 		if (he->h_addrtype == AF_INET && af_type == AF_INET6) {
1480Sstevel@tonic-gate 			ret = dns_netdb_aliases(he->h_addr_list,
1490Sstevel@tonic-gate 				host->h_addr_list, (char **)&addrp6,
1500Sstevel@tonic-gate 				DNS_MAPDLIST, &count, af_type);
1510Sstevel@tonic-gate 		} else {
1520Sstevel@tonic-gate 			ret = dns_netdb_aliases(he->h_addr_list,
1530Sstevel@tonic-gate 				host->h_addr_list, (char **)&addrp6,
1540Sstevel@tonic-gate 				DNS_ADDRLIST, &count, af_type);
1550Sstevel@tonic-gate 		}
1560Sstevel@tonic-gate 		if (ret != NSS_STR_PARSE_SUCCESS)
1570Sstevel@tonic-gate 			return (ret);
1580Sstevel@tonic-gate 		/* h_aliases */
1590Sstevel@tonic-gate 		host->h_aliases = host->h_addr_list + count + 1;
1600Sstevel@tonic-gate 		ret = dns_netdb_aliases(he->h_aliases, host->h_aliases,
1610Sstevel@tonic-gate 			(char **)&addrp6, DNS_ALIASES, &count, af_type);
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 	if (ret == NSS_STR_PARSE_PARSE)
1640Sstevel@tonic-gate 		ret = NSS_STR_PARSE_SUCCESS;
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	return (ret);
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate 
1692830Sdjl /*
1702830Sdjl  * Convert the hostent structure into string in the following
1712830Sdjl  * format:
1722830Sdjl  *
1732830Sdjl  * IP-address official-host-name nicknames ...
1742830Sdjl  *
1752830Sdjl  * If more than one IP-addresses matches the official-host-name,
1762830Sdjl  * the above line will be followed by:
1772830Sdjl  * IP-address-1 official-host-name
1782830Sdjl  * IP-address-2 official-host-name
1792830Sdjl  * ...
1802830Sdjl  *
1812830Sdjl  * This is so that the str2hostent function in libnsl
1822830Sdjl  * can convert the string back to the original hostent
1832830Sdjl  * data.
1842830Sdjl  */
1852830Sdjl int
ent2str(struct hostent * hp,nss_XbyY_args_t * ap,int af_type)1862830Sdjl ent2str(
1872830Sdjl 	struct hostent	*hp,
1882830Sdjl 	nss_XbyY_args_t *ap,
1892830Sdjl 	int		af_type)
1902830Sdjl {
1912830Sdjl 	char		**p;
1922830Sdjl 	char		obuf[INET6_ADDRSTRLEN];
1932830Sdjl 	void		*addr;
1942830Sdjl 	struct in_addr	in4;
1952830Sdjl 	int		af;
1962830Sdjl 	int		n;
1972830Sdjl 	const char	*res;
1982830Sdjl 	char		**q;
1992830Sdjl 	int		l = ap->buf.buflen;
2002830Sdjl 	char		*s = ap->buf.buffer;
2012830Sdjl 
2022830Sdjl 	/*
2032830Sdjl 	 * for "hosts" lookup, we only want address type of
2042830Sdjl 	 * AF_INET. For "ipnodes", we can have both AF_INET
2052830Sdjl 	 * and AF_INET6.
2062830Sdjl 	 */
2072830Sdjl 	if (af_type == AF_INET && hp->h_addrtype != AF_INET)
2082830Sdjl 		return (NSS_STR_PARSE_PARSE);
2092830Sdjl 
2102830Sdjl 	for (p = hp->h_addr_list; *p != 0; p++) {
2112830Sdjl 
2122830Sdjl 		if (p != hp->h_addr_list) {
2132830Sdjl 			*s = '\n';
2142830Sdjl 			s++;
2152830Sdjl 			l--;
2162830Sdjl 		}
2172830Sdjl 
2182830Sdjl 		if (hp->h_addrtype == AF_INET6) {
2192830Sdjl 			/* LINTED: E_BAD_PTR_CAST_ALIGN */
2202830Sdjl 			if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)*p)) {
2212830Sdjl 				/* LINTED: E_BAD_PTR_CAST_ALIGN */
2222830Sdjl 				IN6_V4MAPPED_TO_INADDR((struct in6_addr *)*p,
2235161Smichen 				    &in4);
2242830Sdjl 				af = AF_INET;
2252830Sdjl 				addr = &in4;
2262830Sdjl 			} else {
2272830Sdjl 				af = AF_INET6;
2282830Sdjl 				addr = *p;
2292830Sdjl 			}
2302830Sdjl 		} else {
2312830Sdjl 			af = AF_INET;
2322830Sdjl 			addr = *p;
2332830Sdjl 		}
2342830Sdjl 		res = inet_ntop(af, addr, obuf, sizeof (obuf));
2352830Sdjl 		if (res == NULL)
2362830Sdjl 			return (NSS_STR_PARSE_PARSE);
2372830Sdjl 
2385161Smichen 		if ((n = snprintf(s, l, "%s", res)) >= l)
2392830Sdjl 			return (NSS_STR_PARSE_ERANGE);
2402830Sdjl 		l -= n;
2412830Sdjl 		s += n;
2425161Smichen 		if (hp->h_name != NULL && *hp->h_name != '\0') {
2435161Smichen 			if ((n = snprintf(s, l, " %s", hp->h_name)) >= l)
2445161Smichen 				return (NSS_STR_PARSE_ERANGE);
2455161Smichen 			l -= n;
2465161Smichen 			s += n;
2475161Smichen 		}
2482830Sdjl 		if (p == hp->h_addr_list) {
2492830Sdjl 			for (q = hp->h_aliases; q && *q; q++) {
2502830Sdjl 				if ((n = snprintf(s, l, " %s", *q)) >= l)
2512830Sdjl 					return (NSS_STR_PARSE_ERANGE);
2522830Sdjl 				l -= n;
2532830Sdjl 				s += n;
2542830Sdjl 			}
2552830Sdjl 		}
2562830Sdjl 	}
2572830Sdjl 
2582830Sdjl 	ap->returnlen = s - ap->buf.buffer;
2592830Sdjl 	return (NSS_STR_PARSE_SUCCESS);
2602830Sdjl }
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate nss_backend_t *
_nss_dns_constr(dns_backend_op_t ops[],int n_ops)2630Sstevel@tonic-gate _nss_dns_constr(dns_backend_op_t ops[], int n_ops)
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate 	dns_backend_ptr_t	be;
2660Sstevel@tonic-gate 
2672830Sdjl 	if ((be = (dns_backend_ptr_t)malloc(sizeof (*be))) == 0)
2680Sstevel@tonic-gate 		return (0);
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	be->ops = ops;
2710Sstevel@tonic-gate 	be->n_ops = n_ops;
2722830Sdjl 	return ((nss_backend_t *)be);
2732830Sdjl }
2742830Sdjl 
2753176Smichen /*
2766666Ssm26363  * name_is_alias(aliases_ptr, name_ptr)
2776666Ssm26363  * Verify name matches an alias in the provided aliases list.
2786666Ssm26363  *
2796666Ssm26363  * Within DNS there should be only one canonical name, aliases should
2806666Ssm26363  * all refer to the one canonical.  However alias chains do occur and
2816666Ssm26363  * pre BIND 9 servers may also respond with multiple CNAMEs.  This
2826666Ssm26363  * routine checks if a given name has been provided as a CNAME in the
2836666Ssm26363  * response.  This assumes that the chains have been sent in-order.
2846666Ssm26363  *
2856666Ssm26363  * INPUT:
2866666Ssm26363  *  aliases_ptr: space separated list of alias names.
2876666Ssm26363  *  name_ptr: name to look for in aliases_ptr list.
28810544SStacey.Marshall@Sun.COM  * RETURNS: NSS_SUCCESS or NSS_NOTFOUND
2896666Ssm26363  *  NSS_SUCCESS indicates that the name is listed in the collected aliases.
2906666Ssm26363  */
2916666Ssm26363 static nss_status_t
name_is_alias(char * aliases_ptr,char * name_ptr)2926666Ssm26363 name_is_alias(char *aliases_ptr, char *name_ptr) {
2936666Ssm26363 	char *host_ptr;
2946666Ssm26363 	/* Loop through alias string and compare it against host string. */
2956666Ssm26363 	while (*aliases_ptr != '\0') {
2966666Ssm26363 		host_ptr = name_ptr;
2976666Ssm26363 
2986666Ssm26363 		/* Compare name with alias. */
2996666Ssm26363 		while (tolower(*host_ptr) == tolower(*aliases_ptr) &&
3006666Ssm26363 		    *host_ptr != '\0') {
3016666Ssm26363 			host_ptr++;
3026666Ssm26363 			aliases_ptr++;
3036666Ssm26363 		}
3046666Ssm26363 
3056666Ssm26363 		/*
3066666Ssm26363 		 * If name was exhausted and the next character in the
3076666Ssm26363 		 * alias is either the end-of-string or space
3086666Ssm26363 		 * character then we have a match.
3096666Ssm26363 		 */
3106666Ssm26363 		if (*host_ptr == '\0' &&
3116666Ssm26363 		    (*aliases_ptr == '\0' || *aliases_ptr == ' ')) {
3126666Ssm26363 			return (NSS_SUCCESS);
3136666Ssm26363 		}
3146666Ssm26363 
3156666Ssm26363 		/* Alias did not match, step over remainder of alias. */
3166666Ssm26363 		while (*aliases_ptr != ' ' && *aliases_ptr != '\0')
3176666Ssm26363 			aliases_ptr++;
3186666Ssm26363 		/* Step over separator character. */
3196666Ssm26363 		while (*aliases_ptr == ' ') aliases_ptr++;
3206666Ssm26363 	}
32110544SStacey.Marshall@Sun.COM 	return (NSS_NOTFOUND);
3226666Ssm26363 }
3236666Ssm26363 
3246666Ssm26363 /*
3252830Sdjl  * nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode)
3262830Sdjl  *      nss2 get hosts/ipnodes with ttl backend DNS search engine.
3272830Sdjl  *
3282830Sdjl  * This API is given a pointer to a packed buffer, and the buffer size
3292830Sdjl  * It's job is to perform the appropriate res_nsearch, extract the
3302830Sdjl  * results and build a unmarshalled hosts/ipnodes result buffer.
3312830Sdjl  * Additionally in the extended results a nssuint_t ttl is placed.
3322830Sdjl  * This ttl is the lessor of the ttl's extracted from the result.
3332830Sdjl  *
3342830Sdjl  * ***Currently the first version of this API only performs simple
3352830Sdjl  *    single res_nsearch lookups for with T_A or T_AAAA results.
3362830Sdjl  *    Other searches are deferred to the generic API w/t ttls.
3372830Sdjl  *
3382830Sdjl  *    This function is not a generic res_* operation.  It only performs
3392830Sdjl  *    a single T_A or T_AAAA lookups***
3402830Sdjl  *
3412830Sdjl  * RETURNS:  NSS_SUCCESS or NSS_ERROR
3422830Sdjl  *	If an NSS_ERROR result is returned, nscd is expected
3432830Sdjl  *	to resubmit the gethosts request using the old style
3442830Sdjl  *	nsswitch lookup format.
3452830Sdjl  */
3462830Sdjl 
3472830Sdjl nss_status_t
_nss_dns_gethost_withttl(void * buffer,size_t bufsize,int ipnode)3482830Sdjl _nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode)
3492830Sdjl {
3502830Sdjl 	/* nss buffer variables */
3512830Sdjl 	nss_pheader_t	*pbuf = (nss_pheader_t *)buffer;
3522830Sdjl 	nss_XbyY_args_t	arg;
3532830Sdjl 	char		*dbname;
3542830Sdjl 	int		dbop;
3552830Sdjl 	nss_status_t	sret;
3562830Sdjl 	size_t		bsize, blen;
3572830Sdjl 	char		*bptr;
3582830Sdjl 	/* resolver query variables */
3592924Smichen 	struct __res_state stat, *statp;	/* dns state block */
3602924Smichen 	union msg {
3612924Smichen 		uchar_t	buf[NS_MAXMSG];		/* max legal DNS answer size */
3622924Smichen 		HEADER	h;
3632924Smichen 	} resbuf;
3642924Smichen 	char aliases[NS_MAXMSG];		/* set of aliases */
3652830Sdjl 	const char	*name;
3662830Sdjl 	int		qtype;
3672830Sdjl 	/* answer parsing variables */
3682830Sdjl 	HEADER		*hp;
3692830Sdjl 	uchar_t		*cp;	/* current location in message */
3702830Sdjl 	uchar_t		*bom;	/* start of message */
3712830Sdjl 	uchar_t		*eom;	/* end of message */
3722830Sdjl 	uchar_t		*eor;	/* end of record */
3732830Sdjl 	int		ancount, qdcount;
3742830Sdjl 	int		type, class;
3752830Sdjl 	nssuint_t	nttl, ttl, *pttl;	/* The purpose of this API */
3762830Sdjl 	int		n, ret;
3772830Sdjl 	const char	*np;
3782830Sdjl 	/* temporary buffers */
3792830Sdjl 	char		nbuf[INET6_ADDRSTRLEN];	/* address parser */
3802830Sdjl 	char		host[MAXHOSTNAMELEN];	/* result host name */
3812830Sdjl 	char		ans[MAXHOSTNAMELEN];	/* record name */
3822830Sdjl 	char		aname[MAXHOSTNAMELEN];	/* alias result (C_NAME) */
3832830Sdjl 	/* misc variables */
3842830Sdjl 	int		af;
3852830Sdjl 	char		*ap, *apc;
38610544SStacey.Marshall@Sun.COM 	int		hlen = 0, alen, iplen, len, isans;
3872830Sdjl 
3882924Smichen 	statp = &stat;
3892924Smichen 	(void) memset(statp, '\0', sizeof (struct __res_state));
3902924Smichen 	if (res_ninit(statp) == -1)
3912924Smichen 		return (NSS_ERROR);
3922924Smichen 
3932924Smichen 	ap = apc = (char *)aliases;
3942830Sdjl 	alen = 0;
3952830Sdjl 	ttl = (nssuint_t)0xFFFFFFF;		/* start w/max, find smaller */
3962830Sdjl 
3972830Sdjl 	/* save space for ttl otherwise, why bother... */
3982830Sdjl 	bsize = pbuf->data_len - sizeof (nssuint_t);
3992830Sdjl 	bptr = (char *)buffer + pbuf->data_off;
4002830Sdjl 	blen = 0;
4012830Sdjl 	sret = nss_packed_getkey(buffer, bufsize, &dbname, &dbop, &arg);
4022830Sdjl 	if (sret != NSS_SUCCESS) {
403*10545SStacey.Marshall@Sun.COM 		res_ndestroy(statp);
4042830Sdjl 		return (NSS_ERROR);
4052830Sdjl 	}
4062830Sdjl 
4072830Sdjl 	if (ipnode) {
4082830Sdjl 		/* initially only handle the simple cases */
4092924Smichen 		if (arg.key.ipnode.flags != 0) {
410*10545SStacey.Marshall@Sun.COM 			res_ndestroy(statp);
4112830Sdjl 			return (NSS_ERROR);
4122924Smichen 		}
4132830Sdjl 		name = arg.key.ipnode.name;
4142830Sdjl 		if (arg.key.ipnode.af_family == AF_INET6)
4152830Sdjl 			qtype = T_AAAA;
4162830Sdjl 		else
4172830Sdjl 			qtype = T_A;
4182830Sdjl 	} else {
4192830Sdjl 		name = arg.key.name;
4202830Sdjl 		qtype = T_A;
4212830Sdjl 	}
4222924Smichen 	ret = res_nsearch(statp, name, C_IN, qtype, resbuf.buf, NS_MAXMSG);
4232830Sdjl 	if (ret == -1) {
4242924Smichen 		if (statp->res_h_errno == HOST_NOT_FOUND) {
4252830Sdjl 			pbuf->p_herrno = HOST_NOT_FOUND;
4262830Sdjl 			pbuf->p_status = NSS_NOTFOUND;
4272830Sdjl 			pbuf->data_len = 0;
428*10545SStacey.Marshall@Sun.COM 			res_ndestroy(statp);
4292830Sdjl 			return (NSS_NOTFOUND);
4302830Sdjl 		}
4312830Sdjl 		/* else lookup error - handle in general code */
432*10545SStacey.Marshall@Sun.COM 		res_ndestroy(statp);
4332830Sdjl 		return (NSS_ERROR);
4342830Sdjl 	}
4352830Sdjl 
4362924Smichen 	cp = resbuf.buf;
4372924Smichen 	hp = (HEADER *)&resbuf.h;
4382830Sdjl 	bom = cp;
4392830Sdjl 	eom = cp + ret;
4402830Sdjl 
4412830Sdjl 	ancount = ntohs(hp->ancount);
4422830Sdjl 	qdcount = ntohs(hp->qdcount);
4432830Sdjl 	cp += HFIXEDSZ;
4442924Smichen 	if (qdcount != 1) {
445*10545SStacey.Marshall@Sun.COM 		res_ndestroy(statp);
4462830Sdjl 		return (NSS_ERROR);
4472924Smichen 	}
4482830Sdjl 	n = dn_expand(bom, eom, cp, host, MAXHOSTNAMELEN);
4492830Sdjl 	if (n < 0) {
450*10545SStacey.Marshall@Sun.COM 		res_ndestroy(statp);
4512830Sdjl 		return (NSS_ERROR);
4522830Sdjl 	} else
4532830Sdjl 		hlen = strlen(host);
4545161Smichen 	/* no host name is an error, return */
4555161Smichen 	if (hlen <= 0) {
456*10545SStacey.Marshall@Sun.COM 		res_ndestroy(statp);
4575161Smichen 		return (NSS_ERROR);
4585161Smichen 	}
4592830Sdjl 	cp += n + QFIXEDSZ;
4602924Smichen 	if (cp > eom) {
461*10545SStacey.Marshall@Sun.COM 		res_ndestroy(statp);
4622830Sdjl 		return (NSS_ERROR);
4632924Smichen 	}
4642830Sdjl 	while (ancount-- > 0 && cp < eom && blen < bsize) {
4652830Sdjl 		n = dn_expand(bom, eom, cp, ans, MAXHOSTNAMELEN);
4662830Sdjl 		if (n > 0) {
4676666Ssm26363 			/*
4686666Ssm26363 			 * Check that the expanded name is either the
4696666Ssm26363 			 * name we asked for or a learned alias.
4706666Ssm26363 			 */
47110544SStacey.Marshall@Sun.COM 			if ((isans = strncasecmp(host, ans, hlen)) != 0 &&
47210544SStacey.Marshall@Sun.COM 			    (alen == 0 || name_is_alias(aliases, ans)
47310544SStacey.Marshall@Sun.COM 			    == NSS_NOTFOUND)) {
474*10545SStacey.Marshall@Sun.COM 				res_ndestroy(statp);
4752830Sdjl 				return (NSS_ERROR);	/* spoof? */
4762924Smichen 			}
4772830Sdjl 		}
4782830Sdjl 		cp += n;
4792830Sdjl 		/* bounds check */
4802830Sdjl 		type = ns_get16(cp);			/* type */
4812830Sdjl 		cp += INT16SZ;
4822830Sdjl 		class = ns_get16(cp);			/* class */
4832830Sdjl 		cp += INT16SZ;
48410544SStacey.Marshall@Sun.COM 		nttl = (nssuint_t)ns_get32(cp);		/* ttl in sec */
4852830Sdjl 		if (nttl < ttl)
4862830Sdjl 			ttl = nttl;
4872830Sdjl 		cp += INT32SZ;
4882830Sdjl 		n = ns_get16(cp);			/* len */
4892830Sdjl 		cp += INT16SZ;
4902830Sdjl 		if (class != C_IN) {
4912830Sdjl 			cp += n;
4922830Sdjl 			continue;
4932830Sdjl 		}
4942830Sdjl 		eor = cp + n;
4952830Sdjl 		if (type == T_CNAME) {
4966666Ssm26363 			/*
49710544SStacey.Marshall@Sun.COM 			 * The name looked up is really an alias and the
49810544SStacey.Marshall@Sun.COM 			 * canonical name should be in the RDATA.
49910544SStacey.Marshall@Sun.COM 			 * A canonical name may have several aliases but an
50010544SStacey.Marshall@Sun.COM 			 * alias should only have one canonical name.
50110544SStacey.Marshall@Sun.COM 			 * However multiple CNAMEs and CNAME chains do exist!
50210544SStacey.Marshall@Sun.COM 			 *
50310544SStacey.Marshall@Sun.COM 			 * Just error out on attempted buffer overflow exploit,
50410544SStacey.Marshall@Sun.COM 			 * generic code will syslog.
50510544SStacey.Marshall@Sun.COM 			 *
5066666Ssm26363 			 */
5072830Sdjl 			n = dn_expand(bom, eor, cp, aname, MAXHOSTNAMELEN);
50810544SStacey.Marshall@Sun.COM 			if (n > 0 && (len = strlen(aname)) > 0) {
50910544SStacey.Marshall@Sun.COM 				if (isans == 0) { /* host matched ans. */
5102830Sdjl 					/*
51110544SStacey.Marshall@Sun.COM 					 * Append host to alias list.
5122830Sdjl 					 */
51310544SStacey.Marshall@Sun.COM 					if (alen + hlen + 2 > NS_MAXMSG) {
514*10545SStacey.Marshall@Sun.COM 						res_ndestroy(statp);
5152830Sdjl 						return (NSS_ERROR);
5163176Smichen 					}
5172830Sdjl 					*apc++ = ' ';
5182830Sdjl 					alen++;
51910544SStacey.Marshall@Sun.COM 					(void) strlcpy(apc, host,
52010544SStacey.Marshall@Sun.COM 					    NS_MAXMSG - alen);
52110544SStacey.Marshall@Sun.COM 					alen += hlen;
52210544SStacey.Marshall@Sun.COM 					apc += hlen;
5232830Sdjl 				}
52410544SStacey.Marshall@Sun.COM 				/*
52510544SStacey.Marshall@Sun.COM 				 * Overwrite host with canonical name.
52610544SStacey.Marshall@Sun.COM 				 */
52710544SStacey.Marshall@Sun.COM 				if (strlcpy(host, aname, MAXHOSTNAMELEN) >=
52810544SStacey.Marshall@Sun.COM 				    MAXHOSTNAMELEN) {
529*10545SStacey.Marshall@Sun.COM 					res_ndestroy(statp);
53010544SStacey.Marshall@Sun.COM 					return (NSS_ERROR);
53110544SStacey.Marshall@Sun.COM 				}
53210544SStacey.Marshall@Sun.COM 				hlen = len;
5332830Sdjl 			}
5342830Sdjl 			cp += n;
5352830Sdjl 			continue;
5362830Sdjl 		}
5372830Sdjl 		if (type != qtype) {
5382830Sdjl 			cp += n;
5392830Sdjl 			continue;
5402830Sdjl 		}
5412830Sdjl 		/* check data size */
5422830Sdjl 		if ((type == T_A && n != INADDRSZ) ||
5432830Sdjl 		    (type == T_AAAA && n != IN6ADDRSZ)) {
5442830Sdjl 			cp += n;
5452830Sdjl 			continue;
5462830Sdjl 		}
5472830Sdjl 		af = (type == T_A ? AF_INET : AF_INET6);
5482830Sdjl 		np = inet_ntop(af, (void *)cp, nbuf, INET6_ADDRSTRLEN);
5492924Smichen 		if (np == NULL) {
550*10545SStacey.Marshall@Sun.COM 			res_ndestroy(statp);
5512830Sdjl 			return (NSS_ERROR);
5522924Smichen 		}
5532830Sdjl 		cp += n;
5542830Sdjl 		/* append IP host aliases to results */
5552830Sdjl 		iplen = strlen(np);
5562830Sdjl 		/* ip <SP> hostname [<SP>][aliases] */
5572830Sdjl 		len = iplen + 2 + hlen + alen;
5582830Sdjl 		if (alen > 0)
5592830Sdjl 			len++;
5603176Smichen 		if (blen + len > bsize) {
561*10545SStacey.Marshall@Sun.COM 			res_ndestroy(statp);
5622830Sdjl 			return (NSS_ERROR);
5633176Smichen 		}
5642830Sdjl 		(void) strlcpy(bptr, np, bsize - blen);
5652830Sdjl 		blen += iplen;
5662830Sdjl 		bptr += iplen;
5672830Sdjl 		*bptr++ = ' ';
5682830Sdjl 		blen++;
5692830Sdjl 		(void) strlcpy(bptr, host, bsize - blen);
5702830Sdjl 		blen += hlen;
5712830Sdjl 		bptr += hlen;
5722830Sdjl 		if (alen > 0) {
5732830Sdjl 			*bptr++ = ' ';
5742830Sdjl 			blen++;
5752830Sdjl 			(void) strlcpy(bptr, ap, bsize - blen);
5762830Sdjl 			blen += alen;
5772830Sdjl 			bptr += alen;
5782830Sdjl 		}
5792830Sdjl 		*bptr++ = '\n';
5802830Sdjl 		blen++;
5812830Sdjl 	}
5822830Sdjl 	/* Presumably the buffer is now filled. */
5832830Sdjl 	len = ROUND_UP(blen, sizeof (nssuint_t));
5842830Sdjl 	/* still room? */
5852830Sdjl 	if (len + sizeof (nssuint_t) > pbuf->data_len) {
5862830Sdjl 		/* sigh, no, what happened? */
587*10545SStacey.Marshall@Sun.COM 		res_ndestroy(statp);
5882830Sdjl 		return (NSS_ERROR);
5892830Sdjl 	}
5902830Sdjl 	pbuf->ext_off = pbuf->data_off + len;
5912830Sdjl 	pbuf->ext_len = sizeof (nssuint_t);
5922830Sdjl 	pbuf->data_len = blen;
5932830Sdjl 	pttl = (nssuint_t *)((void *)((char *)pbuf + pbuf->ext_off));
5942830Sdjl 	*pttl = ttl;
595*10545SStacey.Marshall@Sun.COM 	res_ndestroy(statp);
5962830Sdjl 	return (NSS_SUCCESS);
5972830Sdjl }
598