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