]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - inet/getnetgrent_r.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / inet / getnetgrent_r.c
index 91cdcce4681cd8210c5c34eefaf824d1557456da..53ae648ceddd782762a59bfbbd3c78b8f099efe6 100644 (file)
@@ -1,5 +1,4 @@
-/* Copyright (C) 1996,1997,1998,1999,2002,2004,2005,2007,2011
-       Free Software Foundation, Inc.
+/* Copyright (C) 1996-2015 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -13,9 +12,8 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 #include <assert.h>
 #include <atomic.h>
@@ -28,6 +26,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.  */
@@ -57,14 +56,18 @@ setup (void **fctp, service_user **nipp)
         same result every time.  So we need no locking.  */
       no_more = __nss_netgroup_lookup (nipp, "setnetgrent", fctp);
       startp = no_more ? (service_user *) -1 : *nipp;
+#ifdef PTR_MANGLE
       PTR_MANGLE (startp);
+#endif
       atomic_write_barrier ();
       startp_initialized = true;
     }
   else
     {
       service_user *nip = startp;
+#ifdef PTR_DEMANGLE
       PTR_DEMANGLE (nip);
+#endif
       if (nip == (service_user *) -1)
        /* No services at all.  */
        return 1;
@@ -101,7 +104,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");
@@ -168,19 +171,31 @@ __internal_setnetgrent_reuse (const char *group, struct __netgrent *datap,
   return status == NSS_STATUS_SUCCESS;
 }
 
-int internal_setnetgrent (const char *group, struct __netgrent *datap);
-libc_hidden_proto (internal_setnetgrent)
-
 int
-internal_setnetgrent (const char *group, struct __netgrent *datap)
+internal_function
+__internal_setnetgrent (const char *group, struct __netgrent *datap)
 {
   /* Free list of all netgroup names from last run.  */
   free_memory (datap);
 
   return __internal_setnetgrent_reuse (group, datap, &errno);
 }
-libc_hidden_def (internal_setnetgrent)
-strong_alias (internal_setnetgrent, __internal_setnetgrent)
+libc_hidden_def (__internal_setnetgrent)
+
+static int
+nscd_setnetgrent (const char *group)
+{
+#ifdef USE_NSCD
+  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])
+    return __nscd_setnetgrent (group, &dataset);
+#endif
+  return -1;
+}
 
 int
 setnetgrent (const char *group)
@@ -189,25 +204,24 @@ setnetgrent (const char *group)
 
   __libc_lock_lock (lock);
 
-  result = internal_setnetgrent (group, &dataset);
+  result = nscd_setnetgrent (group);
+  if (result < 0)
+    result = __internal_setnetgrent (group, &dataset);
 
   __libc_lock_unlock (lock);
 
   return result;
 }
 
-void internal_endnetgrent (struct __netgrent *datap);
-libc_hidden_proto (internal_endnetgrent)
-
 void
-internal_endnetgrent (struct __netgrent *datap)
+internal_function
+__internal_endnetgrent (struct __netgrent *datap)
 {
   endnetgrent_hook (datap);
   /* Now free list of all netgroup names from last run.  */
   free_memory (datap);
 }
-libc_hidden_def (internal_endnetgrent)
-strong_alias (internal_endnetgrent, __internal_endnetgrent)
+libc_hidden_def (__internal_endnetgrent)
 
 
 void
@@ -215,19 +229,42 @@ endnetgrent (void)
 {
   __libc_lock_lock (lock);
 
-  internal_endnetgrent (&dataset);
+  __internal_endnetgrent (&dataset);
 
   __libc_lock_unlock (lock);
 }
 
+#ifdef USE_NSCD
+static const char *
+get_nonempty_val (const char *in)
+{
+  if (*in == '\0')
+    return NULL;
+  return in;
+}
 
-int internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
-                           struct __netgrent *datap,
-                           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 = get_nonempty_val (datap->cursor);
+  datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
+  datap->val.triple.user = get_nonempty_val (datap->cursor);
+  datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
+  datap->val.triple.domain = get_nonempty_val (datap->cursor);
+  datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
+
+  return NSS_STATUS_SUCCESS;
+}
+#endif
 
 int
-internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
+internal_function
+__internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
                          struct __netgrent *datap,
                          char *buffer, size_t buflen, int *errnop)
 {
@@ -239,72 +276,88 @@ 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);
-  while (! no_more)
+  int no_more = datap->nip == NULL;
+  if (! no_more)
     {
-      status = DL_CALL_FCT (*fct, (datap, buffer, buflen, &errno));
+#ifdef USE_NSCD
+      /* This bogus function pointer is a special marker left by
+        __nscd_setnetgrent to tell us to use the data it left
+        before considering any modules.  */
+      if (datap->nip == (service_user *) -1l)
+       fct = nscd_getnetgrent;
+      else
+#endif
+       {
+         fct = __nss_lookup_function (datap->nip, "getnetgrent_r");
+         no_more = fct == NULL;
+       }
 
-      if (status == NSS_STATUS_RETURN)
+      while (! no_more)
        {
-         /* This was the last one for this group.  Look at next group
-            if available.  */
-         int found = 0;
-         while (datap->needed_groups != NULL && ! found)
+         status = DL_CALL_FCT (*fct, (datap, buffer, buflen, &errno));
+
+         if (status == NSS_STATUS_RETURN
+             /* The service returned a NOTFOUND, but there are more groups that
+                we need to resolve before we give up.  */
+             || (status == NSS_STATUS_NOTFOUND && datap->needed_groups != NULL))
            {
-             struct name_list *tmp = datap->needed_groups;
-             datap->needed_groups = datap->needed_groups->next;
-             tmp->next = datap->known_groups;
-             datap->known_groups = tmp;
+             /* This was the last one for this group.  Look at next group
+                if available.  */
+             int found = 0;
+             while (datap->needed_groups != NULL && ! found)
+               {
+                 struct name_list *tmp = datap->needed_groups;
+                 datap->needed_groups = datap->needed_groups->next;
+                 tmp->next = datap->known_groups;
+                 datap->known_groups = tmp;
 
-             found = __internal_setnetgrent_reuse (datap->known_groups->name,
-                                                   datap, errnop);
-           }
+                 found = __internal_setnetgrent_reuse (datap->known_groups->name,
+                                                       datap, errnop);
+               }
 
-         if (found && datap->nip != NULL)
-           {
-             fct = __nss_lookup_function (datap->nip, "getnetgrent_r");
-             if (fct != NULL)
-               continue;
+             if (found && datap->nip != NULL)
+               {
+                 fct = __nss_lookup_function (datap->nip, "getnetgrent_r");
+                 if (fct != NULL)
+                   continue;
+               }
            }
-       }
-      else if (status == NSS_STATUS_SUCCESS && datap->type == group_val)
-       {
-         /* The last entry was a name of another netgroup.  */
-         struct name_list *namep;
-
-         /* Ignore if we've seen the name before.  */
-         for (namep = datap->known_groups; namep != NULL;
-              namep = namep->next)
-           if (strcmp (datap->val.group, namep->name) == 0)
-             break;
-         if (namep == NULL)
-           for (namep = datap->needed_groups; namep != NULL;
-                namep = namep->next)
-             if (strcmp (datap->val.group, namep->name) == 0)
-               break
-         if (namep != NULL)
-           /* Really ignore.  */
-           continue;
-
-         size_t group_len = strlen (datap->val.group) + 1;
-         namep = (struct name_list *) malloc (sizeof (struct name_list)
-                                              + group_len);
-         if (namep == NULL)
-           /* We are out of memory.  */
-           status = NSS_STATUS_RETURN;
-         else
+         else if (status == NSS_STATUS_SUCCESS && datap->type == group_val)
            {
-             namep->next = datap->needed_groups;
-             memcpy (namep->name, datap->val.group, group_len);
-             datap->needed_groups = namep;
-             /* And get the next entry.  */
-             continue;
+             /* The last entry was a name of another netgroup.  */
+             struct name_list *namep;
+
+             /* Ignore if we've seen the name before.  */
+             for (namep = datap->known_groups; namep != NULL;
+                  namep = namep->next)
+               if (strcmp (datap->val.group, namep->name) == 0)
+                 break;
+             if (namep == NULL)
+               for (namep = datap->needed_groups; namep != NULL;
+                    namep = namep->next)
+                 if (strcmp (datap->val.group, namep->name) == 0)
+                   break;
+             if (namep != NULL)
+               /* Really ignore.  */
+               continue;
+
+             size_t group_len = strlen (datap->val.group) + 1;
+             namep = (struct name_list *) malloc (sizeof (struct name_list)
+                                                 + group_len);
+             if (namep == NULL)
+               /* We are out of memory.  */
+               status = NSS_STATUS_RETURN;
+             else
+               {
+                 namep->next = datap->needed_groups;
+                 memcpy (namep->name, datap->val.group, group_len);
+                 datap->needed_groups = namep;
+                 /* And get the next entry.  */
+                 continue;
+               }
            }
+         break;
        }
-
-      break;
     }
 
   if (status == NSS_STATUS_SUCCESS)
@@ -316,8 +369,7 @@ internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
 
   return status == NSS_STATUS_SUCCESS ? 1 : 0;
 }
-libc_hidden_def (internal_getnetgrent_r)
-strong_alias (internal_getnetgrent_r, __internal_getnetgrent_r)
+libc_hidden_def (__internal_getnetgrent_r)
 
 /* The real entry point.  */
 int
@@ -328,8 +380,8 @@ __getnetgrent_r (char **hostp, char **userp, char **domainp,
 
   __libc_lock_lock (lock);
 
-  status = internal_getnetgrent_r (hostp, userp, domainp, &dataset,
-                                  buffer, buflen, &errno);
+  status = __internal_getnetgrent_r (hostp, userp, domainp, &dataset,
+                                    buffer, buflen, &errno);
 
   __libc_lock_unlock (lock);
 
@@ -342,6 +394,20 @@ int
 innetgr (const char *netgroup, const char *host, const char *user,
         const char *domain)
 {
+#ifdef USE_NSCD
+  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;
+    }
+#endif
+
   union
   {
     enum nss_status (*f) (const char *, struct __netgrent *);
@@ -453,7 +519,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;
        }