17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5cb5caa98Sdjl  * Common Development and Distribution License (the "License").
6cb5caa98Sdjl  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2298a55d33SStacey Marshall  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23cb5caa98Sdjl  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
25e48cae6fSRobert Mustacchi /*
26e48cae6fSRobert Mustacchi  * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
27*778e4551SAndy Fiddaman  * Copyright 2023 Oxide Computer Company
28e48cae6fSRobert Mustacchi  */
297c478bd9Sstevel@tonic-gate 
30cb5caa98Sdjl /*
31cb5caa98Sdjl  *	dns_common.c
32cb5caa98Sdjl  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include "dns_common.h"
35e48cae6fSRobert Mustacchi #include <sys/types.h>
36e48cae6fSRobert Mustacchi #include <sys/socket.h>
37e48cae6fSRobert Mustacchi #include <ifaddrs.h>
38e48cae6fSRobert Mustacchi #include <net/if.h>
397c478bd9Sstevel@tonic-gate 
40cb5caa98Sdjl #pragma weak	dn_expand
41cb5caa98Sdjl #pragma weak	res_ninit
420e50326aSStacey Marshall #pragma weak	res_ndestroy
43cb5caa98Sdjl #pragma weak	res_nsearch
44cb5caa98Sdjl #pragma weak	res_nclose
45cb5caa98Sdjl #pragma weak	ns_get16
46cb5caa98Sdjl #pragma weak	ns_get32
47cb5caa98Sdjl #pragma weak	__ns_get16
48cb5caa98Sdjl #pragma weak	__ns_get32
49cb5caa98Sdjl 
507c478bd9Sstevel@tonic-gate #define	DNS_ALIASES	0
517c478bd9Sstevel@tonic-gate #define	DNS_ADDRLIST	1
527c478bd9Sstevel@tonic-gate #define	DNS_MAPDLIST	2
537c478bd9Sstevel@tonic-gate 
54940a40eaSsm #ifndef	tolower
55940a40eaSsm #define	tolower(c) ((c) >= 'A' && (c) <= 'Z' ? (c) | 0x20 : (c))
56940a40eaSsm #endif
57940a40eaSsm 
587c478bd9Sstevel@tonic-gate static int
dns_netdb_aliases(char ** from_list,char ** to_list,char ** aliaspp,int type,int * count,int af_type)59*778e4551SAndy Fiddaman dns_netdb_aliases(char **from_list, char **to_list, char **aliaspp, int type,
60*778e4551SAndy Fiddaman     int *count, int af_type)
617c478bd9Sstevel@tonic-gate {
627c478bd9Sstevel@tonic-gate 	char		*fstr;
637c478bd9Sstevel@tonic-gate 	int		cnt = 0;
647c478bd9Sstevel@tonic-gate 	size_t		len;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	*count = 0;
677c478bd9Sstevel@tonic-gate 	if ((char *)to_list >= *aliaspp)
687c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 	for (fstr = from_list[cnt]; fstr != NULL; fstr = from_list[cnt]) {
71*778e4551SAndy Fiddaman 		if (type == DNS_ALIASES) {
727c478bd9Sstevel@tonic-gate 			len = strlen(fstr) + 1;
73*778e4551SAndy Fiddaman 		} else {
74*778e4551SAndy Fiddaman 			len = (af_type == AF_INET) ? sizeof (struct in_addr) :
75*778e4551SAndy Fiddaman 			    sizeof (struct in6_addr);
76*778e4551SAndy Fiddaman 		}
777c478bd9Sstevel@tonic-gate 		*aliaspp -= len;
787c478bd9Sstevel@tonic-gate 		to_list[cnt] = *aliaspp;
797c478bd9Sstevel@tonic-gate 		if (*aliaspp <= (char *)&to_list[cnt+1])
807c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_ERANGE);
817c478bd9Sstevel@tonic-gate 		if (type == DNS_MAPDLIST) {
82cb5caa98Sdjl 			/* LINTED: E_BAD_PTR_CAST_ALIGN */
83cb5caa98Sdjl 			struct in6_addr *addr6p = (struct in6_addr *)*aliaspp;
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 			(void) memset(addr6p, '\0', sizeof (struct in6_addr));
867c478bd9Sstevel@tonic-gate 			(void) memcpy(&addr6p->s6_addr[12], fstr,
87*778e4551SAndy Fiddaman 			    sizeof (struct in_addr));
887c478bd9Sstevel@tonic-gate 			addr6p->s6_addr[10] = 0xffU;
897c478bd9Sstevel@tonic-gate 			addr6p->s6_addr[11] = 0xffU;
907c478bd9Sstevel@tonic-gate 			++cnt;
917c478bd9Sstevel@tonic-gate 		} else {
927c478bd9Sstevel@tonic-gate 			(void) memcpy (*aliaspp, fstr, len);
937c478bd9Sstevel@tonic-gate 			++cnt;
947c478bd9Sstevel@tonic-gate 		}
957c478bd9Sstevel@tonic-gate 	}
967c478bd9Sstevel@tonic-gate 	to_list[cnt] = NULL;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	*count = cnt;
997c478bd9Sstevel@tonic-gate 	if (cnt == 0)
1007c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	return (NSS_STR_PARSE_SUCCESS);
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate int
ent2result(struct hostent * he,nss_XbyY_args_t * argp,int af_type)107*778e4551SAndy Fiddaman ent2result(struct hostent *he, nss_XbyY_args_t *argp, int af_type)
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate 	char		*buffer, *limit;
1107c478bd9Sstevel@tonic-gate 	int		buflen = argp->buf.buflen;
1117c478bd9Sstevel@tonic-gate 	int		ret, count;
1127c478bd9Sstevel@tonic-gate 	size_t len;
113*778e4551SAndy Fiddaman 	struct hostent	*host;
1147c478bd9Sstevel@tonic-gate 	struct in_addr	*addrp;
1157c478bd9Sstevel@tonic-gate 	struct in6_addr	*addrp6;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	limit = argp->buf.buffer + buflen;
118cb5caa98Sdjl 	host = (struct hostent *)argp->buf.result;
1197c478bd9Sstevel@tonic-gate 	buffer = argp->buf.buffer;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	/* h_addrtype and h_length */
1227c478bd9Sstevel@tonic-gate 	host->h_addrtype = af_type;
123*778e4551SAndy Fiddaman 	host->h_length = (af_type == AF_INET) ? sizeof (struct in_addr) :
124*778e4551SAndy Fiddaman 	    sizeof (struct in6_addr);
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	/* h_name */
1277c478bd9Sstevel@tonic-gate 	len = strlen(he->h_name) + 1;
1287c478bd9Sstevel@tonic-gate 	host->h_name = buffer;
1297c478bd9Sstevel@tonic-gate 	if (host->h_name + len >= limit)
1307c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
1317c478bd9Sstevel@tonic-gate 	(void) memcpy(host->h_name, he->h_name, len);
1327c478bd9Sstevel@tonic-gate 	buffer += len;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	/* h_addr_list */
1357c478bd9Sstevel@tonic-gate 	if (af_type == AF_INET) {
136cb5caa98Sdjl 		addrp = (struct in_addr *)ROUND_DOWN(limit, sizeof (*addrp));
137*778e4551SAndy Fiddaman 		host->h_addr_list = (char **)ROUND_UP(buffer, sizeof (char **));
1387c478bd9Sstevel@tonic-gate 		ret = dns_netdb_aliases(he->h_addr_list, host->h_addr_list,
139*778e4551SAndy Fiddaman 		    (char **)&addrp, DNS_ADDRLIST, &count, af_type);
1407c478bd9Sstevel@tonic-gate 		if (ret != NSS_STR_PARSE_SUCCESS)
1417c478bd9Sstevel@tonic-gate 			return (ret);
1427c478bd9Sstevel@tonic-gate 		/* h_aliases */
1437c478bd9Sstevel@tonic-gate 		host->h_aliases = host->h_addr_list + count + 1;
1447c478bd9Sstevel@tonic-gate 		ret = dns_netdb_aliases(he->h_aliases, host->h_aliases,
145*778e4551SAndy Fiddaman 		    (char **)&addrp, DNS_ALIASES, &count, af_type);
1467c478bd9Sstevel@tonic-gate 	} else {
147*778e4551SAndy Fiddaman 		addrp6 = (struct in6_addr *)ROUND_DOWN(limit, sizeof (*addrp6));
148*778e4551SAndy Fiddaman 		host->h_addr_list = (char **)ROUND_UP(buffer, sizeof (char **));
1497c478bd9Sstevel@tonic-gate 		if (he->h_addrtype == AF_INET && af_type == AF_INET6) {
1507c478bd9Sstevel@tonic-gate 			ret = dns_netdb_aliases(he->h_addr_list,
151*778e4551SAndy Fiddaman 			    host->h_addr_list, (char **)&addrp6,
152*778e4551SAndy Fiddaman 			    DNS_MAPDLIST, &count, af_type);
1537c478bd9Sstevel@tonic-gate 		} else {
1547c478bd9Sstevel@tonic-gate 			ret = dns_netdb_aliases(he->h_addr_list,
155*778e4551SAndy Fiddaman 			    host->h_addr_list, (char **)&addrp6,
156*778e4551SAndy Fiddaman 			    DNS_ADDRLIST, &count, af_type);
1577c478bd9Sstevel@tonic-gate 		}
1587c478bd9Sstevel@tonic-gate 		if (ret != NSS_STR_PARSE_SUCCESS)
1597c478bd9Sstevel@tonic-gate 			return (ret);
1607c478bd9Sstevel@tonic-gate 		/* h_aliases */
1617c478bd9Sstevel@tonic-gate 		host->h_aliases = host->h_addr_list + count + 1;
1627c478bd9Sstevel@tonic-gate 		ret = dns_netdb_aliases(he->h_aliases, host->h_aliases,
163*778e4551SAndy Fiddaman 		    (char **)&addrp6, DNS_ALIASES, &count, af_type);
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate 	if (ret == NSS_STR_PARSE_PARSE)
1667c478bd9Sstevel@tonic-gate 		ret = NSS_STR_PARSE_SUCCESS;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	return (ret);
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
171cb5caa98Sdjl /*
172cb5caa98Sdjl  * Convert the hostent structure into string in the following
173cb5caa98Sdjl  * format:
174cb5caa98Sdjl  *
175cb5caa98Sdjl  * IP-address official-host-name nicknames ...
176cb5caa98Sdjl  *
177cb5caa98Sdjl  * If more than one IP-addresses matches the official-host-name,
178cb5caa98Sdjl  * the above line will be followed by:
179cb5caa98Sdjl  * IP-address-1 official-host-name
180cb5caa98Sdjl  * IP-address-2 official-host-name
181cb5caa98Sdjl  * ...
182cb5caa98Sdjl  *
183cb5caa98Sdjl  * This is so that the str2hostent function in libnsl
184cb5caa98Sdjl  * can convert the string back to the original hostent
185cb5caa98Sdjl  * data.
186cb5caa98Sdjl  */
187cb5caa98Sdjl int
ent2str(struct hostent * hp,nss_XbyY_args_t * ap,int af_type)188*778e4551SAndy Fiddaman ent2str(struct hostent	*hp, nss_XbyY_args_t *ap, int af_type)
189cb5caa98Sdjl {
190cb5caa98Sdjl 	char		**p;
191cb5caa98Sdjl 	char		obuf[INET6_ADDRSTRLEN];
192cb5caa98Sdjl 	void		*addr;
193cb5caa98Sdjl 	struct in_addr	in4;
194cb5caa98Sdjl 	int		af;
195cb5caa98Sdjl 	int		n;
196cb5caa98Sdjl 	const char	*res;
197cb5caa98Sdjl 	char		**q;
198cb5caa98Sdjl 	int		l = ap->buf.buflen;
199cb5caa98Sdjl 	char		*s = ap->buf.buffer;
200cb5caa98Sdjl 
201cb5caa98Sdjl 	/*
202cb5caa98Sdjl 	 * for "hosts" lookup, we only want address type of
203cb5caa98Sdjl 	 * AF_INET. For "ipnodes", we can have both AF_INET
204cb5caa98Sdjl 	 * and AF_INET6.
205cb5caa98Sdjl 	 */
206cb5caa98Sdjl 	if (af_type == AF_INET && hp->h_addrtype != AF_INET)
207cb5caa98Sdjl 		return (NSS_STR_PARSE_PARSE);
208cb5caa98Sdjl 
209cb5caa98Sdjl 	for (p = hp->h_addr_list; *p != 0; p++) {
210cb5caa98Sdjl 
211cb5caa98Sdjl 		if (p != hp->h_addr_list) {
212cb5caa98Sdjl 			*s = '\n';
213cb5caa98Sdjl 			s++;
214cb5caa98Sdjl 			l--;
215cb5caa98Sdjl 		}
216cb5caa98Sdjl 
217cb5caa98Sdjl 		if (hp->h_addrtype == AF_INET6) {
218cb5caa98Sdjl 			/* LINTED: E_BAD_PTR_CAST_ALIGN */
219cb5caa98Sdjl 			if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)*p)) {
220cb5caa98Sdjl 				/* LINTED: E_BAD_PTR_CAST_ALIGN */
221cb5caa98Sdjl 				IN6_V4MAPPED_TO_INADDR((struct in6_addr *)*p,
22280b80bf0Smichen 				    &in4);
223cb5caa98Sdjl 				af = AF_INET;
224cb5caa98Sdjl 				addr = &in4;
225cb5caa98Sdjl 			} else {
226cb5caa98Sdjl 				af = AF_INET6;
227cb5caa98Sdjl 				addr = *p;
228cb5caa98Sdjl 			}
229cb5caa98Sdjl 		} else {
230cb5caa98Sdjl 			af = AF_INET;
231cb5caa98Sdjl 			addr = *p;
232cb5caa98Sdjl 		}
233cb5caa98Sdjl 		res = inet_ntop(af, addr, obuf, sizeof (obuf));
234cb5caa98Sdjl 		if (res == NULL)
235cb5caa98Sdjl 			return (NSS_STR_PARSE_PARSE);
236cb5caa98Sdjl 
23780b80bf0Smichen 		if ((n = snprintf(s, l, "%s", res)) >= l)
238cb5caa98Sdjl 			return (NSS_STR_PARSE_ERANGE);
239cb5caa98Sdjl 		l -= n;
240cb5caa98Sdjl 		s += n;
24180b80bf0Smichen 		if (hp->h_name != NULL && *hp->h_name != '\0') {
24280b80bf0Smichen 			if ((n = snprintf(s, l, " %s", hp->h_name)) >= l)
24380b80bf0Smichen 				return (NSS_STR_PARSE_ERANGE);
24480b80bf0Smichen 			l -= n;
24580b80bf0Smichen 			s += n;
24680b80bf0Smichen 		}
247cb5caa98Sdjl 		if (p == hp->h_addr_list) {
248cb5caa98Sdjl 			for (q = hp->h_aliases; q && *q; q++) {
249cb5caa98Sdjl 				if ((n = snprintf(s, l, " %s", *q)) >= l)
250cb5caa98Sdjl 					return (NSS_STR_PARSE_ERANGE);
251cb5caa98Sdjl 				l -= n;
252cb5caa98Sdjl 				s += n;
253cb5caa98Sdjl 			}
254cb5caa98Sdjl 		}
255cb5caa98Sdjl 	}
256cb5caa98Sdjl 
257cb5caa98Sdjl 	ap->returnlen = s - ap->buf.buffer;
258cb5caa98Sdjl 	return (NSS_STR_PARSE_SUCCESS);
259cb5caa98Sdjl }
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate nss_backend_t *
_nss_dns_constr(dns_backend_op_t ops[],int n_ops)2627c478bd9Sstevel@tonic-gate _nss_dns_constr(dns_backend_op_t ops[], int n_ops)
2637c478bd9Sstevel@tonic-gate {
2647c478bd9Sstevel@tonic-gate 	dns_backend_ptr_t	be;
2657c478bd9Sstevel@tonic-gate 
266cb5caa98Sdjl 	if ((be = (dns_backend_ptr_t)malloc(sizeof (*be))) == 0)
2677c478bd9Sstevel@tonic-gate 		return (0);
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	be->ops = ops;
2707c478bd9Sstevel@tonic-gate 	be->n_ops = n_ops;
271cb5caa98Sdjl 	return ((nss_backend_t *)be);
272cb5caa98Sdjl }
273cb5caa98Sdjl 
274940a40eaSsm /*
275940a40eaSsm  * name_is_alias(aliases_ptr, name_ptr)
276940a40eaSsm  * Verify name matches an alias in the provided aliases list.
277940a40eaSsm  *
278940a40eaSsm  * Within DNS there should be only one canonical name, aliases should
279940a40eaSsm  * all refer to the one canonical.  However alias chains do occur and
280940a40eaSsm  * pre BIND 9 servers may also respond with multiple CNAMEs.  This
281940a40eaSsm  * routine checks if a given name has been provided as a CNAME in the
282940a40eaSsm  * response.  This assumes that the chains have been sent in-order.
283940a40eaSsm  *
284940a40eaSsm  * INPUT:
285940a40eaSsm  *  aliases_ptr: space separated list of alias names.
286940a40eaSsm  *  name_ptr: name to look for in aliases_ptr list.
28798a55d33SStacey Marshall  * RETURNS: NSS_SUCCESS or NSS_NOTFOUND
288940a40eaSsm  *  NSS_SUCCESS indicates that the name is listed in the collected aliases.
289940a40eaSsm  */
290940a40eaSsm static nss_status_t
name_is_alias(char * aliases_ptr,char * name_ptr)291*778e4551SAndy Fiddaman name_is_alias(char *aliases_ptr, char *name_ptr)
292*778e4551SAndy Fiddaman {
293940a40eaSsm 	char *host_ptr;
294940a40eaSsm 	/* Loop through alias string and compare it against host string. */
295940a40eaSsm 	while (*aliases_ptr != '\0') {
296940a40eaSsm 		host_ptr = name_ptr;
297940a40eaSsm 
298940a40eaSsm 		/* Compare name with alias. */
299940a40eaSsm 		while (tolower(*host_ptr) == tolower(*aliases_ptr) &&
300940a40eaSsm 		    *host_ptr != '\0') {
301940a40eaSsm 			host_ptr++;
302940a40eaSsm 			aliases_ptr++;
303940a40eaSsm 		}
304940a40eaSsm 
305940a40eaSsm 		/*
306940a40eaSsm 		 * If name was exhausted and the next character in the
307940a40eaSsm 		 * alias is either the end-of-string or space
308940a40eaSsm 		 * character then we have a match.
309940a40eaSsm 		 */
310940a40eaSsm 		if (*host_ptr == '\0' &&
311940a40eaSsm 		    (*aliases_ptr == '\0' || *aliases_ptr == ' ')) {
312940a40eaSsm 			return (NSS_SUCCESS);
313940a40eaSsm 		}
314940a40eaSsm 
315940a40eaSsm 		/* Alias did not match, step over remainder of alias. */
316940a40eaSsm 		while (*aliases_ptr != ' ' && *aliases_ptr != '\0')
317940a40eaSsm 			aliases_ptr++;
318940a40eaSsm 		/* Step over separator character. */
319940a40eaSsm 		while (*aliases_ptr == ' ') aliases_ptr++;
320940a40eaSsm 	}
32198a55d33SStacey Marshall 	return (NSS_NOTFOUND);
322940a40eaSsm }
323940a40eaSsm 
324e48cae6fSRobert Mustacchi static int
_nss_has_interfaces(boolean_t * v4,boolean_t * v6)325e48cae6fSRobert Mustacchi _nss_has_interfaces(boolean_t *v4, boolean_t *v6)
326e48cae6fSRobert Mustacchi {
327e48cae6fSRobert Mustacchi 	struct ifaddrs *ifp, *i;
328e48cae6fSRobert Mustacchi 	struct in_addr in4;
329e48cae6fSRobert Mustacchi 	struct in6_addr in6;
330e48cae6fSRobert Mustacchi 	const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
331e48cae6fSRobert Mustacchi 
332e48cae6fSRobert Mustacchi 	*v4 = *v6 = B_FALSE;
333e48cae6fSRobert Mustacchi 
334e48cae6fSRobert Mustacchi 	if (getifaddrs(&ifp) != 0)
335e48cae6fSRobert Mustacchi 		return (-1);
336e48cae6fSRobert Mustacchi 
337e48cae6fSRobert Mustacchi 	for (i = ifp; i != NULL; i = i->ifa_next) {
338e48cae6fSRobert Mustacchi 		if (i->ifa_flags & IFF_LOOPBACK)
339e48cae6fSRobert Mustacchi 			continue;
340e48cae6fSRobert Mustacchi 		if ((i->ifa_flags & IFF_UP) == 0)
341e48cae6fSRobert Mustacchi 			continue;
342e48cae6fSRobert Mustacchi 
343e48cae6fSRobert Mustacchi 		if (i->ifa_addr->sa_family == AF_INET) {
344e48cae6fSRobert Mustacchi 			if (*v4 != B_FALSE)
345e48cae6fSRobert Mustacchi 				continue;
346e48cae6fSRobert Mustacchi 
347e48cae6fSRobert Mustacchi 			if (((struct sockaddr_in *)i->ifa_addr)->
348e48cae6fSRobert Mustacchi 			    sin_addr.s_addr == INADDR_ANY)
349e48cae6fSRobert Mustacchi 				continue;
350e48cae6fSRobert Mustacchi 			*v4 = B_TRUE;
351e48cae6fSRobert Mustacchi 		}
352e48cae6fSRobert Mustacchi 
353e48cae6fSRobert Mustacchi 		if (i->ifa_addr->sa_family == AF_INET6) {
354e48cae6fSRobert Mustacchi 			if (*v6 != B_FALSE)
355e48cae6fSRobert Mustacchi 				continue;
356e48cae6fSRobert Mustacchi 
357e48cae6fSRobert Mustacchi 			if (memcmp(&in6addr_any,
358e48cae6fSRobert Mustacchi 			    &((struct sockaddr_in6 *)i->ifa_addr)->sin6_addr,
359e48cae6fSRobert Mustacchi 			    sizeof (struct in6_addr)) == 0)
360e48cae6fSRobert Mustacchi 				continue;
361e48cae6fSRobert Mustacchi 			*v6 = B_TRUE;
362e48cae6fSRobert Mustacchi 		}
363e48cae6fSRobert Mustacchi 	}
364e48cae6fSRobert Mustacchi 
365e48cae6fSRobert Mustacchi 	freeifaddrs(ifp);
366e48cae6fSRobert Mustacchi 	return (0);
367e48cae6fSRobert Mustacchi }
368e48cae6fSRobert Mustacchi 
369cb5caa98Sdjl /*
370cb5caa98Sdjl  * nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode)
371cb5caa98Sdjl  *      nss2 get hosts/ipnodes with ttl backend DNS search engine.
372cb5caa98Sdjl  *
373cb5caa98Sdjl  * This API is given a pointer to a packed buffer, and the buffer size
374cb5caa98Sdjl  * It's job is to perform the appropriate res_nsearch, extract the
375cb5caa98Sdjl  * results and build a unmarshalled hosts/ipnodes result buffer.
376cb5caa98Sdjl  * Additionally in the extended results a nssuint_t ttl is placed.
377cb5caa98Sdjl  * This ttl is the lessor of the ttl's extracted from the result.
378cb5caa98Sdjl  *
379cb5caa98Sdjl  * RETURNS:  NSS_SUCCESS or NSS_ERROR
380cb5caa98Sdjl  *	If an NSS_ERROR result is returned, nscd is expected
381cb5caa98Sdjl  *	to resubmit the gethosts request using the old style
382cb5caa98Sdjl  *	nsswitch lookup format.
383cb5caa98Sdjl  */
384cb5caa98Sdjl 
385cb5caa98Sdjl nss_status_t
_nss_dns_gethost_withttl(void * buffer,size_t bufsize,int ipnode)386cb5caa98Sdjl _nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode)
387cb5caa98Sdjl {
388cb5caa98Sdjl 	/* nss buffer variables */
389cb5caa98Sdjl 	nss_pheader_t	*pbuf = (nss_pheader_t *)buffer;
390cb5caa98Sdjl 	nss_XbyY_args_t	arg;
391cb5caa98Sdjl 	char		*dbname;
392cb5caa98Sdjl 	int		dbop;
393cb5caa98Sdjl 	nss_status_t	sret;
394cb5caa98Sdjl 	size_t		bsize, blen;
395cb5caa98Sdjl 	char		*bptr;
396cb5caa98Sdjl 	/* resolver query variables */
397c70a8a3bSmichen 	struct __res_state stat, *statp;	/* dns state block */
398c70a8a3bSmichen 	union msg {
399c70a8a3bSmichen 		uchar_t	buf[NS_MAXMSG];		/* max legal DNS answer size */
400c70a8a3bSmichen 		HEADER	h;
401c70a8a3bSmichen 	} resbuf;
402c70a8a3bSmichen 	char aliases[NS_MAXMSG];		/* set of aliases */
403cb5caa98Sdjl 	const char	*name;
404cb5caa98Sdjl 	int		qtype;
405cb5caa98Sdjl 	/* answer parsing variables */
406cb5caa98Sdjl 	HEADER		*hp;
407cb5caa98Sdjl 	uchar_t		*cp;	/* current location in message */
408cb5caa98Sdjl 	uchar_t		*bom;	/* start of message */
409cb5caa98Sdjl 	uchar_t		*eom;	/* end of message */
410cb5caa98Sdjl 	uchar_t		*eor;	/* end of record */
411cb5caa98Sdjl 	int		ancount, qdcount;
412cb5caa98Sdjl 	int		type, class;
413cb5caa98Sdjl 	nssuint_t	nttl, ttl, *pttl;	/* The purpose of this API */
414cb5caa98Sdjl 	int		n, ret;
415cb5caa98Sdjl 	const char	*np;
416cb5caa98Sdjl 	/* temporary buffers */
417cb5caa98Sdjl 	char		nbuf[INET6_ADDRSTRLEN];	/* address parser */
418cb5caa98Sdjl 	char		host[MAXHOSTNAMELEN];	/* result host name */
419cb5caa98Sdjl 	char		ans[MAXHOSTNAMELEN];	/* record name */
420cb5caa98Sdjl 	char		aname[MAXHOSTNAMELEN];	/* alias result (C_NAME) */
421cb5caa98Sdjl 	/* misc variables */
422cb5caa98Sdjl 	int		af;
423cb5caa98Sdjl 	char		*ap, *apc;
42498a55d33SStacey Marshall 	int		hlen = 0, alen, iplen, len, isans;
425e48cae6fSRobert Mustacchi 	boolean_t	has_v4 = B_FALSE, has_v6 = B_FALSE;
426e48cae6fSRobert Mustacchi 	int		flags, family, pass2 = 0;
427cb5caa98Sdjl 
428c70a8a3bSmichen 	statp = &stat;
429c70a8a3bSmichen 	(void) memset(statp, '\0', sizeof (struct __res_state));
430e48cae6fSRobert Mustacchi 	if (res_ninit(statp) == -1) {
431c70a8a3bSmichen 		return (NSS_ERROR);
432e48cae6fSRobert Mustacchi 	}
433c70a8a3bSmichen 
434c70a8a3bSmichen 	ap = apc = (char *)aliases;
435cb5caa98Sdjl 	alen = 0;
436cb5caa98Sdjl 	ttl = (nssuint_t)0xFFFFFFF;		/* start w/max, find smaller */
437cb5caa98Sdjl 
438cb5caa98Sdjl 	/* save space for ttl otherwise, why bother... */
439cb5caa98Sdjl 	bsize = pbuf->data_len - sizeof (nssuint_t);
440cb5caa98Sdjl 	bptr = (char *)buffer + pbuf->data_off;
441cb5caa98Sdjl 	blen = 0;
442cb5caa98Sdjl 	sret = nss_packed_getkey(buffer, bufsize, &dbname, &dbop, &arg);
443cb5caa98Sdjl 	if (sret != NSS_SUCCESS) {
4440e50326aSStacey Marshall 		res_ndestroy(statp);
445cb5caa98Sdjl 		return (NSS_ERROR);
446cb5caa98Sdjl 	}
447cb5caa98Sdjl 
448e48cae6fSRobert Mustacchi 	/*
449e48cae6fSRobert Mustacchi 	 * There may be flags set when we are handling ipnode. There are three
450e48cae6fSRobert Mustacchi 	 * different values for flags:
451e48cae6fSRobert Mustacchi 	 *
452e48cae6fSRobert Mustacchi 	 *  o AI_V4MAPPED
453e48cae6fSRobert Mustacchi 	 *  o AI_ALL
454e48cae6fSRobert Mustacchi 	 *  o AI_ADDRCONFIG
455e48cae6fSRobert Mustacchi 	 *
456e48cae6fSRobert Mustacchi 	 * The first two only have a meaning when af_family is ipv6. The latter
457e48cae6fSRobert Mustacchi 	 * means something in both cases. These flags are documented in
458e48cae6fSRobert Mustacchi 	 * getipnodebyname(3SOCKET), though the combinations leave a little
459e48cae6fSRobert Mustacchi 	 * something to be desired. It would be great if we could actually use
460e48cae6fSRobert Mustacchi 	 * getipnodebyname directly here since it already knows how to handle
461e48cae6fSRobert Mustacchi 	 * this kind of logic; however, we're not quite so lucky. Ideally we
462e48cae6fSRobert Mustacchi 	 * would add such an interface to libresolv.so.2 to handle this kind of
463e48cae6fSRobert Mustacchi 	 * thing, but that's rather painful as well. We'll summarize what has to
464e48cae6fSRobert Mustacchi 	 * happen below:
465e48cae6fSRobert Mustacchi 	 *
466e48cae6fSRobert Mustacchi 	 * AI_ALL is only meaningful when AI_V4MAPPED is also specified. Both
467e48cae6fSRobert Mustacchi 	 * are ignored if the family is not AF_INET6
468e48cae6fSRobert Mustacchi 	 *
469e48cae6fSRobert Mustacchi 	 * family == AF_INET, flags | AI_ADDRCONFIG
470e48cae6fSRobert Mustacchi 	 *  - lookup A records iff we have v4 plumbed
471e48cae6fSRobert Mustacchi 	 * family == AF_INET, !(flags | AI_ADDRCONFIG)
472e48cae6fSRobert Mustacchi 	 *  - lookup A records
473e48cae6fSRobert Mustacchi 	 * family == AF_INET6, flags == 0 || flags == AI_ALL
474e48cae6fSRobert Mustacchi 	 *  - lookup AAAA records
475e48cae6fSRobert Mustacchi 	 * family == AF_INET6, flags | AI_V4MAPPED
476e48cae6fSRobert Mustacchi 	 *  - lookup AAAA, if none, lookup A
477e48cae6fSRobert Mustacchi 	 * family == AF_INET6, flags | AI_ADDRCONFIG
478e48cae6fSRobert Mustacchi 	 *  - lookup AAAA records if ipv6
479e48cae6fSRobert Mustacchi 	 * family == AF_INET6, flags | AI_V4MAPPED && flags | AI_ALL
480e48cae6fSRobert Mustacchi 	 *  - lookup AAAA records, lookup A records
481e48cae6fSRobert Mustacchi 	 * family == AF_INET6, flags | AI_V4MAPPED && flags | AI_ADDRCONFIG
482e48cae6fSRobert Mustacchi 	 *  - lookup AAAA records if ipv6
483e48cae6fSRobert Mustacchi 	 *  - If no AAAA && ipv4 exists, lookup A
484e48cae6fSRobert Mustacchi 	 * family == AF_INET6, flags | AI_V4MAPPED && flags | AI_ADDRCONFIG &&
485e48cae6fSRobert Mustacchi 	 * flags | AI_ALL
486e48cae6fSRobert Mustacchi 	 *  - lookup AAAA records if ipv6
487e48cae6fSRobert Mustacchi 	 *  - loookup A records if ipv4
488e48cae6fSRobert Mustacchi 	 */
489cb5caa98Sdjl 	if (ipnode) {
490cb5caa98Sdjl 		/* initially only handle the simple cases */
491cb5caa98Sdjl 		name = arg.key.ipnode.name;
492e48cae6fSRobert Mustacchi 		flags = arg.key.ipnode.flags;
493e48cae6fSRobert Mustacchi 		family = arg.key.ipnode.af_family;
494e48cae6fSRobert Mustacchi 		if (flags != 0) {
495e48cae6fSRobert Mustacchi 			/*
496e48cae6fSRobert Mustacchi 			 * Figure out our first pass. We'll determine if we need
497e48cae6fSRobert Mustacchi 			 * to do a second pass afterwards once we successfully
498e48cae6fSRobert Mustacchi 			 * finish our first pass.
499e48cae6fSRobert Mustacchi 			 */
500e48cae6fSRobert Mustacchi 			if ((flags & AI_ADDRCONFIG) != 0) {
501e48cae6fSRobert Mustacchi 				if (_nss_has_interfaces(&has_v4, &has_v6) !=
502e48cae6fSRobert Mustacchi 				    0) {
503e48cae6fSRobert Mustacchi 					res_ndestroy(statp);
504e48cae6fSRobert Mustacchi 					return (NSS_ERROR);
505e48cae6fSRobert Mustacchi 				}
506e48cae6fSRobert Mustacchi 				/* Impossible situations... */
507e48cae6fSRobert Mustacchi 				if (family == AF_INET && has_v4 == B_FALSE) {
508e48cae6fSRobert Mustacchi 					res_ndestroy(statp);
509e48cae6fSRobert Mustacchi 					return (NSS_NOTFOUND);
510e48cae6fSRobert Mustacchi 				}
511e48cae6fSRobert Mustacchi 				if (family == AF_INET6 && has_v6 == B_FALSE &&
512e48cae6fSRobert Mustacchi 				    !(flags & AI_V4MAPPED)) {
513e48cae6fSRobert Mustacchi 					res_ndestroy(statp);
514e48cae6fSRobert Mustacchi 					return (NSS_NOTFOUND);
515e48cae6fSRobert Mustacchi 				}
516e48cae6fSRobert Mustacchi 				if (family == AF_INET6 && has_v6)
517e48cae6fSRobert Mustacchi 					qtype = T_AAAA;
518e48cae6fSRobert Mustacchi 				if (family == AF_INET || (family == AF_INET6 &&
519e48cae6fSRobert Mustacchi 				    has_v6 == B_FALSE && flags & AI_V4MAPPED))
520e48cae6fSRobert Mustacchi 					qtype = T_A;
521e48cae6fSRobert Mustacchi 			} else {
522e48cae6fSRobert Mustacchi 				has_v4 = has_v6 = B_TRUE;
523e48cae6fSRobert Mustacchi 				if (family == AF_INET6)
524e48cae6fSRobert Mustacchi 					qtype = T_AAAA;
525e48cae6fSRobert Mustacchi 				else
526e48cae6fSRobert Mustacchi 					qtype = T_A;
527e48cae6fSRobert Mustacchi 			}
528e48cae6fSRobert Mustacchi 		} else {
529e48cae6fSRobert Mustacchi 			if (family == AF_INET6)
530e48cae6fSRobert Mustacchi 				qtype = T_AAAA;
531e48cae6fSRobert Mustacchi 			else
532e48cae6fSRobert Mustacchi 				qtype = T_A;
533e48cae6fSRobert Mustacchi 		}
534cb5caa98Sdjl 	} else {
535cb5caa98Sdjl 		name = arg.key.name;
536cb5caa98Sdjl 		qtype = T_A;
537cb5caa98Sdjl 	}
538e48cae6fSRobert Mustacchi 
539e48cae6fSRobert Mustacchi searchagain:
540c70a8a3bSmichen 	ret = res_nsearch(statp, name, C_IN, qtype, resbuf.buf, NS_MAXMSG);
541cb5caa98Sdjl 	if (ret == -1) {
542e48cae6fSRobert Mustacchi 		/*
543e48cae6fSRobert Mustacchi 		 * We want to continue on unless we got NO_RECOVERY. Otherwise,
544e48cae6fSRobert Mustacchi 		 * HOST_NOT_FOUND, TRY_AGAIN, and NO_DATA all suggest to me that
545e48cae6fSRobert Mustacchi 		 * we should keep going.
546e48cae6fSRobert Mustacchi 		 */
547e48cae6fSRobert Mustacchi 		if (statp->res_h_errno == NO_RECOVERY) {
548e48cae6fSRobert Mustacchi 			/* else lookup error - handle in general code */
549e48cae6fSRobert Mustacchi 			res_ndestroy(statp);
550e48cae6fSRobert Mustacchi 			return (NSS_ERROR);
551e48cae6fSRobert Mustacchi 		}
552e48cae6fSRobert Mustacchi 
553e48cae6fSRobert Mustacchi 		/*
554e48cae6fSRobert Mustacchi 		 * We found something on our first pass. Make sure that we do
555e48cae6fSRobert Mustacchi 		 * not clobber this information. This ultimately means that we
556e48cae6fSRobert Mustacchi 		 * were successful.
557e48cae6fSRobert Mustacchi 		 */
558e48cae6fSRobert Mustacchi 		if (pass2 == 2)
559e48cae6fSRobert Mustacchi 			goto out;
560e48cae6fSRobert Mustacchi 
561e48cae6fSRobert Mustacchi 		/*
562e48cae6fSRobert Mustacchi 		 * If we're on the second pass (eg. we need to check both for A
563e48cae6fSRobert Mustacchi 		 * and AAAA records), or we were only ever doing a search for
564e48cae6fSRobert Mustacchi 		 * one type of record and are not supposed to do a second pass,
565e48cae6fSRobert Mustacchi 		 * then we need to return that we couldn't find anything to the
566e48cae6fSRobert Mustacchi 		 * user.
567e48cae6fSRobert Mustacchi 		 */
568e48cae6fSRobert Mustacchi 		if (pass2 == 1 || flags == 0 || family == AF_INET ||
569e48cae6fSRobert Mustacchi 		    (family == AF_INET6 && !(flags & AI_V4MAPPED))) {
570cb5caa98Sdjl 			pbuf->p_herrno = HOST_NOT_FOUND;
571cb5caa98Sdjl 			pbuf->p_status = NSS_NOTFOUND;
572cb5caa98Sdjl 			pbuf->data_len = 0;
5730e50326aSStacey Marshall 			res_ndestroy(statp);
574cb5caa98Sdjl 			return (NSS_NOTFOUND);
575cb5caa98Sdjl 		}
576e48cae6fSRobert Mustacchi 
577e48cae6fSRobert Mustacchi 		/*
578e48cae6fSRobert Mustacchi 		 * If we were only requested to search for flags on an IPv6
579e48cae6fSRobert Mustacchi 		 * interface or we have no IPv4 interface, we stick to only
580e48cae6fSRobert Mustacchi 		 * doing a single pass and bail now.
581e48cae6fSRobert Mustacchi 		 */
582e48cae6fSRobert Mustacchi 		if ((flags & AI_ADDRCONFIG) && !(flags & AI_ALL) &&
583e48cae6fSRobert Mustacchi 		    has_v4 == B_FALSE) {
584e48cae6fSRobert Mustacchi 			pbuf->p_herrno = HOST_NOT_FOUND;
585e48cae6fSRobert Mustacchi 			pbuf->p_status = NSS_NOTFOUND;
586e48cae6fSRobert Mustacchi 			pbuf->data_len = 0;
587e48cae6fSRobert Mustacchi 			res_ndestroy(statp);
588e48cae6fSRobert Mustacchi 			return (NSS_NOTFOUND);
589e48cae6fSRobert Mustacchi 		}
590e48cae6fSRobert Mustacchi 		qtype = T_A;
591e48cae6fSRobert Mustacchi 		flags = 0;
592e48cae6fSRobert Mustacchi 		pass2 = 1;
593e48cae6fSRobert Mustacchi 		goto searchagain;
594cb5caa98Sdjl 	}
595cb5caa98Sdjl 
596c70a8a3bSmichen 	cp = resbuf.buf;
597c70a8a3bSmichen 	hp = (HEADER *)&resbuf.h;
598cb5caa98Sdjl 	bom = cp;
599cb5caa98Sdjl 	eom = cp + ret;
600cb5caa98Sdjl 
601cb5caa98Sdjl 	ancount = ntohs(hp->ancount);
602cb5caa98Sdjl 	qdcount = ntohs(hp->qdcount);
603cb5caa98Sdjl 	cp += HFIXEDSZ;
604c70a8a3bSmichen 	if (qdcount != 1) {
6050e50326aSStacey Marshall 		res_ndestroy(statp);
606cb5caa98Sdjl 		return (NSS_ERROR);
607c70a8a3bSmichen 	}
608cb5caa98Sdjl 	n = dn_expand(bom, eom, cp, host, MAXHOSTNAMELEN);
609cb5caa98Sdjl 	if (n < 0) {
6100e50326aSStacey Marshall 		res_ndestroy(statp);
611cb5caa98Sdjl 		return (NSS_ERROR);
612cb5caa98Sdjl 	} else
613cb5caa98Sdjl 		hlen = strlen(host);
61480b80bf0Smichen 	/* no host name is an error, return */
61580b80bf0Smichen 	if (hlen <= 0) {
6160e50326aSStacey Marshall 		res_ndestroy(statp);
61780b80bf0Smichen 		return (NSS_ERROR);
61880b80bf0Smichen 	}
619cb5caa98Sdjl 	cp += n + QFIXEDSZ;
620c70a8a3bSmichen 	if (cp > eom) {
6210e50326aSStacey Marshall 		res_ndestroy(statp);
622cb5caa98Sdjl 		return (NSS_ERROR);
623c70a8a3bSmichen 	}
624cb5caa98Sdjl 	while (ancount-- > 0 && cp < eom && blen < bsize) {
625cb5caa98Sdjl 		n = dn_expand(bom, eom, cp, ans, MAXHOSTNAMELEN);
626cb5caa98Sdjl 		if (n > 0) {
627940a40eaSsm 			/*
628940a40eaSsm 			 * Check that the expanded name is either the
629940a40eaSsm 			 * name we asked for or a learned alias.
630940a40eaSsm 			 */
63198a55d33SStacey Marshall 			if ((isans = strncasecmp(host, ans, hlen)) != 0 &&
63298a55d33SStacey Marshall 			    (alen == 0 || name_is_alias(aliases, ans)
63398a55d33SStacey Marshall 			    == NSS_NOTFOUND)) {
6340e50326aSStacey Marshall 				res_ndestroy(statp);
635cb5caa98Sdjl 				return (NSS_ERROR);	/* spoof? */
636c70a8a3bSmichen 			}
637cb5caa98Sdjl 		}
638cb5caa98Sdjl 		cp += n;
639cb5caa98Sdjl 		/* bounds check */
640cb5caa98Sdjl 		type = ns_get16(cp);			/* type */
641cb5caa98Sdjl 		cp += INT16SZ;
642cb5caa98Sdjl 		class = ns_get16(cp);			/* class */
643cb5caa98Sdjl 		cp += INT16SZ;
64498a55d33SStacey Marshall 		nttl = (nssuint_t)ns_get32(cp);		/* ttl in sec */
645cb5caa98Sdjl 		if (nttl < ttl)
646cb5caa98Sdjl 			ttl = nttl;
647cb5caa98Sdjl 		cp += INT32SZ;
648cb5caa98Sdjl 		n = ns_get16(cp);			/* len */
649cb5caa98Sdjl 		cp += INT16SZ;
650cb5caa98Sdjl 		if (class != C_IN) {
651cb5caa98Sdjl 			cp += n;
652cb5caa98Sdjl 			continue;
653cb5caa98Sdjl 		}
654cb5caa98Sdjl 		eor = cp + n;
655cb5caa98Sdjl 		if (type == T_CNAME) {
656940a40eaSsm 			/*
65798a55d33SStacey Marshall 			 * The name looked up is really an alias and the
65898a55d33SStacey Marshall 			 * canonical name should be in the RDATA.
65998a55d33SStacey Marshall 			 * A canonical name may have several aliases but an
66098a55d33SStacey Marshall 			 * alias should only have one canonical name.
66198a55d33SStacey Marshall 			 * However multiple CNAMEs and CNAME chains do exist!
66298a55d33SStacey Marshall 			 *
66398a55d33SStacey Marshall 			 * Just error out on attempted buffer overflow exploit,
66498a55d33SStacey Marshall 			 * generic code will syslog.
66598a55d33SStacey Marshall 			 *
666940a40eaSsm 			 */
667cb5caa98Sdjl 			n = dn_expand(bom, eor, cp, aname, MAXHOSTNAMELEN);
66898a55d33SStacey Marshall 			if (n > 0 && (len = strlen(aname)) > 0) {
66998a55d33SStacey Marshall 				if (isans == 0) { /* host matched ans. */
670cb5caa98Sdjl 					/*
67198a55d33SStacey Marshall 					 * Append host to alias list.
672cb5caa98Sdjl 					 */
67398a55d33SStacey Marshall 					if (alen + hlen + 2 > NS_MAXMSG) {
6740e50326aSStacey Marshall 						res_ndestroy(statp);
675cb5caa98Sdjl 						return (NSS_ERROR);
676458d6ca5Smichen 					}
677cb5caa98Sdjl 					*apc++ = ' ';
678cb5caa98Sdjl 					alen++;
67998a55d33SStacey Marshall 					(void) strlcpy(apc, host,
68098a55d33SStacey Marshall 					    NS_MAXMSG - alen);
68198a55d33SStacey Marshall 					alen += hlen;
68298a55d33SStacey Marshall 					apc += hlen;
68398a55d33SStacey Marshall 				}
68498a55d33SStacey Marshall 				/*
68598a55d33SStacey Marshall 				 * Overwrite host with canonical name.
68698a55d33SStacey Marshall 				 */
68798a55d33SStacey Marshall 				if (strlcpy(host, aname, MAXHOSTNAMELEN) >=
68898a55d33SStacey Marshall 				    MAXHOSTNAMELEN) {
6890e50326aSStacey Marshall 					res_ndestroy(statp);
69098a55d33SStacey Marshall 					return (NSS_ERROR);
691cb5caa98Sdjl 				}
69298a55d33SStacey Marshall 				hlen = len;
693cb5caa98Sdjl 			}
694cb5caa98Sdjl 			cp += n;
695cb5caa98Sdjl 			continue;
696cb5caa98Sdjl 		}
697cb5caa98Sdjl 		if (type != qtype) {
698cb5caa98Sdjl 			cp += n;
699cb5caa98Sdjl 			continue;
700cb5caa98Sdjl 		}
701cb5caa98Sdjl 		/* check data size */
702cb5caa98Sdjl 		if ((type == T_A && n != INADDRSZ) ||
703cb5caa98Sdjl 		    (type == T_AAAA && n != IN6ADDRSZ)) {
704cb5caa98Sdjl 			cp += n;
705cb5caa98Sdjl 			continue;
706cb5caa98Sdjl 		}
707cb5caa98Sdjl 		af = (type == T_A ? AF_INET : AF_INET6);
708cb5caa98Sdjl 		np = inet_ntop(af, (void *)cp, nbuf, INET6_ADDRSTRLEN);
709c70a8a3bSmichen 		if (np == NULL) {
7100e50326aSStacey Marshall 			res_ndestroy(statp);
711cb5caa98Sdjl 			return (NSS_ERROR);
712c70a8a3bSmichen 		}
713cb5caa98Sdjl 		cp += n;
714cb5caa98Sdjl 		/* append IP host aliases to results */
715cb5caa98Sdjl 		iplen = strlen(np);
716cb5caa98Sdjl 		/* ip <SP> hostname [<SP>][aliases] */
717cb5caa98Sdjl 		len = iplen + 2 + hlen + alen;
718cb5caa98Sdjl 		if (alen > 0)
719cb5caa98Sdjl 			len++;
720458d6ca5Smichen 		if (blen + len > bsize) {
7210e50326aSStacey Marshall 			res_ndestroy(statp);
722cb5caa98Sdjl 			return (NSS_ERROR);
723458d6ca5Smichen 		}
724cb5caa98Sdjl 		(void) strlcpy(bptr, np, bsize - blen);
725cb5caa98Sdjl 		blen += iplen;
726cb5caa98Sdjl 		bptr += iplen;
727cb5caa98Sdjl 		*bptr++ = ' ';
728cb5caa98Sdjl 		blen++;
729cb5caa98Sdjl 		(void) strlcpy(bptr, host, bsize - blen);
730cb5caa98Sdjl 		blen += hlen;
731cb5caa98Sdjl 		bptr += hlen;
732cb5caa98Sdjl 		if (alen > 0) {
733cb5caa98Sdjl 			*bptr++ = ' ';
734cb5caa98Sdjl 			blen++;
735cb5caa98Sdjl 			(void) strlcpy(bptr, ap, bsize - blen);
736cb5caa98Sdjl 			blen += alen;
737cb5caa98Sdjl 			bptr += alen;
738cb5caa98Sdjl 		}
739cb5caa98Sdjl 		*bptr++ = '\n';
740cb5caa98Sdjl 		blen++;
741cb5caa98Sdjl 	}
742e48cae6fSRobert Mustacchi 
743e48cae6fSRobert Mustacchi 	/* Depending on our flags we may need to go back another time. */
744e48cae6fSRobert Mustacchi 	if (qtype == T_AAAA && family == AF_INET6 &&
745e48cae6fSRobert Mustacchi 	    ((flags & AI_V4MAPPED) != 0) && ((flags & AI_ALL) != 0) &&
746e48cae6fSRobert Mustacchi 	    has_v4 == B_TRUE) {
747e48cae6fSRobert Mustacchi 		qtype = T_A;
748e48cae6fSRobert Mustacchi 		pass2 = 2; /* Indicate that we found data this pass */
749e48cae6fSRobert Mustacchi 		goto searchagain;
750e48cae6fSRobert Mustacchi 	}
751e48cae6fSRobert Mustacchi 
752*778e4551SAndy Fiddaman out:
753cb5caa98Sdjl 	/* Presumably the buffer is now filled. */
754cb5caa98Sdjl 	len = ROUND_UP(blen, sizeof (nssuint_t));
755cb5caa98Sdjl 	/* still room? */
756cb5caa98Sdjl 	if (len + sizeof (nssuint_t) > pbuf->data_len) {
757cb5caa98Sdjl 		/* sigh, no, what happened? */
7580e50326aSStacey Marshall 		res_ndestroy(statp);
759cb5caa98Sdjl 		return (NSS_ERROR);
760cb5caa98Sdjl 	}
761*778e4551SAndy Fiddaman 
762cb5caa98Sdjl 	pbuf->ext_off = pbuf->data_off + len;
763cb5caa98Sdjl 	pbuf->ext_len = sizeof (nssuint_t);
764cb5caa98Sdjl 	pbuf->data_len = blen;
765cb5caa98Sdjl 	pttl = (nssuint_t *)((void *)((char *)pbuf + pbuf->ext_off));
766cb5caa98Sdjl 	*pttl = ttl;
7670e50326aSStacey Marshall 	res_ndestroy(statp);
768cb5caa98Sdjl 	return (NSS_SUCCESS);
7697c478bd9Sstevel@tonic-gate }
770