Back to index

glibc  2.9
dns-host.c
Go to the documentation of this file.
00001 /* Copyright (C) 1996-2004, 2007, 2008 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Extended from original form by Ulrich Drepper <drepper@cygnus.com>, 1996.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 /* Parts of this file are plain copies of the file `gethtnamadr.c' from
00021    the bind package and it has the following copyright.  */
00022 
00023 /*
00024  * ++Copyright++ 1985, 1988, 1993
00025  * -
00026  * Copyright (c) 1985, 1988, 1993
00027  *    The Regents of the University of California.  All rights reserved.
00028  *
00029  * Redistribution and use in source and binary forms, with or without
00030  * modification, are permitted provided that the following conditions
00031  * are met:
00032  * 1. Redistributions of source code must retain the above copyright
00033  *    notice, this list of conditions and the following disclaimer.
00034  * 2. Redistributions in binary form must reproduce the above copyright
00035  *    notice, this list of conditions and the following disclaimer in the
00036  *    documentation and/or other materials provided with the distribution.
00037  * 4. Neither the name of the University nor the names of its contributors
00038  *    may be used to endorse or promote products derived from this software
00039  *    without specific prior written permission.
00040  *
00041  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00042  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00043  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00044  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00045  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00046  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00047  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00048  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00049  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00050  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00051  * SUCH DAMAGE.
00052  * -
00053  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
00054  *
00055  * Permission to use, copy, modify, and distribute this software for any
00056  * purpose with or without fee is hereby granted, provided that the above
00057  * copyright notice and this permission notice appear in all copies, and that
00058  * the name of Digital Equipment Corporation not be used in advertising or
00059  * publicity pertaining to distribution of the document or software without
00060  * specific, written prior permission.
00061  *
00062  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
00063  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
00064  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
00065  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
00066  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
00067  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
00068  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00069  * SOFTWARE.
00070  * -
00071  * --Copyright--
00072  */
00073 
00074 #include <assert.h>
00075 #include <ctype.h>
00076 #include <errno.h>
00077 #include <netdb.h>
00078 #include <stdio.h>
00079 #include <stdlib.h>
00080 #include <stddef.h>
00081 #include <string.h>
00082 #include <sys/syslog.h>
00083 
00084 #include "nsswitch.h"
00085 
00086 /* Get implementation for some internal functions.  */
00087 #include <resolv/mapv4v6addr.h>
00088 #include <resolv/mapv4v6hostent.h>
00089 
00090 #define RESOLVSORT
00091 
00092 /* Maximum number of aliases we allow.  */
00093 #define MAX_NR_ALIASES      48
00094 #define MAX_NR_ADDRS 48
00095 
00096 #if PACKETSZ > 65536
00097 # define MAXPACKET   PACKETSZ
00098 #else
00099 # define MAXPACKET   65536
00100 #endif
00101 /* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length.  */
00102 #ifdef MAXHOSTNAMELEN
00103 # undef MAXHOSTNAMELEN
00104 #endif
00105 #define MAXHOSTNAMELEN 256
00106 
00107 static const char AskedForGot[] = "\
00108 gethostby*.getanswer: asked for \"%s\", got \"%s\"";
00109 
00110 
00111 /* We need this time later.  */
00112 typedef union querybuf
00113 {
00114   HEADER hdr;
00115   u_char buf[MAXPACKET];
00116 } querybuf;
00117 
00118 /* These functions are defined in res_comp.c.  */
00119 #define NS_MAXCDNAME 255    /* maximum compressed domain name */
00120 extern int __ns_name_ntop (const u_char *, char *, size_t);
00121 extern int __ns_name_unpack (const u_char *, const u_char *,
00122                           const u_char *, u_char *, size_t);
00123 
00124 
00125 static enum nss_status getanswer_r (const querybuf *answer, int anslen,
00126                                 const char *qname, int qtype,
00127                                 struct hostent *result, char *buffer,
00128                                 size_t buflen, int *errnop, int *h_errnop,
00129                                 int map, int32_t *ttlp, char **canonp);
00130 
00131 static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
00132                                    const querybuf *answer2, int anslen2,
00133                                    const char *qname,
00134                                    struct gaih_addrtuple **pat,
00135                                    char *buffer, size_t buflen,
00136                                    int *errnop, int *h_errnop,
00137                                    int32_t *ttlp);
00138 
00139 extern enum nss_status _nss_dns_gethostbyname3_r (const char *name, int af,
00140                                             struct hostent *result,
00141                                             char *buffer, size_t buflen,
00142                                             int *errnop, int *h_errnop,
00143                                             int32_t *ttlp,
00144                                             char **canonp);
00145 hidden_proto (_nss_dns_gethostbyname3_r)
00146 
00147 enum nss_status
00148 _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
00149                         char *buffer, size_t buflen, int *errnop,
00150                         int *h_errnop, int32_t *ttlp, char **canonp)
00151 {
00152   union
00153   {
00154     querybuf *buf;
00155     u_char *ptr;
00156   } host_buffer;
00157   querybuf *orig_host_buffer;
00158   char tmp[NS_MAXDNAME];
00159   int size, type, n;
00160   const char *cp;
00161   int map = 0;
00162   int olderr = errno;
00163   enum nss_status status;
00164 
00165   if (__res_maybe_init (&_res, 0) == -1)
00166     return NSS_STATUS_UNAVAIL;
00167 
00168   switch (af) {
00169   case AF_INET:
00170     size = INADDRSZ;
00171     type = T_A;
00172     break;
00173   case AF_INET6:
00174     size = IN6ADDRSZ;
00175     type = T_AAAA;
00176     break;
00177   default:
00178     *h_errnop = NO_DATA;
00179     *errnop = EAFNOSUPPORT;
00180     return NSS_STATUS_UNAVAIL;
00181   }
00182 
00183   result->h_addrtype = af;
00184   result->h_length = size;
00185 
00186   /*
00187    * if there aren't any dots, it could be a user-level alias.
00188    * this is also done in res_query() since we are not the only
00189    * function that looks up host names.
00190    */
00191   if (strchr (name, '.') == NULL
00192       && (cp = res_hostalias (&_res, name, tmp, sizeof (tmp))) != NULL)
00193     name = cp;
00194 
00195   host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
00196 
00197   n = __libc_res_nsearch (&_res, name, C_IN, type, host_buffer.buf->buf,
00198                        1024, &host_buffer.ptr, NULL, NULL, NULL);
00199   if (n < 0)
00200     {
00201       status = (errno == ECONNREFUSED
00202               ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND);
00203       *h_errnop = h_errno;
00204       if (h_errno == TRY_AGAIN)
00205        *errnop = EAGAIN;
00206       else
00207        __set_errno (olderr);
00208 
00209       /* If we are looking for a IPv6 address and mapping is enabled
00210         by having the RES_USE_INET6 bit in _res.options set, we try
00211         another lookup.  */
00212       if (af == AF_INET6 && (_res.options & RES_USE_INET6))
00213        n = __libc_res_nsearch (&_res, name, C_IN, T_A, host_buffer.buf->buf,
00214                             host_buffer.buf != orig_host_buffer
00215                             ? MAXPACKET : 1024, &host_buffer.ptr,
00216                             NULL, NULL, NULL);
00217 
00218       if (n < 0)
00219        {
00220          if (host_buffer.buf != orig_host_buffer)
00221            free (host_buffer.buf);
00222          return status;
00223        }
00224 
00225       map = 1;
00226 
00227       result->h_addrtype = AF_INET;
00228       result->h_length = INADDRSZ;
00229     }
00230 
00231   status = getanswer_r (host_buffer.buf, n, name, type, result, buffer, buflen,
00232                      errnop, h_errnop, map, ttlp, canonp);
00233   if (host_buffer.buf != orig_host_buffer)
00234     free (host_buffer.buf);
00235   return status;
00236 }
00237 hidden_def (_nss_dns_gethostbyname3_r)
00238 
00239 
00240 enum nss_status
00241 _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
00242                         char *buffer, size_t buflen, int *errnop,
00243                         int *h_errnop)
00244 {
00245   return _nss_dns_gethostbyname3_r (name, af, result, buffer, buflen, errnop,
00246                                 h_errnop, NULL, NULL);
00247 }
00248 
00249 
00250 enum nss_status
00251 _nss_dns_gethostbyname_r (const char *name, struct hostent *result,
00252                        char *buffer, size_t buflen, int *errnop,
00253                        int *h_errnop)
00254 {
00255   enum nss_status status = NSS_STATUS_NOTFOUND;
00256 
00257   if (_res.options & RES_USE_INET6)
00258     status = _nss_dns_gethostbyname3_r (name, AF_INET6, result, buffer,
00259                                    buflen, errnop, h_errnop, NULL, NULL);
00260   if (status == NSS_STATUS_NOTFOUND)
00261     status = _nss_dns_gethostbyname3_r (name, AF_INET, result, buffer,
00262                                    buflen, errnop, h_errnop, NULL, NULL);
00263 
00264   return status;
00265 }
00266 
00267 
00268 enum nss_status
00269 _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
00270                         char *buffer, size_t buflen, int *errnop,
00271                         int *herrnop, int32_t *ttlp)
00272 {
00273   if (__res_maybe_init (&_res, 0) == -1)
00274     return NSS_STATUS_UNAVAIL;
00275 
00276   /*
00277    * if there aren't any dots, it could be a user-level alias.
00278    * this is also done in res_query() since we are not the only
00279    * function that looks up host names.
00280    */
00281   if (strchr (name, '.') == NULL)
00282     {
00283       char *tmp = alloca (NS_MAXDNAME);
00284       const char *cp = res_hostalias (&_res, name, tmp, NS_MAXDNAME);
00285       if (cp != NULL)
00286        name = cp;
00287     }
00288 
00289   union
00290   {
00291     querybuf *buf;
00292     u_char *ptr;
00293   } host_buffer;
00294   querybuf *orig_host_buffer;
00295   host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
00296   u_char *ans2p = NULL;
00297   int nans2p = 0;
00298   int resplen2 = 0;
00299 
00300   int olderr = errno;
00301   enum nss_status status;
00302   int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC,
00303                            host_buffer.buf->buf, 2048, &host_buffer.ptr,
00304                            &ans2p, &nans2p, &resplen2);
00305   if (n < 0)
00306     {
00307       status = (errno == ECONNREFUSED
00308               ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND);
00309       *herrnop = h_errno;
00310       if (h_errno == TRY_AGAIN)
00311        *errnop = EAGAIN;
00312       else
00313        __set_errno (olderr);
00314 
00315       if (host_buffer.buf != orig_host_buffer)
00316        free (host_buffer.buf);
00317 
00318       return status;
00319     }
00320 
00321   status = gaih_getanswer(host_buffer.buf, n, (const querybuf *) ans2p,
00322                        resplen2, name, pat, buffer, buflen,
00323                        errnop, herrnop, ttlp);
00324 
00325   if (host_buffer.buf != orig_host_buffer)
00326     free (host_buffer.buf);
00327 
00328   return status;
00329 }
00330 
00331 
00332 extern enum nss_status _nss_dns_gethostbyaddr2_r (const void *addr,
00333                                             socklen_t len, int af,
00334                                             struct hostent *result,
00335                                             char *buffer, size_t buflen,
00336                                             int *errnop, int *h_errnop,
00337                                             int32_t *ttlp);
00338 hidden_proto (_nss_dns_gethostbyaddr2_r)
00339 
00340 enum nss_status
00341 _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
00342                         struct hostent *result, char *buffer, size_t buflen,
00343                         int *errnop, int *h_errnop, int32_t *ttlp)
00344 {
00345   static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
00346   static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
00347   static const u_char v6local[] = { 0,0, 0,1 };
00348   const u_char *uaddr = (const u_char *)addr;
00349   struct host_data
00350   {
00351     char *aliases[MAX_NR_ALIASES];
00352     unsigned char host_addr[16];   /* IPv4 or IPv6 */
00353     char *h_addr_ptrs[MAX_NR_ADDRS + 1];
00354     char linebuffer[0];
00355   } *host_data = (struct host_data *) buffer;
00356   union
00357   {
00358     querybuf *buf;
00359     u_char *ptr;
00360   } host_buffer;
00361   querybuf *orig_host_buffer;
00362   char qbuf[MAXDNAME+1], *qp = NULL;
00363   size_t size;
00364   int n, status;
00365   int olderr = errno;
00366 
00367   if (__res_maybe_init (&_res, 0) == -1)
00368     return NSS_STATUS_UNAVAIL;
00369 
00370   if (af == AF_INET6 && len == IN6ADDRSZ
00371       && (memcmp (uaddr, mapped, sizeof mapped) == 0
00372          || (memcmp (uaddr, tunnelled, sizeof tunnelled) == 0
00373              && memcmp (&uaddr[sizeof tunnelled], v6local, sizeof v6local))))
00374     {
00375       /* Unmap. */
00376       addr += sizeof mapped;
00377       uaddr += sizeof mapped;
00378       af = AF_INET;
00379       len = INADDRSZ;
00380     }
00381 
00382   switch (af)
00383     {
00384     case AF_INET:
00385       size = INADDRSZ;
00386       break;
00387     case AF_INET6:
00388       size = IN6ADDRSZ;
00389       break;
00390     default:
00391       *errnop = EAFNOSUPPORT;
00392       *h_errnop = NETDB_INTERNAL;
00393       return NSS_STATUS_UNAVAIL;
00394     }
00395   if (size > len)
00396     {
00397       *errnop = EAFNOSUPPORT;
00398       *h_errnop = NETDB_INTERNAL;
00399       return NSS_STATUS_UNAVAIL;
00400     }
00401 
00402   host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
00403 
00404   switch (af)
00405     {
00406     case AF_INET:
00407       sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", (uaddr[3] & 0xff),
00408               (uaddr[2] & 0xff), (uaddr[1] & 0xff), (uaddr[0] & 0xff));
00409       break;
00410     case AF_INET6:
00411       /* Only lookup with the byte string format if the user wants it.  */
00412       if (__builtin_expect (_res.options & RES_USEBSTRING, 0))
00413        {
00414          qp = stpcpy (qbuf, "\\[x");
00415          for (n = 0; n < IN6ADDRSZ; ++n)
00416            qp += sprintf (qp, "%02hhx", uaddr[n]);
00417          strcpy (qp, "].ip6.arpa");
00418          n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR,
00419                              host_buffer.buf->buf, 1024, &host_buffer.ptr,
00420                              NULL, NULL, NULL);
00421          if (n >= 0)
00422            goto got_it_already;
00423        }
00424       qp = qbuf;
00425       for (n = IN6ADDRSZ - 1; n >= 0; n--)
00426        {
00427          static const char nibblechar[16] = "0123456789abcdef";
00428          *qp++ = nibblechar[uaddr[n] & 0xf];
00429          *qp++ = '.';
00430          *qp++ = nibblechar[(uaddr[n] >> 4) & 0xf];
00431          *qp++ = '.';
00432        }
00433       strcpy(qp, "ip6.arpa");
00434       break;
00435     default:
00436       /* Cannot happen.  */
00437       break;
00438     }
00439 
00440   n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
00441                       1024, &host_buffer.ptr, NULL, NULL, NULL);
00442   if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0)
00443     {
00444       strcpy (qp, "ip6.int");
00445       n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
00446                           host_buffer.buf != orig_host_buffer
00447                           ? MAXPACKET : 1024, &host_buffer.ptr,
00448                           NULL, NULL, NULL);
00449     }
00450   if (n < 0)
00451     {
00452       *h_errnop = h_errno;
00453       __set_errno (olderr);
00454       if (host_buffer.buf != orig_host_buffer)
00455        free (host_buffer.buf);
00456       return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
00457     }
00458 
00459  got_it_already:
00460   status = getanswer_r (host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen,
00461                      errnop, h_errnop, 0 /* XXX */, ttlp, NULL);
00462   if (host_buffer.buf != orig_host_buffer)
00463     free (host_buffer.buf);
00464   if (status != NSS_STATUS_SUCCESS)
00465     return status;
00466 
00467 #ifdef SUNSECURITY
00468   This is not implemented because it is not possible to use the current
00469   source from bind in a multi-threaded program.
00470 #endif
00471 
00472   result->h_addrtype = af;
00473   result->h_length = len;
00474   memcpy (host_data->host_addr, addr, len);
00475   host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
00476   host_data->h_addr_ptrs[1] = NULL;
00477 #if 0
00478   /* XXX I think this is wrong.  Why should an IPv4 address be
00479      converted to IPv6 if the user explicitly asked for IPv4?  */
00480   if (af == AF_INET && (_res.options & RES_USE_INET6))
00481     {
00482       map_v4v6_address ((char *) host_data->host_addr,
00483                      (char *) host_data->host_addr);
00484       result->h_addrtype = AF_INET6;
00485       result->h_length = IN6ADDRSZ;
00486     }
00487 #endif
00488   *h_errnop = NETDB_SUCCESS;
00489   return NSS_STATUS_SUCCESS;
00490 }
00491 hidden_def (_nss_dns_gethostbyaddr2_r)
00492 
00493 
00494 enum nss_status
00495 _nss_dns_gethostbyaddr_r (const void *addr, socklen_t len, int af,
00496                        struct hostent *result, char *buffer, size_t buflen,
00497                        int *errnop, int *h_errnop)
00498 {
00499   return _nss_dns_gethostbyaddr2_r (addr, len, af, result, buffer, buflen,
00500                                 errnop, h_errnop, NULL);
00501 }
00502 
00503 #ifdef RESOLVSORT
00504 static void addrsort (char **ap, int num);
00505 
00506 static void
00507 addrsort (char **ap, int num)
00508 {
00509   int i, j;
00510   char **p;
00511   short aval[MAX_NR_ADDRS];
00512   int needsort = 0;
00513 
00514   p = ap;
00515   if (num > MAX_NR_ADDRS)
00516     num = MAX_NR_ADDRS;
00517   for (i = 0; i < num; i++, p++)
00518     {
00519       for (j = 0 ; (unsigned)j < _res.nsort; j++)
00520        if (_res.sort_list[j].addr.s_addr ==
00521            (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
00522          break;
00523       aval[i] = j;
00524       if (needsort == 0 && i > 0 && j < aval[i-1])
00525        needsort = i;
00526     }
00527   if (!needsort)
00528     return;
00529 
00530   while (needsort++ < num)
00531     for (j = needsort - 2; j >= 0; j--)
00532       if (aval[j] > aval[j+1])
00533        {
00534          char *hp;
00535 
00536          i = aval[j];
00537          aval[j] = aval[j+1];
00538          aval[j+1] = i;
00539 
00540          hp = ap[j];
00541          ap[j] = ap[j+1];
00542          ap[j+1] = hp;
00543        }
00544       else
00545        break;
00546 }
00547 #endif
00548 
00549 static enum nss_status
00550 getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
00551             struct hostent *result, char *buffer, size_t buflen,
00552             int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp)
00553 {
00554   struct host_data
00555   {
00556     char *aliases[MAX_NR_ALIASES];
00557     unsigned char host_addr[16];   /* IPv4 or IPv6 */
00558     char *h_addr_ptrs[0];
00559   } *host_data;
00560   int linebuflen;
00561   register const HEADER *hp;
00562   const u_char *end_of_message, *cp;
00563   int n, ancount, qdcount;
00564   int haveanswer, had_error;
00565   char *bp, **ap, **hap;
00566   char tbuf[MAXDNAME];
00567   const char *tname;
00568   int (*name_ok) (const char *);
00569   u_char packtmp[NS_MAXCDNAME];
00570   int have_to_map = 0;
00571   int32_t ttl = 0;
00572   uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
00573   buffer += pad;
00574   if (__builtin_expect (buflen < sizeof (struct host_data) + pad, 0))
00575     {
00576       /* The buffer is too small.  */
00577     too_small:
00578       *errnop = ERANGE;
00579       *h_errnop = NETDB_INTERNAL;
00580       return NSS_STATUS_TRYAGAIN;
00581     }
00582   host_data = (struct host_data *) buffer;
00583   linebuflen = buflen - sizeof (struct host_data);
00584   if (buflen - sizeof (struct host_data) != linebuflen)
00585     linebuflen = INT_MAX;
00586 
00587   tname = qname;
00588   result->h_name = NULL;
00589   end_of_message = answer->buf + anslen;
00590   switch (qtype)
00591     {
00592     case T_A:
00593     case T_AAAA:
00594       name_ok = res_hnok;
00595       break;
00596     case T_PTR:
00597       name_ok = res_dnok;
00598       break;
00599     default:
00600       *errnop = ENOENT;
00601       return NSS_STATUS_UNAVAIL;  /* XXX should be abort(); */
00602     }
00603 
00604   /*
00605    * find first satisfactory answer
00606    */
00607   hp = &answer->hdr;
00608   ancount = ntohs (hp->ancount);
00609   qdcount = ntohs (hp->qdcount);
00610   cp = answer->buf + HFIXEDSZ;
00611   if (__builtin_expect (qdcount, 1) != 1)
00612     {
00613       *h_errnop = NO_RECOVERY;
00614       return NSS_STATUS_UNAVAIL;
00615     }
00616   if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen)
00617     goto too_small;
00618   bp = (char *) &host_data->h_addr_ptrs[ancount + 1];
00619   linebuflen -= (ancount + 1) * sizeof (char *);
00620 
00621   n = __ns_name_unpack (answer->buf, end_of_message, cp,
00622                      packtmp, sizeof packtmp);
00623   if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
00624     {
00625       if (__builtin_expect (errno, 0) == EMSGSIZE)
00626        goto too_small;
00627 
00628       n = -1;
00629     }
00630 
00631   if (n > 0 && bp[0] == '.')
00632     bp[0] = '\0';
00633 
00634   if (__builtin_expect (n < 0 || ((*name_ok) (bp) == 0 && (errno = EBADMSG)),
00635                      0))
00636     {
00637       *errnop = errno;
00638       *h_errnop = NO_RECOVERY;
00639       return NSS_STATUS_UNAVAIL;
00640     }
00641   cp += n + QFIXEDSZ;
00642 
00643   if (qtype == T_A || qtype == T_AAAA)
00644     {
00645       /* res_send() has already verified that the query name is the
00646        * same as the one we sent; this just gets the expanded name
00647        * (i.e., with the succeeding search-domain tacked on).
00648        */
00649       n = strlen (bp) + 1;             /* for the \0 */
00650       if (n >= MAXHOSTNAMELEN)
00651        {
00652          *h_errnop = NO_RECOVERY;
00653          *errnop = ENOENT;
00654          return NSS_STATUS_TRYAGAIN;
00655        }
00656       result->h_name = bp;
00657       bp += n;
00658       linebuflen -= n;
00659       if (linebuflen < 0)
00660        goto too_small;
00661       /* The qname can be abbreviated, but h_name is now absolute. */
00662       qname = result->h_name;
00663     }
00664 
00665   ap = host_data->aliases;
00666   *ap = NULL;
00667   result->h_aliases = host_data->aliases;
00668   hap = host_data->h_addr_ptrs;
00669   *hap = NULL;
00670   result->h_addr_list = host_data->h_addr_ptrs;
00671   haveanswer = 0;
00672   had_error = 0;
00673 
00674   while (ancount-- > 0 && cp < end_of_message && had_error == 0)
00675     {
00676       int type, class;
00677 
00678       n = __ns_name_unpack (answer->buf, end_of_message, cp,
00679                          packtmp, sizeof packtmp);
00680       if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
00681        {
00682          if (__builtin_expect (errno, 0) == EMSGSIZE)
00683            goto too_small;
00684 
00685          n = -1;
00686        }
00687 
00688       if (__builtin_expect (n < 0 || (*name_ok) (bp) == 0, 0))
00689        {
00690          ++had_error;
00691          continue;
00692        }
00693       cp += n;                            /* name */
00694 
00695       if (__builtin_expect (cp + 10 > end_of_message, 0))
00696        {
00697          ++had_error;
00698          continue;
00699        }
00700 
00701       type = __ns_get16 (cp);
00702       cp += INT16SZ;               /* type */
00703       class = __ns_get16 (cp);
00704       cp += INT16SZ;               /* class */
00705       ttl = __ns_get32 (cp);
00706       cp += INT32SZ;               /* TTL */
00707       n = __ns_get16 (cp);
00708       cp += INT16SZ;               /* len */
00709       if (__builtin_expect (class != C_IN, 0))
00710        {
00711          /* XXX - debug? syslog? */
00712          cp += n;
00713          continue;                 /* XXX - had_error++ ? */
00714        }
00715 
00716       if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME)
00717        {
00718          if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
00719            continue;
00720          n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
00721          if (__builtin_expect (n < 0 || (*name_ok) (tbuf) == 0, 0))
00722            {
00723              ++had_error;
00724              continue;
00725            }
00726          cp += n;
00727          /* Store alias.  */
00728          *ap++ = bp;
00729          n = strlen (bp) + 1;             /* For the \0.  */
00730          if (__builtin_expect (n, 0) >= MAXHOSTNAMELEN)
00731            {
00732              ++had_error;
00733              continue;
00734            }
00735          bp += n;
00736          linebuflen -= n;
00737          /* Get canonical name.  */
00738          n = strlen (tbuf) + 1;    /* For the \0.  */
00739          if (__builtin_expect (n > linebuflen, 0))
00740            goto too_small;
00741          if (__builtin_expect (n, 0) >= MAXHOSTNAMELEN)
00742            {
00743              ++had_error;
00744              continue;
00745            }
00746          result->h_name = bp;
00747          bp = __mempcpy (bp, tbuf, n);    /* Cannot overflow.  */
00748          linebuflen -= n;
00749          continue;
00750        }
00751 
00752       if (qtype == T_PTR && type == T_CNAME)
00753        {
00754          n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
00755          if (__builtin_expect (n < 0 || res_dnok (tbuf) == 0, 0))
00756            {
00757              ++had_error;
00758              continue;
00759            }
00760          cp += n;
00761          /* Get canonical name.  */
00762          n = strlen (tbuf) + 1;   /* For the \0.  */
00763          if (__builtin_expect (n > linebuflen, 0))
00764            goto too_small;
00765          if (__builtin_expect (n, 0) >= MAXHOSTNAMELEN)
00766            {
00767              ++had_error;
00768              continue;
00769            }
00770          tname = bp;
00771          bp = __mempcpy (bp, tbuf, n);    /* Cannot overflow.  */
00772          linebuflen -= n;
00773          continue;
00774        }
00775       if (__builtin_expect (type == T_SIG, 0)
00776          || __builtin_expect (type == T_KEY, 0)
00777          || __builtin_expect (type == T_NXT, 0))
00778        {
00779          /* We don't support DNSSEC yet.  For now, ignore the record
00780             and send a low priority message to syslog.  */
00781          syslog (LOG_DEBUG | LOG_AUTH,
00782               "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
00783                 qname, p_class (C_IN), p_type(qtype), p_type (type));
00784          cp += n;
00785          continue;
00786        }
00787 
00788       if (type == T_A && qtype == T_AAAA && map)
00789        have_to_map = 1;
00790       else if (__builtin_expect (type != qtype, 0))
00791        {
00792          syslog (LOG_NOTICE | LOG_AUTH,
00793               "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
00794                 qname, p_class (C_IN), p_type (qtype), p_type (type));
00795          cp += n;
00796          continue;                 /* XXX - had_error++ ? */
00797        }
00798 
00799       switch (type)
00800        {
00801        case T_PTR:
00802          if (__builtin_expect (__strcasecmp (tname, bp) != 0, 0))
00803            {
00804              syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, qname, bp);
00805              cp += n;
00806              continue;                    /* XXX - had_error++ ? */
00807            }
00808 
00809          n = __ns_name_unpack (answer->buf, end_of_message, cp,
00810                             packtmp, sizeof packtmp);
00811          if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
00812            {
00813              if (__builtin_expect (errno, 0) == EMSGSIZE)
00814               goto too_small;
00815 
00816              n = -1;
00817            }
00818 
00819          if (__builtin_expect (n < 0 || res_hnok (bp) == 0, 0))
00820            {
00821              ++had_error;
00822              break;
00823            }
00824 #if MULTI_PTRS_ARE_ALIASES
00825          cp += n;
00826          if (haveanswer == 0)
00827            result->h_name = bp;
00828          else if (ap < &host_data->aliases[MAXALIASES-1])
00829            *ap++ = bp;
00830          else
00831            n = -1;
00832          if (n != -1)
00833            {
00834              n = strlen (bp) + 1;  /* for the \0 */
00835              if (__builtin_expect (n, 0) >= MAXHOSTNAMELEN)
00836               {
00837                 ++had_error;
00838                 break;
00839               }
00840              bp += n;
00841              linebuflen -= n;
00842            }
00843          break;
00844 #else
00845          result->h_name = bp;
00846          if (have_to_map)
00847            {
00848              n = strlen (bp) + 1;  /* for the \0 */
00849              if (__builtin_expect (n >= MAXHOSTNAMELEN, 0))
00850               {
00851                 ++had_error;
00852                 break;
00853               }
00854              bp += n;
00855              linebuflen -= n;
00856              map_v4v6_hostent (result, &bp, &linebuflen);
00857            }
00858          *h_errnop = NETDB_SUCCESS;
00859          return NSS_STATUS_SUCCESS;
00860 #endif
00861        case T_A:
00862        case T_AAAA:
00863          if (__builtin_expect (strcasecmp (result->h_name, bp), 0) != 0)
00864            {
00865              syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, result->h_name, bp);
00866              cp += n;
00867              continue;                    /* XXX - had_error++ ? */
00868            }
00869          if (n != result->h_length)
00870            {
00871              cp += n;
00872              continue;
00873            }
00874          if (!haveanswer)
00875            {
00876              register int nn;
00877 
00878              if (ttlp != NULL && ttl != 0)
00879               *ttlp = ttl;
00880              if (canonp != NULL)
00881               *canonp = bp;
00882              result->h_name = bp;
00883              nn = strlen (bp) + 1; /* for the \0 */
00884              bp += nn;
00885              linebuflen -= nn;
00886            }
00887 
00888          linebuflen -= sizeof (align) - ((u_long) bp % sizeof (align));
00889          bp += sizeof (align) - ((u_long) bp % sizeof (align));
00890 
00891          if (__builtin_expect (n > linebuflen, 0))
00892            goto too_small;
00893          bp = __mempcpy (*hap++ = bp, cp, n);
00894          cp += n;
00895          linebuflen -= n;
00896          break;
00897        default:
00898          abort ();
00899        }
00900       if (had_error == 0)
00901        ++haveanswer;
00902     }
00903 
00904   if (haveanswer > 0)
00905     {
00906       *ap = NULL;
00907       *hap = NULL;
00908 #if defined RESOLVSORT
00909       /*
00910        * Note: we sort even if host can take only one address
00911        * in its return structures - should give it the "best"
00912        * address in that case, not some random one
00913        */
00914       if (_res.nsort && haveanswer > 1 && qtype == T_A)
00915        addrsort (host_data->h_addr_ptrs, haveanswer);
00916 #endif /*RESOLVSORT*/
00917 
00918       if (result->h_name == NULL)
00919        {
00920          n = strlen (qname) + 1;   /* For the \0.  */
00921          if (n > linebuflen)
00922            goto too_small;
00923          if (n >= MAXHOSTNAMELEN)
00924            goto no_recovery;
00925          result->h_name = bp;
00926          bp = __mempcpy (bp, qname, n);   /* Cannot overflow.  */
00927          linebuflen -= n;
00928        }
00929 
00930       if (have_to_map)
00931        map_v4v6_hostent (result, &bp, &linebuflen);
00932       *h_errnop = NETDB_SUCCESS;
00933       return NSS_STATUS_SUCCESS;
00934     }
00935  no_recovery:
00936   *h_errnop = NO_RECOVERY;
00937   *errnop = ENOENT;
00938   /* Special case here: if the resolver sent a result but it only
00939      contains a CNAME while we are looking for a T_A or T_AAAA record,
00940      we fail with NOTFOUND instead of TRYAGAIN.  */
00941   return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases
00942           ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN);
00943 }
00944 
00945 
00946 static enum nss_status
00947 gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
00948                     struct gaih_addrtuple ***patp,
00949                     char **bufferp, size_t *buflenp,
00950                     int *errnop, int *h_errnop, int32_t *ttlp, int *firstp)
00951 {
00952   char *buffer = *bufferp;
00953   size_t buflen = *buflenp;
00954 
00955   struct gaih_addrtuple **pat = *patp;
00956   const HEADER *hp = &answer->hdr;
00957   int ancount = ntohs (hp->ancount);
00958   int qdcount = ntohs (hp->qdcount);
00959   const u_char *cp = answer->buf + HFIXEDSZ;
00960   const u_char *end_of_message = answer->buf + anslen;
00961   if (__builtin_expect (qdcount != 1, 0))
00962     {
00963       *h_errnop = NO_RECOVERY;
00964       return NSS_STATUS_UNAVAIL;
00965     }
00966 
00967   u_char packtmp[NS_MAXCDNAME];
00968   int n = __ns_name_unpack (answer->buf, end_of_message, cp,
00969                          packtmp, sizeof packtmp);
00970   /* We unpack the name to check it for validity.  But we do not need
00971      it later.  */
00972   if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1)
00973     {
00974       if (__builtin_expect (errno, 0) == EMSGSIZE)
00975        {
00976        too_small:
00977          *errnop = ERANGE;
00978          *h_errnop = NETDB_INTERNAL;
00979          return NSS_STATUS_TRYAGAIN;
00980        }
00981 
00982       n = -1;
00983     }
00984 
00985   if (__builtin_expect (n < 0 || (res_hnok (buffer) == 0
00986                               && (errno = EBADMSG)), 0))
00987     {
00988       *errnop = errno;
00989       *h_errnop = NO_RECOVERY;
00990       return NSS_STATUS_UNAVAIL;
00991     }
00992   cp += n + QFIXEDSZ;
00993 
00994   int haveanswer = 0;
00995   int had_error = 0;
00996   char *canon = NULL;
00997   char *h_name = NULL;
00998   int h_namelen = 0;
00999 
01000   if (ancount == 0)
01001     return NSS_STATUS_NOTFOUND;
01002 
01003   while (ancount-- > 0 && cp < end_of_message && had_error == 0)
01004     {
01005       n = __ns_name_unpack (answer->buf, end_of_message, cp,
01006                          packtmp, sizeof packtmp);
01007       if (n != -1 &&
01008          (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
01009        {
01010          if (__builtin_expect (errno, 0) == EMSGSIZE)
01011            goto too_small;
01012 
01013          n = -1;
01014        }
01015       if (__builtin_expect (n < 0 || res_hnok (buffer) == 0, 0))
01016        {
01017          ++had_error;
01018          continue;
01019        }
01020       if (*firstp)
01021        {
01022          h_name = buffer;
01023          buffer += h_namelen;
01024          buflen -= h_namelen;
01025        }
01026 
01027       cp += n;                            /* name */
01028 
01029       if (__builtin_expect (cp + 10 > end_of_message, 0))
01030        {
01031          ++had_error;
01032          continue;
01033        }
01034 
01035       int type = __ns_get16 (cp);
01036       cp += INT16SZ;               /* type */
01037       int class = __ns_get16 (cp);
01038       cp += INT16SZ;               /* class */
01039       int32_t ttl = __ns_get32 (cp);
01040       cp += INT32SZ;               /* TTL */
01041       n = __ns_get16 (cp);
01042       cp += INT16SZ;               /* len */
01043 
01044       if (class != C_IN)
01045        {
01046          cp += n;
01047          continue;
01048        }
01049 
01050       if (type == T_CNAME)
01051        {
01052          char tbuf[MAXDNAME];
01053          n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
01054          if (__builtin_expect (n < 0 || res_hnok (tbuf) == 0, 0))
01055            {
01056              ++had_error;
01057              continue;
01058            }
01059          cp += n;
01060 
01061          if (*firstp)
01062            {
01063              /* Reclaim buffer space.  */
01064              if (h_name + h_namelen == buffer)
01065               {
01066                 buffer = h_name;
01067                 buflen += h_namelen;
01068               }
01069 
01070              n = strlen (tbuf) + 1;
01071              if (__builtin_expect (n > buflen, 0))
01072               goto too_small;
01073              if (__builtin_expect (n >= MAXHOSTNAMELEN, 0))
01074               {
01075                 ++had_error;
01076                 continue;
01077               }
01078 
01079              canon = buffer;
01080              buffer = __mempcpy (buffer, tbuf, n);
01081              buflen -= n;
01082              h_namelen = 0;
01083            }
01084          continue;
01085        }
01086 #if 1
01087       // We should not see any types other than those explicitly listed
01088       // below.  Some types sent by server seem missing, though.  Just
01089       // collect the data for now.
01090       if (__builtin_expect (type != T_A && type != T_AAAA, 0))
01091 #else
01092       if (__builtin_expect (type == T_SIG, 0)
01093          || __builtin_expect (type == T_KEY, 0)
01094          || __builtin_expect (type == T_NXT, 0)
01095          || __builtin_expect (type == T_PTR, 0)
01096          || __builtin_expect (type == T_DNAME, 0))
01097 #endif
01098        {
01099          /* We don't support DNSSEC yet.  For now, ignore the record
01100             and send a low priority message to syslog.
01101 
01102             We also don't expect T_PTR or T_DNAME messages.  */
01103          syslog (LOG_DEBUG | LOG_AUTH,
01104                 "getaddrinfo*.gaih_getanswer: got type \"%s\"",
01105                 p_type (type));
01106          cp += n;
01107          continue;
01108        }
01109       if (type != T_A && type != T_AAAA)
01110        abort ();
01111 
01112       if (*pat == NULL)
01113        {
01114          uintptr_t pad = (-(uintptr_t) buffer
01115                         % __alignof__ (struct gaih_addrtuple));
01116          buffer += pad;
01117          buflen = buflen > pad ? buflen - pad : 0;
01118 
01119          if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple),
01120                             0))
01121            goto too_small;
01122 
01123          *pat = (struct gaih_addrtuple *) buffer;
01124          buffer += sizeof (struct gaih_addrtuple);
01125          buflen -= sizeof (struct gaih_addrtuple);
01126        }
01127 
01128       (*pat)->name = NULL;
01129       (*pat)->next = NULL;
01130 
01131       if (*firstp)
01132        {
01133          if (ttl != 0 && ttlp != NULL)
01134            *ttlp = ttl;
01135 
01136          if (canon != NULL)
01137            {
01138              (*pat)->name = canon;
01139 
01140              /* Reclaim buffer space.  */
01141              if (h_name + h_namelen == buffer)
01142               {
01143                 buffer = h_name;
01144                 buflen += h_namelen;
01145               }
01146            }
01147          else
01148            (*pat)->name = h_name;
01149 
01150          *firstp = 0;
01151        }
01152 
01153       (*pat)->family = type == T_A ? AF_INET : AF_INET6;
01154       if (__builtin_expect ((type == T_A && n != INADDRSZ)
01155                          || (type == T_AAAA && n != IN6ADDRSZ), 0))
01156        {
01157          ++had_error;
01158          continue;
01159        }
01160       memcpy ((*pat)->addr, cp, n);
01161       cp += n;
01162       (*pat)->scopeid = 0;
01163 
01164       pat = &((*pat)->next);
01165 
01166       haveanswer = 1;
01167     }
01168 
01169   if (haveanswer)
01170     {
01171       *patp = pat;
01172       *bufferp = buffer;
01173       *buflenp = buflen;
01174 
01175       *h_errnop = NETDB_SUCCESS;
01176       return NSS_STATUS_SUCCESS;
01177     }
01178 
01179   /* Special case here: if the resolver sent a result but it only
01180      contains a CNAME while we are looking for a T_A or T_AAAA record,
01181      we fail with NOTFOUND instead of TRYAGAIN.  */
01182   return canon == NULL ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
01183 }
01184 
01185 
01186 static enum nss_status
01187 gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
01188               int anslen2, const char *qname,
01189               struct gaih_addrtuple **pat, char *buffer, size_t buflen,
01190               int *errnop, int *h_errnop, int32_t *ttlp)
01191 {
01192   int first = 1;
01193 
01194   enum nss_status status = NSS_STATUS_NOTFOUND;
01195 
01196   if (anslen1 > 0)
01197     status = gaih_getanswer_slice(answer1, anslen1, qname,
01198                               &pat, &buffer, &buflen,
01199                               errnop, h_errnop, ttlp,
01200                               &first);
01201   if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
01202        || (status == NSS_STATUS_TRYAGAIN
01203           && (errno != ERANGE || *h_errnop != NO_RECOVERY)))
01204       && answer2 != NULL && anslen2 > 0)
01205     {
01206       enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname,
01207                                                &pat, &buffer, &buflen,
01208                                                errnop, h_errnop, ttlp,
01209                                                &first);
01210       if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
01211        status = status2;
01212     }
01213 
01214   return status;
01215 }