Back to index

glibc  2.9
nscd_initgroups.c
Go to the documentation of this file.
00001 /* Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
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 <grp.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <unistd.h>
00026 #include <not-cancel.h>
00027 
00028 #include "nscd-client.h"
00029 #include "nscd_proto.h"
00030 
00031 
00032 /* We use the same mapping as in nscd_getgr.   */
00033 libc_locked_map_ptr (extern, __gr_map_handle) attribute_hidden;
00034 
00035 
00036 int
00037 __nscd_getgrouplist (const char *user, gid_t group, long int *size,
00038                    gid_t **groupsp, long int limit)
00039 {
00040   size_t userlen = strlen (user) + 1;
00041   int gc_cycle;
00042   int nretries = 0;
00043 
00044   /* If the mapping is available, try to search there instead of
00045      communicating with the nscd.  */
00046   struct mapped_database *mapped;
00047   mapped = __nscd_get_map_ref (GETFDGR, "group", &__gr_map_handle, &gc_cycle);
00048 
00049  retry:;
00050   char *respdata = NULL;
00051   int retval = -1;
00052   int sock = -1;
00053   initgr_response_header initgr_resp;
00054 
00055   if (mapped != NO_MAPPING)
00056     {
00057       struct datahead *found = __nscd_cache_search (INITGROUPS, user,
00058                                               userlen, mapped);
00059       if (found != NULL)
00060        {
00061          respdata = (char *) (&found->data[0].initgrdata + 1);
00062          initgr_resp = found->data[0].initgrdata;
00063          char *recend = (char *) found->data + found->recsize;
00064 
00065          /* Now check if we can trust initgr_resp fields.  If GC is
00066             in progress, it can contain anything.  */
00067          if (mapped->head->gc_cycle != gc_cycle)
00068            {
00069              retval = -2;
00070              goto out;
00071            }
00072 
00073          if (respdata + initgr_resp.ngrps * sizeof (int32_t) > recend)
00074            goto out;
00075        }
00076     }
00077 
00078   /* If we do not have the cache mapped, try to get the data over the
00079      socket.  */
00080   if (respdata == NULL)
00081     {
00082       sock = __nscd_open_socket (user, userlen, INITGROUPS, &initgr_resp,
00083                              sizeof (initgr_resp));
00084       if (sock == -1)
00085        {
00086          /* nscd not running or wrong version.  */
00087          __nss_not_use_nscd_group = 1;
00088          goto out;
00089        }
00090     }
00091 
00092   if (initgr_resp.found == 1)
00093     {
00094       /* The following code assumes that gid_t and int32_t are the
00095         same size.  This is the case for al existing implementation.
00096         If this should change some code needs to be added which
00097         doesn't use memcpy but instead copies each array element one
00098         by one.  */
00099       assert (sizeof (int32_t) == sizeof (gid_t));
00100       assert (initgr_resp.ngrps >= 0);
00101 
00102       /* Make sure we have enough room.  We always count GROUP in even
00103         though we might not end up adding it.  */
00104       if (*size < initgr_resp.ngrps + 1)
00105        {
00106          gid_t *newp = realloc (*groupsp,
00107                              (initgr_resp.ngrps + 1) * sizeof (gid_t));
00108          if (newp == NULL)
00109            /* We cannot increase the buffer size.  */
00110            goto out_close;
00111 
00112          *groupsp = newp;
00113          *size = initgr_resp.ngrps + 1;
00114        }
00115 
00116       if (respdata == NULL)
00117        {
00118          /* Read the data from the socket.  */
00119          if ((size_t) __readall (sock, *groupsp, initgr_resp.ngrps
00120                                             * sizeof (gid_t))
00121              == initgr_resp.ngrps * sizeof (gid_t))
00122            retval = initgr_resp.ngrps;
00123        }
00124       else
00125        {
00126          /* Just copy the data.  */
00127          retval = initgr_resp.ngrps;
00128          memcpy (*groupsp, respdata, retval * sizeof (gid_t));
00129        }
00130     }
00131   else
00132     {
00133       if (__builtin_expect (initgr_resp.found == -1, 0))
00134        {
00135          /* The daemon does not cache this database.  */
00136          __nss_not_use_nscd_group = 1;
00137          goto out_close;
00138        }
00139 
00140       /* No group found yet.   */
00141       retval = 0;
00142 
00143       assert (*size >= 1);
00144     }
00145 
00146   /* Check whether GROUP is part of the mix.  If not, add it.  */
00147   if (retval >= 0)
00148     {
00149       int cnt;
00150       for (cnt = 0; cnt < retval; ++cnt)
00151        if ((*groupsp)[cnt] == group)
00152          break;
00153 
00154       if (cnt == retval)
00155        (*groupsp)[retval++] = group;
00156     }
00157 
00158  out_close:
00159   if (sock != -1)
00160     close_not_cancel_no_status (sock);
00161  out:
00162   if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
00163     {
00164       /* When we come here this means there has been a GC cycle while we
00165         were looking for the data.  This means the data might have been
00166         inconsistent.  Retry if possible.  */
00167       if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
00168        {
00169          /* nscd is just running gc now.  Disable using the mapping.  */
00170          if (atomic_decrement_val (&mapped->counter) == 0)
00171            __nscd_unmap (mapped);
00172          mapped = NO_MAPPING;
00173        }
00174 
00175       if (retval != -1)
00176        goto retry;
00177     }
00178 
00179   return retval;
00180 }