1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Copyright (c) 2013, Joyent, Inc. All rights reserved. 27 */ 28 29 /* 30 * dns_common.c 31 */ 32 33 #include "dns_common.h" 34 #include <sys/types.h> 35 #include <sys/socket.h> 36 #include <ifaddrs.h> 37 #include <net/if.h> 38 39 #pragma weak dn_expand 40 #pragma weak res_ninit 41 #pragma weak res_ndestroy 42 #pragma weak res_nsearch 43 #pragma weak res_nclose 44 #pragma weak ns_get16 45 #pragma weak ns_get32 46 #pragma weak __ns_get16 47 #pragma weak __ns_get32 48 49 #define DNS_ALIASES 0 50 #define DNS_ADDRLIST 1 51 #define DNS_MAPDLIST 2 52 53 #ifndef tolower 54 #define tolower(c) ((c) >= 'A' && (c) <= 'Z' ? (c) | 0x20 : (c)) 55 #endif 56 57 static int 58 dns_netdb_aliases(from_list, to_list, aliaspp, type, count, af_type) 59 char **from_list, **to_list, **aliaspp; 60 int type, *count, af_type; 61 { 62 char *fstr; 63 int cnt = 0; 64 size_t len; 65 66 *count = 0; 67 if ((char *)to_list >= *aliaspp) 68 return (NSS_STR_PARSE_ERANGE); 69 70 for (fstr = from_list[cnt]; fstr != NULL; fstr = from_list[cnt]) { 71 if (type == DNS_ALIASES) 72 len = strlen(fstr) + 1; 73 else 74 len = (af_type == AF_INET) ? sizeof (struct in_addr) 75 : sizeof (struct in6_addr); 76 *aliaspp -= len; 77 to_list[cnt] = *aliaspp; 78 if (*aliaspp <= (char *)&to_list[cnt+1]) 79 return (NSS_STR_PARSE_ERANGE); 80 if (type == DNS_MAPDLIST) { 81 /* LINTED: E_BAD_PTR_CAST_ALIGN */ 82 struct in6_addr *addr6p = (struct in6_addr *)*aliaspp; 83 84 (void) memset(addr6p, '\0', sizeof (struct in6_addr)); 85 (void) memcpy(&addr6p->s6_addr[12], fstr, 86 sizeof (struct in_addr)); 87 addr6p->s6_addr[10] = 0xffU; 88 addr6p->s6_addr[11] = 0xffU; 89 ++cnt; 90 } else { 91 (void) memcpy (*aliaspp, fstr, len); 92 ++cnt; 93 } 94 } 95 to_list[cnt] = NULL; 96 97 *count = cnt; 98 if (cnt == 0) 99 return (NSS_STR_PARSE_PARSE); 100 101 return (NSS_STR_PARSE_SUCCESS); 102 } 103 104 105 int 106 ent2result(he, argp, af_type) 107 struct hostent *he; 108 nss_XbyY_args_t *argp; 109 int af_type; 110 { 111 char *buffer, *limit; 112 int buflen = argp->buf.buflen; 113 int ret, count; 114 size_t len; 115 struct hostent *host; 116 struct in_addr *addrp; 117 struct in6_addr *addrp6; 118 119 limit = argp->buf.buffer + buflen; 120 host = (struct hostent *)argp->buf.result; 121 buffer = argp->buf.buffer; 122 123 /* h_addrtype and h_length */ 124 host->h_addrtype = af_type; 125 host->h_length = (af_type == AF_INET) ? sizeof (struct in_addr) 126 : sizeof (struct in6_addr); 127 128 /* h_name */ 129 len = strlen(he->h_name) + 1; 130 host->h_name = buffer; 131 if (host->h_name + len >= limit) 132 return (NSS_STR_PARSE_ERANGE); 133 (void) memcpy(host->h_name, he->h_name, len); 134 buffer += len; 135 136 /* h_addr_list */ 137 if (af_type == AF_INET) { 138 addrp = (struct in_addr *)ROUND_DOWN(limit, sizeof (*addrp)); 139 host->h_addr_list = (char **) 140 ROUND_UP(buffer, sizeof (char **)); 141 ret = dns_netdb_aliases(he->h_addr_list, host->h_addr_list, 142 (char **)&addrp, DNS_ADDRLIST, &count, af_type); 143 if (ret != NSS_STR_PARSE_SUCCESS) 144 return (ret); 145 /* h_aliases */ 146 host->h_aliases = host->h_addr_list + count + 1; 147 ret = dns_netdb_aliases(he->h_aliases, host->h_aliases, 148 (char **)&addrp, DNS_ALIASES, &count, af_type); 149 } else { 150 addrp6 = (struct in6_addr *) 151 ROUND_DOWN(limit, sizeof (*addrp6)); 152 host->h_addr_list = (char **) 153 ROUND_UP(buffer, sizeof (char **)); 154 if (he->h_addrtype == AF_INET && af_type == AF_INET6) { 155 ret = dns_netdb_aliases(he->h_addr_list, 156 host->h_addr_list, (char **)&addrp6, 157 DNS_MAPDLIST, &count, af_type); 158 } else { 159 ret = dns_netdb_aliases(he->h_addr_list, 160 host->h_addr_list, (char **)&addrp6, 161 DNS_ADDRLIST, &count, af_type); 162 } 163 if (ret != NSS_STR_PARSE_SUCCESS) 164 return (ret); 165 /* h_aliases */ 166 host->h_aliases = host->h_addr_list + count + 1; 167 ret = dns_netdb_aliases(he->h_aliases, host->h_aliases, 168 (char **)&addrp6, DNS_ALIASES, &count, af_type); 169 } 170 if (ret == NSS_STR_PARSE_PARSE) 171 ret = NSS_STR_PARSE_SUCCESS; 172 173 return (ret); 174 } 175 176 /* 177 * Convert the hostent structure into string in the following 178 * format: 179 * 180 * IP-address official-host-name nicknames ... 181 * 182 * If more than one IP-addresses matches the official-host-name, 183 * the above line will be followed by: 184 * IP-address-1 official-host-name 185 * IP-address-2 official-host-name 186 * ... 187 * 188 * This is so that the str2hostent function in libnsl 189 * can convert the string back to the original hostent 190 * data. 191 */ 192 int 193 ent2str( 194 struct hostent *hp, 195 nss_XbyY_args_t *ap, 196 int af_type) 197 { 198 char **p; 199 char obuf[INET6_ADDRSTRLEN]; 200 void *addr; 201 struct in_addr in4; 202 int af; 203 int n; 204 const char *res; 205 char **q; 206 int l = ap->buf.buflen; 207 char *s = ap->buf.buffer; 208 209 /* 210 * for "hosts" lookup, we only want address type of 211 * AF_INET. For "ipnodes", we can have both AF_INET 212 * and AF_INET6. 213 */ 214 if (af_type == AF_INET && hp->h_addrtype != AF_INET) 215 return (NSS_STR_PARSE_PARSE); 216 217 for (p = hp->h_addr_list; *p != 0; p++) { 218 219 if (p != hp->h_addr_list) { 220 *s = '\n'; 221 s++; 222 l--; 223 } 224 225 if (hp->h_addrtype == AF_INET6) { 226 /* LINTED: E_BAD_PTR_CAST_ALIGN */ 227 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)*p)) { 228 /* LINTED: E_BAD_PTR_CAST_ALIGN */ 229 IN6_V4MAPPED_TO_INADDR((struct in6_addr *)*p, 230 &in4); 231 af = AF_INET; 232 addr = &in4; 233 } else { 234 af = AF_INET6; 235 addr = *p; 236 } 237 } else { 238 af = AF_INET; 239 addr = *p; 240 } 241 res = inet_ntop(af, addr, obuf, sizeof (obuf)); 242 if (res == NULL) 243 return (NSS_STR_PARSE_PARSE); 244 245 if ((n = snprintf(s, l, "%s", res)) >= l) 246 return (NSS_STR_PARSE_ERANGE); 247 l -= n; 248 s += n; 249 if (hp->h_name != NULL && *hp->h_name != '\0') { 250 if ((n = snprintf(s, l, " %s", hp->h_name)) >= l) 251 return (NSS_STR_PARSE_ERANGE); 252 l -= n; 253 s += n; 254 } 255 if (p == hp->h_addr_list) { 256 for (q = hp->h_aliases; q && *q; q++) { 257 if ((n = snprintf(s, l, " %s", *q)) >= l) 258 return (NSS_STR_PARSE_ERANGE); 259 l -= n; 260 s += n; 261 } 262 } 263 } 264 265 ap->returnlen = s - ap->buf.buffer; 266 return (NSS_STR_PARSE_SUCCESS); 267 } 268 269 nss_backend_t * 270 _nss_dns_constr(dns_backend_op_t ops[], int n_ops) 271 { 272 dns_backend_ptr_t be; 273 274 if ((be = (dns_backend_ptr_t)malloc(sizeof (*be))) == 0) 275 return (0); 276 277 be->ops = ops; 278 be->n_ops = n_ops; 279 return ((nss_backend_t *)be); 280 } 281 282 /* 283 * name_is_alias(aliases_ptr, name_ptr) 284 * Verify name matches an alias in the provided aliases list. 285 * 286 * Within DNS there should be only one canonical name, aliases should 287 * all refer to the one canonical. However alias chains do occur and 288 * pre BIND 9 servers may also respond with multiple CNAMEs. This 289 * routine checks if a given name has been provided as a CNAME in the 290 * response. This assumes that the chains have been sent in-order. 291 * 292 * INPUT: 293 * aliases_ptr: space separated list of alias names. 294 * name_ptr: name to look for in aliases_ptr list. 295 * RETURNS: NSS_SUCCESS or NSS_NOTFOUND 296 * NSS_SUCCESS indicates that the name is listed in the collected aliases. 297 */ 298 static nss_status_t 299 name_is_alias(char *aliases_ptr, char *name_ptr) { 300 char *host_ptr; 301 /* Loop through alias string and compare it against host string. */ 302 while (*aliases_ptr != '\0') { 303 host_ptr = name_ptr; 304 305 /* Compare name with alias. */ 306 while (tolower(*host_ptr) == tolower(*aliases_ptr) && 307 *host_ptr != '\0') { 308 host_ptr++; 309 aliases_ptr++; 310 } 311 312 /* 313 * If name was exhausted and the next character in the 314 * alias is either the end-of-string or space 315 * character then we have a match. 316 */ 317 if (*host_ptr == '\0' && 318 (*aliases_ptr == '\0' || *aliases_ptr == ' ')) { 319 return (NSS_SUCCESS); 320 } 321 322 /* Alias did not match, step over remainder of alias. */ 323 while (*aliases_ptr != ' ' && *aliases_ptr != '\0') 324 aliases_ptr++; 325 /* Step over separator character. */ 326 while (*aliases_ptr == ' ') aliases_ptr++; 327 } 328 return (NSS_NOTFOUND); 329 } 330 331 static int 332 _nss_has_interfaces(boolean_t *v4, boolean_t *v6) 333 { 334 struct ifaddrs *ifp, *i; 335 struct in_addr in4; 336 struct in6_addr in6; 337 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 338 339 *v4 = *v6 = B_FALSE; 340 341 if (getifaddrs(&ifp) != 0) 342 return (-1); 343 344 for (i = ifp; i != NULL; i = i->ifa_next) { 345 if (i->ifa_flags & IFF_LOOPBACK) 346 continue; 347 if ((i->ifa_flags & IFF_UP) == 0) 348 continue; 349 350 if (i->ifa_addr->sa_family == AF_INET) { 351 if (*v4 != B_FALSE) 352 continue; 353 354 if (((struct sockaddr_in *)i->ifa_addr)-> 355 sin_addr.s_addr == INADDR_ANY) 356 continue; 357 *v4 = B_TRUE; 358 } 359 360 if (i->ifa_addr->sa_family == AF_INET6) { 361 if (*v6 != B_FALSE) 362 continue; 363 364 if (memcmp(&in6addr_any, 365 &((struct sockaddr_in6 *)i->ifa_addr)->sin6_addr, 366 sizeof (struct in6_addr)) == 0) 367 continue; 368 *v6 = B_TRUE; 369 } 370 } 371 372 freeifaddrs(ifp); 373 return (0); 374 } 375 376 /* 377 * nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode) 378 * nss2 get hosts/ipnodes with ttl backend DNS search engine. 379 * 380 * This API is given a pointer to a packed buffer, and the buffer size 381 * It's job is to perform the appropriate res_nsearch, extract the 382 * results and build a unmarshalled hosts/ipnodes result buffer. 383 * Additionally in the extended results a nssuint_t ttl is placed. 384 * This ttl is the lessor of the ttl's extracted from the result. 385 * 386 * RETURNS: NSS_SUCCESS or NSS_ERROR 387 * If an NSS_ERROR result is returned, nscd is expected 388 * to resubmit the gethosts request using the old style 389 * nsswitch lookup format. 390 */ 391 392 nss_status_t 393 _nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode) 394 { 395 /* nss buffer variables */ 396 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 397 nss_XbyY_args_t arg; 398 char *dbname; 399 int dbop; 400 nss_status_t sret; 401 size_t bsize, blen; 402 char *bptr; 403 /* resolver query variables */ 404 struct __res_state stat, *statp; /* dns state block */ 405 union msg { 406 uchar_t buf[NS_MAXMSG]; /* max legal DNS answer size */ 407 HEADER h; 408 } resbuf; 409 char aliases[NS_MAXMSG]; /* set of aliases */ 410 const char *name; 411 int qtype; 412 /* answer parsing variables */ 413 HEADER *hp; 414 uchar_t *cp; /* current location in message */ 415 uchar_t *bom; /* start of message */ 416 uchar_t *eom; /* end of message */ 417 uchar_t *eor; /* end of record */ 418 int ancount, qdcount; 419 int type, class; 420 nssuint_t nttl, ttl, *pttl; /* The purpose of this API */ 421 int n, ret; 422 const char *np; 423 /* temporary buffers */ 424 char nbuf[INET6_ADDRSTRLEN]; /* address parser */ 425 char host[MAXHOSTNAMELEN]; /* result host name */ 426 char ans[MAXHOSTNAMELEN]; /* record name */ 427 char aname[MAXHOSTNAMELEN]; /* alias result (C_NAME) */ 428 /* misc variables */ 429 int af; 430 char *ap, *apc; 431 int hlen = 0, alen, iplen, len, isans; 432 boolean_t has_v4 = B_FALSE, has_v6 = B_FALSE; 433 int flags, family, pass2 = 0; 434 435 statp = &stat; 436 (void) memset(statp, '\0', sizeof (struct __res_state)); 437 if (res_ninit(statp) == -1) { 438 return (NSS_ERROR); 439 } 440 441 ap = apc = (char *)aliases; 442 alen = 0; 443 ttl = (nssuint_t)0xFFFFFFF; /* start w/max, find smaller */ 444 445 /* save space for ttl otherwise, why bother... */ 446 bsize = pbuf->data_len - sizeof (nssuint_t); 447 bptr = (char *)buffer + pbuf->data_off; 448 blen = 0; 449 sret = nss_packed_getkey(buffer, bufsize, &dbname, &dbop, &arg); 450 if (sret != NSS_SUCCESS) { 451 res_ndestroy(statp); 452 return (NSS_ERROR); 453 } 454 455 /* 456 * There may be flags set when we are handling ipnode. There are three 457 * different values for flags: 458 * 459 * o AI_V4MAPPED 460 * o AI_ALL 461 * o AI_ADDRCONFIG 462 * 463 * The first two only have a meaning when af_family is ipv6. The latter 464 * means something in both cases. These flags are documented in 465 * getipnodebyname(3SOCKET), though the combinations leave a little 466 * something to be desired. It would be great if we could actually use 467 * getipnodebyname directly here since it already knows how to handle 468 * this kind of logic; however, we're not quite so lucky. Ideally we 469 * would add such an interface to libresolv.so.2 to handle this kind of 470 * thing, but that's rather painful as well. We'll summarize what has to 471 * happen below: 472 * 473 * AI_ALL is only meaningful when AI_V4MAPPED is also specified. Both 474 * are ignored if the family is not AF_INET6 475 * 476 * family == AF_INET, flags | AI_ADDRCONFIG 477 * - lookup A records iff we have v4 plumbed 478 * family == AF_INET, !(flags | AI_ADDRCONFIG) 479 * - lookup A records 480 * family == AF_INET6, flags == 0 || flags == AI_ALL 481 * - lookup AAAA records 482 * family == AF_INET6, flags | AI_V4MAPPED 483 * - lookup AAAA, if none, lookup A 484 * family == AF_INET6, flags | AI_ADDRCONFIG 485 * - lookup AAAA records if ipv6 486 * family == AF_INET6, flags | AI_V4MAPPED && flags | AI_ALL 487 * - lookup AAAA records, lookup A records 488 * family == AF_INET6, flags | AI_V4MAPPED && flags | AI_ADDRCONFIG 489 * - lookup AAAA records if ipv6 490 * - If no AAAA && ipv4 exists, lookup A 491 * family == AF_INET6, flags | AI_V4MAPPED && flags | AI_ADDRCONFIG && 492 * flags | AI_ALL 493 * - lookup AAAA records if ipv6 494 * - loookup A records if ipv4 495 */ 496 if (ipnode) { 497 /* initially only handle the simple cases */ 498 name = arg.key.ipnode.name; 499 flags = arg.key.ipnode.flags; 500 family = arg.key.ipnode.af_family; 501 if (flags != 0) { 502 /* 503 * Figure out our first pass. We'll determine if we need 504 * to do a second pass afterwards once we successfully 505 * finish our first pass. 506 */ 507 if ((flags & AI_ADDRCONFIG) != 0) { 508 if (_nss_has_interfaces(&has_v4, &has_v6) != 509 0) { 510 res_ndestroy(statp); 511 return (NSS_ERROR); 512 } 513 /* Impossible situations... */ 514 if (family == AF_INET && has_v4 == B_FALSE) { 515 res_ndestroy(statp); 516 return (NSS_NOTFOUND); 517 } 518 if (family == AF_INET6 && has_v6 == B_FALSE && 519 !(flags & AI_V4MAPPED)) { 520 res_ndestroy(statp); 521 return (NSS_NOTFOUND); 522 } 523 if (family == AF_INET6 && has_v6) 524 qtype = T_AAAA; 525 if (family == AF_INET || (family == AF_INET6 && 526 has_v6 == B_FALSE && flags & AI_V4MAPPED)) 527 qtype = T_A; 528 } else { 529 has_v4 = has_v6 = B_TRUE; 530 if (family == AF_INET6) 531 qtype = T_AAAA; 532 else 533 qtype = T_A; 534 } 535 } else { 536 if (family == AF_INET6) 537 qtype = T_AAAA; 538 else 539 qtype = T_A; 540 } 541 } else { 542 name = arg.key.name; 543 qtype = T_A; 544 } 545 546 searchagain: 547 ret = res_nsearch(statp, name, C_IN, qtype, resbuf.buf, NS_MAXMSG); 548 if (ret == -1) { 549 /* 550 * We want to continue on unless we got NO_RECOVERY. Otherwise, 551 * HOST_NOT_FOUND, TRY_AGAIN, and NO_DATA all suggest to me that 552 * we should keep going. 553 */ 554 if (statp->res_h_errno == NO_RECOVERY) { 555 /* else lookup error - handle in general code */ 556 res_ndestroy(statp); 557 return (NSS_ERROR); 558 } 559 560 /* 561 * We found something on our first pass. Make sure that we do 562 * not clobber this information. This ultimately means that we 563 * were successful. 564 */ 565 if (pass2 == 2) 566 goto out; 567 568 /* 569 * If we're on the second pass (eg. we need to check both for A 570 * and AAAA records), or we were only ever doing a search for 571 * one type of record and are not supposed to do a second pass, 572 * then we need to return that we couldn't find anything to the 573 * user. 574 */ 575 if (pass2 == 1 || flags == 0 || family == AF_INET || 576 (family == AF_INET6 && !(flags & AI_V4MAPPED))) { 577 pbuf->p_herrno = HOST_NOT_FOUND; 578 pbuf->p_status = NSS_NOTFOUND; 579 pbuf->data_len = 0; 580 res_ndestroy(statp); 581 return (NSS_NOTFOUND); 582 } 583 584 /* 585 * If we were only requested to search for flags on an IPv6 586 * interface or we have no IPv4 interface, we stick to only 587 * doing a single pass and bail now. 588 */ 589 if ((flags & AI_ADDRCONFIG) && !(flags & AI_ALL) && 590 has_v4 == B_FALSE) { 591 pbuf->p_herrno = HOST_NOT_FOUND; 592 pbuf->p_status = NSS_NOTFOUND; 593 pbuf->data_len = 0; 594 res_ndestroy(statp); 595 return (NSS_NOTFOUND); 596 } 597 qtype = T_A; 598 flags = 0; 599 pass2 = 1; 600 goto searchagain; 601 } 602 603 cp = resbuf.buf; 604 hp = (HEADER *)&resbuf.h; 605 bom = cp; 606 eom = cp + ret; 607 608 ancount = ntohs(hp->ancount); 609 qdcount = ntohs(hp->qdcount); 610 cp += HFIXEDSZ; 611 if (qdcount != 1) { 612 res_ndestroy(statp); 613 return (NSS_ERROR); 614 } 615 n = dn_expand(bom, eom, cp, host, MAXHOSTNAMELEN); 616 if (n < 0) { 617 res_ndestroy(statp); 618 return (NSS_ERROR); 619 } else 620 hlen = strlen(host); 621 /* no host name is an error, return */ 622 if (hlen <= 0) { 623 res_ndestroy(statp); 624 return (NSS_ERROR); 625 } 626 cp += n + QFIXEDSZ; 627 if (cp > eom) { 628 res_ndestroy(statp); 629 return (NSS_ERROR); 630 } 631 while (ancount-- > 0 && cp < eom && blen < bsize) { 632 n = dn_expand(bom, eom, cp, ans, MAXHOSTNAMELEN); 633 if (n > 0) { 634 /* 635 * Check that the expanded name is either the 636 * name we asked for or a learned alias. 637 */ 638 if ((isans = strncasecmp(host, ans, hlen)) != 0 && 639 (alen == 0 || name_is_alias(aliases, ans) 640 == NSS_NOTFOUND)) { 641 res_ndestroy(statp); 642 return (NSS_ERROR); /* spoof? */ 643 } 644 } 645 cp += n; 646 /* bounds check */ 647 type = ns_get16(cp); /* type */ 648 cp += INT16SZ; 649 class = ns_get16(cp); /* class */ 650 cp += INT16SZ; 651 nttl = (nssuint_t)ns_get32(cp); /* ttl in sec */ 652 if (nttl < ttl) 653 ttl = nttl; 654 cp += INT32SZ; 655 n = ns_get16(cp); /* len */ 656 cp += INT16SZ; 657 if (class != C_IN) { 658 cp += n; 659 continue; 660 } 661 eor = cp + n; 662 if (type == T_CNAME) { 663 /* 664 * The name looked up is really an alias and the 665 * canonical name should be in the RDATA. 666 * A canonical name may have several aliases but an 667 * alias should only have one canonical name. 668 * However multiple CNAMEs and CNAME chains do exist! 669 * 670 * Just error out on attempted buffer overflow exploit, 671 * generic code will syslog. 672 * 673 */ 674 n = dn_expand(bom, eor, cp, aname, MAXHOSTNAMELEN); 675 if (n > 0 && (len = strlen(aname)) > 0) { 676 if (isans == 0) { /* host matched ans. */ 677 /* 678 * Append host to alias list. 679 */ 680 if (alen + hlen + 2 > NS_MAXMSG) { 681 res_ndestroy(statp); 682 return (NSS_ERROR); 683 } 684 *apc++ = ' '; 685 alen++; 686 (void) strlcpy(apc, host, 687 NS_MAXMSG - alen); 688 alen += hlen; 689 apc += hlen; 690 } 691 /* 692 * Overwrite host with canonical name. 693 */ 694 if (strlcpy(host, aname, MAXHOSTNAMELEN) >= 695 MAXHOSTNAMELEN) { 696 res_ndestroy(statp); 697 return (NSS_ERROR); 698 } 699 hlen = len; 700 } 701 cp += n; 702 continue; 703 } 704 if (type != qtype) { 705 cp += n; 706 continue; 707 } 708 /* check data size */ 709 if ((type == T_A && n != INADDRSZ) || 710 (type == T_AAAA && n != IN6ADDRSZ)) { 711 cp += n; 712 continue; 713 } 714 af = (type == T_A ? AF_INET : AF_INET6); 715 np = inet_ntop(af, (void *)cp, nbuf, INET6_ADDRSTRLEN); 716 if (np == NULL) { 717 res_ndestroy(statp); 718 return (NSS_ERROR); 719 } 720 cp += n; 721 /* append IP host aliases to results */ 722 iplen = strlen(np); 723 /* ip <SP> hostname [<SP>][aliases] */ 724 len = iplen + 2 + hlen + alen; 725 if (alen > 0) 726 len++; 727 if (blen + len > bsize) { 728 res_ndestroy(statp); 729 return (NSS_ERROR); 730 } 731 (void) strlcpy(bptr, np, bsize - blen); 732 blen += iplen; 733 bptr += iplen; 734 *bptr++ = ' '; 735 blen++; 736 (void) strlcpy(bptr, host, bsize - blen); 737 blen += hlen; 738 bptr += hlen; 739 if (alen > 0) { 740 *bptr++ = ' '; 741 blen++; 742 (void) strlcpy(bptr, ap, bsize - blen); 743 blen += alen; 744 bptr += alen; 745 } 746 *bptr++ = '\n'; 747 blen++; 748 } 749 750 /* Depending on our flags we may need to go back another time. */ 751 if (qtype == T_AAAA && family == AF_INET6 && 752 ((flags & AI_V4MAPPED) != 0) && ((flags & AI_ALL) != 0) && 753 has_v4 == B_TRUE) { 754 qtype = T_A; 755 pass2 = 2; /* Indicate that we found data this pass */ 756 goto searchagain; 757 } 758 759 /* Presumably the buffer is now filled. */ 760 len = ROUND_UP(blen, sizeof (nssuint_t)); 761 /* still room? */ 762 if (len + sizeof (nssuint_t) > pbuf->data_len) { 763 /* sigh, no, what happened? */ 764 res_ndestroy(statp); 765 return (NSS_ERROR); 766 } 767 out: 768 pbuf->ext_off = pbuf->data_off + len; 769 pbuf->ext_len = sizeof (nssuint_t); 770 pbuf->data_len = blen; 771 pttl = (nssuint_t *)((void *)((char *)pbuf + pbuf->ext_off)); 772 *pttl = ttl; 773 res_ndestroy(statp); 774 return (NSS_SUCCESS); 775 } 776