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