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