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

glibc/2.7/nscd/nscd_getgr_r.c

    1: /* Copyright (C) 1998-2000, 2002-2005, 2006, 2007
    2:    Free Software Foundation, Inc.
    3:    This file is part of the GNU C Library.
    4:    Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
    5: 
    6:    The GNU C Library is free software; you can redistribute it and/or
    7:    modify it under the terms of the GNU Lesser General Public
    8:    License as published by the Free Software Foundation; either
    9:    version 2.1 of the License, or (at your option) any later version.
   10: 
   11:    The GNU C Library is distributed in the hope that it will be useful,
   12:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   13:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14:    Lesser General Public License for more details.
   15: 
   16:    You should have received a copy of the GNU Lesser General Public
   17:    License along with the GNU C Library; if not, write to the Free
   18:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   19:    02111-1307 USA.  */
   20: 
   21: #include <alloca.h>
   22: #include <assert.h>
   23: #include <errno.h>
   24: #include <grp.h>
   25: #include <stdint.h>
   26: #include <stdio.h>
   27: #include <stdlib.h>
   28: #include <string.h>
   29: #include <unistd.h>
   30: #include <sys/mman.h>
   31: #include <sys/socket.h>
   32: #include <sys/uio.h>
   33: #include <sys/un.h>
   34: #include <not-cancel.h>
   35: #include <stdio-common/_itoa.h>
   36: 
   37: #include "nscd-client.h"
   38: #include "nscd_proto.h"
   39: 
   40: int __nss_not_use_nscd_group;
   41: 
   42: static int nscd_getgr_r (const char *key, size_t keylen, request_type type,
   43:                          struct group *resultbuf, char *buffer,
   44:                          size_t buflen, struct group **result)
   45:      internal_function;
   46: 
   47: 
   48: int
   49: __nscd_getgrnam_r (const char *name, struct group *resultbuf, char *buffer,
   50:                    size_t buflen, struct group **result)
   51: {
   52:   return nscd_getgr_r (name, strlen (name) + 1, GETGRBYNAME, resultbuf,
   53:                        buffer, buflen, result);
   54: }
   55: 
   56: 
   57: int
   58: __nscd_getgrgid_r (gid_t gid, struct group *resultbuf, char *buffer,
   59:                    size_t buflen, struct group **result)
   60: {
   61:   char buf[3 * sizeof (gid_t)];
   62:   buf[sizeof (buf) - 1] = '\0';
   63:   char *cp = _itoa_word (gid, buf + sizeof (buf) - 1, 10, 0);
   64: 
   65:   return nscd_getgr_r (cp, buf + sizeof (buf) - cp, GETGRBYGID, resultbuf,
   66:                        buffer, buflen, result);
   67: }
   68: 
   69: 
   70: libc_locked_map_ptr (,__gr_map_handle) attribute_hidden;
   71: /* Note that we only free the structure if necessary.  The memory
   72:    mapping is not removed since it is not visible to the malloc
   73:    handling.  */
   74: libc_freeres_fn (gr_map_free)
   75: {
   76:   if (__gr_map_handle.mapped != NO_MAPPING)
   77:     {
   78:       void *p = __gr_map_handle.mapped;
   79:       __gr_map_handle.mapped = NO_MAPPING;
   80:       free (p);
   81:     }
   82: }
   83: 
   84: 
   85: static int
   86: internal_function
   87: nscd_getgr_r (const char *key, size_t keylen, request_type type,
   88:               struct group *resultbuf, char *buffer, size_t buflen,
   89:               struct group **result)
   90: {
   91:   int gc_cycle;
   92:   int nretries = 0;
   93:   const uint32_t *len = NULL;
   94:   size_t lensize = 0;
   95: 
   96:   /* If the mapping is available, try to search there instead of
   97:      communicating with the nscd.  */
   98:   struct mapped_database *mapped = __nscd_get_map_ref (GETFDGR, "group",
   99:                                                        &__gr_map_handle,
  100:                                                        &gc_cycle);
  101:  retry:;
  102:   const char *gr_name = NULL;
  103:   size_t gr_name_len = 0;
  104:   int retval = -1;
  105:   const char *recend = (const char *) ~UINTMAX_C (0);
  106:   gr_response_header gr_resp;
  107: 
  108:   if (mapped != NO_MAPPING)
  109:     {
  110:       struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
  111:       if (found != NULL)
  112:         {
  113:           len = (const uint32_t *) (&found->data[0].grdata + 1);
  114:           gr_resp = found->data[0].grdata;
  115:           gr_name = ((const char *) len
  116:                      + gr_resp.gr_mem_cnt * sizeof (uint32_t));
  117:           gr_name_len = gr_resp.gr_name_len + gr_resp.gr_passwd_len;
  118:           recend = (const char *) found->data + found->recsize;
  119:           /* Now check if we can trust gr_resp fields.  If GC is
  120:              in progress, it can contain anything.  */
  121:           if (mapped->head->gc_cycle != gc_cycle)
  122:             {
  123:               retval = -2;
  124:               goto out;
  125:             }
  126: 
  127:           /* The alignment is always sufficient, unless GC is in progress.  */
  128:           assert (((uintptr_t) len & (__alignof__ (*len) - 1)) == 0);
  129:         }
  130:     }
  131: 
  132:   int sock = -1;
  133:   if (gr_name == NULL)
  134:     {
  135:       sock = __nscd_open_socket (key, keylen, type, &gr_resp,
  136:                                  sizeof (gr_resp));
  137:       if (sock == -1)
  138:         {
  139:           __nss_not_use_nscd_group = 1;
  140:           goto out;
  141:         }
  142:     }
  143: 
  144:   /* No value found so far.  */
  145:   *result = NULL;
  146: 
  147:   if (__builtin_expect (gr_resp.found == -1, 0))
  148:     {
  149:       /* The daemon does not cache this database.  */
  150:       __nss_not_use_nscd_group = 1;
  151:       goto out_close;
  152:     }
  153: 
  154:   if (gr_resp.found == 1)
  155:     {
  156:       struct iovec vec[2];
  157:       char *p = buffer;
  158:       size_t total_len;
  159:       uintptr_t align;
  160:       nscd_ssize_t cnt;
  161: 
  162:       /* Now allocate the buffer the array for the group members.  We must
  163:          align the pointer.  */
  164:       align = ((__alignof__ (char *) - (p - ((char *) 0)))
  165:                & (__alignof__ (char *) - 1));
  166:       total_len = (align + (1 + gr_resp.gr_mem_cnt) * sizeof (char *)
  167:                    + gr_resp.gr_name_len + gr_resp.gr_passwd_len);
  168:       if (__builtin_expect (buflen < total_len, 0))
  169:         {
  170:         no_room:
  171:           __set_errno (ERANGE);
  172:           retval = ERANGE;
  173:           goto out_close;
  174:         }
  175:       buflen -= total_len;
  176: 
  177:       p += align;
  178:       resultbuf->gr_mem = (char **) p;
  179:       p += (1 + gr_resp.gr_mem_cnt) * sizeof (char *);
  180: 
  181:       /* Set pointers for strings.  */
  182:       resultbuf->gr_name = p;
  183:       p += gr_resp.gr_name_len;
  184:       resultbuf->gr_passwd = p;
  185:       p += gr_resp.gr_passwd_len;
  186: 
  187:       /* Fill in what we know now.  */
  188:       resultbuf->gr_gid = gr_resp.gr_gid;
  189: 
  190:       /* Read the length information, group name, and password.  */
  191:       if (gr_name == NULL)
  192:         {
  193:           /* Handle a simple, usual case: no group members.  */
  194:           if (__builtin_expect (gr_resp.gr_mem_cnt == 0, 1))
  195:             {
  196:               size_t n = gr_resp.gr_name_len + gr_resp.gr_passwd_len;
  197:               if (__builtin_expect (__readall (sock, resultbuf->gr_name, n)
  198:                                     != (ssize_t) n, 0))
  199:                 goto out_close;
  200:             }
  201:           else
  202:             {
  203:               /* Allocate array to store lengths.  */
  204:               if (lensize == 0)
  205:                 {
  206:                   lensize = gr_resp.gr_mem_cnt * sizeof (uint32_t);
  207:                   len = (uint32_t *) alloca (lensize);
  208:                 }
  209:               else if (gr_resp.gr_mem_cnt * sizeof (uint32_t) > lensize)
  210:                 len = extend_alloca (len, lensize,
  211:                                      gr_resp.gr_mem_cnt * sizeof (uint32_t));
  212: 
  213:               vec[0].iov_base = (void *) len;
  214:               vec[0].iov_len = gr_resp.gr_mem_cnt * sizeof (uint32_t);
  215:               vec[1].iov_base = resultbuf->gr_name;
  216:               vec[1].iov_len = gr_resp.gr_name_len + gr_resp.gr_passwd_len;
  217:               total_len = vec[0].iov_len + vec[1].iov_len;
  218: 
  219:               /* Get this data.  */
  220:               size_t n = __readvall (sock, vec, 2);
  221:               if (__builtin_expect (n != total_len, 0))
  222:                 goto out_close;
  223:             }
  224:         }
  225:       else
  226:         /* We already have the data.  Just copy the group name and
  227:            password.  */
  228:         memcpy (resultbuf->gr_name, gr_name,
  229:                 gr_resp.gr_name_len + gr_resp.gr_passwd_len);
  230: 
  231:       /* Clear the terminating entry.  */
  232:       resultbuf->gr_mem[gr_resp.gr_mem_cnt] = NULL;
  233: 
  234:       /* Prepare reading the group members.  */
  235:       total_len = 0;
  236:       for (cnt = 0; cnt < gr_resp.gr_mem_cnt; ++cnt)
  237:         {
  238:           resultbuf->gr_mem[cnt] = p;
  239:           total_len += len[cnt];
  240:           p += len[cnt];
  241:         }
  242: 
  243:       if (__builtin_expect (gr_name + gr_name_len + total_len > recend, 0))
  244:         {
  245:           /* len array might contain garbage during nscd GC cycle,
  246:              retry rather than fail in that case.  */
  247:           if (gr_name != NULL && mapped->head->gc_cycle != gc_cycle)
  248:             retval = -2;
  249:           goto out_close;
  250:         }
  251:       if (__builtin_expect (total_len > buflen, 0))
  252:         {
  253:           /* len array might contain garbage during nscd GC cycle,
  254:              retry rather than fail in that case.  */
  255:           if (gr_name != NULL && mapped->head->gc_cycle != gc_cycle)
  256:             {
  257:               retval = -2;
  258:               goto out_close;
  259:             }
  260:           else
  261:             goto no_room;
  262:         }
  263: 
  264:       retval = 0;
  265: 
  266:       /* If there are no group members TOTAL_LEN is zero.  */
  267:       if (gr_name == NULL)
  268:         {
  269:           if (total_len > 0
  270:               && __builtin_expect (__readall (sock, resultbuf->gr_mem[0],
  271:                                               total_len) != total_len, 0))
  272:             {
  273:               /* The `errno' to some value != ERANGE.  */
  274:               __set_errno (ENOENT);
  275:               retval = ENOENT;
  276:             }
  277:           else
  278:             *result = resultbuf;
  279:         }
  280:       else
  281:         {
  282:           /* Copy the group member names.  */
  283:           memcpy (resultbuf->gr_mem[0], gr_name + gr_name_len, total_len);
  284: 
  285:           /* Try to detect corrupt databases.  */
  286:           if (resultbuf->gr_name[gr_name_len - 1] != '\0'
  287:               || resultbuf->gr_passwd[gr_resp.gr_passwd_len - 1] != '\0'
  288:               || ({for (cnt = 0; cnt < gr_resp.gr_mem_cnt; ++cnt)
  289:                     if (resultbuf->gr_mem[cnt][len[cnt] - 1] != '\0')
  290:                       break;
  291:                   cnt < gr_resp.gr_mem_cnt; }))
  292:             {
  293:               /* We cannot use the database.  */
  294:               retval = mapped->head->gc_cycle != gc_cycle ? -2 : -1;
  295:               goto out_close;
  296:             }
  297: 
  298:           *result = resultbuf;
  299:         }
  300:     }
  301:   else
  302:     {
  303:       /* Set errno to 0 to indicate no error, just no found record.  */
  304:       __set_errno (0);
  305:       /* Even though we have not found anything, the result is zero.  */
  306:       retval = 0;
  307:     }
  308: 
  309:  out_close:
  310:   if (sock != -1)
  311:     close_not_cancel_no_status (sock);
  312:  out:
  313:   if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
  314:     {
  315:       /* When we come here this means there has been a GC cycle while we
  316:          were looking for the data.  This means the data might have been
  317:          inconsistent.  Retry if possible.  */
  318:       if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
  319:         {
  320:           /* nscd is just running gc now.  Disable using the mapping.  */
  321:           if (atomic_decrement_val (&mapped->counter) == 0)
  322:             __nscd_unmap (mapped);
  323:           mapped = NO_MAPPING;
  324:         }
  325: 
  326:       if (retval != -1)
  327:         goto retry;
  328:     }
  329: 
  330:   return retval;
  331: }
Syntax (Markdown)