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*e48cae6fSRobert Mustacchi /* 26*e48cae6fSRobert Mustacchi * Copyright (c) 2013, Joyent, Inc. All rights reserved. 27*e48cae6fSRobert Mustacchi */ 287c478bd9Sstevel@tonic-gate 29cb5caa98Sdjl /* 30cb5caa98Sdjl * dns_common.c 31cb5caa98Sdjl */ 32cb5caa98Sdjl 337c478bd9Sstevel@tonic-gate #include "dns_common.h" 34*e48cae6fSRobert Mustacchi #include <sys/types.h> 35*e48cae6fSRobert Mustacchi #include <sys/socket.h> 36*e48cae6fSRobert Mustacchi #include <ifaddrs.h> 37*e48cae6fSRobert 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 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 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 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 * 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 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*e48cae6fSRobert Mustacchi static int 332*e48cae6fSRobert Mustacchi _nss_has_interfaces(boolean_t *v4, boolean_t *v6) 333*e48cae6fSRobert Mustacchi { 334*e48cae6fSRobert Mustacchi struct ifaddrs *ifp, *i; 335*e48cae6fSRobert Mustacchi struct in_addr in4; 336*e48cae6fSRobert Mustacchi struct in6_addr in6; 337*e48cae6fSRobert Mustacchi const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 338*e48cae6fSRobert Mustacchi 339*e48cae6fSRobert Mustacchi *v4 = *v6 = B_FALSE; 340*e48cae6fSRobert Mustacchi 341*e48cae6fSRobert Mustacchi if (getifaddrs(&ifp) != 0) 342*e48cae6fSRobert Mustacchi return (-1); 343*e48cae6fSRobert Mustacchi 344*e48cae6fSRobert Mustacchi for (i = ifp; i != NULL; i = i->ifa_next) { 345*e48cae6fSRobert Mustacchi if (i->ifa_flags & IFF_LOOPBACK) 346*e48cae6fSRobert Mustacchi continue; 347*e48cae6fSRobert Mustacchi if ((i->ifa_flags & IFF_UP) == 0) 348*e48cae6fSRobert Mustacchi continue; 349*e48cae6fSRobert Mustacchi 350*e48cae6fSRobert Mustacchi if (i->ifa_addr->sa_family == AF_INET) { 351*e48cae6fSRobert Mustacchi if (*v4 != B_FALSE) 352*e48cae6fSRobert Mustacchi continue; 353*e48cae6fSRobert Mustacchi 354*e48cae6fSRobert Mustacchi if (((struct sockaddr_in *)i->ifa_addr)-> 355*e48cae6fSRobert Mustacchi sin_addr.s_addr == INADDR_ANY) 356*e48cae6fSRobert Mustacchi continue; 357*e48cae6fSRobert Mustacchi *v4 = B_TRUE; 358*e48cae6fSRobert Mustacchi } 359*e48cae6fSRobert Mustacchi 360*e48cae6fSRobert Mustacchi if (i->ifa_addr->sa_family == AF_INET6) { 361*e48cae6fSRobert Mustacchi if (*v6 != B_FALSE) 362*e48cae6fSRobert Mustacchi continue; 363*e48cae6fSRobert Mustacchi 364*e48cae6fSRobert Mustacchi if (memcmp(&in6addr_any, 365*e48cae6fSRobert Mustacchi &((struct sockaddr_in6 *)i->ifa_addr)->sin6_addr, 366*e48cae6fSRobert Mustacchi sizeof (struct in6_addr)) == 0) 367*e48cae6fSRobert Mustacchi continue; 368*e48cae6fSRobert Mustacchi *v6 = B_TRUE; 369*e48cae6fSRobert Mustacchi } 370*e48cae6fSRobert Mustacchi } 371*e48cae6fSRobert Mustacchi 372*e48cae6fSRobert Mustacchi freeifaddrs(ifp); 373*e48cae6fSRobert Mustacchi return (0); 374*e48cae6fSRobert Mustacchi } 375*e48cae6fSRobert 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 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*e48cae6fSRobert Mustacchi boolean_t has_v4 = B_FALSE, has_v6 = B_FALSE; 433*e48cae6fSRobert Mustacchi int flags, family, pass2 = 0; 434cb5caa98Sdjl 435c70a8a3bSmichen statp = &stat; 436c70a8a3bSmichen (void) memset(statp, '\0', sizeof (struct __res_state)); 437*e48cae6fSRobert Mustacchi if (res_ninit(statp) == -1) { 438cb5caa98Sdjl return (NSS_ERROR); 439*e48cae6fSRobert 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*e48cae6fSRobert Mustacchi /* 456*e48cae6fSRobert Mustacchi * There may be flags set when we are handling ipnode. There are three 457*e48cae6fSRobert Mustacchi * different values for flags: 458*e48cae6fSRobert Mustacchi * 459*e48cae6fSRobert Mustacchi * o AI_V4MAPPED 460*e48cae6fSRobert Mustacchi * o AI_ALL 461*e48cae6fSRobert Mustacchi * o AI_ADDRCONFIG 462*e48cae6fSRobert Mustacchi * 463*e48cae6fSRobert Mustacchi * The first two only have a meaning when af_family is ipv6. The latter 464*e48cae6fSRobert Mustacchi * means something in both cases. These flags are documented in 465*e48cae6fSRobert Mustacchi * getipnodebyname(3SOCKET), though the combinations leave a little 466*e48cae6fSRobert Mustacchi * something to be desired. It would be great if we could actually use 467*e48cae6fSRobert Mustacchi * getipnodebyname directly here since it already knows how to handle 468*e48cae6fSRobert Mustacchi * this kind of logic; however, we're not quite so lucky. Ideally we 469*e48cae6fSRobert Mustacchi * would add such an interface to libresolv.so.2 to handle this kind of 470*e48cae6fSRobert Mustacchi * thing, but that's rather painful as well. We'll summarize what has to 471*e48cae6fSRobert Mustacchi * happen below: 472*e48cae6fSRobert Mustacchi * 473*e48cae6fSRobert Mustacchi * AI_ALL is only meaningful when AI_V4MAPPED is also specified. Both 474*e48cae6fSRobert Mustacchi * are ignored if the family is not AF_INET6 475*e48cae6fSRobert Mustacchi * 476*e48cae6fSRobert Mustacchi * family == AF_INET, flags | AI_ADDRCONFIG 477*e48cae6fSRobert Mustacchi * - lookup A records iff we have v4 plumbed 478*e48cae6fSRobert Mustacchi * family == AF_INET, !(flags | AI_ADDRCONFIG) 479*e48cae6fSRobert Mustacchi * - lookup A records 480*e48cae6fSRobert Mustacchi * family == AF_INET6, flags == 0 || flags == AI_ALL 481*e48cae6fSRobert Mustacchi * - lookup AAAA records 482*e48cae6fSRobert Mustacchi * family == AF_INET6, flags | AI_V4MAPPED 483*e48cae6fSRobert Mustacchi * - lookup AAAA, if none, lookup A 484*e48cae6fSRobert Mustacchi * family == AF_INET6, flags | AI_ADDRCONFIG 485*e48cae6fSRobert Mustacchi * - lookup AAAA records if ipv6 486*e48cae6fSRobert Mustacchi * family == AF_INET6, flags | AI_V4MAPPED && flags | AI_ALL 487*e48cae6fSRobert Mustacchi * - lookup AAAA records, lookup A records 488*e48cae6fSRobert Mustacchi * family == AF_INET6, flags | AI_V4MAPPED && flags | AI_ADDRCONFIG 489*e48cae6fSRobert Mustacchi * - lookup AAAA records if ipv6 490*e48cae6fSRobert Mustacchi * - If no AAAA && ipv4 exists, lookup A 491*e48cae6fSRobert Mustacchi * family == AF_INET6, flags | AI_V4MAPPED && flags | AI_ADDRCONFIG && 492*e48cae6fSRobert Mustacchi * flags | AI_ALL 493*e48cae6fSRobert Mustacchi * - lookup AAAA records if ipv6 494*e48cae6fSRobert Mustacchi * - loookup A records if ipv4 495*e48cae6fSRobert Mustacchi */ 496cb5caa98Sdjl if (ipnode) { 497cb5caa98Sdjl /* initially only handle the simple cases */ 498*e48cae6fSRobert Mustacchi name = arg.key.ipnode.name; 499*e48cae6fSRobert Mustacchi flags = arg.key.ipnode.flags; 500*e48cae6fSRobert Mustacchi family = arg.key.ipnode.af_family; 501*e48cae6fSRobert Mustacchi if (flags != 0) { 502*e48cae6fSRobert Mustacchi /* 503*e48cae6fSRobert Mustacchi * Figure out our first pass. We'll determine if we need 504*e48cae6fSRobert Mustacchi * to do a second pass afterwards once we successfully 505*e48cae6fSRobert Mustacchi * finish our first pass. 506*e48cae6fSRobert Mustacchi */ 507*e48cae6fSRobert Mustacchi if ((flags & AI_ADDRCONFIG) != 0) { 508*e48cae6fSRobert Mustacchi if (_nss_has_interfaces(&has_v4, &has_v6) != 509*e48cae6fSRobert Mustacchi 0) { 5100e50326aSStacey Marshall res_ndestroy(statp); 511cb5caa98Sdjl return (NSS_ERROR); 512c70a8a3bSmichen } 513*e48cae6fSRobert Mustacchi /* Impossible situations... */ 514*e48cae6fSRobert Mustacchi if (family == AF_INET && has_v4 == B_FALSE) { 515*e48cae6fSRobert Mustacchi res_ndestroy(statp); 516*e48cae6fSRobert Mustacchi return (NSS_NOTFOUND); 517*e48cae6fSRobert Mustacchi } 518*e48cae6fSRobert Mustacchi if (family == AF_INET6 && has_v6 == B_FALSE && 519*e48cae6fSRobert Mustacchi !(flags & AI_V4MAPPED)) { 520*e48cae6fSRobert Mustacchi res_ndestroy(statp); 521*e48cae6fSRobert Mustacchi return (NSS_NOTFOUND); 522*e48cae6fSRobert Mustacchi } 523*e48cae6fSRobert Mustacchi if (family == AF_INET6 && has_v6) 524*e48cae6fSRobert Mustacchi qtype = T_AAAA; 525*e48cae6fSRobert Mustacchi if (family == AF_INET || (family == AF_INET6 && 526*e48cae6fSRobert Mustacchi has_v6 == B_FALSE && flags & AI_V4MAPPED)) 527*e48cae6fSRobert Mustacchi qtype = T_A; 528*e48cae6fSRobert Mustacchi } else { 529*e48cae6fSRobert Mustacchi has_v4 = has_v6 = B_TRUE; 530*e48cae6fSRobert Mustacchi if (family == AF_INET6) 531cb5caa98Sdjl qtype = T_AAAA; 532cb5caa98Sdjl else 533cb5caa98Sdjl qtype = T_A; 534*e48cae6fSRobert Mustacchi } 535*e48cae6fSRobert Mustacchi } else { 536*e48cae6fSRobert Mustacchi if (family == AF_INET6) 537*e48cae6fSRobert Mustacchi qtype = T_AAAA; 538*e48cae6fSRobert Mustacchi else 539*e48cae6fSRobert Mustacchi qtype = T_A; 540*e48cae6fSRobert Mustacchi } 541cb5caa98Sdjl } else { 542cb5caa98Sdjl name = arg.key.name; 543cb5caa98Sdjl qtype = T_A; 544cb5caa98Sdjl } 545*e48cae6fSRobert Mustacchi 546*e48cae6fSRobert Mustacchi searchagain: 547c70a8a3bSmichen ret = res_nsearch(statp, name, C_IN, qtype, resbuf.buf, NS_MAXMSG); 548cb5caa98Sdjl if (ret == -1) { 549*e48cae6fSRobert Mustacchi /* 550*e48cae6fSRobert Mustacchi * We want to continue on unless we got NO_RECOVERY. Otherwise, 551*e48cae6fSRobert Mustacchi * HOST_NOT_FOUND, TRY_AGAIN, and NO_DATA all suggest to me that 552*e48cae6fSRobert Mustacchi * we should keep going. 553*e48cae6fSRobert Mustacchi */ 554*e48cae6fSRobert Mustacchi if (statp->res_h_errno == NO_RECOVERY) { 555*e48cae6fSRobert Mustacchi /* else lookup error - handle in general code */ 556*e48cae6fSRobert Mustacchi res_ndestroy(statp); 557*e48cae6fSRobert Mustacchi return (NSS_ERROR); 558*e48cae6fSRobert Mustacchi } 559*e48cae6fSRobert Mustacchi 560*e48cae6fSRobert Mustacchi /* 561*e48cae6fSRobert Mustacchi * We found something on our first pass. Make sure that we do 562*e48cae6fSRobert Mustacchi * not clobber this information. This ultimately means that we 563*e48cae6fSRobert Mustacchi * were successful. 564*e48cae6fSRobert Mustacchi */ 565*e48cae6fSRobert Mustacchi if (pass2 == 2) 566*e48cae6fSRobert Mustacchi goto out; 567*e48cae6fSRobert Mustacchi 568*e48cae6fSRobert Mustacchi /* 569*e48cae6fSRobert Mustacchi * If we're on the second pass (eg. we need to check both for A 570*e48cae6fSRobert Mustacchi * and AAAA records), or we were only ever doing a search for 571*e48cae6fSRobert Mustacchi * one type of record and are not supposed to do a second pass, 572*e48cae6fSRobert Mustacchi * then we need to return that we couldn't find anything to the 573*e48cae6fSRobert Mustacchi * user. 574*e48cae6fSRobert Mustacchi */ 575*e48cae6fSRobert Mustacchi if (pass2 == 1 || flags == 0 || family == AF_INET || 576*e48cae6fSRobert 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*e48cae6fSRobert Mustacchi 584*e48cae6fSRobert Mustacchi /* 585*e48cae6fSRobert Mustacchi * If we were only requested to search for flags on an IPv6 586*e48cae6fSRobert Mustacchi * interface or we have no IPv4 interface, we stick to only 587*e48cae6fSRobert Mustacchi * doing a single pass and bail now. 588*e48cae6fSRobert Mustacchi */ 589*e48cae6fSRobert Mustacchi if ((flags & AI_ADDRCONFIG) && !(flags & AI_ALL) && 590*e48cae6fSRobert Mustacchi has_v4 == B_FALSE) { 591*e48cae6fSRobert Mustacchi pbuf->p_herrno = HOST_NOT_FOUND; 592*e48cae6fSRobert Mustacchi pbuf->p_status = NSS_NOTFOUND; 593*e48cae6fSRobert Mustacchi pbuf->data_len = 0; 5940e50326aSStacey Marshall res_ndestroy(statp); 595*e48cae6fSRobert Mustacchi return (NSS_NOTFOUND); 596*e48cae6fSRobert Mustacchi } 597*e48cae6fSRobert Mustacchi qtype = T_A; 598*e48cae6fSRobert Mustacchi flags = 0; 599*e48cae6fSRobert Mustacchi pass2 = 1; 600*e48cae6fSRobert 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*e48cae6fSRobert Mustacchi 750*e48cae6fSRobert Mustacchi /* Depending on our flags we may need to go back another time. */ 751*e48cae6fSRobert Mustacchi if (qtype == T_AAAA && family == AF_INET6 && 752*e48cae6fSRobert Mustacchi ((flags & AI_V4MAPPED) != 0) && ((flags & AI_ALL) != 0) && 753*e48cae6fSRobert Mustacchi has_v4 == B_TRUE) { 754*e48cae6fSRobert Mustacchi qtype = T_A; 755*e48cae6fSRobert Mustacchi pass2 = 2; /* Indicate that we found data this pass */ 756*e48cae6fSRobert Mustacchi goto searchagain; 757*e48cae6fSRobert Mustacchi } 758*e48cae6fSRobert 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*e48cae6fSRobert 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