Back to index

glibc  2.9
nis-hosts.c
Go to the documentation of this file.
00001 /* Copyright (C) 1996-2000, 2002, 2003, 2006, 2007, 2008
00002    Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <assert.h>
00022 #include <nss.h>
00023 #include <ctype.h>
00024 /* The following is an ugly trick to avoid a prototype declaration for
00025    _nss_nis_endgrent.  */
00026 #define _nss_nis_endhostent _nss_nis_endhostent_XXX
00027 #include <netdb.h>
00028 #undef _nss_nis_endhostent
00029 #include <string.h>
00030 #include <netinet/in.h>
00031 #include <arpa/inet.h>
00032 #include <resolv.h>
00033 #include <bits/libc-lock.h>
00034 #include <rpcsvc/yp.h>
00035 #include <rpcsvc/ypclnt.h>
00036 
00037 #include "nss-nis.h"
00038 
00039 /* Get implementation for some internal functions. */
00040 #include <resolv/mapv4v6addr.h>
00041 
00042 #define ENTNAME         hostent
00043 #define DATABASE        "hosts"
00044 #define NEED_H_ERRNO
00045 
00046 #define EXTRA_ARGS      , af, flags
00047 #define EXTRA_ARGS_DECL , int af, int flags
00048 
00049 #define ENTDATA hostent_data
00050 struct hostent_data
00051   {
00052     unsigned char host_addr[16];   /* IPv4 or IPv6 address.  */
00053     char *h_addr_ptrs[2];   /* Points to that and null terminator.  */
00054   };
00055 
00056 #define TRAILING_LIST_MEMBER            h_aliases
00057 #define TRAILING_LIST_SEPARATOR_P       isspace
00058 #include <nss/nss_files/files-parse.c>
00059 LINE_PARSER
00060 ("#",
00061  {
00062    char *addr;
00063 
00064    STRING_FIELD (addr, isspace, 1);
00065 
00066    assert (af == AF_INET || af == AF_INET6 || af == AF_UNSPEC);
00067 
00068    /* Parse address.  */
00069    if (af != AF_INET6 && inet_pton (AF_INET, addr, entdata->host_addr) > 0)
00070      {
00071        assert ((flags & AI_V4MAPPED) == 0 || af != AF_UNSPEC);
00072        if (flags & AI_V4MAPPED)
00073          {
00074            map_v4v6_address ((char *) entdata->host_addr,
00075                              (char *) entdata->host_addr);
00076            result->h_addrtype = AF_INET6;
00077            result->h_length = IN6ADDRSZ;
00078          }
00079        else
00080          {
00081            result->h_addrtype = AF_INET;
00082            result->h_length = INADDRSZ;
00083          }
00084      }
00085    else if (af != AF_INET
00086             && inet_pton (AF_INET6, addr, entdata->host_addr) > 0)
00087      {
00088        result->h_addrtype = AF_INET6;
00089        result->h_length = IN6ADDRSZ;
00090      }
00091    else
00092      /* Illegal address: ignore line.  */
00093      return 0;
00094 
00095    /* Store a pointer to the address in the expected form.  */
00096    entdata->h_addr_ptrs[0] = (char *) entdata->host_addr;
00097    entdata->h_addr_ptrs[1] = NULL;
00098    result->h_addr_list = entdata->h_addr_ptrs;
00099 
00100    STRING_FIELD (result->h_name, isspace, 1);
00101  })
00102 
00103 
00104 __libc_lock_define_initialized (static, lock)
00105 
00106 static bool_t new_start = 1;
00107 static char *oldkey = NULL;
00108 static int oldkeylen = 0;
00109 
00110 
00111 enum nss_status
00112 _nss_nis_sethostent (int stayopen)
00113 {
00114   __libc_lock_lock (lock);
00115 
00116   new_start = 1;
00117   if (oldkey != NULL)
00118     {
00119       free (oldkey);
00120       oldkey = NULL;
00121       oldkeylen = 0;
00122     }
00123 
00124   __libc_lock_unlock (lock);
00125 
00126   return NSS_STATUS_SUCCESS;
00127 }
00128 /* Make _nss_nis_endhostent an alias of _nss_nis_sethostent.  We do this
00129    even though the prototypes don't match.  The argument of sethostent
00130    is used so this makes no difference.  */
00131 strong_alias (_nss_nis_sethostent, _nss_nis_endhostent)
00132 
00133 
00134 /* The calling function always need to get a lock first. */
00135 static enum nss_status
00136 internal_nis_gethostent_r (struct hostent *host, char *buffer,
00137                         size_t buflen, int *errnop, int *h_errnop,
00138                         int af, int flags)
00139 {
00140   char *domain;
00141   if (__builtin_expect (yp_get_default_domain (&domain), 0))
00142     return NSS_STATUS_UNAVAIL;
00143 
00144   uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data);
00145   buffer += pad;
00146 
00147   struct parser_data *data = (void *) buffer;
00148   if (__builtin_expect (buflen < sizeof *data + 1 + pad, 0))
00149     {
00150       *errnop = ERANGE;
00151       *h_errnop = NETDB_INTERNAL;
00152       return NSS_STATUS_TRYAGAIN;
00153     }
00154   buflen -= pad;
00155 
00156   /* Get the next entry until we found a correct one. */
00157   const size_t linebuflen = buffer + buflen - data->linebuffer;
00158   int parse_res;
00159   do
00160     {
00161       char *result;
00162       int len;
00163       char *outkey;
00164       int keylen;
00165       int yperr;
00166       if (new_start)
00167         yperr = yp_first (domain, "hosts.byname", &outkey, &keylen, &result,
00168                        &len);
00169       else
00170         yperr = yp_next (domain, "hosts.byname", oldkey, oldkeylen, &outkey,
00171                       &keylen, &result, &len);
00172 
00173       if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
00174         {
00175          enum nss_status retval = yperr2nss (yperr);
00176 
00177          switch (retval)
00178            {
00179            case NSS_STATUS_TRYAGAIN:
00180              *errnop = errno;
00181              *h_errnop = TRY_AGAIN;
00182              break;
00183            case NSS_STATUS_NOTFOUND:
00184              *h_errnop = HOST_NOT_FOUND;
00185              break;
00186            default:
00187              *h_errnop = NO_RECOVERY;
00188              break;
00189            }
00190          return retval;
00191        }
00192 
00193       if (__builtin_expect ((size_t) (len + 1) > linebuflen, 0))
00194         {
00195           free (result);
00196          *h_errnop = NETDB_INTERNAL;
00197           *errnop = ERANGE;
00198           return NSS_STATUS_TRYAGAIN;
00199         }
00200 
00201       char *p = strncpy (data->linebuffer, result, len);
00202       data->linebuffer[len] = '\0';
00203       while (isspace (*p))
00204        ++p;
00205       free (result);
00206 
00207       parse_res = parse_line (p, host, data, buflen, errnop, af, flags);
00208       if (__builtin_expect (parse_res == -1, 0))
00209        {
00210          free (outkey);
00211          *h_errnop = NETDB_INTERNAL;
00212          *errnop = ERANGE;
00213          return NSS_STATUS_TRYAGAIN;
00214        }
00215       free (oldkey);
00216       oldkey = outkey;
00217       oldkeylen = keylen;
00218       new_start = 0;
00219     }
00220   while (!parse_res);
00221 
00222   *h_errnop = NETDB_SUCCESS;
00223   return NSS_STATUS_SUCCESS;
00224 }
00225 
00226 
00227 enum nss_status
00228 _nss_nis_gethostent_r (struct hostent *host, char *buffer, size_t buflen,
00229                      int *errnop, int *h_errnop)
00230 {
00231   enum nss_status status;
00232 
00233   __libc_lock_lock (lock);
00234 
00235   status = internal_nis_gethostent_r (host, buffer, buflen, errnop, h_errnop,
00236                       ((_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET),
00237                      ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0 ));
00238 
00239   __libc_lock_unlock (lock);
00240 
00241   return status;
00242 }
00243 
00244 
00245 static enum nss_status
00246 internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
00247                         char *buffer, size_t buflen, int *errnop,
00248                         int *h_errnop, int flags)
00249 {
00250   uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data);
00251   buffer += pad;
00252 
00253   struct parser_data *data = (void *) buffer;
00254 
00255   if (name == NULL)
00256     {
00257       *errnop = EINVAL;
00258       return NSS_STATUS_UNAVAIL;
00259     }
00260 
00261   char *domain;
00262   if (yp_get_default_domain (&domain))
00263     return NSS_STATUS_UNAVAIL;
00264 
00265   if (buflen < sizeof *data + 1 + pad)
00266     {
00267       *h_errnop = NETDB_INTERNAL;
00268       *errnop = ERANGE;
00269       return NSS_STATUS_TRYAGAIN;
00270     }
00271   buflen -= pad;
00272 
00273   /* Convert name to lowercase.  */
00274   size_t namlen = strlen (name);
00275   char name2[namlen + 1];
00276   size_t i;
00277 
00278   for (i = 0; i < namlen; ++i)
00279     name2[i] = tolower (name[i]);
00280   name2[i] = '\0';
00281 
00282   char *result;
00283   int len;
00284   int yperr = yp_match (domain, "hosts.byname", name2, namlen, &result, &len);
00285 
00286   if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
00287     {
00288       enum nss_status retval = yperr2nss (yperr);
00289 
00290       if (retval == NSS_STATUS_TRYAGAIN)
00291        {
00292          *h_errnop = TRY_AGAIN;
00293          *errnop = errno;
00294        }
00295       if (retval == NSS_STATUS_NOTFOUND)
00296        *h_errnop = HOST_NOT_FOUND;
00297       return retval;
00298     }
00299 
00300   const size_t linebuflen = buffer + buflen - data->linebuffer;
00301   if (__builtin_expect ((size_t) (len + 1) > linebuflen, 0))
00302     {
00303       free (result);
00304       *h_errnop = NETDB_INTERNAL;
00305       *errnop = ERANGE;
00306       return NSS_STATUS_TRYAGAIN;
00307     }
00308 
00309   char *p = strncpy (data->linebuffer, result, len);
00310   data->linebuffer[len] = '\0';
00311   while (isspace (*p))
00312     ++p;
00313   free (result);
00314 
00315   int parse_res = parse_line (p, host, data, buflen, errnop, af, flags);
00316 
00317   if (__builtin_expect (parse_res < 1 || host->h_addrtype != af, 0))
00318     {
00319       if (parse_res == -1)
00320        {
00321          *h_errnop = NETDB_INTERNAL;
00322          return NSS_STATUS_TRYAGAIN;
00323        }
00324       else
00325        {
00326          *h_errnop = HOST_NOT_FOUND;
00327          return NSS_STATUS_NOTFOUND;
00328        }
00329     }
00330 
00331   *h_errnop = NETDB_SUCCESS;
00332   return NSS_STATUS_SUCCESS;
00333 }
00334 
00335 
00336 enum nss_status
00337 _nss_nis_gethostbyname2_r (const char *name, int af, struct hostent *host,
00338                         char *buffer, size_t buflen, int *errnop,
00339                         int *h_errnop)
00340 {
00341   if (af != AF_INET && af != AF_INET6)
00342     {
00343       *h_errnop = HOST_NOT_FOUND;
00344       return NSS_STATUS_NOTFOUND;
00345     }
00346 
00347   return internal_gethostbyname2_r (name, af, host, buffer, buflen, errnop,
00348                                 h_errnop,
00349                       ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0));
00350 }
00351 
00352 
00353 enum nss_status
00354 _nss_nis_gethostbyname_r (const char *name, struct hostent *host, char *buffer,
00355                        size_t buflen, int *errnop, int *h_errnop)
00356 {
00357   if (_res.options & RES_USE_INET6)
00358     {
00359       enum nss_status status;
00360 
00361       status = internal_gethostbyname2_r (name, AF_INET6, host, buffer, buflen,
00362                                      errnop, h_errnop, AI_V4MAPPED);
00363       if (status == NSS_STATUS_SUCCESS)
00364        return status;
00365     }
00366 
00367   return internal_gethostbyname2_r (name, AF_INET, host, buffer, buflen,
00368                                 errnop, h_errnop, 0);
00369 }
00370 
00371 
00372 enum nss_status
00373 _nss_nis_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af,
00374                        struct hostent *host, char *buffer, size_t buflen,
00375                        int *errnop, int *h_errnop)
00376 {
00377   char *domain;
00378   if (__builtin_expect (yp_get_default_domain (&domain), 0))
00379     return NSS_STATUS_UNAVAIL;
00380 
00381   uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data);
00382   buffer += pad;
00383 
00384   struct parser_data *data = (void *) buffer;
00385   if (__builtin_expect (buflen < sizeof *data + 1 + pad, 0))
00386     {
00387       *errnop = ERANGE;
00388       *h_errnop = NETDB_INTERNAL;
00389       return NSS_STATUS_TRYAGAIN;
00390     }
00391   buflen -= pad;
00392 
00393   char *buf = inet_ntoa (*(const struct in_addr *) addr);
00394 
00395   char *result;
00396   int len;
00397   int yperr = yp_match (domain, "hosts.byaddr", buf, strlen (buf), &result,
00398                      &len);
00399 
00400   if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
00401     {
00402       enum nss_status retval = yperr2nss (yperr);
00403 
00404       if (retval == NSS_STATUS_TRYAGAIN)
00405        {
00406          *h_errnop = TRY_AGAIN;
00407          *errnop = errno;
00408        }
00409       else if (retval == NSS_STATUS_NOTFOUND)
00410        *h_errnop = HOST_NOT_FOUND;
00411 
00412       return retval;
00413     }
00414 
00415   const size_t linebuflen = buffer + buflen - data->linebuffer;
00416   if (__builtin_expect ((size_t) (len + 1) > linebuflen, 0))
00417     {
00418       free (result);
00419       *errnop = ERANGE;
00420       *h_errnop = NETDB_INTERNAL;
00421       return NSS_STATUS_TRYAGAIN;
00422     }
00423 
00424   char *p = strncpy (data->linebuffer, result, len);
00425   data->linebuffer[len] = '\0';
00426   while (isspace (*p))
00427     ++p;
00428   free (result);
00429 
00430   int parse_res = parse_line (p, host, data, buflen, errnop, af,
00431                            ((_res.options & RES_USE_INET6)
00432                             ? AI_V4MAPPED : 0));
00433   if (__builtin_expect (parse_res < 1, 0))
00434     {
00435       if (parse_res == -1)
00436        {
00437          *h_errnop = NETDB_INTERNAL;
00438          return NSS_STATUS_TRYAGAIN;
00439        }
00440       else
00441        {
00442          *h_errnop = HOST_NOT_FOUND;
00443          return NSS_STATUS_NOTFOUND;
00444        }
00445     }
00446 
00447   *h_errnop = NETDB_SUCCESS;
00448   return NSS_STATUS_SUCCESS;
00449 }
00450 
00451 
00452 enum nss_status
00453 _nss_nis_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
00454                         char *buffer, size_t buflen, int *errnop,
00455                         int *herrnop, int32_t *ttlp)
00456 {
00457   char *domain;
00458   if (yp_get_default_domain (&domain))
00459     return NSS_STATUS_UNAVAIL;
00460 
00461   /* Convert name to lowercase.  */
00462   size_t namlen = strlen (name);
00463   char name2[namlen + 1];
00464   size_t i;
00465 
00466   for (i = 0; i < namlen; ++i)
00467     name2[i] = tolower (name[i]);
00468   name2[i] = '\0';
00469 
00470   char *result;
00471   int len;
00472   int yperr = yp_match (domain, "hosts.byname", name2, namlen, &result, &len);
00473 
00474   if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
00475     {
00476       enum nss_status retval = yperr2nss (yperr);
00477 
00478       if (retval == NSS_STATUS_TRYAGAIN)
00479        {
00480          *herrnop = TRY_AGAIN;
00481          *errnop = errno;
00482        }
00483       if (retval == NSS_STATUS_NOTFOUND)
00484        *herrnop = HOST_NOT_FOUND;
00485       return retval;
00486     }
00487 
00488   struct parser_data data;
00489   struct hostent host;
00490   int parse_res = parse_line (result, &host, &data, buflen, errnop, AF_UNSPEC,
00491                            0);
00492   if (__builtin_expect (parse_res < 1, 0))
00493     {
00494       if (parse_res == -1)
00495        {
00496          *herrnop = NETDB_INTERNAL;
00497          return NSS_STATUS_TRYAGAIN;
00498        }
00499       else
00500        {
00501          *herrnop = HOST_NOT_FOUND;
00502          return NSS_STATUS_NOTFOUND;
00503        }
00504     }
00505 
00506   if (*pat == NULL)
00507     {
00508       uintptr_t pad = (-(uintptr_t) buffer
00509                      % __alignof__ (struct gaih_addrtuple));
00510       buffer += pad;
00511       buflen = buflen > pad ? buflen - pad : 0;
00512 
00513       if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple), 0))
00514        {
00515        erange:
00516          free (result);
00517          *errnop = ERANGE;
00518          *herrnop = NETDB_INTERNAL;
00519          return NSS_STATUS_TRYAGAIN;
00520        }
00521 
00522       *pat = (struct gaih_addrtuple *) buffer;
00523       buffer += sizeof (struct gaih_addrtuple);
00524       buflen -= sizeof (struct gaih_addrtuple);
00525     }
00526 
00527   (*pat)->next = NULL;
00528   size_t h_name_len = strlen (host.h_name);
00529   if (h_name_len >= buflen)
00530     goto erange;
00531   (*pat)->name = memcpy (buffer, host.h_name, h_name_len + 1);
00532   (*pat)->family = host.h_addrtype;
00533   memcpy ((*pat)->addr, host.h_addr_list[0], host.h_length);
00534   (*pat)->scopeid = 0;
00535   assert (host.h_addr_list[1] == NULL);
00536 
00537   free (result);
00538 
00539   return NSS_STATUS_SUCCESS;
00540 }