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