(linenum→info "unix/slp.c:2238")

glibc/2.7/nscd/nscd_gethst_r.c

    1: /* Copyright (C) 1998-2005, 2006, 2007 Free Software Foundation, Inc.
    2:    This file is part of the GNU C Library.
    3:    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
    4: 
    5:    The GNU C Library is free software; you can redistribute it and/or
    6:    modify it under the terms of the GNU Lesser General Public
    7:    License as published by the Free Software Foundation; either
    8:    version 2.1 of the License, or (at your option) any later version.
    9: 
   10:    The GNU C Library is distributed in the hope that it will be useful,
   11:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   12:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13:    Lesser General Public License for more details.
   14: 
   15:    You should have received a copy of the GNU Lesser General Public
   16:    License along with the GNU C Library; if not, write to the Free
   17:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   18:    02111-1307 USA.  */
   19: 
   20: #include <errno.h>
   21: #include <resolv.h>
   22: #include <stdio.h>
   23: #include <string.h>
   24: #include <arpa/nameser.h>
   25: #include <not-cancel.h>
   26: 
   27: #include "nscd-client.h"
   28: #include "nscd_proto.h"
   29: 
   30: int __nss_not_use_nscd_hosts;
   31: 
   32: static int nscd_gethst_r (const char *key, size_t keylen, request_type type,
   33:                           struct hostent *resultbuf, char *buffer,
   34:                           size_t buflen, struct hostent **result,
   35:                           int *h_errnop) internal_function;
   36: 
   37: 
   38: int
   39: __nscd_gethostbyname_r (const char *name, struct hostent *resultbuf,
   40:                         char *buffer, size_t buflen, struct hostent **result,
   41:                         int *h_errnop)
   42: {
   43:   request_type reqtype;
   44: 
   45:   reqtype = (_res.options & RES_USE_INET6) ? GETHOSTBYNAMEv6 : GETHOSTBYNAME;
   46: 
   47:   return nscd_gethst_r (name, strlen (name) + 1, reqtype, resultbuf,
   48:                         buffer, buflen, result, h_errnop);
   49: }
   50: 
   51: 
   52: int
   53: __nscd_gethostbyname2_r (const char *name, int af, struct hostent *resultbuf,
   54:                          char *buffer, size_t buflen, struct hostent **result,
   55:                          int *h_errnop)
   56: {
   57:   request_type reqtype;
   58: 
   59:   reqtype = af == AF_INET6 ? GETHOSTBYNAMEv6 : GETHOSTBYNAME;
   60: 
   61:   return nscd_gethst_r (name, strlen (name) + 1, reqtype, resultbuf,
   62:                         buffer, buflen, result, h_errnop);
   63: }
   64: 
   65: 
   66: int
   67: __nscd_gethostbyaddr_r (const void *addr, socklen_t len, int type,
   68:                         struct hostent *resultbuf, char *buffer, size_t buflen,
   69:                         struct hostent **result, int *h_errnop)
   70: {
   71:   request_type reqtype;
   72: 
   73:   if (!((len == INADDRSZ && type == AF_INET)
   74:         || (len == IN6ADDRSZ && type == AF_INET6)))
   75:     /* LEN and TYPE do not match.  */
   76:     return -1;
   77: 
   78:   reqtype = type == AF_INET6 ? GETHOSTBYADDRv6 : GETHOSTBYADDR;
   79: 
   80:   return nscd_gethst_r (addr, len, reqtype, resultbuf, buffer, buflen, result,
   81:                         h_errnop);
   82: }
   83: 
   84: 
   85: libc_locked_map_ptr (, __hst_map_handle) attribute_hidden;
   86: /* Note that we only free the structure if necessary.  The memory
   87:    mapping is not removed since it is not visible to the malloc
   88:    handling.  */
   89: libc_freeres_fn (hst_map_free)
   90: {
   91:   if (__hst_map_handle.mapped != NO_MAPPING)
   92:     {
   93:       void *p = __hst_map_handle.mapped;
   94:       __hst_map_handle.mapped = NO_MAPPING;
   95:       free (p);
   96:     }
   97: }
   98: 
   99: 
  100: static int
  101: internal_function
  102: nscd_gethst_r (const char *key, size_t keylen, request_type type,
  103:                struct hostent *resultbuf, char *buffer, size_t buflen,
  104:                struct hostent **result, int *h_errnop)
  105: {
  106:   int gc_cycle;
  107:   int nretries = 0;
  108: 
  109:   /* If the mapping is available, try to search there instead of
  110:      communicating with the nscd.  */
  111:   struct mapped_database *mapped;
  112:   mapped = __nscd_get_map_ref (GETFDHST, "hosts", &__hst_map_handle,
  113:                                &gc_cycle);
  114: 
  115:  retry:;
  116:   const char *h_name = NULL;
  117:   const uint32_t *aliases_len = NULL;
  118:   const char *addr_list = NULL;
  119:   size_t addr_list_len = 0;
  120:   int retval = -1;
  121:   const char *recend = (const char *) ~UINTMAX_C (0);
  122:   int sock = -1;
  123:   hst_response_header hst_resp;
  124:   if (mapped != NO_MAPPING)
  125:     {
  126:       /* No const qualifier, as it can change during garbage collection.  */
  127:       struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
  128:       if (found != NULL)
  129:         {
  130:           h_name = (char *) (&found->data[0].hstdata + 1);
  131:           hst_resp = found->data[0].hstdata;
  132:           aliases_len = (uint32_t *) (h_name + hst_resp.h_name_len);
  133:           addr_list = ((char *) aliases_len
  134:                        + hst_resp.h_aliases_cnt * sizeof (uint32_t));
  135:           addr_list_len = hst_resp.h_addr_list_cnt * INADDRSZ;
  136:           recend = (const char *) found->data + found->recsize;
  137:           /* Now check if we can trust hst_resp fields.  If GC is
  138:              in progress, it can contain anything.  */
  139:           if (mapped->head->gc_cycle != gc_cycle)
  140:             {
  141:               retval = -2;
  142:               goto out;
  143:             }
  144: 
  145: #ifndef _STRING_ARCH_unaligned
  146:           /* The aliases_len array in the mapped database might very
  147:              well be unaligned.  We will access it word-wise so on
  148:              platforms which do not tolerate unaligned accesses we
  149:              need to make an aligned copy.  */
  150:           if (((uintptr_t) aliases_len & (__alignof__ (*aliases_len) - 1))
  151:               != 0)
  152:             {
  153:               uint32_t *tmp = alloca (hst_resp.h_aliases_cnt
  154:                                       * sizeof (uint32_t));
  155:               aliases_len = memcpy (tmp, aliases_len,
  156:                                     hst_resp.h_aliases_cnt
  157:                                     * sizeof (uint32_t));
  158:             }
  159: #endif
  160:           if (type != GETHOSTBYADDR && type != GETHOSTBYNAME)
  161:             {
  162:               if (hst_resp.h_length == INADDRSZ)
  163:                 addr_list += addr_list_len;
  164:               addr_list_len = hst_resp.h_addr_list_cnt * IN6ADDRSZ;
  165:             }
  166:           if (__builtin_expect ((const char *) addr_list + addr_list_len
  167:                                 > recend, 0))
  168:             goto out;
  169:         }
  170:     }
  171: 
  172:   if (h_name == NULL)
  173:     {
  174:       sock = __nscd_open_socket (key, keylen, type, &hst_resp,
  175:                                  sizeof (hst_resp));
  176:       if (sock == -1)
  177:         {
  178:           __nss_not_use_nscd_hosts = 1;
  179:           goto out;
  180:         }
  181:     }
  182: 
  183:   /* No value found so far.  */
  184:   *result = NULL;
  185: 
  186:   if (__builtin_expect (hst_resp.found == -1, 0))
  187:     {
  188:       /* The daemon does not cache this database.  */
  189:       __nss_not_use_nscd_hosts = 1;
  190:       goto out_close;
  191:     }
  192: 
  193:   if (hst_resp.found == 1)
  194:     {
  195:       char *cp = buffer;
  196:       uintptr_t align1;
  197:       uintptr_t align2;
  198:       size_t total_len;
  199:       ssize_t cnt;
  200:       char *ignore;
  201:       int n;
  202: 
  203:       /* A first check whether the buffer is sufficiently large is possible.  */
  204:       /* Now allocate the buffer the array for the group members.  We must
  205:          align the pointer and the base of the h_addr_list pointers.  */
  206:       align1 = ((__alignof__ (char *) - (cp - ((char *) 0)))
  207:                 & (__alignof__ (char *) - 1));
  208:       align2 = ((__alignof__ (char *) - ((cp + align1 + hst_resp.h_name_len)
  209:                                          - ((char *) 0)))
  210:                 & (__alignof__ (char *) - 1));
  211:       if (buflen < (align1 + hst_resp.h_name_len + align2
  212:                     + ((hst_resp.h_aliases_cnt + hst_resp.h_addr_list_cnt
  213:                         + 2)
  214:                        * sizeof (char *))
  215:                     + hst_resp.h_addr_list_cnt * (type == AF_INET
  216:                                                   ? INADDRSZ : IN6ADDRSZ)))
  217:         {
  218:         no_room:
  219:           *h_errnop = NETDB_INTERNAL;
  220:           __set_errno (ERANGE);
  221:           retval = ERANGE;
  222:           goto out_close;
  223:         }
  224:       cp += align1;
  225: 
  226:       /* Prepare the result as far as we can.  */
  227:       resultbuf->h_aliases = (char **) cp;
  228:       cp += (hst_resp.h_aliases_cnt + 1) * sizeof (char *);
  229:       resultbuf->h_addr_list = (char **) cp;
  230:       cp += (hst_resp.h_addr_list_cnt + 1) * sizeof (char *);
  231: 
  232:       resultbuf->h_name = cp;
  233:       cp += hst_resp.h_name_len + align2;
  234: 
  235:       if (type == GETHOSTBYADDR || type == GETHOSTBYNAME)
  236:         {
  237:           resultbuf->h_addrtype = AF_INET;
  238:           resultbuf->h_length = INADDRSZ;
  239:         }
  240:       else
  241:         {
  242:           resultbuf->h_addrtype = AF_INET6;
  243:           resultbuf->h_length = IN6ADDRSZ;
  244:         }
  245:       for (cnt = 0; cnt < hst_resp.h_addr_list_cnt; ++cnt)
  246:         {
  247:           resultbuf->h_addr_list[cnt] = cp;
  248:           cp += resultbuf->h_length;
  249:         }
  250:       resultbuf->h_addr_list[cnt] = NULL;
  251: 
  252:       if (h_name == NULL)
  253:         {
  254:           struct iovec vec[4];
  255: 
  256:           vec[0].iov_base = resultbuf->h_name;
  257:           vec[0].iov_len = hst_resp.h_name_len;
  258:           total_len = hst_resp.h_name_len;
  259:           n = 1;
  260: 
  261:           if (hst_resp.h_aliases_cnt > 0)
  262:             {
  263:               aliases_len = alloca (hst_resp.h_aliases_cnt
  264:                                     * sizeof (uint32_t));
  265:               vec[n].iov_base = (void *) aliases_len;
  266:               vec[n].iov_len = hst_resp.h_aliases_cnt * sizeof (uint32_t);
  267: 
  268:               total_len += hst_resp.h_aliases_cnt * sizeof (uint32_t);
  269:               ++n;
  270:             }
  271: 
  272:           if (type == GETHOSTBYADDR || type == GETHOSTBYNAME)
  273:             {
  274:               vec[n].iov_base = resultbuf->h_addr_list[0];
  275:               vec[n].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ;
  276: 
  277:               total_len += hst_resp.h_addr_list_cnt * INADDRSZ;
  278: 
  279:               ++n;
  280:             }
  281:           else
  282:             {
  283:               if (hst_resp.h_length == INADDRSZ)
  284:                 {
  285:                   ignore = alloca (hst_resp.h_addr_list_cnt * INADDRSZ);
  286:                   vec[n].iov_base = ignore;
  287:                   vec[n].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ;
  288: 
  289:                   total_len += hst_resp.h_addr_list_cnt * INADDRSZ;
  290: 
  291:                   ++n;
  292:                 }
  293: 
  294:               vec[n].iov_base = resultbuf->h_addr_list[0];
  295:               vec[n].iov_len = hst_resp.h_addr_list_cnt * IN6ADDRSZ;
  296: 
  297:               total_len += hst_resp.h_addr_list_cnt * IN6ADDRSZ;
  298: 
  299:               ++n;
  300:             }
  301: 
  302:           if ((size_t) __readvall (sock, vec, n) != total_len)
  303:             goto out_close;
  304:         }
  305:       else
  306:         {
  307:           memcpy (resultbuf->h_name, h_name, hst_resp.h_name_len);
  308:           memcpy (resultbuf->h_addr_list[0], addr_list, addr_list_len);
  309:         }
  310: 
  311:       /*  Now we also can read the aliases.  */
  312:       total_len = 0;
  313:       for (cnt = 0; cnt < hst_resp.h_aliases_cnt; ++cnt)
  314:         {
  315:           resultbuf->h_aliases[cnt] = cp;
  316:           cp += aliases_len[cnt];
  317:           total_len += aliases_len[cnt];
  318:         }
  319:       resultbuf->h_aliases[cnt] = NULL;
  320: 
  321:       if (__builtin_expect ((const char *) addr_list + addr_list_len
  322:                             + total_len > recend, 0))
  323:         {
  324:           /* aliases_len array might contain garbage during nscd GC cycle,
  325:              retry rather than fail in that case.  */
  326:           if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle)
  327:             retval = -2;
  328:           goto out_close;
  329:         }
  330:       /* See whether this would exceed the buffer capacity.  */
  331:       if (__builtin_expect (cp > buffer + buflen, 0))
  332:         {
  333:           /* aliases_len array might contain garbage during nscd GC cycle,
  334:              retry rather than fail in that case.  */
  335:           if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle)
  336:             {
  337:               retval = -2;
  338:               goto out_close;
  339:             }
  340:           goto no_room;
  341:         }
  342: 
  343:       /* And finally read the aliases.  */
  344:       if (addr_list == NULL)
  345:         {
  346:           if (total_len == 0
  347:               || ((size_t) __readall (sock, resultbuf->h_aliases[0], total_len)
  348:                   == total_len))
  349:             {
  350:               retval = 0;
  351:               *result = resultbuf;
  352:             }
  353:         }
  354:       else
  355:         {
  356:           memcpy (resultbuf->h_aliases[0],
  357:                   (const char *) addr_list + addr_list_len, total_len);
  358: 
  359:           /* Try to detect corrupt databases.  */
  360:           if (resultbuf->h_name[hst_resp.h_name_len - 1] != '\0'
  361:               || ({for (cnt = 0; cnt < hst_resp.h_aliases_cnt; ++cnt)
  362:                      if (resultbuf->h_aliases[cnt][aliases_len[cnt] - 1]
  363:                          != '\0')
  364:                        break;
  365:                    cnt < hst_resp.h_aliases_cnt; }))
  366:             {
  367:               /* We cannot use the database.  */
  368:               if (mapped->head->gc_cycle != gc_cycle)
  369:                 retval = -2;
  370:               goto out_close;
  371:             }
  372: 
  373:           retval = 0;
  374:           *result = resultbuf;
  375:         }
  376:     }
  377:   else
  378:     {
  379:       /* Store the error number.  */
  380:       *h_errnop = hst_resp.error;
  381: 
  382:       /* Set errno to 0 to indicate no error, just no found record.  */
  383:       __set_errno (0);
  384:       /* Even though we have not found anything, the result is zero.  */
  385:       retval = 0;
  386:     }
  387: 
  388:  out_close:
  389:   if (sock != -1)
  390:     close_not_cancel_no_status (sock);
  391:  out:
  392:   if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
  393:     {
  394:       /* When we come here this means there has been a GC cycle while we
  395:          were looking for the data.  This means the data might have been
  396:          inconsistent.  Retry if possible.  */
  397:       if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
  398:         {
  399:           /* nscd is just running gc now.  Disable using the mapping.  */
  400:           if (atomic_decrement_val (&mapped->counter) == 0)
  401:             __nscd_unmap (mapped);
  402:           mapped = NO_MAPPING;
  403:         }
  404: 
  405:       if (retval != -1)
  406:         goto retry;
  407:     }
  408: 
  409:   return retval;
  410: }
Syntax (Markdown)