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
dns_netdb_aliases(from_list,to_list,aliaspp,type,count,af_type)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
ent2result(he,argp,af_type)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
ent2str(struct hostent * hp,nss_XbyY_args_t * ap,int af_type)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 *
_nss_dns_constr(dns_backend_op_t ops[],int n_ops)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
name_is_alias(char * aliases_ptr,char * name_ptr)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
_nss_has_interfaces(boolean_t * v4,boolean_t * v6)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
_nss_dns_gethost_withttl(void * buffer,size_t bufsize,int ipnode)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