xref: /titanic_41/usr/src/lib/nsswitch/dns/common/dns_common.c (revision 099ad03fa646c3c5fc58f9436eb9cba67a40b929)
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  */
25*099ad03fSRobert Mustacchi /*
26*099ad03fSRobert Mustacchi  * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
27*099ad03fSRobert Mustacchi  */
287c478bd9Sstevel@tonic-gate 
29cb5caa98Sdjl /*
30cb5caa98Sdjl  *	dns_common.c
31cb5caa98Sdjl  */
32cb5caa98Sdjl 
337c478bd9Sstevel@tonic-gate #include "dns_common.h"
34*099ad03fSRobert Mustacchi #include <sys/types.h>
35*099ad03fSRobert Mustacchi #include <sys/socket.h>
36*099ad03fSRobert Mustacchi #include <ifaddrs.h>
37*099ad03fSRobert Mustacchi #include <net/if.h>
387c478bd9Sstevel@tonic-gate 
39cb5caa98Sdjl #pragma weak	dn_expand
40cb5caa98Sdjl #pragma weak	res_ninit
410e50326aSStacey Marshall #pragma weak	res_ndestroy
42cb5caa98Sdjl #pragma weak	res_nsearch
43cb5caa98Sdjl #pragma weak	res_nclose
44cb5caa98Sdjl #pragma weak	ns_get16
45cb5caa98Sdjl #pragma weak	ns_get32
46cb5caa98Sdjl #pragma weak	__ns_get16
47cb5caa98Sdjl #pragma weak	__ns_get32
48cb5caa98Sdjl 
497c478bd9Sstevel@tonic-gate #define	DNS_ALIASES	0
507c478bd9Sstevel@tonic-gate #define	DNS_ADDRLIST	1
517c478bd9Sstevel@tonic-gate #define	DNS_MAPDLIST	2
527c478bd9Sstevel@tonic-gate 
53940a40eaSsm26363 #ifndef	tolower
54940a40eaSsm26363 #define	tolower(c) ((c) >= 'A' && (c) <= 'Z' ? (c) | 0x20 : (c))
55940a40eaSsm26363 #endif
56940a40eaSsm26363 
577c478bd9Sstevel@tonic-gate static int
dns_netdb_aliases(from_list,to_list,aliaspp,type,count,af_type)587c478bd9Sstevel@tonic-gate dns_netdb_aliases(from_list, to_list, aliaspp, type, count, af_type)
597c478bd9Sstevel@tonic-gate 	char	**from_list, **to_list,	**aliaspp;
607c478bd9Sstevel@tonic-gate 	int	type, *count, 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]) {
717c478bd9Sstevel@tonic-gate 		if (type == DNS_ALIASES)
727c478bd9Sstevel@tonic-gate 			len = strlen(fstr) + 1;
737c478bd9Sstevel@tonic-gate 		else
747c478bd9Sstevel@tonic-gate 			len = (af_type == AF_INET) ? sizeof (struct in_addr)
757c478bd9Sstevel@tonic-gate 						: sizeof (struct in6_addr);
767c478bd9Sstevel@tonic-gate 		*aliaspp -= len;
777c478bd9Sstevel@tonic-gate 		to_list[cnt] = *aliaspp;
787c478bd9Sstevel@tonic-gate 		if (*aliaspp <= (char *)&to_list[cnt+1])
797c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_ERANGE);
807c478bd9Sstevel@tonic-gate 		if (type == DNS_MAPDLIST) {
81cb5caa98Sdjl 			/* LINTED: E_BAD_PTR_CAST_ALIGN */
827c478bd9Sstevel@tonic-gate 			struct in6_addr *addr6p = (struct in6_addr *)*aliaspp;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 			(void) memset(addr6p, '\0', sizeof (struct in6_addr));
857c478bd9Sstevel@tonic-gate 			(void) memcpy(&addr6p->s6_addr[12], fstr,
867c478bd9Sstevel@tonic-gate 					sizeof (struct in_addr));
877c478bd9Sstevel@tonic-gate 			addr6p->s6_addr[10] = 0xffU;
887c478bd9Sstevel@tonic-gate 			addr6p->s6_addr[11] = 0xffU;
897c478bd9Sstevel@tonic-gate 			++cnt;
907c478bd9Sstevel@tonic-gate 		} else {
917c478bd9Sstevel@tonic-gate 			(void) memcpy (*aliaspp, fstr, len);
927c478bd9Sstevel@tonic-gate 			++cnt;
937c478bd9Sstevel@tonic-gate 		}
947c478bd9Sstevel@tonic-gate 	}
957c478bd9Sstevel@tonic-gate 	to_list[cnt] = NULL;
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	*count = cnt;
987c478bd9Sstevel@tonic-gate 	if (cnt == 0)
997c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	return (NSS_STR_PARSE_SUCCESS);
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate int
ent2result(he,argp,af_type)1067c478bd9Sstevel@tonic-gate ent2result(he, argp, af_type)
1077c478bd9Sstevel@tonic-gate 	struct hostent		*he;
1087c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t		*argp;
1097c478bd9Sstevel@tonic-gate 	int			af_type;
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate 	char		*buffer, *limit;
1127c478bd9Sstevel@tonic-gate 	int		buflen = argp->buf.buflen;
1137c478bd9Sstevel@tonic-gate 	int		ret, count;
1147c478bd9Sstevel@tonic-gate 	size_t len;
1157c478bd9Sstevel@tonic-gate 	struct hostent 	*host;
1167c478bd9Sstevel@tonic-gate 	struct in_addr	*addrp;
1177c478bd9Sstevel@tonic-gate 	struct in6_addr	*addrp6;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	limit = argp->buf.buffer + buflen;
1207c478bd9Sstevel@tonic-gate 	host = (struct hostent *)argp->buf.result;
1217c478bd9Sstevel@tonic-gate 	buffer = argp->buf.buffer;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	/* h_addrtype and h_length */
1247c478bd9Sstevel@tonic-gate 	host->h_addrtype = af_type;
1257c478bd9Sstevel@tonic-gate 	host->h_length = (af_type == AF_INET) ? sizeof (struct in_addr)
1267c478bd9Sstevel@tonic-gate 					: sizeof (struct in6_addr);
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	/* h_name */
1297c478bd9Sstevel@tonic-gate 	len = strlen(he->h_name) + 1;
1307c478bd9Sstevel@tonic-gate 	host->h_name = buffer;
1317c478bd9Sstevel@tonic-gate 	if (host->h_name + len >= limit)
1327c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
1337c478bd9Sstevel@tonic-gate 	(void) memcpy(host->h_name, he->h_name, len);
1347c478bd9Sstevel@tonic-gate 	buffer += len;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	/* h_addr_list */
1377c478bd9Sstevel@tonic-gate 	if (af_type == AF_INET) {
1387c478bd9Sstevel@tonic-gate 		addrp = (struct in_addr *)ROUND_DOWN(limit, sizeof (*addrp));
1397c478bd9Sstevel@tonic-gate 		host->h_addr_list = (char **)
1407c478bd9Sstevel@tonic-gate 				ROUND_UP(buffer, sizeof (char **));
1417c478bd9Sstevel@tonic-gate 		ret = dns_netdb_aliases(he->h_addr_list, host->h_addr_list,
1427c478bd9Sstevel@tonic-gate 			(char **)&addrp, DNS_ADDRLIST, &count, af_type);
1437c478bd9Sstevel@tonic-gate 		if (ret != NSS_STR_PARSE_SUCCESS)
1447c478bd9Sstevel@tonic-gate 			return (ret);
1457c478bd9Sstevel@tonic-gate 		/* h_aliases */
1467c478bd9Sstevel@tonic-gate 		host->h_aliases = host->h_addr_list + count + 1;
1477c478bd9Sstevel@tonic-gate 		ret = dns_netdb_aliases(he->h_aliases, host->h_aliases,
1487c478bd9Sstevel@tonic-gate 			(char **)&addrp, DNS_ALIASES, &count, af_type);
1497c478bd9Sstevel@tonic-gate 	} else {
1507c478bd9Sstevel@tonic-gate 		addrp6 = (struct in6_addr *)
1517c478bd9Sstevel@tonic-gate 			ROUND_DOWN(limit, sizeof (*addrp6));
1527c478bd9Sstevel@tonic-gate 		host->h_addr_list = (char **)
1537c478bd9Sstevel@tonic-gate 			ROUND_UP(buffer, sizeof (char **));
1547c478bd9Sstevel@tonic-gate 		if (he->h_addrtype == AF_INET && af_type == AF_INET6) {
1557c478bd9Sstevel@tonic-gate 			ret = dns_netdb_aliases(he->h_addr_list,
1567c478bd9Sstevel@tonic-gate 				host->h_addr_list, (char **)&addrp6,
1577c478bd9Sstevel@tonic-gate 				DNS_MAPDLIST, &count, af_type);
1587c478bd9Sstevel@tonic-gate 		} else {
1597c478bd9Sstevel@tonic-gate 			ret = dns_netdb_aliases(he->h_addr_list,
1607c478bd9Sstevel@tonic-gate 				host->h_addr_list, (char **)&addrp6,
1617c478bd9Sstevel@tonic-gate 				DNS_ADDRLIST, &count, af_type);
1627c478bd9Sstevel@tonic-gate 		}
1637c478bd9Sstevel@tonic-gate 		if (ret != NSS_STR_PARSE_SUCCESS)
1647c478bd9Sstevel@tonic-gate 			return (ret);
1657c478bd9Sstevel@tonic-gate 		/* h_aliases */
1667c478bd9Sstevel@tonic-gate 		host->h_aliases = host->h_addr_list + count + 1;
1677c478bd9Sstevel@tonic-gate 		ret = dns_netdb_aliases(he->h_aliases, host->h_aliases,
1687c478bd9Sstevel@tonic-gate 			(char **)&addrp6, DNS_ALIASES, &count, af_type);
1697c478bd9Sstevel@tonic-gate 	}
1707c478bd9Sstevel@tonic-gate 	if (ret == NSS_STR_PARSE_PARSE)
1717c478bd9Sstevel@tonic-gate 		ret = NSS_STR_PARSE_SUCCESS;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	return (ret);
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate 
176cb5caa98Sdjl /*
177cb5caa98Sdjl  * Convert the hostent structure into string in the following
178cb5caa98Sdjl  * format:
179cb5caa98Sdjl  *
180cb5caa98Sdjl  * IP-address official-host-name nicknames ...
181cb5caa98Sdjl  *
182cb5caa98Sdjl  * If more than one IP-addresses matches the official-host-name,
183cb5caa98Sdjl  * the above line will be followed by:
184cb5caa98Sdjl  * IP-address-1 official-host-name
185cb5caa98Sdjl  * IP-address-2 official-host-name
186cb5caa98Sdjl  * ...
187cb5caa98Sdjl  *
188cb5caa98Sdjl  * This is so that the str2hostent function in libnsl
189cb5caa98Sdjl  * can convert the string back to the original hostent
190cb5caa98Sdjl  * data.
191cb5caa98Sdjl  */
192cb5caa98Sdjl int
ent2str(struct hostent * hp,nss_XbyY_args_t * ap,int af_type)193cb5caa98Sdjl ent2str(
194cb5caa98Sdjl 	struct hostent	*hp,
195cb5caa98Sdjl 	nss_XbyY_args_t *ap,
196cb5caa98Sdjl 	int		af_type)
197cb5caa98Sdjl {
198cb5caa98Sdjl 	char		**p;
199cb5caa98Sdjl 	char		obuf[INET6_ADDRSTRLEN];
200cb5caa98Sdjl 	void		*addr;
201cb5caa98Sdjl 	struct in_addr	in4;
202cb5caa98Sdjl 	int		af;
203cb5caa98Sdjl 	int		n;
204cb5caa98Sdjl 	const char	*res;
205cb5caa98Sdjl 	char		**q;
206cb5caa98Sdjl 	int		l = ap->buf.buflen;
207cb5caa98Sdjl 	char		*s = ap->buf.buffer;
208cb5caa98Sdjl 
209cb5caa98Sdjl 	/*
210cb5caa98Sdjl 	 * for "hosts" lookup, we only want address type of
211cb5caa98Sdjl 	 * AF_INET. For "ipnodes", we can have both AF_INET
212cb5caa98Sdjl 	 * and AF_INET6.
213cb5caa98Sdjl 	 */
214cb5caa98Sdjl 	if (af_type == AF_INET && hp->h_addrtype != AF_INET)
215cb5caa98Sdjl 		return (NSS_STR_PARSE_PARSE);
216cb5caa98Sdjl 
217cb5caa98Sdjl 	for (p = hp->h_addr_list; *p != 0; p++) {
218cb5caa98Sdjl 
219cb5caa98Sdjl 		if (p != hp->h_addr_list) {
220cb5caa98Sdjl 			*s = '\n';
221cb5caa98Sdjl 			s++;
222cb5caa98Sdjl 			l--;
223cb5caa98Sdjl 		}
224cb5caa98Sdjl 
225cb5caa98Sdjl 		if (hp->h_addrtype == AF_INET6) {
226cb5caa98Sdjl 			/* LINTED: E_BAD_PTR_CAST_ALIGN */
227cb5caa98Sdjl 			if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)*p)) {
228cb5caa98Sdjl 				/* LINTED: E_BAD_PTR_CAST_ALIGN */
229cb5caa98Sdjl 				IN6_V4MAPPED_TO_INADDR((struct in6_addr *)*p,
230cb5caa98Sdjl 				    &in4);
231cb5caa98Sdjl 				af = AF_INET;
232cb5caa98Sdjl 				addr = &in4;
233cb5caa98Sdjl 			} else {
234cb5caa98Sdjl 				af = AF_INET6;
235cb5caa98Sdjl 				addr = *p;
236cb5caa98Sdjl 			}
237cb5caa98Sdjl 		} else {
238cb5caa98Sdjl 			af = AF_INET;
239cb5caa98Sdjl 			addr = *p;
240cb5caa98Sdjl 		}
241cb5caa98Sdjl 		res = inet_ntop(af, addr, obuf, sizeof (obuf));
242cb5caa98Sdjl 		if (res == NULL)
243cb5caa98Sdjl 			return (NSS_STR_PARSE_PARSE);
244cb5caa98Sdjl 
24580b80bf0Smichen 		if ((n = snprintf(s, l, "%s", res)) >= l)
246cb5caa98Sdjl 			return (NSS_STR_PARSE_ERANGE);
247cb5caa98Sdjl 		l -= n;
248cb5caa98Sdjl 		s += n;
24980b80bf0Smichen 		if (hp->h_name != NULL && *hp->h_name != '\0') {
25080b80bf0Smichen 			if ((n = snprintf(s, l, " %s", hp->h_name)) >= l)
25180b80bf0Smichen 				return (NSS_STR_PARSE_ERANGE);
25280b80bf0Smichen 			l -= n;
25380b80bf0Smichen 			s += n;
25480b80bf0Smichen 		}
255cb5caa98Sdjl 		if (p == hp->h_addr_list) {
256cb5caa98Sdjl 			for (q = hp->h_aliases; q && *q; q++) {
257cb5caa98Sdjl 				if ((n = snprintf(s, l, " %s", *q)) >= l)
258cb5caa98Sdjl 					return (NSS_STR_PARSE_ERANGE);
259cb5caa98Sdjl 				l -= n;
260cb5caa98Sdjl 				s += n;
261cb5caa98Sdjl 			}
262cb5caa98Sdjl 		}
263cb5caa98Sdjl 	}
264cb5caa98Sdjl 
265cb5caa98Sdjl 	ap->returnlen = s - ap->buf.buffer;
266cb5caa98Sdjl 	return (NSS_STR_PARSE_SUCCESS);
267cb5caa98Sdjl }
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate nss_backend_t *
_nss_dns_constr(dns_backend_op_t ops[],int n_ops)2707c478bd9Sstevel@tonic-gate _nss_dns_constr(dns_backend_op_t ops[], int n_ops)
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate 	dns_backend_ptr_t	be;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	if ((be = (dns_backend_ptr_t)malloc(sizeof (*be))) == 0)
2757c478bd9Sstevel@tonic-gate 		return (0);
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	be->ops = ops;
2787c478bd9Sstevel@tonic-gate 	be->n_ops = n_ops;
2797c478bd9Sstevel@tonic-gate 	return ((nss_backend_t *)be);
2807c478bd9Sstevel@tonic-gate }
281cb5caa98Sdjl 
282458d6ca5Smichen /*
283940a40eaSsm26363  * name_is_alias(aliases_ptr, name_ptr)
284940a40eaSsm26363  * Verify name matches an alias in the provided aliases list.
285940a40eaSsm26363  *
286940a40eaSsm26363  * Within DNS there should be only one canonical name, aliases should
287940a40eaSsm26363  * all refer to the one canonical.  However alias chains do occur and
288940a40eaSsm26363  * pre BIND 9 servers may also respond with multiple CNAMEs.  This
289940a40eaSsm26363  * routine checks if a given name has been provided as a CNAME in the
290940a40eaSsm26363  * response.  This assumes that the chains have been sent in-order.
291940a40eaSsm26363  *
292940a40eaSsm26363  * INPUT:
293940a40eaSsm26363  *  aliases_ptr: space separated list of alias names.
294940a40eaSsm26363  *  name_ptr: name to look for in aliases_ptr list.
29598a55d33SStacey Marshall  * RETURNS: NSS_SUCCESS or NSS_NOTFOUND
296940a40eaSsm26363  *  NSS_SUCCESS indicates that the name is listed in the collected aliases.
297940a40eaSsm26363  */
298940a40eaSsm26363 static nss_status_t
name_is_alias(char * aliases_ptr,char * name_ptr)299940a40eaSsm26363 name_is_alias(char *aliases_ptr, char *name_ptr) {
300940a40eaSsm26363 	char *host_ptr;
301940a40eaSsm26363 	/* Loop through alias string and compare it against host string. */
302940a40eaSsm26363 	while (*aliases_ptr != '\0') {
303940a40eaSsm26363 		host_ptr = name_ptr;
304940a40eaSsm26363 
305940a40eaSsm26363 		/* Compare name with alias. */
306940a40eaSsm26363 		while (tolower(*host_ptr) == tolower(*aliases_ptr) &&
307940a40eaSsm26363 		    *host_ptr != '\0') {
308940a40eaSsm26363 			host_ptr++;
309940a40eaSsm26363 			aliases_ptr++;
310940a40eaSsm26363 		}
311940a40eaSsm26363 
312940a40eaSsm26363 		/*
313940a40eaSsm26363 		 * If name was exhausted and the next character in the
314940a40eaSsm26363 		 * alias is either the end-of-string or space
315940a40eaSsm26363 		 * character then we have a match.
316940a40eaSsm26363 		 */
317940a40eaSsm26363 		if (*host_ptr == '\0' &&
318940a40eaSsm26363 		    (*aliases_ptr == '\0' || *aliases_ptr == ' ')) {
319940a40eaSsm26363 			return (NSS_SUCCESS);
320940a40eaSsm26363 		}
321940a40eaSsm26363 
322940a40eaSsm26363 		/* Alias did not match, step over remainder of alias. */
323940a40eaSsm26363 		while (*aliases_ptr != ' ' && *aliases_ptr != '\0')
324940a40eaSsm26363 			aliases_ptr++;
325940a40eaSsm26363 		/* Step over separator character. */
326940a40eaSsm26363 		while (*aliases_ptr == ' ') aliases_ptr++;
327940a40eaSsm26363 	}
32898a55d33SStacey Marshall 	return (NSS_NOTFOUND);
329940a40eaSsm26363 }
330940a40eaSsm26363 
331*099ad03fSRobert Mustacchi static int
_nss_has_interfaces(boolean_t * v4,boolean_t * v6)332*099ad03fSRobert Mustacchi _nss_has_interfaces(boolean_t *v4, boolean_t *v6)
333*099ad03fSRobert Mustacchi {
334*099ad03fSRobert Mustacchi 	struct ifaddrs *ifp, *i;
335*099ad03fSRobert Mustacchi 	struct in_addr in4;
336*099ad03fSRobert Mustacchi 	struct in6_addr in6;
337*099ad03fSRobert Mustacchi 	const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
338*099ad03fSRobert Mustacchi 
339*099ad03fSRobert Mustacchi 	*v4 = *v6 = B_FALSE;
340*099ad03fSRobert Mustacchi 
341*099ad03fSRobert Mustacchi 	if (getifaddrs(&ifp) != 0)
342*099ad03fSRobert Mustacchi 		return (-1);
343*099ad03fSRobert Mustacchi 
344*099ad03fSRobert Mustacchi 	for (i = ifp; i != NULL; i = i->ifa_next) {
345*099ad03fSRobert Mustacchi 		if (i->ifa_flags & IFF_LOOPBACK)
346*099ad03fSRobert Mustacchi 			continue;
347*099ad03fSRobert Mustacchi 		if ((i->ifa_flags & IFF_UP) == 0)
348*099ad03fSRobert Mustacchi 			continue;
349*099ad03fSRobert Mustacchi 
350*099ad03fSRobert Mustacchi 		if (i->ifa_addr->sa_family == AF_INET) {
351*099ad03fSRobert Mustacchi 			if (*v4 != B_FALSE)
352*099ad03fSRobert Mustacchi 				continue;
353*099ad03fSRobert Mustacchi 
354*099ad03fSRobert Mustacchi 			if (((struct sockaddr_in *)i->ifa_addr)->
355*099ad03fSRobert Mustacchi 			    sin_addr.s_addr == INADDR_ANY)
356*099ad03fSRobert Mustacchi 				continue;
357*099ad03fSRobert Mustacchi 			*v4 = B_TRUE;
358*099ad03fSRobert Mustacchi 		}
359*099ad03fSRobert Mustacchi 
360*099ad03fSRobert Mustacchi 		if (i->ifa_addr->sa_family == AF_INET6) {
361*099ad03fSRobert Mustacchi 			if (*v6 != B_FALSE)
362*099ad03fSRobert Mustacchi 				continue;
363*099ad03fSRobert Mustacchi 
364*099ad03fSRobert Mustacchi 			if (memcmp(&in6addr_any,
365*099ad03fSRobert Mustacchi 			    &((struct sockaddr_in6 *)i->ifa_addr)->sin6_addr,
366*099ad03fSRobert Mustacchi 			    sizeof (struct in6_addr)) == 0)
367*099ad03fSRobert Mustacchi 				continue;
368*099ad03fSRobert Mustacchi 			*v6 = B_TRUE;
369*099ad03fSRobert Mustacchi 		}
370*099ad03fSRobert Mustacchi 	}
371*099ad03fSRobert Mustacchi 
372*099ad03fSRobert Mustacchi 	freeifaddrs(ifp);
373*099ad03fSRobert Mustacchi 	return (0);
374*099ad03fSRobert Mustacchi }
375*099ad03fSRobert Mustacchi 
376940a40eaSsm26363 /*
377cb5caa98Sdjl  * nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode)
378cb5caa98Sdjl  *      nss2 get hosts/ipnodes with ttl backend DNS search engine.
379cb5caa98Sdjl  *
380cb5caa98Sdjl  * This API is given a pointer to a packed buffer, and the buffer size
381cb5caa98Sdjl  * It's job is to perform the appropriate res_nsearch, extract the
382cb5caa98Sdjl  * results and build a unmarshalled hosts/ipnodes result buffer.
383cb5caa98Sdjl  * Additionally in the extended results a nssuint_t ttl is placed.
384cb5caa98Sdjl  * This ttl is the lessor of the ttl's extracted from the result.
385cb5caa98Sdjl  *
386cb5caa98Sdjl  * RETURNS:  NSS_SUCCESS or NSS_ERROR
387cb5caa98Sdjl  *	If an NSS_ERROR result is returned, nscd is expected
388cb5caa98Sdjl  *	to resubmit the gethosts request using the old style
389cb5caa98Sdjl  *	nsswitch lookup format.
390cb5caa98Sdjl  */
391cb5caa98Sdjl 
392cb5caa98Sdjl nss_status_t
_nss_dns_gethost_withttl(void * buffer,size_t bufsize,int ipnode)393cb5caa98Sdjl _nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode)
394cb5caa98Sdjl {
395cb5caa98Sdjl 	/* nss buffer variables */
396cb5caa98Sdjl 	nss_pheader_t	*pbuf = (nss_pheader_t *)buffer;
397cb5caa98Sdjl 	nss_XbyY_args_t	arg;
398cb5caa98Sdjl 	char		*dbname;
399cb5caa98Sdjl 	int		dbop;
400cb5caa98Sdjl 	nss_status_t	sret;
401cb5caa98Sdjl 	size_t		bsize, blen;
402cb5caa98Sdjl 	char		*bptr;
403cb5caa98Sdjl 	/* resolver query variables */
404c70a8a3bSmichen 	struct __res_state stat, *statp;	/* dns state block */
405c70a8a3bSmichen 	union msg {
406c70a8a3bSmichen 		uchar_t	buf[NS_MAXMSG];		/* max legal DNS answer size */
407c70a8a3bSmichen 		HEADER	h;
408c70a8a3bSmichen 	} resbuf;
409c70a8a3bSmichen 	char aliases[NS_MAXMSG];		/* set of aliases */
410cb5caa98Sdjl 	const char	*name;
411cb5caa98Sdjl 	int		qtype;
412cb5caa98Sdjl 	/* answer parsing variables */
413cb5caa98Sdjl 	HEADER		*hp;
414cb5caa98Sdjl 	uchar_t		*cp;	/* current location in message */
415cb5caa98Sdjl 	uchar_t		*bom;	/* start of message */
416cb5caa98Sdjl 	uchar_t		*eom;	/* end of message */
417cb5caa98Sdjl 	uchar_t		*eor;	/* end of record */
418cb5caa98Sdjl 	int		ancount, qdcount;
419cb5caa98Sdjl 	int		type, class;
420cb5caa98Sdjl 	nssuint_t	nttl, ttl, *pttl;	/* The purpose of this API */
421cb5caa98Sdjl 	int		n, ret;
422cb5caa98Sdjl 	const char	*np;
423cb5caa98Sdjl 	/* temporary buffers */
424cb5caa98Sdjl 	char		nbuf[INET6_ADDRSTRLEN];	/* address parser */
425cb5caa98Sdjl 	char		host[MAXHOSTNAMELEN];	/* result host name */
426cb5caa98Sdjl 	char		ans[MAXHOSTNAMELEN];	/* record name */
427cb5caa98Sdjl 	char		aname[MAXHOSTNAMELEN];	/* alias result (C_NAME) */
428cb5caa98Sdjl 	/* misc variables */
429cb5caa98Sdjl 	int		af;
430cb5caa98Sdjl 	char		*ap, *apc;
43198a55d33SStacey Marshall 	int		hlen = 0, alen, iplen, len, isans;
432*099ad03fSRobert Mustacchi 	boolean_t	has_v4 = B_FALSE, has_v6 = B_FALSE;
433*099ad03fSRobert Mustacchi 	int		flags, family, pass2 = 0;
434cb5caa98Sdjl 
435c70a8a3bSmichen 	statp = &stat;
436c70a8a3bSmichen 	(void) memset(statp, '\0', sizeof (struct __res_state));
437*099ad03fSRobert Mustacchi 	if (res_ninit(statp) == -1) {
438cb5caa98Sdjl 		return (NSS_ERROR);
439*099ad03fSRobert Mustacchi 	}
440c70a8a3bSmichen 
441c70a8a3bSmichen 	ap = apc = (char *)aliases;
442cb5caa98Sdjl 	alen = 0;
443cb5caa98Sdjl 	ttl = (nssuint_t)0xFFFFFFF;		/* start w/max, find smaller */
444cb5caa98Sdjl 
445cb5caa98Sdjl 	/* save space for ttl otherwise, why bother... */
446cb5caa98Sdjl 	bsize = pbuf->data_len - sizeof (nssuint_t);
447cb5caa98Sdjl 	bptr = (char *)buffer + pbuf->data_off;
448cb5caa98Sdjl 	blen = 0;
449cb5caa98Sdjl 	sret = nss_packed_getkey(buffer, bufsize, &dbname, &dbop, &arg);
450cb5caa98Sdjl 	if (sret != NSS_SUCCESS) {
4510e50326aSStacey Marshall 		res_ndestroy(statp);
452cb5caa98Sdjl 		return (NSS_ERROR);
453cb5caa98Sdjl 	}
454cb5caa98Sdjl 
455*099ad03fSRobert Mustacchi 	/*
456*099ad03fSRobert Mustacchi 	 * There may be flags set when we are handling ipnode. There are three
457*099ad03fSRobert Mustacchi 	 * different values for flags:
458*099ad03fSRobert Mustacchi 	 *
459*099ad03fSRobert Mustacchi 	 *  o AI_V4MAPPED
460*099ad03fSRobert Mustacchi 	 *  o AI_ALL
461*099ad03fSRobert Mustacchi 	 *  o AI_ADDRCONFIG
462*099ad03fSRobert Mustacchi 	 *
463*099ad03fSRobert Mustacchi 	 * The first two only have a meaning when af_family is ipv6. The latter
464*099ad03fSRobert Mustacchi 	 * means something in both cases. These flags are documented in
465*099ad03fSRobert Mustacchi 	 * getipnodebyname(3SOCKET), though the combinations leave a little
466*099ad03fSRobert Mustacchi 	 * something to be desired. It would be great if we could actually use
467*099ad03fSRobert Mustacchi 	 * getipnodebyname directly here since it already knows how to handle
468*099ad03fSRobert Mustacchi 	 * this kind of logic; however, we're not quite so lucky. Ideally we
469*099ad03fSRobert Mustacchi 	 * would add such an interface to libresolv.so.2 to handle this kind of
470*099ad03fSRobert Mustacchi 	 * thing, but that's rather painful as well. We'll summarize what has to
471*099ad03fSRobert Mustacchi 	 * happen below:
472*099ad03fSRobert Mustacchi 	 *
473*099ad03fSRobert Mustacchi 	 * AI_ALL is only meaningful when AI_V4MAPPED is also specified. Both
474*099ad03fSRobert Mustacchi 	 * are ignored if the family is not AF_INET6
475*099ad03fSRobert Mustacchi 	 *
476*099ad03fSRobert Mustacchi 	 * family == AF_INET, flags | AI_ADDRCONFIG
477*099ad03fSRobert Mustacchi 	 *  - lookup A records iff we have v4 plumbed
478*099ad03fSRobert Mustacchi 	 * family == AF_INET, !(flags | AI_ADDRCONFIG)
479*099ad03fSRobert Mustacchi 	 *  - lookup A records
480*099ad03fSRobert Mustacchi 	 * family == AF_INET6, flags == 0 || flags == AI_ALL
481*099ad03fSRobert Mustacchi 	 *  - lookup AAAA records
482*099ad03fSRobert Mustacchi 	 * family == AF_INET6, flags | AI_V4MAPPED
483*099ad03fSRobert Mustacchi 	 *  - lookup AAAA, if none, lookup A
484*099ad03fSRobert Mustacchi 	 * family == AF_INET6, flags | AI_ADDRCONFIG
485*099ad03fSRobert Mustacchi 	 *  - lookup AAAA records if ipv6
486*099ad03fSRobert Mustacchi 	 * family == AF_INET6, flags | AI_V4MAPPED && flags | AI_ALL
487*099ad03fSRobert Mustacchi 	 *  - lookup AAAA records, lookup A records
488*099ad03fSRobert Mustacchi 	 * family == AF_INET6, flags | AI_V4MAPPED && flags | AI_ADDRCONFIG
489*099ad03fSRobert Mustacchi 	 *  - lookup AAAA records if ipv6
490*099ad03fSRobert Mustacchi 	 *  - If no AAAA && ipv4 exists, lookup A
491*099ad03fSRobert Mustacchi 	 * family == AF_INET6, flags | AI_V4MAPPED && flags | AI_ADDRCONFIG &&
492*099ad03fSRobert Mustacchi 	 * flags | AI_ALL
493*099ad03fSRobert Mustacchi 	 *  - lookup AAAA records if ipv6
494*099ad03fSRobert Mustacchi 	 *  - loookup A records if ipv4
495*099ad03fSRobert Mustacchi 	 */
496cb5caa98Sdjl 	if (ipnode) {
497cb5caa98Sdjl 		/* initially only handle the simple cases */
498*099ad03fSRobert Mustacchi 		name = arg.key.ipnode.name;
499*099ad03fSRobert Mustacchi 		flags = arg.key.ipnode.flags;
500*099ad03fSRobert Mustacchi 		family = arg.key.ipnode.af_family;
501*099ad03fSRobert Mustacchi 		if (flags != 0) {
502*099ad03fSRobert Mustacchi 			/*
503*099ad03fSRobert Mustacchi 			 * Figure out our first pass. We'll determine if we need
504*099ad03fSRobert Mustacchi 			 * to do a second pass afterwards once we successfully
505*099ad03fSRobert Mustacchi 			 * finish our first pass.
506*099ad03fSRobert Mustacchi 			 */
507*099ad03fSRobert Mustacchi 			if ((flags & AI_ADDRCONFIG) != 0) {
508*099ad03fSRobert Mustacchi 				if (_nss_has_interfaces(&has_v4, &has_v6) !=
509*099ad03fSRobert Mustacchi 				    0) {
5100e50326aSStacey Marshall 					res_ndestroy(statp);
511cb5caa98Sdjl 					return (NSS_ERROR);
512c70a8a3bSmichen 				}
513*099ad03fSRobert Mustacchi 				/* Impossible situations... */
514*099ad03fSRobert Mustacchi 				if (family == AF_INET && has_v4 == B_FALSE) {
515*099ad03fSRobert Mustacchi 					res_ndestroy(statp);
516*099ad03fSRobert Mustacchi 					return (NSS_NOTFOUND);
517*099ad03fSRobert Mustacchi 				}
518*099ad03fSRobert Mustacchi 				if (family == AF_INET6 && has_v6 == B_FALSE &&
519*099ad03fSRobert Mustacchi 				    !(flags & AI_V4MAPPED)) {
520*099ad03fSRobert Mustacchi 					res_ndestroy(statp);
521*099ad03fSRobert Mustacchi 					return (NSS_NOTFOUND);
522*099ad03fSRobert Mustacchi 				}
523*099ad03fSRobert Mustacchi 				if (family == AF_INET6 && has_v6)
524*099ad03fSRobert Mustacchi 					qtype = T_AAAA;
525*099ad03fSRobert Mustacchi 				if (family == AF_INET || (family == AF_INET6 &&
526*099ad03fSRobert Mustacchi 				    has_v6 == B_FALSE && flags & AI_V4MAPPED))
527*099ad03fSRobert Mustacchi 					qtype = T_A;
528*099ad03fSRobert Mustacchi 			} else {
529*099ad03fSRobert Mustacchi 				has_v4 = has_v6 = B_TRUE;
530*099ad03fSRobert Mustacchi 				if (family == AF_INET6)
531cb5caa98Sdjl 					qtype = T_AAAA;
532cb5caa98Sdjl 				else
533cb5caa98Sdjl 					qtype = T_A;
534*099ad03fSRobert Mustacchi 			}
535*099ad03fSRobert Mustacchi 		} else {
536*099ad03fSRobert Mustacchi 			if (family == AF_INET6)
537*099ad03fSRobert Mustacchi 				qtype = T_AAAA;
538*099ad03fSRobert Mustacchi 			else
539*099ad03fSRobert Mustacchi 				qtype = T_A;
540*099ad03fSRobert Mustacchi 		}
541cb5caa98Sdjl 	} else {
542cb5caa98Sdjl 		name = arg.key.name;
543cb5caa98Sdjl 		qtype = T_A;
544cb5caa98Sdjl 	}
545*099ad03fSRobert Mustacchi 
546*099ad03fSRobert Mustacchi searchagain:
547c70a8a3bSmichen 	ret = res_nsearch(statp, name, C_IN, qtype, resbuf.buf, NS_MAXMSG);
548cb5caa98Sdjl 	if (ret == -1) {
549*099ad03fSRobert Mustacchi 		/*
550*099ad03fSRobert Mustacchi 		 * We want to continue on unless we got NO_RECOVERY. Otherwise,
551*099ad03fSRobert Mustacchi 		 * HOST_NOT_FOUND, TRY_AGAIN, and NO_DATA all suggest to me that
552*099ad03fSRobert Mustacchi 		 * we should keep going.
553*099ad03fSRobert Mustacchi 		 */
554*099ad03fSRobert Mustacchi 		if (statp->res_h_errno == NO_RECOVERY) {
555*099ad03fSRobert Mustacchi 			/* else lookup error - handle in general code */
556*099ad03fSRobert Mustacchi 			res_ndestroy(statp);
557*099ad03fSRobert Mustacchi 			return (NSS_ERROR);
558*099ad03fSRobert Mustacchi 		}
559*099ad03fSRobert Mustacchi 
560*099ad03fSRobert Mustacchi 		/*
561*099ad03fSRobert Mustacchi 		 * We found something on our first pass. Make sure that we do
562*099ad03fSRobert Mustacchi 		 * not clobber this information. This ultimately means that we
563*099ad03fSRobert Mustacchi 		 * were successful.
564*099ad03fSRobert Mustacchi 		 */
565*099ad03fSRobert Mustacchi 		if (pass2 == 2)
566*099ad03fSRobert Mustacchi 			goto out;
567*099ad03fSRobert Mustacchi 
568*099ad03fSRobert Mustacchi 		/*
569*099ad03fSRobert Mustacchi 		 * If we're on the second pass (eg. we need to check both for A
570*099ad03fSRobert Mustacchi 		 * and AAAA records), or we were only ever doing a search for
571*099ad03fSRobert Mustacchi 		 * one type of record and are not supposed to do a second pass,
572*099ad03fSRobert Mustacchi 		 * then we need to return that we couldn't find anything to the
573*099ad03fSRobert Mustacchi 		 * user.
574*099ad03fSRobert Mustacchi 		 */
575*099ad03fSRobert Mustacchi 		if (pass2 == 1 || flags == 0 || family == AF_INET ||
576*099ad03fSRobert Mustacchi 		    (family == AF_INET6 && !(flags & AI_V4MAPPED))) {
577cb5caa98Sdjl 			pbuf->p_herrno = HOST_NOT_FOUND;
578cb5caa98Sdjl 			pbuf->p_status = NSS_NOTFOUND;
579cb5caa98Sdjl 			pbuf->data_len = 0;
5800e50326aSStacey Marshall 			res_ndestroy(statp);
581cb5caa98Sdjl 			return (NSS_NOTFOUND);
582cb5caa98Sdjl 		}
583*099ad03fSRobert Mustacchi 
584*099ad03fSRobert Mustacchi 		/*
585*099ad03fSRobert Mustacchi 		 * If we were only requested to search for flags on an IPv6
586*099ad03fSRobert Mustacchi 		 * interface or we have no IPv4 interface, we stick to only
587*099ad03fSRobert Mustacchi 		 * doing a single pass and bail now.
588*099ad03fSRobert Mustacchi 		 */
589*099ad03fSRobert Mustacchi 		if ((flags & AI_ADDRCONFIG) && !(flags & AI_ALL) &&
590*099ad03fSRobert Mustacchi 		    has_v4 == B_FALSE) {
591*099ad03fSRobert Mustacchi 			pbuf->p_herrno = HOST_NOT_FOUND;
592*099ad03fSRobert Mustacchi 			pbuf->p_status = NSS_NOTFOUND;
593*099ad03fSRobert Mustacchi 			pbuf->data_len = 0;
5940e50326aSStacey Marshall 			res_ndestroy(statp);
595*099ad03fSRobert Mustacchi 			return (NSS_NOTFOUND);
596*099ad03fSRobert Mustacchi 		}
597*099ad03fSRobert Mustacchi 		qtype = T_A;
598*099ad03fSRobert Mustacchi 		flags = 0;
599*099ad03fSRobert Mustacchi 		pass2 = 1;
600*099ad03fSRobert Mustacchi 		goto searchagain;
601cb5caa98Sdjl 	}
602cb5caa98Sdjl 
603c70a8a3bSmichen 	cp = resbuf.buf;
604c70a8a3bSmichen 	hp = (HEADER *)&resbuf.h;
605cb5caa98Sdjl 	bom = cp;
606cb5caa98Sdjl 	eom = cp + ret;
607cb5caa98Sdjl 
608cb5caa98Sdjl 	ancount = ntohs(hp->ancount);
609cb5caa98Sdjl 	qdcount = ntohs(hp->qdcount);
610cb5caa98Sdjl 	cp += HFIXEDSZ;
611c70a8a3bSmichen 	if (qdcount != 1) {
6120e50326aSStacey Marshall 		res_ndestroy(statp);
613cb5caa98Sdjl 		return (NSS_ERROR);
614c70a8a3bSmichen 	}
615cb5caa98Sdjl 	n = dn_expand(bom, eom, cp, host, MAXHOSTNAMELEN);
616cb5caa98Sdjl 	if (n < 0) {
6170e50326aSStacey Marshall 		res_ndestroy(statp);
618cb5caa98Sdjl 		return (NSS_ERROR);
619cb5caa98Sdjl 	} else
620cb5caa98Sdjl 		hlen = strlen(host);
62180b80bf0Smichen 	/* no host name is an error, return */
62280b80bf0Smichen 	if (hlen <= 0) {
6230e50326aSStacey Marshall 		res_ndestroy(statp);
62480b80bf0Smichen 		return (NSS_ERROR);
62580b80bf0Smichen 	}
626cb5caa98Sdjl 	cp += n + QFIXEDSZ;
627c70a8a3bSmichen 	if (cp > eom) {
6280e50326aSStacey Marshall 		res_ndestroy(statp);
629cb5caa98Sdjl 		return (NSS_ERROR);
630c70a8a3bSmichen 	}
631cb5caa98Sdjl 	while (ancount-- > 0 && cp < eom && blen < bsize) {
632cb5caa98Sdjl 		n = dn_expand(bom, eom, cp, ans, MAXHOSTNAMELEN);
633cb5caa98Sdjl 		if (n > 0) {
634940a40eaSsm26363 			/*
635940a40eaSsm26363 			 * Check that the expanded name is either the
636940a40eaSsm26363 			 * name we asked for or a learned alias.
637940a40eaSsm26363 			 */
63898a55d33SStacey Marshall 			if ((isans = strncasecmp(host, ans, hlen)) != 0 &&
63998a55d33SStacey Marshall 			    (alen == 0 || name_is_alias(aliases, ans)
64098a55d33SStacey Marshall 			    == NSS_NOTFOUND)) {
6410e50326aSStacey Marshall 				res_ndestroy(statp);
642cb5caa98Sdjl 				return (NSS_ERROR);	/* spoof? */
643cb5caa98Sdjl 			}
644c70a8a3bSmichen 		}
645cb5caa98Sdjl 		cp += n;
646cb5caa98Sdjl 		/* bounds check */
647cb5caa98Sdjl 		type = ns_get16(cp);			/* type */
648cb5caa98Sdjl 		cp += INT16SZ;
649cb5caa98Sdjl 		class = ns_get16(cp);			/* class */
650cb5caa98Sdjl 		cp += INT16SZ;
651cb5caa98Sdjl 		nttl = (nssuint_t)ns_get32(cp);		/* ttl in sec */
652cb5caa98Sdjl 		if (nttl < ttl)
653cb5caa98Sdjl 			ttl = nttl;
654cb5caa98Sdjl 		cp += INT32SZ;
655cb5caa98Sdjl 		n = ns_get16(cp);			/* len */
656cb5caa98Sdjl 		cp += INT16SZ;
657cb5caa98Sdjl 		if (class != C_IN) {
658cb5caa98Sdjl 			cp += n;
659cb5caa98Sdjl 			continue;
660cb5caa98Sdjl 		}
661cb5caa98Sdjl 		eor = cp + n;
662cb5caa98Sdjl 		if (type == T_CNAME) {
663940a40eaSsm26363 			/*
66498a55d33SStacey Marshall 			 * The name looked up is really an alias and the
66598a55d33SStacey Marshall 			 * canonical name should be in the RDATA.
66698a55d33SStacey Marshall 			 * A canonical name may have several aliases but an
66798a55d33SStacey Marshall 			 * alias should only have one canonical name.
66898a55d33SStacey Marshall 			 * However multiple CNAMEs and CNAME chains do exist!
66998a55d33SStacey Marshall 			 *
67098a55d33SStacey Marshall 			 * Just error out on attempted buffer overflow exploit,
67198a55d33SStacey Marshall 			 * generic code will syslog.
67298a55d33SStacey Marshall 			 *
673940a40eaSsm26363 			 */
674cb5caa98Sdjl 			n = dn_expand(bom, eor, cp, aname, MAXHOSTNAMELEN);
67598a55d33SStacey Marshall 			if (n > 0 && (len = strlen(aname)) > 0) {
67698a55d33SStacey Marshall 				if (isans == 0) { /* host matched ans. */
677cb5caa98Sdjl 					/*
67898a55d33SStacey Marshall 					 * Append host to alias list.
679cb5caa98Sdjl 					 */
68098a55d33SStacey Marshall 					if (alen + hlen + 2 > NS_MAXMSG) {
6810e50326aSStacey Marshall 						res_ndestroy(statp);
682cb5caa98Sdjl 						return (NSS_ERROR);
683458d6ca5Smichen 					}
684cb5caa98Sdjl 					*apc++ = ' ';
685cb5caa98Sdjl 					alen++;
68698a55d33SStacey Marshall 					(void) strlcpy(apc, host,
68798a55d33SStacey Marshall 					    NS_MAXMSG - alen);
68898a55d33SStacey Marshall 					alen += hlen;
68998a55d33SStacey Marshall 					apc += hlen;
690cb5caa98Sdjl 				}
69198a55d33SStacey Marshall 				/*
69298a55d33SStacey Marshall 				 * Overwrite host with canonical name.
69398a55d33SStacey Marshall 				 */
69498a55d33SStacey Marshall 				if (strlcpy(host, aname, MAXHOSTNAMELEN) >=
69598a55d33SStacey Marshall 				    MAXHOSTNAMELEN) {
6960e50326aSStacey Marshall 					res_ndestroy(statp);
69798a55d33SStacey Marshall 					return (NSS_ERROR);
69898a55d33SStacey Marshall 				}
69998a55d33SStacey Marshall 				hlen = len;
700cb5caa98Sdjl 			}
701cb5caa98Sdjl 			cp += n;
702cb5caa98Sdjl 			continue;
703cb5caa98Sdjl 		}
704cb5caa98Sdjl 		if (type != qtype) {
705cb5caa98Sdjl 			cp += n;
706cb5caa98Sdjl 			continue;
707cb5caa98Sdjl 		}
708cb5caa98Sdjl 		/* check data size */
709cb5caa98Sdjl 		if ((type == T_A && n != INADDRSZ) ||
710cb5caa98Sdjl 		    (type == T_AAAA && n != IN6ADDRSZ)) {
711cb5caa98Sdjl 			cp += n;
712cb5caa98Sdjl 			continue;
713cb5caa98Sdjl 		}
714cb5caa98Sdjl 		af = (type == T_A ? AF_INET : AF_INET6);
715cb5caa98Sdjl 		np = inet_ntop(af, (void *)cp, nbuf, INET6_ADDRSTRLEN);
716c70a8a3bSmichen 		if (np == NULL) {
7170e50326aSStacey Marshall 			res_ndestroy(statp);
718cb5caa98Sdjl 			return (NSS_ERROR);
719c70a8a3bSmichen 		}
720cb5caa98Sdjl 		cp += n;
721cb5caa98Sdjl 		/* append IP host aliases to results */
722cb5caa98Sdjl 		iplen = strlen(np);
723cb5caa98Sdjl 		/* ip <SP> hostname [<SP>][aliases] */
724cb5caa98Sdjl 		len = iplen + 2 + hlen + alen;
725cb5caa98Sdjl 		if (alen > 0)
726cb5caa98Sdjl 			len++;
727458d6ca5Smichen 		if (blen + len > bsize) {
7280e50326aSStacey Marshall 			res_ndestroy(statp);
729cb5caa98Sdjl 			return (NSS_ERROR);
730458d6ca5Smichen 		}
731cb5caa98Sdjl 		(void) strlcpy(bptr, np, bsize - blen);
732cb5caa98Sdjl 		blen += iplen;
733cb5caa98Sdjl 		bptr += iplen;
734cb5caa98Sdjl 		*bptr++ = ' ';
735cb5caa98Sdjl 		blen++;
736cb5caa98Sdjl 		(void) strlcpy(bptr, host, bsize - blen);
737cb5caa98Sdjl 		blen += hlen;
738cb5caa98Sdjl 		bptr += hlen;
739cb5caa98Sdjl 		if (alen > 0) {
740cb5caa98Sdjl 			*bptr++ = ' ';
741cb5caa98Sdjl 			blen++;
742cb5caa98Sdjl 			(void) strlcpy(bptr, ap, bsize - blen);
743cb5caa98Sdjl 			blen += alen;
744cb5caa98Sdjl 			bptr += alen;
745cb5caa98Sdjl 		}
746cb5caa98Sdjl 		*bptr++ = '\n';
747cb5caa98Sdjl 		blen++;
748cb5caa98Sdjl 	}
749*099ad03fSRobert Mustacchi 
750*099ad03fSRobert Mustacchi 	/* Depending on our flags we may need to go back another time. */
751*099ad03fSRobert Mustacchi 	if (qtype == T_AAAA && family == AF_INET6 &&
752*099ad03fSRobert Mustacchi 	    ((flags & AI_V4MAPPED) != 0) && ((flags & AI_ALL) != 0) &&
753*099ad03fSRobert Mustacchi 	    has_v4 == B_TRUE) {
754*099ad03fSRobert Mustacchi 		qtype = T_A;
755*099ad03fSRobert Mustacchi 		pass2 = 2; /* Indicate that we found data this pass */
756*099ad03fSRobert Mustacchi 		goto searchagain;
757*099ad03fSRobert Mustacchi 	}
758*099ad03fSRobert Mustacchi 
759cb5caa98Sdjl 	/* Presumably the buffer is now filled. */
760cb5caa98Sdjl 	len = ROUND_UP(blen, sizeof (nssuint_t));
761cb5caa98Sdjl 	/* still room? */
762cb5caa98Sdjl 	if (len + sizeof (nssuint_t) > pbuf->data_len) {
763cb5caa98Sdjl 		/* sigh, no, what happened? */
7640e50326aSStacey Marshall 		res_ndestroy(statp);
765cb5caa98Sdjl 		return (NSS_ERROR);
766cb5caa98Sdjl 	}
767*099ad03fSRobert Mustacchi out:
768cb5caa98Sdjl 	pbuf->ext_off = pbuf->data_off + len;
769cb5caa98Sdjl 	pbuf->ext_len = sizeof (nssuint_t);
770cb5caa98Sdjl 	pbuf->data_len = blen;
771cb5caa98Sdjl 	pttl = (nssuint_t *)((void *)((char *)pbuf + pbuf->ext_off));
772cb5caa98Sdjl 	*pttl = ttl;
7730e50326aSStacey Marshall 	res_ndestroy(statp);
774cb5caa98Sdjl 	return (NSS_SUCCESS);
775cb5caa98Sdjl }
776