Updated to fedora-glibc-20050208T0948
[kopensolaris-gnu/glibc.git] / nscd / nscd_getgr_r.c
index 3a66bb8..282912d 100644 (file)
@@ -18,6 +18,7 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <alloca.h>
 #include <assert.h>
 #include <errno.h>
 #include <grp.h>
@@ -66,15 +67,18 @@ __nscd_getgrgid_r (gid_t gid, struct group *resultbuf, char *buffer,
 }
 
 
-libc_locked_map_ptr (map_handle);
+libc_locked_map_ptr (,__gr_map_handle);
 /* Note that we only free the structure if necessary.  The memory
    mapping is not removed since it is not visible to the malloc
    handling.  */
 libc_freeres_fn (gr_map_free)
 {
-
-  if (map_handle.mapped != NO_MAPPING)
-    free (map_handle.mapped);
+  if (__gr_map_handle.mapped != NO_MAPPING)
+    {
+      void *p = __gr_map_handle.mapped;
+      __gr_map_handle.mapped = NO_MAPPING;
+      free (p);
+    }
 }
 
 
@@ -84,19 +88,22 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
              struct group *resultbuf, char *buffer, size_t buflen,
              struct group **result)
 {
-  const gr_response_header *gr_resp = NULL;
+  int gc_cycle;
   const uint32_t *len = NULL;
+  size_t lensize = 0;
+
+  /* If the mapping is available, try to search there instead of
+     communicating with the nscd.  */
+  struct mapped_database *mapped = __nscd_get_map_ref (GETFDGR, "group",
+                                                      &__gr_map_handle,
+                                                      &gc_cycle);
+ retry:;
+  const gr_response_header *gr_resp = NULL;
   const char *gr_name = NULL;
   size_t gr_name_len = 0;
   int retval = -1;
-  int gc_cycle;
   const char *recend = (const char *) ~UINTMAX_C (0);
 
-  /* If the mapping is available, try to search there instead of
-     communicating with the nscd.  */
-  struct mapped_database *mapped = __nscd_get_map_ref (GETFDGR, "group",
-                                                      &map_handle, &gc_cycle);
- retry:
   if (mapped != NO_MAPPING)
     {
       const struct datahead *found = __nscd_cache_search (type, key, keylen,
@@ -176,10 +183,17 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
       resultbuf->gr_gid = gr_resp->gr_gid;
 
       /* Read the length information, group name, and password.  */
-      if (len == NULL)
+      if (gr_name == NULL)
        {
          /* Allocate array to store lengths.  */
-         len = (uint32_t *) alloca (gr_resp->gr_mem_cnt * sizeof (uint32_t));
+         if (lensize == 0)
+           {
+             lensize = gr_resp->gr_mem_cnt * sizeof (uint32_t);
+             len = (uint32_t *) alloca (lensize);
+           }
+         else if (gr_resp->gr_mem_cnt * sizeof (uint32_t) > lensize)
+           len = extend_alloca (len, lensize,
+                                gr_resp->gr_mem_cnt * sizeof (uint32_t));
 
          vec[0].iov_base = (void *) len;
          vec[0].iov_len = gr_resp->gr_mem_cnt * sizeof (uint32_t);
@@ -195,7 +209,8 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
       else
        /* We already have the data.  Just copy the group name and
           password.  */
-       memcpy (resultbuf->gr_name, gr_name, gr_name_len);
+       memcpy (resultbuf->gr_name, gr_name,
+               gr_resp->gr_name_len + gr_resp->gr_passwd_len);
 
       /* Clear the terminating entry.  */
       resultbuf->gr_mem[gr_resp->gr_mem_cnt] = NULL;
@@ -233,6 +248,19 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
          /* Copy the group member names.  */
          memcpy (resultbuf->gr_mem[0], gr_name + gr_name_len, total_len);
 
+         /* Try to detect corrupt databases.  */
+         if (resultbuf->gr_name[gr_name_len - 1] != '\0'
+             || resultbuf->gr_passwd[gr_resp->gr_passwd_len - 1] != '\0'
+             || ({for (cnt = 0; cnt < gr_resp->gr_mem_cnt; ++cnt)
+                    if (resultbuf->gr_mem[cnt][len[cnt] - 1] != '\0')
+                      break;
+                  cnt < gr_resp->gr_mem_cnt; }))
+           {
+             /* We cannot use the database.  */
+             retval = -1;
+             goto out_close;
+           }
+
          *result = resultbuf;
        }
     }
@@ -248,11 +276,20 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
   if (sock != -1)
     close_not_cancel_no_status (sock);
  out:
-  if (__nscd_drop_map_ref (mapped, gc_cycle) != 0)
-    /* When we come here this means there has been a GC cycle while we
-       were looking for the data.  This means the data might have been
-       inconsistent.  Retry.  */
-    goto retry;
+  if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0 && retval != -1)
+    {
+      /* When we come here this means there has been a GC cycle while we
+        were looking for the data.  This means the data might have been
+        inconsistent.  Retry if possible.  */
+      if ((gc_cycle & 1) != 0)
+       {
+         /* nscd is just running gc now.  Disable using the mapping.  */
+         __nscd_unmap (mapped);
+         mapped = NO_MAPPING;
+       }
+
+      goto retry;
+    }
 
   return retval;
 }