Implement caching of nscd
[platform/upstream/glibc.git] / inet / getnetgrent_r.c
index 6aaba7b..8790387 100644 (file)
@@ -28,6 +28,7 @@
 #include "netgroup.h"
 #include "nsswitch.h"
 #include <sysdep.h>
+#include <nscd/nscd_proto.h>
 
 
 /* Protect above variable against multiple uses at the same time.  */
@@ -101,7 +102,7 @@ endnetgrent_hook (struct __netgrent *datap)
 {
   enum nss_status (*endfct) (struct __netgrent *);
 
-  if (datap->nip == NULL)
+  if (datap->nip == NULL || datap->nip == (service_user *) -1l)
     return;
 
   endfct = __nss_lookup_function (datap->nip, "endnetgrent");
@@ -189,8 +190,21 @@ setnetgrent (const char *group)
 
   __libc_lock_lock (lock);
 
+  if (__nss_not_use_nscd_netgroup > 0
+      && ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY)
+    __nss_not_use_nscd_netgroup = 0;
+
+  if (!__nss_not_use_nscd_netgroup
+      && !__nss_database_custom[NSS_DBSIDX_netgroup])
+    {
+      result = __nscd_setnetgrent (group, &dataset);
+      if (result >= 0)
+       goto out;
+    }
+
   result = internal_setnetgrent (group, &dataset);
 
+ out:
   __libc_lock_unlock (lock);
 
   return result;
@@ -226,6 +240,26 @@ int internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
                            char *buffer, size_t buflen, int *errnop);
 libc_hidden_proto (internal_getnetgrent_r)
 
+
+static enum nss_status
+nscd_getnetgrent (struct __netgrent *datap, char *buffer, size_t buflen,
+                 int *errnop)
+{
+  if (datap->cursor >= datap->data + datap->data_size)
+    return NSS_STATUS_UNAVAIL;
+
+  datap->type = triple_val;
+  datap->val.triple.host = datap->cursor;
+  datap->cursor = (char *) rawmemchr (datap->cursor, '\0') + 1;
+  datap->val.triple.user = datap->cursor;
+  datap->cursor = (char *) rawmemchr (datap->cursor, '\0') + 1;
+  datap->val.triple.domain = datap->cursor;
+  datap->cursor = (char *) rawmemchr (datap->cursor, '\0') + 1;
+
+  return NSS_STATUS_SUCCESS;
+}
+
+
 int
 internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
                          struct __netgrent *datap,
@@ -239,9 +273,18 @@ internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
   /* Run through available functions, starting with the same function last
      run.  We will repeat each function as long as it succeeds, and then go
      on to the next service action.  */
-  int no_more = (datap->nip == NULL
-                || (fct = __nss_lookup_function (datap->nip, "getnetgrent_r"))
-                   == NULL);
+  int no_more = datap->nip == NULL;
+  if (! no_more)
+    {
+      if (datap->nip == (service_user *) -1l)
+       fct = nscd_getnetgrent;
+      else
+       {
+         fct = __nss_lookup_function (datap->nip, "getnetgrent_r");
+         no_more = fct == NULL;
+       }
+    }
+
   while (! no_more)
     {
       status = DL_CALL_FCT (*fct, (datap, buffer, buflen, &errno));
@@ -342,6 +385,18 @@ int
 innetgr (const char *netgroup, const char *host, const char *user,
         const char *domain)
 {
+  if (__nss_not_use_nscd_netgroup > 0
+      && ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY)
+    __nss_not_use_nscd_netgroup = 0;
+
+  if (!__nss_not_use_nscd_netgroup
+      && !__nss_database_custom[NSS_DBSIDX_netgroup])
+    {
+      int result = __nscd_innetgr (netgroup, host, user, domain);
+      if (result >= 0)
+       return result;
+    }
+
   union
   {
     enum nss_status (*f) (const char *, struct __netgrent *);
@@ -453,7 +508,7 @@ innetgr (const char *netgroup, const char *host, const char *user,
          entry.needed_groups = tmp->next;
          tmp->next = entry.known_groups;
          entry.known_groups = tmp;
-         current_group = entry.known_groups->name;
+         current_group = tmp->name;
          continue;
        }