Back to index

glibc  2.9
digits_dots.c
Go to the documentation of this file.
00001 /* Copyright (C) 1997, 1999, 2000, 2001, 2004 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by H.J. Lu <hjl@gnu.ai.mit.edu>, 1997.
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 #include <assert.h>
00021 #include <errno.h>
00022 #include <string.h>
00023 #include <stdlib.h>
00024 #include <ctype.h>
00025 #include <wctype.h>
00026 #include <resolv.h>
00027 #include <netdb.h>
00028 #include <arpa/inet.h>
00029 #include "nsswitch.h"
00030 
00031 #ifdef USE_NSCD
00032 # define inet_aton __inet_aton
00033 # include <nscd/nscd_proto.h>
00034 #endif
00035 
00036 int
00037 __nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
00038                          char **buffer, size_t *buffer_size,
00039                          size_t buflen, struct hostent **result,
00040                          enum nss_status *status, int af, int *h_errnop)
00041 {
00042   int save;
00043 
00044   /* We have to test for the use of IPv6 which can only be done by
00045      examining `_res'.  */
00046   if (__res_maybe_init (&_res, 0) == -1)
00047     {
00048       if (h_errnop)
00049        *h_errnop = NETDB_INTERNAL;
00050       *result = NULL;
00051       return -1;
00052     }
00053 
00054   /*
00055    * disallow names consisting only of digits/dots, unless
00056    * they end in a dot.
00057    */
00058   if (isdigit (name[0]) || isxdigit (name[0]) || name[0] == ':')
00059     {
00060       const char *cp;
00061       char *hostname;
00062       typedef unsigned char host_addr_t[16];
00063       host_addr_t *host_addr;
00064       typedef char *host_addr_list_t[2];
00065       host_addr_list_t *h_addr_ptrs;
00066       char **h_alias_ptr;
00067       size_t size_needed;
00068       int addr_size;
00069 
00070       switch (af)
00071        {
00072        case AF_INET:
00073          addr_size = INADDRSZ;
00074          break;
00075 
00076        case AF_INET6:
00077          addr_size = IN6ADDRSZ;
00078          break;
00079 
00080        default:
00081          af = (_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET;
00082          addr_size = af == AF_INET6 ? IN6ADDRSZ : INADDRSZ;
00083          break;
00084        }
00085 
00086       size_needed = (sizeof (*host_addr)
00087                    + sizeof (*h_addr_ptrs) + strlen (name) + 1);
00088 
00089       if (buffer_size == NULL)
00090         {
00091          if (buflen < size_needed)
00092            {
00093              if (h_errnop != NULL)
00094               *h_errnop = TRY_AGAIN;
00095              __set_errno (ERANGE);
00096              goto done;
00097            }
00098        }
00099       else if (buffer_size != NULL && *buffer_size < size_needed)
00100        {
00101          char *new_buf;
00102          *buffer_size = size_needed;
00103          new_buf = (char *) realloc (*buffer, *buffer_size);
00104 
00105          if (new_buf == NULL)
00106            {
00107              save = errno;
00108              free (*buffer);
00109              *buffer = NULL;
00110              *buffer_size = 0;
00111              __set_errno (save);
00112              if (h_errnop != NULL)
00113               *h_errnop = TRY_AGAIN;
00114              *result = NULL;
00115              goto done;
00116            }
00117          *buffer = new_buf;
00118        }
00119 
00120       memset (*buffer, '\0', size_needed);
00121 
00122       host_addr = (host_addr_t *) *buffer;
00123       h_addr_ptrs = (host_addr_list_t *)
00124        ((char *) host_addr + sizeof (*host_addr));
00125       h_alias_ptr = (char **) ((char *) h_addr_ptrs + sizeof (*h_addr_ptrs));
00126       hostname = (char *) h_alias_ptr + sizeof (*h_alias_ptr);
00127 
00128       if (isdigit (name[0]))
00129        {
00130          for (cp = name;; ++cp)
00131            {
00132              if (*cp == '\0')
00133               {
00134                 int ok;
00135 
00136                 if (*--cp == '.')
00137                   break;
00138 
00139                 /* All-numeric, no dot at the end. Fake up a hostent as if
00140                    we'd actually done a lookup.  What if someone types
00141                    255.255.255.255?  The test below will succeed
00142                    spuriously... ???  */
00143                 if (af == AF_INET)
00144                   ok = __inet_aton (name, (struct in_addr *) host_addr);
00145                 else
00146                   {
00147                     assert (af == AF_INET6);
00148                     ok = inet_pton (af, name, host_addr) > 0;
00149                   }
00150                 if (! ok)
00151                   {
00152                     *h_errnop = HOST_NOT_FOUND;
00153                     if (buffer_size)
00154                      *result = NULL;
00155                     goto done;
00156                   }
00157 
00158                 resbuf->h_name = strcpy (hostname, name);
00159                 h_alias_ptr[0] = NULL;
00160                 resbuf->h_aliases = h_alias_ptr;
00161                 (*h_addr_ptrs)[0] = (char *) host_addr;
00162                 (*h_addr_ptrs)[1] = NULL;
00163                 resbuf->h_addr_list = *h_addr_ptrs;
00164                 if (af == AF_INET && (_res.options & RES_USE_INET6))
00165                   {
00166                     /* We need to change the IP v4 address into the
00167                       IP v6 address.  */
00168                     char tmp[INADDRSZ];
00169                     char *p = (char *) host_addr;
00170                     int i;
00171 
00172                     /* Save a copy of the IP v4 address. */
00173                     memcpy (tmp, host_addr, INADDRSZ);
00174                     /* Mark this ipv6 addr as a mapped ipv4. */
00175                     for (i = 0; i < 10; i++)
00176                      *p++ = 0x00;
00177                     *p++ = 0xff;
00178                     *p++ = 0xff;
00179                     /* Copy the IP v4 address. */
00180                     memcpy (p, tmp, INADDRSZ);
00181                     resbuf->h_addrtype = AF_INET6;
00182                     resbuf->h_length = IN6ADDRSZ;
00183                   }
00184                 else
00185                   {
00186                     resbuf->h_addrtype = af;
00187                     resbuf->h_length = addr_size;
00188                   }
00189                 if (h_errnop != NULL)
00190                   *h_errnop = NETDB_SUCCESS;
00191                 if (buffer_size == NULL)
00192                   *status = NSS_STATUS_SUCCESS;
00193                 else
00194                  *result = resbuf;
00195                 goto done;
00196               }
00197 
00198              if (!isdigit (*cp) && *cp != '.')
00199               break;
00200            }
00201        }
00202 
00203       if ((isxdigit (name[0]) && strchr (name, ':') != NULL) || name[0] == ':')
00204        {
00205          const char *cp;
00206          char *hostname;
00207          typedef unsigned char host_addr_t[16];
00208          host_addr_t *host_addr;
00209          typedef char *host_addr_list_t[2];
00210          host_addr_list_t *h_addr_ptrs;
00211          size_t size_needed;
00212          int addr_size;
00213 
00214          switch (af)
00215            {
00216            default:
00217              af = (_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET;
00218              if (af == AF_INET6)
00219               {
00220                 addr_size = IN6ADDRSZ;
00221                 break;
00222               }
00223              /* FALLTHROUGH */
00224 
00225            case AF_INET:
00226              /* This is not possible.  We cannot represent an IPv6 address
00227                in an `struct in_addr' variable.  */
00228              *h_errnop = HOST_NOT_FOUND;
00229              *result = NULL;
00230              goto done;
00231 
00232            case AF_INET6:
00233              addr_size = IN6ADDRSZ;
00234              break;
00235            }
00236 
00237          size_needed = (sizeof (*host_addr)
00238                       + sizeof (*h_addr_ptrs) + strlen (name) + 1);
00239 
00240          if (buffer_size == NULL && buflen < size_needed)
00241            {
00242              if (h_errnop != NULL)
00243               *h_errnop = TRY_AGAIN;
00244              __set_errno (ERANGE);
00245              goto done;
00246            }
00247          else if (buffer_size != NULL && *buffer_size < size_needed)
00248            {
00249              char *new_buf;
00250              *buffer_size = size_needed;
00251              new_buf = realloc (*buffer, *buffer_size);
00252 
00253              if (new_buf == NULL)
00254               {
00255                 save = errno;
00256                 free (*buffer);
00257                 __set_errno (save);
00258                 *buffer = NULL;
00259                 *buffer_size = 0;
00260                 *result = NULL;
00261                 goto done;
00262               }
00263              *buffer = new_buf;
00264            }
00265 
00266          memset (*buffer, '\0', size_needed);
00267 
00268          host_addr = (host_addr_t *) *buffer;
00269          h_addr_ptrs = (host_addr_list_t *)
00270            ((char *) host_addr + sizeof (*host_addr));
00271          hostname = (char *) h_addr_ptrs + sizeof (*h_addr_ptrs);
00272 
00273          for (cp = name;; ++cp)
00274            {
00275              if (!*cp)
00276               {
00277                 if (*--cp == '.')
00278                   break;
00279 
00280                 /* All-IPv6-legal, no dot at the end. Fake up a
00281                    hostent as if we'd actually done a lookup.  */
00282                 if (inet_pton (AF_INET6, name, host_addr) <= 0)
00283                   {
00284                     *h_errnop = HOST_NOT_FOUND;
00285                     if (buffer_size)
00286                      *result = NULL;
00287                     goto done;
00288                   }
00289 
00290                 resbuf->h_name = strcpy (hostname, name);
00291                 h_alias_ptr[0] = NULL;
00292                 resbuf->h_aliases = h_alias_ptr;
00293                 (*h_addr_ptrs)[0] = (char *) host_addr;
00294                 (*h_addr_ptrs)[1] = (char *) 0;
00295                 resbuf->h_addr_list = *h_addr_ptrs;
00296                 resbuf->h_addrtype = AF_INET6;
00297                 resbuf->h_length = addr_size;
00298                 *h_errnop = NETDB_SUCCESS;
00299                 if (buffer_size == NULL)
00300                   *status = NSS_STATUS_SUCCESS;
00301                 else
00302                   *result = resbuf;
00303                 goto done;
00304               }
00305 
00306              if (!isxdigit (*cp) && *cp != ':' && *cp != '.')
00307               break;
00308            }
00309        }
00310     }
00311 
00312   return 0;
00313 
00314 done:
00315   return 1;
00316 }
00317 libc_hidden_def (__nss_hostname_digits_dots)