1/* Copyright (C) 1996-2020 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Extended from original form by Ulrich Drepper <drepper@cygnus.com>, 1996.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19/* Parts of this file are plain copies of the file `gethtnamadr.c' from
20 the bind package and it has the following copyright. */
21
22/*
23 * ++Copyright++ 1985, 1988, 1993
24 * -
25 * Copyright (c) 1985, 1988, 1993
26 * The Regents of the University of California. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 4. Neither the name of the University nor the names of its contributors
37 * may be used to endorse or promote products derived from this software
38 * without specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 * -
52 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
53 *
54 * Permission to use, copy, modify, and distribute this software for any
55 * purpose with or without fee is hereby granted, provided that the above
56 * copyright notice and this permission notice appear in all copies, and that
57 * the name of Digital Equipment Corporation not be used in advertising or
58 * publicity pertaining to distribution of the document or software without
59 * specific, written prior permission.
60 *
61 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
62 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
63 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
64 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
65 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
66 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
67 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
68 * SOFTWARE.
69 * -
70 * --Copyright--
71 */
72
73#include <assert.h>
74#include <ctype.h>
75#include <errno.h>
76#include <netdb.h>
77#include <stdio.h>
78#include <stdlib.h>
79#include <stddef.h>
80#include <string.h>
81#include <libc-pointer-arith.h>
82
83#include "nsswitch.h"
84#include <arpa/nameser.h>
85
86#include <resolv/resolv-internal.h>
87#include <resolv/resolv_context.h>
88
89/* Get implementations of some internal functions. */
90#include <resolv/mapv4v6addr.h>
91#include <resolv/mapv4v6hostent.h>
92
93#define RESOLVSORT
94
95#if PACKETSZ > 65536
96# define MAXPACKET PACKETSZ
97#else
98# define MAXPACKET 65536
99#endif
100/* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length. */
101#ifdef MAXHOSTNAMELEN
102# undef MAXHOSTNAMELEN
103#endif
104#define MAXHOSTNAMELEN 256
105
106/* We need this time later. */
107typedef union querybuf
108{
109 HEADER hdr;
110 u_char buf[MAXPACKET];
111} querybuf;
112
113static enum nss_status getanswer_r (struct resolv_context *ctx,
114 const querybuf *answer, int anslen,
115 const char *qname, int qtype,
116 struct hostent *result, char *buffer,
117 size_t buflen, int *errnop, int *h_errnop,
118 int map, int32_t *ttlp, char **canonp);
119
120static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
121 const querybuf *answer2, int anslen2,
122 const char *qname,
123 struct gaih_addrtuple **pat,
124 char *buffer, size_t buflen,
125 int *errnop, int *h_errnop,
126 int32_t *ttlp);
127
128static enum nss_status gethostbyname3_context (struct resolv_context *ctx,
129 const char *name, int af,
130 struct hostent *result,
131 char *buffer, size_t buflen,
132 int *errnop, int *h_errnop,
133 int32_t *ttlp,
134 char **canonp);
135
136/* Return the expected RDATA length for an address record type (A or
137 AAAA). */
138static int
139rrtype_to_rdata_length (int type)
140{
141 switch (type)
142 {
143 case T_A:
144 return INADDRSZ;
145 case T_AAAA:
146 return IN6ADDRSZ;
147 default:
148 return -1;
149 }
150}
151
152
153enum nss_status
154_nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
155 char *buffer, size_t buflen, int *errnop,
156 int *h_errnop, int32_t *ttlp, char **canonp)
157{
158 struct resolv_context *ctx = __resolv_context_get ();
159 if (ctx == NULL)
160 {
161 *errnop = errno;
162 *h_errnop = NETDB_INTERNAL;
163 return NSS_STATUS_UNAVAIL;
164 }
165 enum nss_status status = gethostbyname3_context
166 (ctx, name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp);
167 __resolv_context_put (ctx);
168 return status;
169}
170
171static enum nss_status
172gethostbyname3_context (struct resolv_context *ctx,
173 const char *name, int af, struct hostent *result,
174 char *buffer, size_t buflen, int *errnop,
175 int *h_errnop, int32_t *ttlp, char **canonp)
176{
177 union
178 {
179 querybuf *buf;
180 u_char *ptr;
181 } host_buffer;
182 querybuf *orig_host_buffer;
183 char tmp[NS_MAXDNAME];
184 int size, type, n;
185 const char *cp;
186 int map = 0;
187 int olderr = errno;
188 enum nss_status status;
189
190 switch (af) {
191 case AF_INET:
192 size = INADDRSZ;
193 type = T_A;
194 break;
195 case AF_INET6:
196 size = IN6ADDRSZ;
197 type = T_AAAA;
198 break;
199 default:
200 *h_errnop = NO_DATA;
201 *errnop = EAFNOSUPPORT;
202 return NSS_STATUS_UNAVAIL;
203 }
204
205 result->h_addrtype = af;
206 result->h_length = size;
207
208 /*
209 * if there aren't any dots, it could be a user-level alias.
210 * this is also done in res_query() since we are not the only
211 * function that looks up host names.
212 */
213 if (strchr (name, '.') == NULL
214 && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL)
215 name = cp;
216
217 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
218
219 n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf,
220 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
221 if (n < 0)
222 {
223 switch (errno)
224 {
225 case ESRCH:
226 status = NSS_STATUS_TRYAGAIN;
227 h_errno = TRY_AGAIN;
228 break;
229 /* System has run out of file descriptors. */
230 case EMFILE:
231 case ENFILE:
232 h_errno = NETDB_INTERNAL;
233 /* Fall through. */
234 case ECONNREFUSED:
235 case ETIMEDOUT:
236 status = NSS_STATUS_UNAVAIL;
237 break;
238 default:
239 status = NSS_STATUS_NOTFOUND;
240 break;
241 }
242 *h_errnop = h_errno;
243 if (h_errno == TRY_AGAIN)
244 *errnop = EAGAIN;
245 else
246 __set_errno (olderr);
247
248 /* If we are looking for an IPv6 address and mapping is enabled
249 by having the RES_USE_INET6 bit in _res.options set, we try
250 another lookup. */
251 if (af == AF_INET6 && res_use_inet6 ())
252 n = __res_context_search (ctx, name, C_IN, T_A, host_buffer.buf->buf,
253 host_buffer.buf != orig_host_buffer
254 ? MAXPACKET : 1024, &host_buffer.ptr,
255 NULL, NULL, NULL, NULL);
256
257 if (n < 0)
258 {
259 if (host_buffer.buf != orig_host_buffer)
260 free (host_buffer.buf);
261 return status;
262 }
263
264 map = 1;
265
266 result->h_addrtype = AF_INET;
267 result->h_length = INADDRSZ;
268 }
269
270 status = getanswer_r
271 (ctx, host_buffer.buf, n, name, type, result, buffer, buflen,
272 errnop, h_errnop, map, ttlp, canonp);
273 if (host_buffer.buf != orig_host_buffer)
274 free (host_buffer.buf);
275 return status;
276}
277
278/* Verify that the name looks like a host name. There is no point in
279 sending a query which will not produce a usable name in the
280 response. */
281static enum nss_status
282check_name (const char *name, int *h_errnop)
283{
284 if (res_hnok (name))
285 return NSS_STATUS_SUCCESS;
286 *h_errnop = HOST_NOT_FOUND;
287 return NSS_STATUS_NOTFOUND;
288}
289
290enum nss_status
291_nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
292 char *buffer, size_t buflen, int *errnop,
293 int *h_errnop)
294{
295 enum nss_status status = check_name (name, h_errnop);
296 if (status != NSS_STATUS_SUCCESS)
297 return status;
298 return _nss_dns_gethostbyname3_r (name, af, result, buffer, buflen, errnop,
299 h_errnop, NULL, NULL);
300}
301
302
303enum nss_status
304_nss_dns_gethostbyname_r (const char *name, struct hostent *result,
305 char *buffer, size_t buflen, int *errnop,
306 int *h_errnop)
307{
308 enum nss_status status = check_name (name, h_errnop);
309 if (status != NSS_STATUS_SUCCESS)
310 return status;
311 struct resolv_context *ctx = __resolv_context_get ();
312 if (ctx == NULL)
313 {
314 *errnop = errno;
315 *h_errnop = NETDB_INTERNAL;
316 return NSS_STATUS_UNAVAIL;
317 }
318 status = NSS_STATUS_NOTFOUND;
319 if (res_use_inet6 ())
320 status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer,
321 buflen, errnop, h_errnop, NULL, NULL);
322 if (status == NSS_STATUS_NOTFOUND)
323 status = gethostbyname3_context (ctx, name, AF_INET, result, buffer,
324 buflen, errnop, h_errnop, NULL, NULL);
325 __resolv_context_put (ctx);
326 return status;
327}
328
329
330enum nss_status
331_nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
332 char *buffer, size_t buflen, int *errnop,
333 int *herrnop, int32_t *ttlp)
334{
335 enum nss_status status = check_name (name, herrnop);
336 if (status != NSS_STATUS_SUCCESS)
337 return status;
338 struct resolv_context *ctx = __resolv_context_get ();
339 if (ctx == NULL)
340 {
341 *errnop = errno;
342 *herrnop = NETDB_INTERNAL;
343 return NSS_STATUS_UNAVAIL;
344 }
345
346 /*
347 * if there aren't any dots, it could be a user-level alias.
348 * this is also done in res_query() since we are not the only
349 * function that looks up host names.
350 */
351 if (strchr (name, '.') == NULL)
352 {
353 char *tmp = alloca (NS_MAXDNAME);
354 const char *cp = __res_context_hostalias (ctx, name, tmp, NS_MAXDNAME);
355 if (cp != NULL)
356 name = cp;
357 }
358
359 union
360 {
361 querybuf *buf;
362 u_char *ptr;
363 } host_buffer;
364 querybuf *orig_host_buffer;
365 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
366 u_char *ans2p = NULL;
367 int nans2p = 0;
368 int resplen2 = 0;
369 int ans2p_malloced = 0;
370
371 int olderr = errno;
372 int n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
373 host_buffer.buf->buf, 2048, &host_buffer.ptr,
374 &ans2p, &nans2p, &resplen2, &ans2p_malloced);
375 if (n >= 0)
376 {
377 status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
378 resplen2, name, pat, buffer, buflen,
379 errnop, herrnop, ttlp);
380 }
381 else
382 {
383 switch (errno)
384 {
385 case ESRCH:
386 status = NSS_STATUS_TRYAGAIN;
387 h_errno = TRY_AGAIN;
388 break;
389 /* System has run out of file descriptors. */
390 case EMFILE:
391 case ENFILE:
392 h_errno = NETDB_INTERNAL;
393 /* Fall through. */
394 case ECONNREFUSED:
395 case ETIMEDOUT:
396 status = NSS_STATUS_UNAVAIL;
397 break;
398 default:
399 status = NSS_STATUS_NOTFOUND;
400 break;
401 }
402
403 *herrnop = h_errno;
404 if (h_errno == TRY_AGAIN)
405 *errnop = EAGAIN;
406 else
407 __set_errno (olderr);
408 }
409
410 /* Check whether ans2p was separately allocated. */
411 if (ans2p_malloced)
412 free (ans2p);
413
414 if (host_buffer.buf != orig_host_buffer)
415 free (host_buffer.buf);
416
417 __resolv_context_put (ctx);
418 return status;
419}
420
421
422extern enum nss_status _nss_dns_gethostbyaddr2_r (const void *addr,
423 socklen_t len, int af,
424 struct hostent *result,
425 char *buffer, size_t buflen,
426 int *errnop, int *h_errnop,
427 int32_t *ttlp);
428hidden_proto (_nss_dns_gethostbyaddr2_r)
429
430enum nss_status
431_nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
432 struct hostent *result, char *buffer, size_t buflen,
433 int *errnop, int *h_errnop, int32_t *ttlp)
434{
435 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
436 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
437 static const u_char v6local[] = { 0,0, 0,1 };
438 const u_char *uaddr = (const u_char *)addr;
439 struct host_data
440 {
441 char *aliases[MAX_NR_ALIASES];
442 unsigned char host_addr[16]; /* IPv4 or IPv6 */
443 char *h_addr_ptrs[MAX_NR_ADDRS + 1];
444 char linebuffer[0];
445 } *host_data = (struct host_data *) buffer;
446 union
447 {
448 querybuf *buf;
449 u_char *ptr;
450 } host_buffer;
451 querybuf *orig_host_buffer;
452 char qbuf[MAXDNAME+1], *qp = NULL;
453 size_t size;
454 int n, status;
455 int olderr = errno;
456
457 uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
458 buffer += pad;
459 buflen = buflen > pad ? buflen - pad : 0;
460
461 if (__glibc_unlikely (buflen < sizeof (struct host_data)))
462 {
463 *errnop = ERANGE;
464 *h_errnop = NETDB_INTERNAL;
465 return NSS_STATUS_TRYAGAIN;
466 }
467
468 host_data = (struct host_data *) buffer;
469
470 struct resolv_context *ctx = __resolv_context_get ();
471 if (ctx == NULL)
472 {
473 *errnop = errno;
474 *h_errnop = NETDB_INTERNAL;
475 return NSS_STATUS_UNAVAIL;
476 }
477
478 if (af == AF_INET6 && len == IN6ADDRSZ
479 && (memcmp (uaddr, mapped, sizeof mapped) == 0
480 || (memcmp (uaddr, tunnelled, sizeof tunnelled) == 0
481 && memcmp (&uaddr[sizeof tunnelled], v6local, sizeof v6local))))
482 {
483 /* Unmap. */
484 addr += sizeof mapped;
485 uaddr += sizeof mapped;
486 af = AF_INET;
487 len = INADDRSZ;
488 }
489
490 switch (af)
491 {
492 case AF_INET:
493 size = INADDRSZ;
494 break;
495 case AF_INET6:
496 size = IN6ADDRSZ;
497 break;
498 default:
499 *errnop = EAFNOSUPPORT;
500 *h_errnop = NETDB_INTERNAL;
501 __resolv_context_put (ctx);
502 return NSS_STATUS_UNAVAIL;
503 }
504 if (size > len)
505 {
506 *errnop = EAFNOSUPPORT;
507 *h_errnop = NETDB_INTERNAL;
508 __resolv_context_put (ctx);
509 return NSS_STATUS_UNAVAIL;
510 }
511
512 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
513
514 switch (af)
515 {
516 case AF_INET:
517 sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", (uaddr[3] & 0xff),
518 (uaddr[2] & 0xff), (uaddr[1] & 0xff), (uaddr[0] & 0xff));
519 break;
520 case AF_INET6:
521 qp = qbuf;
522 for (n = IN6ADDRSZ - 1; n >= 0; n--)
523 {
524 static const char nibblechar[16] = "0123456789abcdef";
525 *qp++ = nibblechar[uaddr[n] & 0xf];
526 *qp++ = '.';
527 *qp++ = nibblechar[(uaddr[n] >> 4) & 0xf];
528 *qp++ = '.';
529 }
530 strcpy(qp, "ip6.arpa");
531 break;
532 default:
533 /* Cannot happen. */
534 break;
535 }
536
537 n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
538 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
539 if (n < 0)
540 {
541 *h_errnop = h_errno;
542 __set_errno (olderr);
543 if (host_buffer.buf != orig_host_buffer)
544 free (host_buffer.buf);
545 __resolv_context_put (ctx);
546 return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
547 }
548
549 status = getanswer_r
550 (ctx, host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen,
551 errnop, h_errnop, 0 /* XXX */, ttlp, NULL);
552 if (host_buffer.buf != orig_host_buffer)
553 free (host_buffer.buf);
554 if (status != NSS_STATUS_SUCCESS)
555 {
556 __resolv_context_put (ctx);
557 return status;
558 }
559
560 result->h_addrtype = af;
561 result->h_length = len;
562 memcpy (host_data->host_addr, addr, len);
563 host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
564 host_data->h_addr_ptrs[1] = NULL;
565 *h_errnop = NETDB_SUCCESS;
566 __resolv_context_put (ctx);
567 return NSS_STATUS_SUCCESS;
568}
569hidden_def (_nss_dns_gethostbyaddr2_r)
570
571
572enum nss_status
573_nss_dns_gethostbyaddr_r (const void *addr, socklen_t len, int af,
574 struct hostent *result, char *buffer, size_t buflen,
575 int *errnop, int *h_errnop)
576{
577 return _nss_dns_gethostbyaddr2_r (addr, len, af, result, buffer, buflen,
578 errnop, h_errnop, NULL);
579}
580
581static void
582addrsort (struct resolv_context *ctx, char **ap, int num)
583{
584 int i, j;
585 char **p;
586 short aval[MAX_NR_ADDRS];
587 int needsort = 0;
588 size_t nsort = __resolv_context_sort_count (ctx);
589
590 p = ap;
591 if (num > MAX_NR_ADDRS)
592 num = MAX_NR_ADDRS;
593 for (i = 0; i < num; i++, p++)
594 {
595 for (j = 0 ; (unsigned)j < nsort; j++)
596 {
597 struct resolv_sortlist_entry e
598 = __resolv_context_sort_entry (ctx, j);
599 if (e.addr.s_addr == (((struct in_addr *)(*p))->s_addr & e.mask))
600 break;
601 }
602 aval[i] = j;
603 if (needsort == 0 && i > 0 && j < aval[i-1])
604 needsort = i;
605 }
606 if (!needsort)
607 return;
608
609 while (needsort++ < num)
610 for (j = needsort - 2; j >= 0; j--)
611 if (aval[j] > aval[j+1])
612 {
613 char *hp;
614
615 i = aval[j];
616 aval[j] = aval[j+1];
617 aval[j+1] = i;
618
619 hp = ap[j];
620 ap[j] = ap[j+1];
621 ap[j+1] = hp;
622 }
623 else
624 break;
625}
626
627static enum nss_status
628getanswer_r (struct resolv_context *ctx,
629 const querybuf *answer, int anslen, const char *qname, int qtype,
630 struct hostent *result, char *buffer, size_t buflen,
631 int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp)
632{
633 struct host_data
634 {
635 char *aliases[MAX_NR_ALIASES];
636 unsigned char host_addr[16]; /* IPv4 or IPv6 */
637 char *h_addr_ptrs[0];
638 } *host_data;
639 int linebuflen;
640 const HEADER *hp;
641 const u_char *end_of_message, *cp;
642 int n, ancount, qdcount;
643 int haveanswer, had_error;
644 char *bp, **ap, **hap;
645 char tbuf[MAXDNAME];
646 const char *tname;
647 int (*name_ok) (const char *);
648 u_char packtmp[NS_MAXCDNAME];
649 int have_to_map = 0;
650 uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
651 buffer += pad;
652 buflen = buflen > pad ? buflen - pad : 0;
653 if (__glibc_unlikely (buflen < sizeof (struct host_data)))
654 {
655 /* The buffer is too small. */
656 too_small:
657 *errnop = ERANGE;
658 *h_errnop = NETDB_INTERNAL;
659 return NSS_STATUS_TRYAGAIN;
660 }
661 host_data = (struct host_data *) buffer;
662 linebuflen = buflen - sizeof (struct host_data);
663 if (buflen - sizeof (struct host_data) != linebuflen)
664 linebuflen = INT_MAX;
665
666 tname = qname;
667 result->h_name = NULL;
668 end_of_message = answer->buf + anslen;
669 switch (qtype)
670 {
671 case T_A:
672 case T_AAAA:
673 name_ok = res_hnok;
674 break;
675 case T_PTR:
676 name_ok = res_dnok;
677 break;
678 default:
679 *errnop = ENOENT;
680 return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */
681 }
682
683 /*
684 * find first satisfactory answer
685 */
686 hp = &answer->hdr;
687 ancount = ntohs (hp->ancount);
688 qdcount = ntohs (hp->qdcount);
689 cp = answer->buf + HFIXEDSZ;
690 if (__glibc_unlikely (qdcount != 1))
691 {
692 *h_errnop = NO_RECOVERY;
693 return NSS_STATUS_UNAVAIL;
694 }
695 if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen)
696 goto too_small;
697 bp = (char *) &host_data->h_addr_ptrs[ancount + 1];
698 linebuflen -= (ancount + 1) * sizeof (char *);
699
700 n = __ns_name_unpack (answer->buf, end_of_message, cp,
701 packtmp, sizeof packtmp);
702 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
703 {
704 if (__glibc_unlikely (errno == EMSGSIZE))
705 goto too_small;
706
707 n = -1;
708 }
709
710 if (__glibc_unlikely (n < 0))
711 {
712 *errnop = errno;
713 *h_errnop = NO_RECOVERY;
714 return NSS_STATUS_UNAVAIL;
715 }
716 if (__glibc_unlikely (name_ok (bp) == 0))
717 {
718 errno = EBADMSG;
719 *errnop = EBADMSG;
720 *h_errnop = NO_RECOVERY;
721 return NSS_STATUS_UNAVAIL;
722 }
723 cp += n + QFIXEDSZ;
724
725 if (qtype == T_A || qtype == T_AAAA)
726 {
727 /* res_send() has already verified that the query name is the
728 * same as the one we sent; this just gets the expanded name
729 * (i.e., with the succeeding search-domain tacked on).
730 */
731 n = strlen (bp) + 1; /* for the \0 */
732 if (n >= MAXHOSTNAMELEN)
733 {
734 *h_errnop = NO_RECOVERY;
735 *errnop = ENOENT;
736 return NSS_STATUS_TRYAGAIN;
737 }
738 result->h_name = bp;
739 bp += n;
740 linebuflen -= n;
741 if (linebuflen < 0)
742 goto too_small;
743 /* The qname can be abbreviated, but h_name is now absolute. */
744 qname = result->h_name;
745 }
746
747 ap = host_data->aliases;
748 *ap = NULL;
749 result->h_aliases = host_data->aliases;
750 hap = host_data->h_addr_ptrs;
751 *hap = NULL;
752 result->h_addr_list = host_data->h_addr_ptrs;
753 haveanswer = 0;
754 had_error = 0;
755
756 while (ancount-- > 0 && cp < end_of_message && had_error == 0)
757 {
758 int type, class;
759
760 n = __ns_name_unpack (answer->buf, end_of_message, cp,
761 packtmp, sizeof packtmp);
762 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
763 {
764 if (__glibc_unlikely (errno == EMSGSIZE))
765 goto too_small;
766
767 n = -1;
768 }
769
770 if (__glibc_unlikely (n < 0 || (*name_ok) (bp) == 0))
771 {
772 ++had_error;
773 continue;
774 }
775 cp += n; /* name */
776
777 if (__glibc_unlikely (cp + 10 > end_of_message))
778 {
779 ++had_error;
780 continue;
781 }
782
783 type = __ns_get16 (cp);
784 cp += INT16SZ; /* type */
785 class = __ns_get16 (cp);
786 cp += INT16SZ; /* class */
787 int32_t ttl = __ns_get32 (cp);
788 cp += INT32SZ; /* TTL */
789 n = __ns_get16 (cp);
790 cp += INT16SZ; /* len */
791
792 if (end_of_message - cp < n)
793 {
794 /* RDATA extends beyond the end of the packet. */
795 ++had_error;
796 continue;
797 }
798
799 if (__glibc_unlikely (class != C_IN))
800 {
801 /* XXX - debug? syslog? */
802 cp += n;
803 continue; /* XXX - had_error++ ? */
804 }
805
806 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME)
807 {
808 /* A CNAME could also have a TTL entry. */
809 if (ttlp != NULL && ttl < *ttlp)
810 *ttlp = ttl;
811
812 if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
813 continue;
814 n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
815 if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0))
816 {
817 ++had_error;
818 continue;
819 }
820 cp += n;
821 /* Store alias. */
822 *ap++ = bp;
823 n = strlen (bp) + 1; /* For the \0. */
824 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
825 {
826 ++had_error;
827 continue;
828 }
829 bp += n;
830 linebuflen -= n;
831 /* Get canonical name. */
832 n = strlen (tbuf) + 1; /* For the \0. */
833 if (__glibc_unlikely (n > linebuflen))
834 goto too_small;
835 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
836 {
837 ++had_error;
838 continue;
839 }
840 result->h_name = bp;
841 bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
842 linebuflen -= n;
843 continue;
844 }
845
846 if (qtype == T_PTR && type == T_CNAME)
847 {
848 /* A CNAME could also have a TTL entry. */
849 if (ttlp != NULL && ttl < *ttlp)
850 *ttlp = ttl;
851
852 n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
853 if (__glibc_unlikely (n < 0 || res_dnok (tbuf) == 0))
854 {
855 ++had_error;
856 continue;
857 }
858 cp += n;
859 /* Get canonical name. */
860 n = strlen (tbuf) + 1; /* For the \0. */
861 if (__glibc_unlikely (n > linebuflen))
862 goto too_small;
863 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
864 {
865 ++had_error;
866 continue;
867 }
868 tname = bp;
869 bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
870 linebuflen -= n;
871 continue;
872 }
873
874 if (type == T_A && qtype == T_AAAA && map)
875 have_to_map = 1;
876 else if (__glibc_unlikely (type != qtype))
877 {
878 cp += n;
879 continue; /* XXX - had_error++ ? */
880 }
881
882 switch (type)
883 {
884 case T_PTR:
885 if (__glibc_unlikely (strcasecmp (tname, bp) != 0))
886 {
887 cp += n;
888 continue; /* XXX - had_error++ ? */
889 }
890
891 n = __ns_name_unpack (answer->buf, end_of_message, cp,
892 packtmp, sizeof packtmp);
893 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
894 {
895 if (__glibc_unlikely (errno == EMSGSIZE))
896 goto too_small;
897
898 n = -1;
899 }
900
901 if (__glibc_unlikely (n < 0 || res_hnok (bp) == 0))
902 {
903 ++had_error;
904 break;
905 }
906 if (ttlp != NULL && ttl < *ttlp)
907 *ttlp = ttl;
908 /* bind would put multiple PTR records as aliases, but we don't do
909 that. */
910 result->h_name = bp;
911 *h_errnop = NETDB_SUCCESS;
912 return NSS_STATUS_SUCCESS;
913 case T_A:
914 case T_AAAA:
915 if (__glibc_unlikely (strcasecmp (result->h_name, bp) != 0))
916 {
917 cp += n;
918 continue; /* XXX - had_error++ ? */
919 }
920
921 /* Stop parsing at a record whose length is incorrect. */
922 if (n != rrtype_to_rdata_length (type))
923 {
924 ++had_error;
925 break;
926 }
927
928 /* Skip records of the wrong type. */
929 if (n != result->h_length)
930 {
931 cp += n;
932 continue;
933 }
934 if (!haveanswer)
935 {
936 int nn;
937
938 /* We compose a single hostent out of the entire chain of
939 entries, so the TTL of the hostent is essentially the lowest
940 TTL in the chain. */
941 if (ttlp != NULL && ttl < *ttlp)
942 *ttlp = ttl;
943 if (canonp != NULL)
944 *canonp = bp;
945 result->h_name = bp;
946 nn = strlen (bp) + 1; /* for the \0 */
947 bp += nn;
948 linebuflen -= nn;
949 }
950
951 /* Provide sufficient alignment for both address
952 families. */
953 enum { align = 4 };
954 _Static_assert ((align % __alignof__ (struct in_addr)) == 0,
955 "struct in_addr alignment");
956 _Static_assert ((align % __alignof__ (struct in6_addr)) == 0,
957 "struct in6_addr alignment");
958 {
959 char *new_bp = PTR_ALIGN_UP (bp, align);
960 linebuflen -= new_bp - bp;
961 bp = new_bp;
962 }
963
964 if (__glibc_unlikely (n > linebuflen))
965 goto too_small;
966 bp = __mempcpy (*hap++ = bp, cp, n);
967 cp += n;
968 linebuflen -= n;
969 break;
970 default:
971 abort ();
972 }
973 if (had_error == 0)
974 ++haveanswer;
975 }
976
977 if (haveanswer > 0)
978 {
979 *ap = NULL;
980 *hap = NULL;
981 /*
982 * Note: we sort even if host can take only one address
983 * in its return structures - should give it the "best"
984 * address in that case, not some random one
985 */
986 if (haveanswer > 1 && qtype == T_A
987 && __resolv_context_sort_count (ctx) > 0)
988 addrsort (ctx, host_data->h_addr_ptrs, haveanswer);
989
990 if (result->h_name == NULL)
991 {
992 n = strlen (qname) + 1; /* For the \0. */
993 if (n > linebuflen)
994 goto too_small;
995 if (n >= MAXHOSTNAMELEN)
996 goto no_recovery;
997 result->h_name = bp;
998 bp = __mempcpy (bp, qname, n); /* Cannot overflow. */
999 linebuflen -= n;
1000 }
1001
1002 if (have_to_map)
1003 if (map_v4v6_hostent (result, &bp, &linebuflen))
1004 goto too_small;
1005 *h_errnop = NETDB_SUCCESS;
1006 return NSS_STATUS_SUCCESS;
1007 }
1008 no_recovery:
1009 *h_errnop = NO_RECOVERY;
1010 *errnop = ENOENT;
1011 /* Special case here: if the resolver sent a result but it only
1012 contains a CNAME while we are looking for a T_A or T_AAAA record,
1013 we fail with NOTFOUND instead of TRYAGAIN. */
1014 return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases
1015 ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN);
1016}
1017
1018
1019static enum nss_status
1020gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
1021 struct gaih_addrtuple ***patp,
1022 char **bufferp, size_t *buflenp,
1023 int *errnop, int *h_errnop, int32_t *ttlp, int *firstp)
1024{
1025 char *buffer = *bufferp;
1026 size_t buflen = *buflenp;
1027
1028 struct gaih_addrtuple **pat = *patp;
1029 const HEADER *hp = &answer->hdr;
1030 int ancount = ntohs (hp->ancount);
1031 int qdcount = ntohs (hp->qdcount);
1032 const u_char *cp = answer->buf + HFIXEDSZ;
1033 const u_char *end_of_message = answer->buf + anslen;
1034 if (__glibc_unlikely (qdcount != 1))
1035 {
1036 *h_errnop = NO_RECOVERY;
1037 return NSS_STATUS_UNAVAIL;
1038 }
1039
1040 u_char packtmp[NS_MAXCDNAME];
1041 int n = __ns_name_unpack (answer->buf, end_of_message, cp,
1042 packtmp, sizeof packtmp);
1043 /* We unpack the name to check it for validity. But we do not need
1044 it later. */
1045 if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1)
1046 {
1047 if (__glibc_unlikely (errno == EMSGSIZE))
1048 {
1049 too_small:
1050 *errnop = ERANGE;
1051 *h_errnop = NETDB_INTERNAL;
1052 return NSS_STATUS_TRYAGAIN;
1053 }
1054
1055 n = -1;
1056 }
1057
1058 if (__glibc_unlikely (n < 0))
1059 {
1060 *errnop = errno;
1061 *h_errnop = NO_RECOVERY;
1062 return NSS_STATUS_UNAVAIL;
1063 }
1064 if (__glibc_unlikely (res_hnok (buffer) == 0))
1065 {
1066 errno = EBADMSG;
1067 *errnop = EBADMSG;
1068 *h_errnop = NO_RECOVERY;
1069 return NSS_STATUS_UNAVAIL;
1070 }
1071 cp += n + QFIXEDSZ;
1072
1073 int haveanswer = 0;
1074 int had_error = 0;
1075 char *canon = NULL;
1076 char *h_name = NULL;
1077 int h_namelen = 0;
1078
1079 if (ancount == 0)
1080 {
1081 *h_errnop = HOST_NOT_FOUND;
1082 return NSS_STATUS_NOTFOUND;
1083 }
1084
1085 while (ancount-- > 0 && cp < end_of_message && had_error == 0)
1086 {
1087 n = __ns_name_unpack (answer->buf, end_of_message, cp,
1088 packtmp, sizeof packtmp);
1089 if (n != -1 &&
1090 (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
1091 {
1092 if (__glibc_unlikely (errno == EMSGSIZE))
1093 goto too_small;
1094
1095 n = -1;
1096 }
1097 if (__glibc_unlikely (n < 0 || res_hnok (buffer) == 0))
1098 {
1099 ++had_error;
1100 continue;
1101 }
1102 if (*firstp && canon == NULL)
1103 {
1104 h_name = buffer;
1105 buffer += h_namelen;
1106 buflen -= h_namelen;
1107 }
1108
1109 cp += n; /* name */
1110
1111 if (__glibc_unlikely (cp + 10 > end_of_message))
1112 {
1113 ++had_error;
1114 continue;
1115 }
1116
1117 int type = __ns_get16 (cp);
1118 cp += INT16SZ; /* type */
1119 int class = __ns_get16 (cp);
1120 cp += INT16SZ; /* class */
1121 int32_t ttl = __ns_get32 (cp);
1122 cp += INT32SZ; /* TTL */
1123 n = __ns_get16 (cp);
1124 cp += INT16SZ; /* len */
1125
1126 if (end_of_message - cp < n)
1127 {
1128 /* RDATA extends beyond the end of the packet. */
1129 ++had_error;
1130 continue;
1131 }
1132
1133 if (class != C_IN)
1134 {
1135 cp += n;
1136 continue;
1137 }
1138
1139 if (type == T_CNAME)
1140 {
1141 char tbuf[MAXDNAME];
1142
1143 /* A CNAME could also have a TTL entry. */
1144 if (ttlp != NULL && ttl < *ttlp)
1145 *ttlp = ttl;
1146
1147 n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
1148 if (__glibc_unlikely (n < 0 || res_hnok (tbuf) == 0))
1149 {
1150 ++had_error;
1151 continue;
1152 }
1153 cp += n;
1154
1155 if (*firstp)
1156 {
1157 /* Reclaim buffer space. */
1158 if (h_name + h_namelen == buffer)
1159 {
1160 buffer = h_name;
1161 buflen += h_namelen;
1162 }
1163
1164 n = strlen (tbuf) + 1;
1165 if (__glibc_unlikely (n > buflen))
1166 goto too_small;
1167 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
1168 {
1169 ++had_error;
1170 continue;
1171 }
1172
1173 canon = buffer;
1174 buffer = __mempcpy (buffer, tbuf, n);
1175 buflen -= n;
1176 h_namelen = 0;
1177 }
1178 continue;
1179 }
1180
1181 /* Stop parsing if we encounter a record with incorrect RDATA
1182 length. */
1183 if (type == T_A || type == T_AAAA)
1184 {
1185 if (n != rrtype_to_rdata_length (type))
1186 {
1187 ++had_error;
1188 continue;
1189 }
1190 }
1191 else
1192 {
1193 /* Skip unknown records. */
1194 cp += n;
1195 continue;
1196 }
1197
1198 assert (type == T_A || type == T_AAAA);
1199 if (*pat == NULL)
1200 {
1201 uintptr_t pad = (-(uintptr_t) buffer
1202 % __alignof__ (struct gaih_addrtuple));
1203 buffer += pad;
1204 buflen = buflen > pad ? buflen - pad : 0;
1205
1206 if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple)))
1207 goto too_small;
1208
1209 *pat = (struct gaih_addrtuple *) buffer;
1210 buffer += sizeof (struct gaih_addrtuple);
1211 buflen -= sizeof (struct gaih_addrtuple);
1212 }
1213
1214 (*pat)->name = NULL;
1215 (*pat)->next = NULL;
1216
1217 if (*firstp)
1218 {
1219 /* We compose a single hostent out of the entire chain of
1220 entries, so the TTL of the hostent is essentially the lowest
1221 TTL in the chain. */
1222 if (ttlp != NULL && ttl < *ttlp)
1223 *ttlp = ttl;
1224
1225 (*pat)->name = canon ?: h_name;
1226
1227 *firstp = 0;
1228 }
1229
1230 (*pat)->family = type == T_A ? AF_INET : AF_INET6;
1231 memcpy ((*pat)->addr, cp, n);
1232 cp += n;
1233 (*pat)->scopeid = 0;
1234
1235 pat = &((*pat)->next);
1236
1237 haveanswer = 1;
1238 }
1239
1240 if (haveanswer)
1241 {
1242 *patp = pat;
1243 *bufferp = buffer;
1244 *buflenp = buflen;
1245
1246 *h_errnop = NETDB_SUCCESS;
1247 return NSS_STATUS_SUCCESS;
1248 }
1249
1250 /* Special case here: if the resolver sent a result but it only
1251 contains a CNAME while we are looking for a T_A or T_AAAA record,
1252 we fail with NOTFOUND instead of TRYAGAIN. */
1253 if (canon != NULL)
1254 {
1255 *h_errnop = HOST_NOT_FOUND;
1256 return NSS_STATUS_NOTFOUND;
1257 }
1258
1259 *h_errnop = NETDB_INTERNAL;
1260 return NSS_STATUS_TRYAGAIN;
1261}
1262
1263
1264static enum nss_status
1265gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
1266 int anslen2, const char *qname,
1267 struct gaih_addrtuple **pat, char *buffer, size_t buflen,
1268 int *errnop, int *h_errnop, int32_t *ttlp)
1269{
1270 int first = 1;
1271
1272 enum nss_status status = NSS_STATUS_NOTFOUND;
1273
1274 /* Combining the NSS status of two distinct queries requires some
1275 compromise and attention to symmetry (A or AAAA queries can be
1276 returned in any order). What follows is a breakdown of how this
1277 code is expected to work and why. We discuss only SUCCESS,
1278 TRYAGAIN, NOTFOUND and UNAVAIL, since they are the only returns
1279 that apply (though RETURN and MERGE exist). We make a distinction
1280 between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
1281 A recoverable TRYAGAIN is almost always due to buffer size issues
1282 and returns ERANGE in errno and the caller is expected to retry
1283 with a larger buffer.
1284
1285 Lastly, you may be tempted to make significant changes to the
1286 conditions in this code to bring about symmetry between responses.
1287 Please don't change anything without due consideration for
1288 expected application behaviour. Some of the synthesized responses
1289 aren't very well thought out and sometimes appear to imply that
1290 IPv4 responses are always answer 1, and IPv6 responses are always
1291 answer 2, but that's not true (see the implementation of send_dg
1292 and send_vc to see response can arrive in any order, particularly
1293 for UDP). However, we expect it holds roughly enough of the time
1294 that this code works, but certainly needs to be fixed to make this
1295 a more robust implementation.
1296
1297 ----------------------------------------------
1298 | Answer 1 Status / | Synthesized | Reason |
1299 | Answer 2 Status | Status | |
1300 |--------------------------------------------|
1301 | SUCCESS/SUCCESS | SUCCESS | [1] |
1302 | SUCCESS/TRYAGAIN | TRYAGAIN | [5] |
1303 | SUCCESS/TRYAGAIN' | SUCCESS | [1] |
1304 | SUCCESS/NOTFOUND | SUCCESS | [1] |
1305 | SUCCESS/UNAVAIL | SUCCESS | [1] |
1306 | TRYAGAIN/SUCCESS | TRYAGAIN | [2] |
1307 | TRYAGAIN/TRYAGAIN | TRYAGAIN | [2] |
1308 | TRYAGAIN/TRYAGAIN' | TRYAGAIN | [2] |
1309 | TRYAGAIN/NOTFOUND | TRYAGAIN | [2] |
1310 | TRYAGAIN/UNAVAIL | TRYAGAIN | [2] |
1311 | TRYAGAIN'/SUCCESS | SUCCESS | [3] |
1312 | TRYAGAIN'/TRYAGAIN | TRYAGAIN | [3] |
1313 | TRYAGAIN'/TRYAGAIN' | TRYAGAIN' | [3] |
1314 | TRYAGAIN'/NOTFOUND | TRYAGAIN' | [3] |
1315 | TRYAGAIN'/UNAVAIL | UNAVAIL | [3] |
1316 | NOTFOUND/SUCCESS | SUCCESS | [3] |
1317 | NOTFOUND/TRYAGAIN | TRYAGAIN | [3] |
1318 | NOTFOUND/TRYAGAIN' | TRYAGAIN' | [3] |
1319 | NOTFOUND/NOTFOUND | NOTFOUND | [3] |
1320 | NOTFOUND/UNAVAIL | UNAVAIL | [3] |
1321 | UNAVAIL/SUCCESS | UNAVAIL | [4] |
1322 | UNAVAIL/TRYAGAIN | UNAVAIL | [4] |
1323 | UNAVAIL/TRYAGAIN' | UNAVAIL | [4] |
1324 | UNAVAIL/NOTFOUND | UNAVAIL | [4] |
1325 | UNAVAIL/UNAVAIL | UNAVAIL | [4] |
1326 ----------------------------------------------
1327
1328 [1] If the first response is a success we return success.
1329 This ignores the state of the second answer and in fact
1330 incorrectly sets errno and h_errno to that of the second
1331 answer. However because the response is a success we ignore
1332 *errnop and *h_errnop (though that means you touched errno on
1333 success). We are being conservative here and returning the
1334 likely IPv4 response in the first answer as a success.
1335
1336 [2] If the first response is a recoverable TRYAGAIN we return
1337 that instead of looking at the second response. The
1338 expectation here is that we have failed to get an IPv4 response
1339 and should retry both queries.
1340
1341 [3] If the first response was not a SUCCESS and the second
1342 response is not NOTFOUND (had a SUCCESS, need to TRYAGAIN,
1343 or failed entirely e.g. TRYAGAIN' and UNAVAIL) then use the
1344 result from the second response, otherwise the first responses
1345 status is used. Again we have some odd side-effects when the
1346 second response is NOTFOUND because we overwrite *errnop and
1347 *h_errnop that means that a first answer of NOTFOUND might see
1348 its *errnop and *h_errnop values altered. Whether it matters
1349 in practice that a first response NOTFOUND has the wrong
1350 *errnop and *h_errnop is undecided.
1351
1352 [4] If the first response is UNAVAIL we return that instead of
1353 looking at the second response. The expectation here is that
1354 it will have failed similarly e.g. configuration failure.
1355
1356 [5] Testing this code is complicated by the fact that truncated
1357 second response buffers might be returned as SUCCESS if the
1358 first answer is a SUCCESS. To fix this we add symmetry to
1359 TRYAGAIN with the second response. If the second response
1360 is a recoverable error we now return TRYAGIN even if the first
1361 response was SUCCESS. */
1362
1363 if (anslen1 > 0)
1364 status = gaih_getanswer_slice(answer1, anslen1, qname,
1365 &pat, &buffer, &buflen,
1366 errnop, h_errnop, ttlp,
1367 &first);
1368
1369 if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
1370 || (status == NSS_STATUS_TRYAGAIN
1371 /* We want to look at the second answer in case of an
1372 NSS_STATUS_TRYAGAIN only if the error is non-recoverable, i.e.
1373 *h_errnop is NO_RECOVERY. If not, and if the failure was due to
1374 an insufficient buffer (ERANGE), then we need to drop the results
1375 and pass on the NSS_STATUS_TRYAGAIN to the caller so that it can
1376 repeat the query with a larger buffer. */
1377 && (*errnop != ERANGE || *h_errnop == NO_RECOVERY)))
1378 && answer2 != NULL && anslen2 > 0)
1379 {
1380 enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname,
1381 &pat, &buffer, &buflen,
1382 errnop, h_errnop, ttlp,
1383 &first);
1384 /* Use the second response status in some cases. */
1385 if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
1386 status = status2;
1387 /* Do not return a truncated second response (unless it was
1388 unavoidable e.g. unrecoverable TRYAGAIN). */
1389 if (status == NSS_STATUS_SUCCESS
1390 && (status2 == NSS_STATUS_TRYAGAIN
1391 && *errnop == ERANGE && *h_errnop != NO_RECOVERY))
1392 status = NSS_STATUS_TRYAGAIN;
1393 }
1394
1395 return status;
1396}
1397