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