How to get LDAP support in NSS/compat?

Thorsten Kukuk kukuk@suse.de
Thu May 22 09:34:00 GMT 2003


On Tue, May 20, Thorsten Kukuk wrote:

> It took a little bit longer. Here is a patch for the compat passwd
> function. A patch for initgroups, group and shadow will follow, after
> I cleaned up this version. Some sanity and error checks are missing
> in this patch, but I think this is the way to go and it works already
> for passwd for me.
> 
> Feedback is welcome.
> 
> Uli, does this have a chance to be accepted for glibc as replacement
> for the current compat module? I think this is the way to go.

Next version of my patch. This time, passwd, shadow and group is
implemented. This should be the final version for this services.
Only initgroups_dyn is missing, I disabled it for now.

With this, everything should work.

  Thorsten

-- 
Thorsten Kukuk       http://www.suse.de/~kukuk/        kukuk@suse.de
SuSE Linux AG        Deutschherrnstr. 15-19        D-90429 Nuernberg
--------------------------------------------------------------------    
Key fingerprint = A368 676B 5E1B 3E46 CFCE  2D97 F8FD 4E23 56C6 FB4B
-------------- next part --------------
--- nis/nss_compat/compat-grp.c
+++ nis/nss_compat/compat-grp.c	2003/05/22 08:11:53
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996,1997,1998,1999,2001,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1996,1997,1998,1999,2001,2002, 2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
 
@@ -24,18 +24,20 @@
 #include <ctype.h>
 #include <bits/libc-lock.h>
 #include <string.h>
-#include <rpcsvc/yp.h>
-#include <rpcsvc/ypclnt.h>
-#include <rpcsvc/nis.h>
+#include <rpc/types.h>
 #include <nsswitch.h>
 
-#include "nss-nisplus.h"
-#include "nisplus-parser.h"
-
 static service_user *ni;
-static bool_t use_nisplus; /* default: group_compat: nis */
-static nis_name grptable; /* Name of the group table */
-static size_t grptablelen;
+static enum nss_status (*nss_setgrent)(int stayopen);
+static enum nss_status (*nss_getgrnam_r)(const char *name, struct group *grp,
+					 char *buffer, size_t buflen,
+					 int *errnop);
+static enum nss_status (*nss_getgrgid_r)(gid_t gid, struct group *grp,
+                                        char *buffer, size_t buflen,
+                                        int *errnop);
+static enum nss_status (*nss_getgrent_r)(struct group *grp, char *buffer,
+                                        size_t buflen, int *errnop);
+static enum nss_status (*nss_endgrent)(void);
 
 /* Get the declaration of the parser function.  */
 #define ENTNAME grent
@@ -55,17 +57,14 @@
 
 struct ent_t
   {
-    bool_t nis;
     bool_t nis_first;
-    char *oldkey;
-    int oldkeylen;
-    nis_result *result;
+    bool_t files;
     FILE *stream;
     struct blacklist_t blacklist;
 };
 typedef struct ent_t ent_t;
 
-static ent_t ext_ent = {0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0}};
+static ent_t ext_ent = {0, TRUE, NULL, {NULL, 0, 0}};
 
 /* Protect global state against multiple changers.  */
 __libc_lock_define_initialized (static, lock)
@@ -74,56 +73,27 @@
 static void blacklist_store_name (const char *, ent_t *);
 static int in_blacklist (const char *, int, ent_t *);
 
-static enum nss_status
-_nss_first_init (void)
+/* Initialize the NSS interface/functions. The calling function must
+   hold the lock.  */
+static void
+init_nss_interface (void)
 {
-  if (ni == NULL)
+  if (__nss_database_lookup ("group_compat", NULL, "nis", &ni) >= 0)
     {
-      __nss_database_lookup ("group_compat", NULL, "nis", &ni);
-      use_nisplus = (strcmp (ni->name, "nisplus") == 0);
+      nss_setgrent = __nss_lookup_function (ni, "setgrent");
+      nss_getgrnam_r = __nss_lookup_function (ni, "getgrnam_r");
+      nss_getgrgid_r = __nss_lookup_function (ni, "getgrgid_r");
+      nss_getgrent_r = __nss_lookup_function (ni, "getgrent_r");
+      nss_endgrent = __nss_lookup_function (ni, "endgrent");
     }
-
-  if (grptable == NULL)
-    {
-      static const char key[] = "group.org_dir.";
-      const char *local_dir = nis_local_directory ();
-      size_t len_local_dir = strlen (local_dir);
-
-      grptable = malloc (sizeof (key) + len_local_dir);
-      if (grptable == NULL)
-        return NSS_STATUS_TRYAGAIN;
-
-      grptablelen = ((char *) mempcpy (mempcpy (grptable,
-						key, sizeof (key) - 1),
-				       local_dir, len_local_dir + 1)
-		     - grptable) - 1;
-    }
-
-  return NSS_STATUS_SUCCESS;
 }
 
 static enum nss_status
-internal_setgrent (ent_t *ent)
+internal_setgrent (ent_t *ent, int stayopen)
 {
   enum nss_status status = NSS_STATUS_SUCCESS;
 
-  ent->nis = ent->nis_first = 0;
-
-  if (_nss_first_init () != NSS_STATUS_SUCCESS)
-    return NSS_STATUS_UNAVAIL;
-
-  if (ent->oldkey != NULL)
-    {
-      free (ent->oldkey);
-      ent->oldkey = NULL;
-      ent->oldkeylen = 0;
-    }
-
-  if (ent->result != NULL)
-    {
-      nis_freeresult (ent->result);
-      ent->result = NULL;
-    }
+  ent->files = TRUE;
 
   if (ent->blacklist.data != NULL)
     {
@@ -164,6 +134,9 @@
   else
     rewind (ent->stream);
 
+  if (status == NSS_STATUS_SUCCESS && nss_setgrent)
+    return nss_setgrent (stayopen);
+
   return status;
 }
 
@@ -175,7 +148,10 @@
 
   __libc_lock_lock (lock);
 
-  result = internal_setgrent (&ext_ent);
+  if (ni == NULL)
+    init_nss_interface ();
+
+    result = internal_setgrent (&ext_ent, stayopen);
 
   __libc_lock_unlock (lock);
 
@@ -186,27 +162,15 @@
 static enum nss_status
 internal_endgrent (ent_t *ent)
 {
+  if (nss_endgrent)
+    nss_endgrent();
+
   if (ent->stream != NULL)
     {
       fclose (ent->stream);
       ent->stream = NULL;
     }
 
-  ent->nis = ent->nis_first = 0;
-
-  if (ent->oldkey != NULL)
-    {
-      free (ent->oldkey);
-      ent->oldkey = NULL;
-      ent->oldkeylen = 0;
-    }
-
-  if (ent->result != NULL)
-    {
-      nis_freeresult (ent->result);
-      ent->result = NULL;
-    }
-
   if (ent->blacklist.data != NULL)
     {
       ent->blacklist.current = 1;
@@ -233,239 +197,44 @@
   return result;
 }
 
+/* get the next group from NSS  (+ entry) */
 static enum nss_status
-getgrent_next_nis (struct group *result, ent_t *ent, char *buffer,
+getgrent_next_nss (struct group *result, ent_t *ent, char *buffer,
 		   size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  char *domain;
-  char *outkey, *outval;
-  int outkeylen, outvallen, parse_res;
-  char *p;
-
-  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
-    {
-      ent->nis = 0;
-      return NSS_STATUS_NOTFOUND;
-    }
+  if (!nss_getgrent_r)
+    return NSS_STATUS_UNAVAIL;
 
   do
     {
-      char *save_oldkey;
-      int save_oldlen;
-      bool_t save_nis_first;
-
-      if (ent->nis_first)
-	{
-	  if (yp_first (domain, "group.byname", &outkey, &outkeylen,
-			&outval, &outvallen) != YPERR_SUCCESS)
-	    {
-	      ent->nis = 0;
-	      return NSS_STATUS_UNAVAIL;
-	    }
-
-	  if ( buflen < ((size_t) outvallen + 1))
-	    {
-	      free (outval);
-	      *errnop = ERANGE;
-	      return NSS_STATUS_TRYAGAIN;
-	    }
+      enum nss_status status;
 
-	  save_oldkey = ent->oldkey;
-	  save_oldlen = ent->oldkeylen;
-	  save_nis_first = TRUE;
-	  ent->oldkey = outkey;
-	  ent->oldkeylen = outkeylen;
-	  ent->nis_first = FALSE;
-	}
-      else
-	{
-	  if (yp_next (domain, "group.byname", ent->oldkey, ent->oldkeylen,
-		       &outkey, &outkeylen, &outval, &outvallen)
-	      != YPERR_SUCCESS)
-	    {
-	      ent->nis = 0;
-	      return NSS_STATUS_NOTFOUND;
-	    }
-
-	  if ( buflen < ((size_t) outvallen + 1))
-	    {
-	      free (outval);
-	      *errnop = ERANGE;
-	      return NSS_STATUS_TRYAGAIN;
-	    }
-
-	  save_oldkey = ent->oldkey;
-	  save_oldlen = ent->oldkeylen;
-	  save_nis_first = FALSE;
-	  ent->oldkey = outkey;
-	  ent->oldkeylen = outkeylen;
-	}
-
-      /* Copy the found data to our buffer...  */
-      p = strncpy (buffer, outval, buflen);
-
-      /* ...and free the data.  */
-      free (outval);
-
-      while (isspace (*p))
-	++p;
-
-      parse_res = _nss_files_parse_grent (p, result, data, buflen, errnop);
-      if (parse_res == -1)
-	{
-	  free (ent->oldkey);
-	  ent->oldkey = save_oldkey;
-	  ent->oldkeylen = save_oldlen;
-	  ent->nis_first = save_nis_first;
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      else
-	{
-	  if (!save_nis_first)
-	    free (save_oldkey);
-	}
-
-      if (parse_res &&
-	  in_blacklist (result->gr_name, strlen (result->gr_name), ent))
-	parse_res = 0; /* if result->gr_name in blacklist,search next entry */
+      if ((status = nss_getgrent_r (result, buffer, buflen, errnop)) !=
+          NSS_STATUS_SUCCESS)
+        return status;
     }
-  while (!parse_res);
-
-  return NSS_STATUS_SUCCESS;
-}
-
-static enum nss_status
-getgrent_next_nisplus (struct group *result, ent_t *ent, char *buffer,
-                       size_t buflen, int *errnop)
-{
-  int parse_res;
-
-  do
-    {
-      nis_result *save_oldres;
-      bool_t save_nis_first;
-
-      if (ent->nis_first)
-        {
-	  save_oldres = ent->result;
-	  save_nis_first = TRUE;
-          ent->result = nis_first_entry(grptable);
-          if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
-            {
-              ent->nis = 0;
-              return niserr2nss (ent->result->status);
-            }
-          ent->nis_first = FALSE;
-        }
-      else
-        {
-          nis_result *res;
-
-	  save_oldres = ent->result;
-	  save_nis_first = FALSE;
-          res = nis_next_entry(grptable, &ent->result->cookie);
-          ent->result = res;
-          if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
-            {
-	      ent->nis = 0;
-	      return niserr2nss (ent->result->status);
-            }
-        }
-      parse_res = _nss_nisplus_parse_grent (ent->result, 0, result,
-					    buffer, buflen, errnop);
-      if (parse_res == -1)
-	{
-	  nis_freeresult (ent->result);
-	  ent->result = save_oldres;
-	  ent->nis_first = save_nis_first;
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      else
-	{
-	  if (!save_nis_first)
-	    nis_freeresult (save_oldres);
-	}
-
-      if (parse_res &&
-          in_blacklist (result->gr_name, strlen (result->gr_name), ent))
-        parse_res = 0; /* if result->gr_name in blacklist,search next entry */
-    }
-  while (!parse_res);
+  while (in_blacklist (result->gr_name, strlen (result->gr_name), ent));
 
   return NSS_STATUS_SUCCESS;
 }
 
 /* This function handle the +group entrys in /etc/group */
 static enum nss_status
-getgrnam_plusgroup (const char *name, struct group *result, char *buffer,
-		    size_t buflen, int *errnop)
+getgrnam_plusgroup (const char *name, struct group *result, ent_t *ent,
+		    char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  int parse_res;
-
-  if (use_nisplus) /* Do the NIS+ query here */
-    {
-      nis_result *res;
-      char buf[strlen (name) + 24 + grptablelen];
-
-      sprintf(buf, "[name=%s],%s", name, grptable);
-      res = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
-      if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
-        {
-          enum nss_status status =  niserr2nss (res->status);
-
-          nis_freeresult (res);
-          return status;
-        }
-      parse_res = _nss_nisplus_parse_grent (res, 0, result, buffer, buflen,
-					    errnop);
-      if (parse_res == -1)
-	{
-	  nis_freeresult (res);
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      nis_freeresult (res);
-    }
-  else /* Use NIS */
-    {
-      char *domain, *outval, *p;
-      int outvallen;
-
-      if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
-	return NSS_STATUS_NOTFOUND;
-
-      if (yp_match (domain, "group.byname", name, strlen (name),
-		    &outval, &outvallen) != YPERR_SUCCESS)
-	return NSS_STATUS_NOTFOUND;
-
-      if (buflen < ((size_t) outvallen + 1))
-	{
-	  free (outval);
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
+  if (!nss_getgrnam_r)
+    return NSS_STATUS_UNAVAIL;
 
-      /* Copy the found data to our buffer...  */
-      p = strncpy (buffer, outval, buflen);
+  if (nss_getgrnam_r (name, result, buffer, buflen, errnop) !=
+      NSS_STATUS_SUCCESS)
+    return NSS_STATUS_NOTFOUND;
 
-      /* ... and free the data.  */
-      free (outval);
-      while (isspace (*p))
-        ++p;
-      parse_res = _nss_files_parse_grent (p, result, data, buflen, errnop);
-      if (parse_res == -1)
-	return NSS_STATUS_TRYAGAIN;
-    }
+  if (in_blacklist (result->gr_name, strlen (result->gr_name), ent))
+    return NSS_STATUS_NOTFOUND;
 
-  if (parse_res)
-    /* We found the entry.  */
-    return NSS_STATUS_SUCCESS;
-  else
-    return NSS_STATUS_RETURN;
+  /* We found the entry.  */
+  return NSS_STATUS_SUCCESS;
 }
 
 static enum nss_status
@@ -536,8 +305,8 @@
 	  /* Store the group in the blacklist for the "+" at the end of
 	     /etc/group */
 	  blacklist_store_name (&result->gr_name[1], ent);
-	  status = getgrnam_plusgroup (&result->gr_name[1], result, buffer,
-				       buflen, errnop);
+	  status = getgrnam_plusgroup (&result->gr_name[1], result, ent,
+				       buffer, buflen, errnop);
           if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
             break;
           else
@@ -559,13 +328,9 @@
       /* +:... */
       if (result->gr_name[0] == '+' && result->gr_name[1] == '\0')
 	{
-	  ent->nis = TRUE;
-	  ent->nis_first = TRUE;
+	  ent->files = FALSE;
 
-	  if (use_nisplus)
-	    return getgrent_next_nisplus (result, ent, buffer, buflen, errnop);
-	  else
-	    return getgrent_next_nis (result, ent, buffer, buflen, errnop);
+	  return getgrent_next_nss (result, ent, buffer, buflen, errnop);
 	}
     }
 
@@ -573,39 +338,31 @@
 }
 
 
-static enum nss_status
-internal_getgrent_r (struct group *gr, ent_t *ent, char *buffer,
-		     size_t buflen, int *errnop)
-{
-  if (ent->nis)
-    {
-      if (use_nisplus)
-	return getgrent_next_nisplus (gr, ent, buffer, buflen, errnop);
-      else
-	return getgrent_next_nis (gr, ent, buffer, buflen, errnop);
-    }
-  else
-    return getgrent_next_file (gr, ent, buffer, buflen, errnop);
-}
-
 enum nss_status
 _nss_compat_getgrent_r (struct group *grp, char *buffer, size_t buflen,
 			int *errnop)
 {
-  enum nss_status status = NSS_STATUS_SUCCESS;
+  enum nss_status result = NSS_STATUS_SUCCESS;
 
   __libc_lock_lock (lock);
 
   /* Be prepared that the setgrent function was not called before.  */
-  if (ext_ent.stream == NULL)
-    status = internal_setgrent (&ext_ent);
+  if (ni == NULL)
+    init_nss_interface ();
 
-  if (status == NSS_STATUS_SUCCESS)
-    status = internal_getgrent_r (grp, &ext_ent, buffer, buflen, errnop);
+  if (ext_ent.stream == NULL)
+    result = internal_setgrent (&ext_ent, 1);
 
+  if (result == NSS_STATUS_SUCCESS)
+    {
+      if (ext_ent.files)
+	result = getgrent_next_file (grp, &ext_ent, buffer, buflen, errnop);
+      else
+	result = getgrent_next_nss (grp, &ext_ent, buffer, buflen, errnop);
+    }
   __libc_lock_unlock (lock);
 
-  return status;
+  return result;
 }
 
 /* Searches in /etc/group and the NIS/NIS+ map for a special group */
@@ -681,8 +438,8 @@
 	    {
 	      enum nss_status status;
 
-	      status = getgrnam_plusgroup (name, result, buffer, buflen,
-					   errnop);
+	      status = getgrnam_plusgroup (name, result, ent,
+					   buffer, buflen, errnop);
 	      if (status == NSS_STATUS_RETURN)
 		/* We couldn't parse the entry */
 		continue;
@@ -695,7 +452,8 @@
 	{
 	  enum nss_status status;
 
-	  status = getgrnam_plusgroup (name, result, buffer, buflen, errnop);
+	  status = getgrnam_plusgroup (name, result, ent,
+				       buffer, buflen, errnop);
 	  if (status == NSS_STATUS_RETURN)
 	    /* We couldn't parse the entry */
 	    continue;
@@ -711,99 +469,27 @@
 _nss_compat_getgrnam_r (const char *name, struct group *grp,
 			char *buffer, size_t buflen, int *errnop)
 {
-  ent_t ent = {0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0}};
-  enum nss_status status;
+  ent_t ent = {0, TRUE, NULL, {NULL, 0, 0}};
+  enum nss_status result;
 
   if (name[0] == '-' || name[0] == '+')
     return NSS_STATUS_NOTFOUND;
 
   __libc_lock_lock (lock);
 
-  status = internal_setgrent (&ent);
+  if (ni == NULL)
+    init_nss_interface ();
 
   __libc_lock_unlock (lock);
 
-  if (status != NSS_STATUS_SUCCESS)
-    return status;
+  result = internal_setgrent (&ent, 0);
 
-  status = internal_getgrnam_r (name, grp, &ent, buffer, buflen, errnop);
+  if (result == NSS_STATUS_SUCCESS)
+    result = internal_getgrnam_r (name, grp, &ent, buffer, buflen, errnop);
 
   internal_endgrent (&ent);
 
-  return status;
-}
-
-/* This function handle the + entry in /etc/group */
-static enum nss_status
-getgrgid_plusgroup (gid_t gid, struct group *result, char *buffer,
-		    size_t buflen, int *errnop)
-{
-  struct parser_data *data = (void *) buffer;
-  int parse_res;
-
-  if (use_nisplus) /* Do the NIS+ query here */
-    {
-      nis_result *res;
-      char buf[24 + grptablelen];
-
-      sprintf(buf, "[gid=%lu],%s", (unsigned long int) gid, grptable);
-      res = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
-      if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
-        {
-          enum nss_status status =  niserr2nss (res->status);
-
-          nis_freeresult (res);
-          return status;
-        }
-      if ((parse_res = _nss_nisplus_parse_grent (res, 0, result, buffer,
-						 buflen, errnop)) == -1)
-	{
-	  nis_freeresult (res);
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      nis_freeresult (res);
-    }
-  else /* Use NIS */
-    {
-      char buf[24];
-      char *domain, *outval, *p;
-      int outvallen;
-
-      if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
-	return NSS_STATUS_NOTFOUND;
-
-      snprintf (buf, sizeof (buf), "%lu", (unsigned long int) gid);
-
-      if (yp_match (domain, "group.bygid", buf, strlen (buf),
-		    &outval, &outvallen) != YPERR_SUCCESS)
-	return NSS_STATUS_NOTFOUND;
-
-      if (buflen < ((size_t) outvallen + 1))
-	{
-	  free (outval);
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-
-      /* Copy the found data to our buffer...  */
-      p = strncpy (buffer, outval, buflen);
-
-      /* ... and free the data.  */
-      free (outval);
-
-      while (isspace (*p))
-        p++;
-      parse_res = _nss_files_parse_grent (p, result, data, buflen, errnop);
-      if (parse_res == -1)
-	return NSS_STATUS_TRYAGAIN;
-    }
-
-  if (parse_res)
-    /* We found the entry.  */
-    return NSS_STATUS_SUCCESS;
-  else
-    return NSS_STATUS_RETURN;
+  return result;
 }
 
 /* Searches in /etc/group and the NIS/NIS+ map for a special group id */
@@ -878,8 +564,8 @@
 	  /* Store the group in the blacklist for the "+" at the end of
              /etc/group */
           blacklist_store_name (&result->gr_name[1], ent);
-	  status = getgrnam_plusgroup (&result->gr_name[1], result, buffer,
-				      buflen, errnop);
+	  status = getgrnam_plusgroup (&result->gr_name[1], result, ent,
+				       buffer, buflen, errnop);
 	  if (status == NSS_STATUS_SUCCESS && result->gr_gid == gid)
 	    break;
 	  else
@@ -890,7 +576,7 @@
 	{
 	  enum nss_status status;
 
-	  status = getgrgid_plusgroup (gid, result, buffer, buflen, errnop);
+	  status = nss_getgrgid_r (gid, result, buffer, buflen, errnop);
 	  if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
 	    return NSS_STATUS_NOTFOUND;
 	  else
@@ -905,23 +591,24 @@
 _nss_compat_getgrgid_r (gid_t gid, struct group *grp,
 			char *buffer, size_t buflen, int *errnop)
 {
-  ent_t ent = {0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0}};
-  enum nss_status status;
+  ent_t ent = {0, TRUE, NULL, {NULL, 0, 0}};
+  enum nss_status result;
 
   __libc_lock_lock (lock);
 
-  status = internal_setgrent (&ent);
+  if (ni == NULL)
+    init_nss_interface ();
 
   __libc_lock_unlock (lock);
 
-  if (status != NSS_STATUS_SUCCESS)
-    return status;
+  result = internal_setgrent (&ent, 0);
 
-  status = internal_getgrgid_r (gid, grp, &ent, buffer, buflen, errnop);
+  if (result == NSS_STATUS_SUCCESS)
+    result = internal_getgrgid_r (gid, grp, &ent, buffer, buflen, errnop);
 
   internal_endgrent (&ent);
 
-  return status;
+  return result;
 }
 
 
--- nis/nss_compat/compat-initgroups.c
+++ nis/nss_compat/compat-initgroups.c	2003/05/22 08:14:06
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
 
@@ -17,6 +17,8 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#if 0 /* XXX this one needs to be rewritten.  */
+
 #include <errno.h>
 #include <fcntl.h>
 #include <nss.h>
@@ -718,3 +720,5 @@
   *cp = '\0';
   return strstr (ent->blacklist.data, buf) != NULL;
 }
+
+#endif
--- nis/nss_compat/compat-pwd.c
+++ nis/nss_compat/compat-pwd.c	2003/05/22 07:52:07
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996,1997,1998,1999,2001,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1996,1997,1998,1999,2001,2002,2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
 
@@ -24,20 +24,24 @@
 #include <fcntl.h>
 #include <netdb.h>
 #include <string.h>
-#include <bits/libc-lock.h>
-#include <rpcsvc/yp.h>
+#include <rpc/types.h>
 #include <rpcsvc/ypclnt.h>
-#include <rpcsvc/nis.h>
+#include <bits/libc-lock.h>
 #include <nsswitch.h>
 
 #include "netgroup.h"
-#include "nss-nisplus.h"
-#include "nisplus-parser.h"
 
 static service_user *ni;
-static bool_t use_nisplus; /* default: passwd_compat: nis */
-static nis_name pwdtable; /* Name of the pwd table */
-static size_t pwdtablelen;
+static enum nss_status (*nss_setpwent)(int stayopen);
+static enum nss_status (*nss_getpwnam_r)(const char *name, struct passwd *pwd,
+					 char *buffer, size_t buflen,
+					 int *errnop);
+static enum nss_status (*nss_getpwuid_r)(uid_t uid, struct passwd *pwd,
+					 char *buffer, size_t buflen,
+					 int *errnop);
+static enum nss_status (*nss_getpwent_r)(struct passwd *pwd, char *buffer,
+					 size_t buflen, int *errnop);
+static enum nss_status (*nss_endpwent)(void);
 
 /* Get the declaration of the parser function.  */
 #define ENTNAME pwent
@@ -58,11 +62,8 @@
 struct ent_t
   {
     bool_t netgroup;
-    bool_t nis;
     bool_t first;
-    char *oldkey;
-    int oldkeylen;
-    nis_result *result;
+    bool_t files;
     FILE *stream;
     struct blacklist_t blacklist;
     struct passwd pwd;
@@ -70,7 +71,7 @@
   };
 typedef struct ent_t ent_t;
 
-static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
+static ent_t ext_ent = {0, 0, TRUE, NULL, {NULL, 0, 0},
 			{NULL, NULL, 0, 0, NULL, NULL, NULL}};
 
 /* Protect global state against multiple changers.  */
@@ -80,6 +81,21 @@
 static void blacklist_store_name (const char *, ent_t *);
 static int in_blacklist (const char *, int, ent_t *);
 
+/* Initialize the NSS interface/functions. The calling function must
+   hold the lock.  */
+static void
+init_nss_interface (void)
+{
+  if (__nss_database_lookup ("passwd_compat", NULL, "nis", &ni) >= 0)
+    {
+      nss_setpwent = __nss_lookup_function (ni, "setpwent");
+      nss_getpwnam_r = __nss_lookup_function (ni, "getpwnam_r");
+      nss_getpwuid_r = __nss_lookup_function (ni, "getpwuid_r");
+      nss_getpwent_r = __nss_lookup_function (ni, "getpwent_r");
+      nss_endpwent = __nss_lookup_function (ni, "endpwent");
+    }
+}
+
 static void
 give_pwd_free (struct passwd *pwd)
 {
@@ -186,100 +202,17 @@
 }
 
 static enum nss_status
-insert_passwd_adjunct (char **result, int *len, char *domain, int *errnop)
-{
-  char *p1, *p2, *result2, *res;
-  int len2;
-  size_t namelen;
-
-  /* Check for adjunct style secret passwords.  They can be
-     recognized by a password starting with "##".  */
-  p1 = strchr (*result, ':');
-  if (p1 == NULL || p1[1] != '#' || p1[2] != '#')
-    return NSS_STATUS_SUCCESS;
-  p2 = strchr (p1 + 3, ':');
-
-  namelen = p2 - p1 - 3;
-
-  if (yp_match (domain, "passwd.adjunct.byname", &p1[3], namelen,
-		&result2, &len2) == YPERR_SUCCESS)
-    {
-      /* We found a passwd.adjunct entry.  Merge encrypted
-	 password therein into original result.  */
-      char *encrypted = strchr (result2, ':');
-      char *endp;
-      size_t restlen;
-
-      if (encrypted == NULL || (endp = strchr (++encrypted, ':')) == NULL)
-	{
-	  /* Invalid format of the entry.  This never should happen
-	     unless the data from which the NIS table is generated is
-	     wrong.  We simply ignore it.  */
-	  free (result2);
-	  return NSS_STATUS_SUCCESS;
-	}
-
-      restlen = *len - (p2 - *result);
-      if ((res = malloc (namelen + restlen + (endp - encrypted) + 2)) == NULL)
-	{
-	  free (result2);
-	  return NSS_STATUS_TRYAGAIN;
-	}
-
-      __mempcpy (__mempcpy (__mempcpy (__mempcpy
-				       (res, *result, (p1 - *result)),
-				       ":", 1),
-			    encrypted, endp - encrypted),
-		 p2, restlen + 1);
-
-      free (result2);
-      free (*result);
-      *result = res;
-      *len = strlen (res);
-    }
-  return NSS_STATUS_SUCCESS;
-}
-
-static enum nss_status
-internal_setpwent (ent_t *ent)
+internal_setpwent (ent_t *ent, int stayopen)
 {
   enum nss_status status = NSS_STATUS_SUCCESS;
 
-  ent->nis = ent->first = ent->netgroup = 0;
+  ent->first = ent->netgroup = FALSE;
+  ent->files = TRUE;
 
   /* If something was left over free it.  */
   if (ent->netgroup)
     __internal_endnetgrent (&ent->netgrdata);
 
-  if (ent->oldkey != NULL)
-    {
-      free (ent->oldkey);
-      ent->oldkey = NULL;
-      ent->oldkeylen = 0;
-    }
-
-  if (ent->result != NULL)
-    {
-      nis_freeresult (ent->result);
-      ent->result = NULL;
-    }
-
-  if (pwdtable == NULL)
-    {
-      static const char key[] = "passwd.org_dir.";
-      const char *local_dir = nis_local_directory ();
-      size_t len_local_dir = strlen (local_dir);
-
-      pwdtable = malloc (sizeof (key) + len_local_dir);
-      if (pwdtable == NULL)
-        return NSS_STATUS_TRYAGAIN;
-
-      pwdtablelen = ((char *) mempcpy (mempcpy (pwdtable,
-						key, sizeof (key) - 1),
-				       local_dir, len_local_dir + 1)
-		     - pwdtable) - 1;
-    }
-
   if (ent->blacklist.data != NULL)
     {
       ent->blacklist.current = 1;
@@ -321,6 +254,9 @@
 
   give_pwd_free (&ent->pwd);
 
+  if (status == NSS_STATUS_SUCCESS && nss_setpwent)
+    return nss_setpwent (stayopen);
+
   return status;
 }
 
@@ -333,12 +269,9 @@
   __libc_lock_lock (lock);
 
   if (ni == NULL)
-    {
-      __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
-      use_nisplus = (strcmp (ni->name, "nisplus") == 0);
-    }
+    init_nss_interface ();
 
-  result = internal_setpwent (&ext_ent);
+  result = internal_setpwent (&ext_ent, stayopen);
 
   __libc_lock_unlock (lock);
 
@@ -349,6 +282,9 @@
 static enum nss_status
 internal_endpwent (ent_t *ent)
 {
+  if (nss_endpwent)
+    nss_endpwent();
+
   if (ent->stream != NULL)
     {
       fclose (ent->stream);
@@ -358,26 +294,13 @@
   if (ent->netgroup)
     __internal_endnetgrent (&ent->netgrdata);
 
-  ent->nis = ent->first = ent->netgroup = 0;
-
-  if (ent->oldkey != NULL)
-    {
-      free (ent->oldkey);
-      ent->oldkey = NULL;
-      ent->oldkeylen = 0;
-    }
-
-  if (ent->result != NULL)
-    {
-      nis_freeresult (ent->result);
-      ent->result = NULL;
-    }
+  ent->first = ent->netgroup = FALSE;
 
   if (ent->blacklist.data != NULL)
     {
       ent->blacklist.current = 1;
       ent->blacklist.data[0] = '|';
-     ent->blacklist.data[1] = '\0';
+      ent->blacklist.data[1] = '\0';
     }
   else
     ent->blacklist.current = 0;
@@ -401,19 +324,24 @@
   return result;
 }
 
+
 static enum nss_status
-getpwent_next_nis_netgr (const char *name, struct passwd *result, ent_t *ent,
+getpwent_next_nss_netgr (const char *name, struct passwd *result, ent_t *ent,
 			 char *group, char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  char *ypdomain, *host, *user, *domain, *outval, *p, *p2;
-  int status, outvallen;
+  char *curdomain, *host, *user, *domain, *p2;
+  int status;
   size_t p2len;
 
-  if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
+  /* Leave function if NSS module does not support getpwnam_r,
+     we need this function here.  */
+  if (!nss_getpwnam_r)
+    return NSS_STATUS_UNAVAIL;
+
+  if (yp_get_default_domain (&curdomain) != YPERR_SUCCESS)
     {
-      ent->netgroup = 0;
-      ent->first = 0;
+      ent->netgroup = FALSE;
+      ent->first = FALSE;
       give_pwd_free (&ent->pwd);
       return NSS_STATUS_UNAVAIL;
     }
@@ -428,7 +356,6 @@
   while (1)
     {
       char *saved_cursor;
-      int parse_res;
 
       saved_cursor = ent->netgrdata.cursor;
       status = __internal_getnetgrent_r (&host, &user, &domain,
@@ -445,7 +372,7 @@
       if (user == NULL || user[0] == '-')
 	continue;
 
-      if (domain != NULL && strcmp (ypdomain, domain) != 0)
+      if (domain != NULL && strcmp (curdomain, domain) != 0)
 	continue;
 
       /* If name != NULL, we are called from getpwnam.  */
@@ -453,148 +380,23 @@
 	if (strcmp (user, name) != 0)
 	  continue;
 
-      if (yp_match (ypdomain, "passwd.byname", user,
-		    strlen (user), &outval, &outvallen)
-	  != YPERR_SUCCESS)
-	continue;
-
-      if (insert_passwd_adjunct (&outval, &outvallen, ypdomain, errnop)
-	  != NSS_STATUS_SUCCESS)
-	{
-	  free (outval);
-	  return NSS_STATUS_TRYAGAIN;
-	}
-
       p2len = pwd_need_buflen (&ent->pwd);
       if (p2len > buflen)
 	{
-	  free (outval);
 	  *errnop = ERANGE;
 	  return NSS_STATUS_TRYAGAIN;
 	}
       p2 = buffer + (buflen - p2len);
       buflen -= p2len;
 
-      if (buflen < ((size_t) outvallen + 1))
-	{
-	  free (outval);
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      p = strncpy (buffer, outval, buflen);
-
-      while (isspace (*p))
-	p++;
-      free (outval);
-      parse_res = _nss_files_parse_pwent (p, result, data, buflen, errnop);
-      if (parse_res == -1)
-	{
-	  ent->netgrdata.cursor = saved_cursor;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-
-      if (parse_res && !in_blacklist (result->pw_name,
-				      strlen (result->pw_name), ent))
-	{
-	  /* Store the User in the blacklist for the "+" at the end of
-	     /etc/passwd */
-	  blacklist_store_name (result->pw_name, ent);
-	  copy_pwd_changes (result, &ent->pwd, p2, p2len);
-	  break;
-	}
-    }
-
-  return NSS_STATUS_SUCCESS;
-}
-
-static enum nss_status
-getpwent_next_nisplus_netgr (const char *name, struct passwd *result,
-			     ent_t *ent, char *group, char *buffer,
-			     size_t buflen, int *errnop)
-{
-  char *ypdomain, *host, *user, *domain, *p2;
-  int status, parse_res;
-  size_t p2len;
-  nis_result *nisres;
-
-  /* Maybe we should use domainname here ? We need the current
-     domainname for the domain field in netgroups */
-  if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
-    {
-      ent->netgroup = 0;
-      ent->first = 0;
-      give_pwd_free (&ent->pwd);
-      return NSS_STATUS_UNAVAIL;
-    }
-
-  if (ent->first == TRUE)
-    {
-      bzero (&ent->netgrdata, sizeof (struct __netgrent));
-      __internal_setnetgrent (group, &ent->netgrdata);
-      ent->first = FALSE;
-    }
-
-  while (1)
-    {
-      char *saved_cursor;
-
-      saved_cursor = ent->netgrdata.cursor;
-      status = __internal_getnetgrent_r (&host, &user, &domain,
-					 &ent->netgrdata, buffer, buflen,
-					 errnop);
-      if (status != 1)
-	{
-	  __internal_endnetgrent (&ent->netgrdata);
-	  ent->netgroup = 0;
-	  give_pwd_free (&ent->pwd);
-	  return NSS_STATUS_RETURN;
-	}
-
-      if (user == NULL || user[0] == '-')
+      if (nss_getpwnam_r (user, result, buffer, buflen, errnop) !=
+	  NSS_STATUS_SUCCESS)
 	continue;
 
-      if (domain != NULL && strcmp (ypdomain, domain) != 0)
-	continue;
-
-      /* If name != NULL, we are called from getpwnam */
-      if (name != NULL)
-	if (strcmp (user, name) != 0)
-	  continue;
-
-      p2len = pwd_need_buflen (&ent->pwd);
-      if (p2len > buflen)
-	{
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      p2 = buffer + (buflen - p2len);
-      buflen -= p2len;
-      {
-	char buf[strlen (user) + 30 + pwdtablelen];
-	sprintf(buf, "[name=%s],%s", user, pwdtable);
-	nisres = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
-      }
-      if (niserr2nss (nisres->status) != NSS_STATUS_SUCCESS)
-	{
-	  nis_freeresult (nisres);
-	  continue;
-	}
-      parse_res = _nss_nisplus_parse_pwent (nisres, result, buffer,
-					    buflen, errnop);
-      if (parse_res == -1)
-	{
-	  nis_freeresult (nisres);
-	  ent->netgrdata.cursor = saved_cursor;
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      nis_freeresult (nisres);
-
-      if (parse_res && !in_blacklist (result->pw_name,
-				      strlen (result->pw_name), ent))
+      if (!in_blacklist (result->pw_name, strlen (result->pw_name), ent))
 	{
-	  /* Store the User in the blacklist for the "+" at the end of
-	     /etc/passwd */
+	  /* Store the User in the blacklist for possible the "+" at the
+	     end of /etc/passwd */
 	  blacklist_store_name (result->pw_name, ent);
 	  copy_pwd_changes (result, &ent->pwd, p2, p2len);
 	  break;
@@ -604,100 +406,18 @@
   return NSS_STATUS_SUCCESS;
 }
 
-/* get the next user from NIS+  (+ entry) */
+/* get the next user from NSS  (+ entry) */
 static enum nss_status
-getpwent_next_nisplus (struct passwd *result, ent_t *ent, char *buffer,
-		       size_t buflen, int *errnop)
-{
-  int parse_res;
-  size_t p2len;
-  char *p2;
-
-  p2len = pwd_need_buflen (&ent->pwd);
-  if (p2len > buflen)
-    {
-      *errnop = ERANGE;
-      return NSS_STATUS_TRYAGAIN;
-    }
-  p2 = buffer + (buflen - p2len);
-  buflen -= p2len;
-  do
-    {
-      bool_t saved_first;
-      nis_result *saved_res;
-
-      if (ent->first)
-	{
-	  saved_first = TRUE;
-	  saved_res = ent->result;
-
-	  ent->result = nis_first_entry (pwdtable);
-          if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
-	    {
-	      ent->nis = 0;
-	      give_pwd_free (&ent->pwd);
-	      return niserr2nss (ent->result->status);
-	    }
-	  ent->first = FALSE;
-	}
-      else
-	{
-	  nis_result *res;
-
-	  res = nis_next_entry (pwdtable, &ent->result->cookie);
-	  saved_res = ent->result;
-	  saved_first = FALSE;
-	  ent->result = res;
-	  if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
-	    {
-	      ent->nis = 0;
-	      nis_freeresult (saved_res);
-	      give_pwd_free (&ent->pwd);
-	      return niserr2nss (ent->result->status);
-	    }
-	}
-      parse_res = _nss_nisplus_parse_pwent (ent->result, result, buffer,
-					    buflen, errnop);
-      if (parse_res == -1)
-	{
-	  nis_freeresult (ent->result);
-	  ent->result = saved_res;
-	  ent->first = saved_first;
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      else
-	{
-	  if (!saved_first)
-	    nis_freeresult (saved_res);
-	}
-
-      if (parse_res &&
-	  in_blacklist (result->pw_name, strlen (result->pw_name), ent))
-	parse_res = 0; /* if result->pw_name in blacklist,search next entry */
-    }
-  while (!parse_res);
-
-  copy_pwd_changes (result, &ent->pwd, p2, p2len);
-
-  return NSS_STATUS_SUCCESS;
-}
-
-static enum nss_status
-getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer,
+getpwent_next_nss (struct passwd *result, ent_t *ent, char *buffer,
 		   size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  char *domain, *outkey, *outval, *p, *p2;
-  int outkeylen, outvallen, parse_res;
+  enum nss_status status;
+  char *p2;
   size_t p2len;
 
-  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
-    {
-      ent->nis = 0;
-      give_pwd_free (&ent->pwd);
-      return NSS_STATUS_UNAVAIL;
-    }
+  /* Return if NSS module does not support getpwent_r.  */
+  if (!nss_getpwent_r)
+    return NSS_STATUS_UNAVAIL;
 
   p2len = pwd_need_buflen (&ent->pwd);
   if (p2len > buflen)
@@ -707,103 +427,17 @@
     }
   p2 = buffer + (buflen - p2len);
   buflen -= p2len;
-  do
-    {
-      bool_t saved_first;
-      char *saved_oldkey;
-      int saved_oldlen;
-
-      if (ent->first)
-	{
-	  if (yp_first (domain, "passwd.byname", &outkey, &outkeylen,
-			&outval, &outvallen) != YPERR_SUCCESS)
-	    {
-	      ent->nis = 0;
-	      give_pwd_free (&ent->pwd);
-	      return NSS_STATUS_UNAVAIL;
-	    }
-
-	  if (insert_passwd_adjunct (&outval, &outvallen, domain, errnop) !=
-	      NSS_STATUS_SUCCESS)
-	    {
-	      free (outval);
-	      return NSS_STATUS_TRYAGAIN;
-	    }
-
-	  if (buflen < ((size_t) outvallen + 1))
-	    {
-	      free (outval);
-	      *errnop = ERANGE;
-	      return NSS_STATUS_TRYAGAIN;
-	    }
-
-	  saved_first = TRUE;
-	  saved_oldkey = ent->oldkey;
-	  saved_oldlen = ent->oldkeylen;
-	  ent->oldkey = outkey;
-	  ent->oldkeylen = outkeylen;
-	  ent->first = FALSE;
-	}
-      else
-	{
-	  if (yp_next (domain, "passwd.byname", ent->oldkey, ent->oldkeylen,
-		       &outkey, &outkeylen, &outval, &outvallen)
-	      != YPERR_SUCCESS)
-	    {
-	      ent->nis = 0;
-	      give_pwd_free (&ent->pwd);
-	      return NSS_STATUS_NOTFOUND;
-	    }
 
-	  if (insert_passwd_adjunct (&outval, &outvallen, domain, errnop)
-	      != NSS_STATUS_SUCCESS)
-	    {
-	      free (outval);
-	      return NSS_STATUS_TRYAGAIN;
-	    }
+  if (ent->first)
+    ent->first = FALSE;
 
-	  if (buflen < ((size_t) outvallen + 1))
-	    {
-	      free (outval);
-	      *errnop = ERANGE;
-	      return NSS_STATUS_TRYAGAIN;
-	    }
-
-	  saved_first = FALSE;
-	  saved_oldkey = ent->oldkey;
-	  saved_oldlen = ent->oldkeylen;
-	  ent->oldkey = outkey;
-	  ent->oldkeylen = outkeylen;
-	}
-
-      /* Copy the found data to our buffer  */
-      p = strncpy (buffer, outval, buflen);
-
-      /* ...and free the data.  */
-      free (outval);
-
-      while (isspace (*p))
-	++p;
-      parse_res = _nss_files_parse_pwent (p, result, data, buflen, errnop);
-      if (parse_res == -1)
-	{
-	  free (ent->oldkey);
-	  ent->oldkey = saved_oldkey;
-	  ent->oldkeylen = saved_oldlen;
-	  ent->first = saved_first;
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      else
-	{
-	  if (!saved_first)
-	    free (saved_oldkey);
-	}
-      if (parse_res
-	  && in_blacklist (result->pw_name, strlen (result->pw_name), ent))
-	parse_res = 0;
+  do
+    {
+      if ((status = nss_getpwent_r (result, buffer, buflen, errnop)) !=
+	  NSS_STATUS_SUCCESS)
+	return status;
     }
-  while (!parse_res);
+  while (in_blacklist (result->pw_name, strlen (result->pw_name), ent));
 
   copy_pwd_changes (result, &ent->pwd, p2, p2len);
 
@@ -815,12 +449,13 @@
 getpwnam_plususer (const char *name, struct passwd *result, ent_t *ent,
 		   char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
   struct passwd pwd;
-  int parse_res;
   char *p;
   size_t plen;
 
+  if (!nss_getpwnam_r)
+    return NSS_STATUS_UNAVAIL;
+
   memset (&pwd, '\0', sizeof (struct passwd));
 
   copy_pwd_changes (&pwd, result, NULL, 0);
@@ -834,88 +469,17 @@
   p = buffer + (buflen - plen);
   buflen -= plen;
 
-  if (use_nisplus) /* Do the NIS+ query here */
-    {
-      nis_result *res;
-      char buf[strlen (name) + 24 + pwdtablelen];
-
-      sprintf(buf, "[name=%s],%s", name, pwdtable);
-      res = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
-      if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
-	{
-	  enum nss_status status =  niserr2nss (res->status);
-
-	  nis_freeresult (res);
-	  return status;
-	}
-      parse_res = _nss_nisplus_parse_pwent (res, result, buffer,
-					    buflen, errnop);
-
-      nis_freeresult (res);
-
-      if (parse_res == -1)
-	{
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-
-      if (in_blacklist (result->pw_name, strlen (result->pw_name), ent))
-	return NSS_STATUS_NOTFOUND;
-    }
-  else /* Use NIS */
-    {
-      char *domain, *outval, *ptr;
-      int outvallen;
-
-      if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
-	return NSS_STATUS_NOTFOUND;
-
-      if (yp_match (domain, "passwd.byname", name, strlen (name),
-		    &outval, &outvallen) != YPERR_SUCCESS)
-	return NSS_STATUS_NOTFOUND;
-
-      if (insert_passwd_adjunct (&outval, &outvallen, domain, errnop)
-	  != NSS_STATUS_SUCCESS)
-	{
-	  free (outval);
-	  return NSS_STATUS_TRYAGAIN;
-	}
-
-      if (buflen < ((size_t) outvallen + 1))
-	{
-	  free (outval);
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-
-      ptr = strncpy (buffer, outval, buflen);
-      free (outval);
-
-      while (isspace (*ptr))
-	ptr++;
-
-      parse_res = _nss_files_parse_pwent (ptr, result, data, buflen, errnop);
-      if (parse_res == -1)
-	return NSS_STATUS_TRYAGAIN;
+  if (nss_getpwnam_r (name, result, buffer, buflen, errnop) !=
+      NSS_STATUS_SUCCESS)
+    return NSS_STATUS_NOTFOUND;
 
-      if (in_blacklist (result->pw_name, strlen (result->pw_name), ent))
-	return NSS_STATUS_NOTFOUND;
-    }
+  if (in_blacklist (result->pw_name, strlen (result->pw_name), ent))
+    return NSS_STATUS_NOTFOUND;
 
-  if (parse_res > 0)
-    {
-      copy_pwd_changes (result, &pwd, p, plen);
-      give_pwd_free (&pwd);
-      /* We found the entry.  */
-      return NSS_STATUS_SUCCESS;
-    }
-  else
-    {
-      /* Give buffer the old len back */
-      buflen += plen;
-      give_pwd_free (&pwd);
-    }
-  return NSS_STATUS_RETURN;
+  copy_pwd_changes (result, &pwd, p, plen);
+  give_pwd_free (&pwd);
+  /* We found the entry.  */
+  return NSS_STATUS_SUCCESS;
 }
 
 static enum nss_status
@@ -1000,14 +564,9 @@
 	  ent->first = TRUE;
 	  copy_pwd_changes (&ent->pwd, result, NULL, 0);
 
-	  if (use_nisplus)
-	    status =  getpwent_next_nisplus_netgr (NULL, result, ent,
-						   &result->pw_name[2],
-						   buffer, buflen, errnop);
-	  else
-	    status =  getpwent_next_nis_netgr (NULL, result, ent,
-					       &result->pw_name[2],
-					       buffer, buflen, errnop);
+	  status =  getpwent_next_nss_netgr (NULL, result, ent,
+					     &result->pw_name[2],
+					     buffer, buflen, errnop);
 	  if (status == NSS_STATUS_RETURN)
 	    continue;
 	  else
@@ -1057,14 +616,11 @@
       /* +:... */
       if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
 	{
-	  ent->nis = TRUE;
+	  ent->files = FALSE;
 	  ent->first = TRUE;
 	  copy_pwd_changes (&ent->pwd, result, NULL, 0);
 
-	  if (use_nisplus)
-	    return getpwent_next_nisplus (result, ent, buffer, buflen, errnop);
-	  else
-	    return getpwent_next_nis (result, ent, buffer, buflen, errnop);
+	  return getpwent_next_nss (result, ent, buffer, buflen, errnop);
 	}
     }
 
@@ -1082,53 +638,42 @@
 
       /* We are searching members in a netgroup */
       /* Since this is not the first call, we don't need the group name */
-      if (use_nisplus)
-	status = getpwent_next_nisplus_netgr (NULL, pw, ent, NULL, buffer,
-					      buflen, errnop);
-      else
-	status = getpwent_next_nis_netgr (NULL, pw, ent, NULL, buffer, buflen,
-					  errnop);
+      status = getpwent_next_nss_netgr (NULL, pw, ent, NULL, buffer, buflen,
+					errnop);
       if (status == NSS_STATUS_RETURN)
 	return getpwent_next_file (pw, ent, buffer, buflen, errnop);
       else
 	return status;
     }
   else
-    if (ent->nis)
-      {
-	if (use_nisplus)
-	  return getpwent_next_nisplus (pw, ent, buffer, buflen, errnop);
-	else
-	  return getpwent_next_nis (pw, ent, buffer, buflen, errnop);
-      }
-    else
+    if (ent->files)
       return getpwent_next_file (pw, ent, buffer, buflen, errnop);
+    else
+      return getpwent_next_nss (pw, ent, buffer, buflen, errnop);
+
 }
 
 enum nss_status
 _nss_compat_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen,
 			int *errnop)
 {
-  enum nss_status status = NSS_STATUS_SUCCESS;
+  enum nss_status result = NSS_STATUS_SUCCESS;
 
   __libc_lock_lock (lock);
 
+  /* Be prepared that the setpwent function was not called before.  */
   if (ni == NULL)
-    {
-      __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
-      use_nisplus = (strcmp (ni->name, "nisplus") == 0);
-    }
+    init_nss_interface ();
 
-  /* Be prepared that the setpwent function was not called before.  */
   if (ext_ent.stream == NULL)
-    status = internal_setpwent (&ext_ent);
+    result = internal_setpwent (&ext_ent, 1);
 
-  if (status == NSS_STATUS_SUCCESS)
-    status = internal_getpwent_r (pwd, &ext_ent, buffer, buflen, errnop);
+  if (result == NSS_STATUS_SUCCESS)
+    result = internal_getpwent_r (pwd, &ext_ent, buffer, buflen, errnop);
 
   __libc_lock_unlock (lock);
 
-  return status;
+  return result;
 }
 
 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
@@ -1269,9 +814,9 @@
 _nss_compat_getpwnam_r (const char *name, struct passwd *pwd,
 			char *buffer, size_t buflen, int *errnop)
 {
-  ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
+  enum nss_status result;
+  ent_t ent = {0, 0, TRUE, NULL, {NULL, 0, 0},
 	       {NULL, NULL, 0, 0, NULL, NULL, NULL}};
-  enum nss_status status;
 
   if (name[0] == '-' || name[0] == '+')
     return NSS_STATUS_NOTFOUND;
@@ -1279,35 +824,32 @@
   __libc_lock_lock (lock);
 
   if (ni == NULL)
-    {
-      __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
-      use_nisplus = (strcmp (ni->name, "nisplus") == 0);
-    }
+    init_nss_interface ();
 
   __libc_lock_unlock (lock);
 
-  status = internal_setpwent (&ent);
-  if (status != NSS_STATUS_SUCCESS)
-    return status;
+  result = internal_setpwent (&ent, 0);
 
-  status = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop);
+  if (result == NSS_STATUS_SUCCESS)
+    result = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop);
 
   internal_endpwent (&ent);
 
-  return status;
+  return result;
 }
 
 /* This function handle the + entry in /etc/passwd for getpwuid */
 static enum nss_status
 getpwuid_plususer (uid_t uid, struct passwd *result, char *buffer,
-                   size_t buflen, int *errnop)
+		   size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
   struct passwd pwd;
-  int parse_res;
   char *p;
   size_t plen;
 
+  if (!nss_getpwuid_r)
+    return NSS_STATUS_UNAVAIL;
+
   memset (&pwd, '\0', sizeof (struct passwd));
 
   copy_pwd_changes (&pwd, result, NULL, 0);
@@ -1321,70 +863,8 @@
   p = buffer + (buflen - plen);
   buflen -= plen;
 
-  if (use_nisplus) /* Do the NIS+ query here */
-    {
-      nis_result *res;
-      char buf[1024 + pwdtablelen];
-
-      snprintf (buf, sizeof (buf), "[uid=%lu],%s", (unsigned long int) uid,
-                pwdtable);
-      res = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
-      if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
-        {
-          enum nss_status status =  niserr2nss (res->status);
-
-          nis_freeresult (res);
-          return status;
-        }
-      if ((parse_res = _nss_nisplus_parse_pwent (res, result, buffer,
-                                                 buflen, errnop)) == -1)
-        {
-          nis_freeresult (res);
-          *errnop = ERANGE;
-          return NSS_STATUS_TRYAGAIN;
-        }
-      nis_freeresult (res);
-    }
-  else /* Use NIS */
-    {
-      char buf[1024];
-      char *domain, *outval, *ptr;
-      int outvallen;
-
-      if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
-	return NSS_STATUS_NOTFOUND;
-
-      sprintf (buf, "%lu", (unsigned long int) uid);
-      if (yp_match (domain, "passwd.byuid", buf, strlen (buf),
-                    &outval, &outvallen)
-          != YPERR_SUCCESS)
-	return NSS_STATUS_NOTFOUND;
-
-      if (insert_passwd_adjunct (&outval, &outvallen, domain, errnop)
-          != NSS_STATUS_SUCCESS)
-        {
-          free (outval);
-          return NSS_STATUS_TRYAGAIN;
-        }
-
-      if (buflen < ((size_t) outvallen + 1))
-        {
-          free (outval);
-          *errnop = ERANGE;
-          return NSS_STATUS_TRYAGAIN;
-        }
-
-      ptr = strncpy (buffer, outval, buflen);
-      free (outval);
-
-      while (isspace (*ptr))
-        ptr++;
-      parse_res = _nss_files_parse_pwent (ptr, result, data, buflen, errnop);
-      if (parse_res == -1)
-        return NSS_STATUS_TRYAGAIN;
-    }
-
-  if (parse_res > 0)
+  if (nss_getpwuid_r (uid, result, buffer, buflen, errnop) ==
+      NSS_STATUS_SUCCESS)
     {
       copy_pwd_changes (result, &pwd, p, plen);
       give_pwd_free (&pwd);
@@ -1400,7 +880,7 @@
   return NSS_STATUS_RETURN;
 }
 
-/* Searches in /etc/passwd and the NIS/NIS+ map for a special user id */
+/* Searches in /etc/passwd and the NSS subsystem for a special user id */
 static enum nss_status
 internal_getpwuid_r (uid_t uid, struct passwd *result, ent_t *ent,
                      char *buffer, size_t buflen, int *errnop)
@@ -1569,29 +1049,25 @@
 _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd,
                         char *buffer, size_t buflen, int *errnop)
 {
-  ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
-               {NULL, NULL, 0, 0, NULL, NULL, NULL}};
-  enum nss_status status;
+  enum nss_status result;
+  ent_t ent = {0, 0, TRUE, NULL, {NULL, 0, 0},
+	       {NULL, NULL, 0, 0, NULL, NULL, NULL}};
 
   __libc_lock_lock (lock);
 
   if (ni == NULL)
-    {
-      __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
-      use_nisplus = (strcmp (ni->name, "nisplus") == 0);
-    }
+    init_nss_interface ();
 
   __libc_lock_unlock (lock);
 
-  status = internal_setpwent (&ent);
-  if (status != NSS_STATUS_SUCCESS)
-    return status;
+  result = internal_setpwent (&ent, 0);
 
-  status = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop);
+  if (result == NSS_STATUS_SUCCESS)
+    result = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop);
 
   internal_endpwent (&ent);
 
-  return status;
+  return result;
 }
 
 
--- nis/nss_compat/compat-spwd.c
+++ nis/nss_compat/compat-spwd.c	2003/05/22 07:55:43
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996,1997,1998,1999,2001,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1996,1997,1998,1999,2001,2002,2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
 
@@ -25,19 +25,20 @@
 #include <shadow.h>
 #include <string.h>
 #include <bits/libc-lock.h>
-#include <rpcsvc/yp.h>
+#include <rpc/types.h>
 #include <rpcsvc/ypclnt.h>
-#include <rpcsvc/nis.h>
 #include <nsswitch.h>
 
 #include "netgroup.h"
-#include "nss-nisplus.h"
-#include "nisplus-parser.h"
 
 static service_user *ni;
-static bool_t use_nisplus; /* default: passwd_compat: nis */
-static nis_name pwdtable; /* Name of the password table */
-static size_t pwdtablelen;
+static enum nss_status (*nss_setspent)(int stayopen);
+static enum nss_status (*nss_getspnam_r)(const char *name, struct spwd *sp,
+                                         char *buffer, size_t buflen,
+                                         int *errnop);
+static enum nss_status (*nss_getspent_r)(struct spwd *sp, char *buffer,
+                                         size_t buflen, int *errnop);
+static enum nss_status (*nss_endspent)(void);
 
 /* Get the declaration of the parser function.  */
 #define ENTNAME spent
@@ -58,11 +59,8 @@
 struct ent_t
   {
     bool_t netgroup;
-    bool_t nis;
+    bool_t files;
     bool_t first;
-    char *oldkey;
-    int oldkeylen;
-    nis_result *result;
     FILE *stream;
     struct blacklist_t blacklist;
     struct spwd pwd;
@@ -70,7 +68,7 @@
   };
 typedef struct ent_t ent_t;
 
-static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
+static ent_t ext_ent = {0, TRUE, 0, NULL, {NULL, 0, 0},
 			{NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
 
 /* Protect global state against multiple changers.  */
@@ -80,6 +78,21 @@
 static void blacklist_store_name (const char *, ent_t *);
 static int in_blacklist (const char *, int, ent_t *);
 
+/* Initialize the NSS interface/functions. The calling function must
+   hold the lock.  */
+static void
+init_nss_interface (void)
+{
+  if (__nss_database_lookup ("shadow_compat", "passwd_compat",
+			     "nis", &ni) >= 0)
+    {
+      nss_setspent = __nss_lookup_function (ni, "setspent");
+      nss_getspnam_r = __nss_lookup_function (ni, "getspnam_r");
+      nss_getspent_r = __nss_lookup_function (ni, "getspent_r");
+      nss_endspent = __nss_lookup_function (ni, "endspent");
+    }
+}
+
 static void
 give_spwd_free (struct spwd *pwd)
 {
@@ -142,45 +155,17 @@
 }
 
 static enum nss_status
-internal_setspent (ent_t *ent)
+internal_setspent (ent_t *ent, int stayopen)
 {
   enum nss_status status = NSS_STATUS_SUCCESS;
 
-  ent->nis = ent->first = ent->netgroup = 0;
+  ent->first = ent->netgroup = 0;
+  ent->files = TRUE;
 
   /* If something was left over free it.  */
   if (ent->netgroup)
     __internal_endnetgrent (&ent->netgrdata);
 
-  if (ent->oldkey != NULL)
-    {
-      free (ent->oldkey);
-      ent->oldkey = NULL;
-      ent->oldkeylen = 0;
-    }
-
-  if (ent->result != NULL)
-    {
-      nis_freeresult (ent->result);
-      ent->result = NULL;
-    }
-
-  if (pwdtable == NULL)
-    {
-      static const char key[] = "passwd.org_dir.";
-      const char *local_dir = nis_local_directory ();
-      size_t len_local_dir = strlen (local_dir);
-
-      pwdtable = malloc (sizeof (key) + len_local_dir);
-      if (pwdtable == NULL)
-        return NSS_STATUS_TRYAGAIN;
-
-      pwdtablelen = ((char *) mempcpy (mempcpy (pwdtable,
-						key, sizeof (key) - 1),
-				       local_dir, len_local_dir + 1)
-		     - pwdtable) - 1;
-    }
-
   if (ent->blacklist.data != NULL)
     {
       ent->blacklist.current = 1;
@@ -222,6 +207,9 @@
 
   give_spwd_free (&ent->pwd);
 
+  if (status == NSS_STATUS_SUCCESS && nss_setspent)
+    return nss_setspent (stayopen);
+
   return status;
 }
 
@@ -234,12 +222,9 @@
   __libc_lock_lock (lock);
 
   if (ni == NULL)
-    {
-      __nss_database_lookup ("shadow_compat", "passwd_compat", "nis", &ni);
-      use_nisplus = (strcmp (ni->name, "nisplus") == 0);
-    }
+    init_nss_interface ();
 
-  result = internal_setspent (&ext_ent);
+  result = internal_setspent (&ext_ent, stayopen);
 
   __libc_lock_unlock (lock);
 
@@ -250,6 +235,9 @@
 static enum nss_status
 internal_endspent (ent_t *ent)
 {
+  if (nss_endspent)
+    nss_endspent();
+
   if (ent->stream != NULL)
     {
       fclose (ent->stream);
@@ -259,20 +247,8 @@
   if (ent->netgroup)
     __internal_endnetgrent (&ent->netgrdata);
 
-  ent->nis = ent->first = ent->netgroup = 0;
-
-  if (ent->oldkey != NULL)
-    {
-      free (ent->oldkey);
-      ent->oldkey = NULL;
-      ent->oldkeylen = 0;
-    }
-
-  if (ent->result != NULL)
-    {
-      nis_freeresult (ent->result);
-      ent->result = NULL;
-    }
+  ent->first = ent->netgroup = FALSE;
+  ent->files = TRUE;
 
   if (ent->blacklist.data != NULL)
     {
@@ -304,25 +280,26 @@
 
 
 static enum nss_status
-getspent_next_nis_netgr (const char *name, struct spwd *result, ent_t *ent,
+getspent_next_nss_netgr (const char *name, struct spwd *result, ent_t *ent,
 			 char *group, char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  char *ypdomain, *host, *user, *domain, *outval, *p, *p2;
-  int status, outvallen;
+  char *curdomain, *host, *user, *domain, *p2;
   size_t p2len;
 
-  if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
+  if (!nss_getspnam_r)
+    return NSS_STATUS_UNAVAIL;
+
+  if (yp_get_default_domain (&curdomain) != YPERR_SUCCESS)
     {
-      ent->netgroup = 0;
-      ent->first = 0;
+      ent->netgroup = FALSE;
+      ent->first = FALSE;
       give_spwd_free (&ent->pwd);
       return NSS_STATUS_UNAVAIL;
     }
 
   if (ent->first == TRUE)
     {
-      bzero (&ent->netgrdata, sizeof (struct __netgrent));
+      memset (&ent->netgrdata, 0, sizeof (struct __netgrent));
       __internal_setnetgrent (group, &ent->netgrdata);
       ent->first = FALSE;
     }
@@ -330,7 +307,7 @@
   while (1)
     {
       char *saved_cursor;
-      int parse_res;
+      enum nss_status status;
 
       saved_cursor = ent->netgrdata.cursor;
       status = __internal_getnetgrent_r (&host, &user, &domain,
@@ -339,7 +316,7 @@
       if (status != 1)
 	{
 	  __internal_endnetgrent (&ent->netgrdata);
-	  ent->netgroup = 0;
+	  ent->netgroup = FALSE;
 	  give_spwd_free (&ent->pwd);
 	  return NSS_STATUS_RETURN;
 	}
@@ -347,7 +324,7 @@
       if (user == NULL || user[0] == '-')
 	continue;
 
-      if (domain != NULL && strcmp (ypdomain, domain) != 0)
+      if (domain != NULL && strcmp (curdomain, domain) != 0)
 	continue;
 
       /* If name != NULL, we are called from getpwnam */
@@ -355,139 +332,25 @@
 	if (strcmp (user, name) != 0)
 	  continue;
 
-      if (yp_match (ypdomain, "shadow.byname", user,
-		    strlen (user), &outval, &outvallen)
-	  != YPERR_SUCCESS)
-	continue;
-
       p2len = spwd_need_buflen (&ent->pwd);
       if (p2len > buflen)
 	{
-	  free (outval);
 	  *errnop = ERANGE;
 	  return NSS_STATUS_TRYAGAIN;
 	}
       p2 = buffer + (buflen - p2len);
       buflen -= p2len;
-      if (buflen < ((size_t) outval + 1))
-	{
-	  free (outval);
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      p = strncpy (buffer, outval, buflen);
-      while (isspace (*p))
-	p++;
-      free (outval);
-      parse_res = _nss_files_parse_spent (p, result, data, buflen, errnop);
-      if (parse_res == -1)
-	{
-	  ent->netgrdata.cursor = saved_cursor;
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-
-      if (parse_res)
-	{
-	  /* Store the User in the blacklist for the "+" at the end of
-	     /etc/passwd */
-	  blacklist_store_name (result->sp_namp, ent);
-	  copy_spwd_changes (result, &ent->pwd, p2, p2len);
-	  break;
-	}
-    }
-
-  return NSS_STATUS_SUCCESS;
-}
-
-static enum nss_status
-getspent_next_nisplus_netgr (const char *name, struct spwd *result,
-			     ent_t *ent, char *group, char *buffer,
-			     size_t buflen, int *errnop)
-{
-  char *ypdomain, *host, *user, *domain, *p2;
-  int status, parse_res;
-  size_t p2len;
-  nis_result *nisres;
 
-  /* Maybe we should use domainname here ? We need the current
-     domainname for the domain field in netgroups */
-  if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
-    {
-      ent->netgroup = 0;
-      ent->first = 0;
-      give_spwd_free (&ent->pwd);
-      return NSS_STATUS_UNAVAIL;
-    }
-
-  if (ent->first == TRUE)
-    {
-      bzero (&ent->netgrdata, sizeof (struct __netgrent));
-      __internal_setnetgrent (group, &ent->netgrdata);
-      ent->first = FALSE;
-    }
-
-  while (1)
-    {
-      char *saved_cursor;
-
-      saved_cursor = ent->netgrdata.cursor;
-      status = __internal_getnetgrent_r (&host, &user, &domain,
-                                         &ent->netgrdata, buffer, buflen,
-					 errnop);
-      if (status != 1)
-        {
-          __internal_endnetgrent (&ent->netgrdata);
-          ent->netgroup = 0;
-          give_spwd_free (&ent->pwd);
-          return NSS_STATUS_RETURN;
-        }
-
-      if (user == NULL || user[0] == '-')
-        continue;
-
-      if (domain != NULL && strcmp (ypdomain, domain) != 0)
+      if (nss_getspnam_r (user, result, buffer, buflen, errnop) !=
+          NSS_STATUS_SUCCESS)
         continue;
 
-      /* If name != NULL, we are called from getpwnam */
-      if (name != NULL)
-	if (strcmp (user, name) != 0)
-	  continue;
-
-      p2len = spwd_need_buflen (&ent->pwd);
-      if (p2len > buflen)
+      if (!in_blacklist (result->sp_namp, strlen (result->sp_namp), ent))
         {
-          *errnop = ERANGE;
-          return NSS_STATUS_TRYAGAIN;
-        }
-      p2 = buffer + (buflen - p2len);
-      buflen -= p2len;
-      {
-        char buf[strlen (user) + 30 + pwdtablelen];
-        sprintf (buf, "[name=%s],%s", user, pwdtable);
-        nisres = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
-      }
-      if (niserr2nss (nisres->status) != NSS_STATUS_SUCCESS)
-        {
-          nis_freeresult (nisres);
-          continue;
-        }
-      parse_res = _nss_nisplus_parse_spent (nisres, result, buffer,
-					    buflen, errnop);
-      if (parse_res == -1)
-	{
-	  nis_freeresult (nisres);
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      nis_freeresult (nisres);
-
-      if (parse_res)
-        {
-	  /* Store the User in the blacklist for the "+" at the end of
-	     /etc/passwd */
-	  blacklist_store_name (result->sp_namp, ent);
-	  copy_spwd_changes (result, &ent->pwd, p2, p2len);
+          /* Store the User in the blacklist for possible the "+" at the
+             end of /etc/passwd */
+          blacklist_store_name (result->sp_namp, ent);
+          copy_spwd_changes (result, &ent->pwd, p2, p2len);
           break;
         }
     }
@@ -495,100 +358,17 @@
   return NSS_STATUS_SUCCESS;
 }
 
-static enum nss_status
-getspent_next_nisplus (struct spwd *result, ent_t *ent, char *buffer,
-                       size_t buflen, int *errnop)
-{
-  int parse_res;
-  size_t p2len;
-  char *p2;
-
-  p2len = spwd_need_buflen (&ent->pwd);
-  if (p2len > buflen)
-    {
-      *errnop = ERANGE;
-      return NSS_STATUS_TRYAGAIN;
-    }
-  p2 = buffer + (buflen - p2len);
-  buflen -= p2len;
-  do
-    {
-      bool_t saved_first;
-      nis_result *saved_res;
-
-      if (ent->first)
-        {
-	  saved_first = TRUE;
-	  saved_res = ent->result;
-
-          ent->result = nis_first_entry (pwdtable);
-          if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
-            {
-              ent->nis = 0;
-              give_spwd_free (&ent->pwd);
-              return niserr2nss (ent->result->status);
-            }
-          ent->first = FALSE;
-        }
-      else
-        {
-          nis_result *res;
-
-	  saved_first = FALSE;
-	  saved_res = ent->result;
-
-          res = nis_next_entry (pwdtable, &ent->result->cookie);
-          ent->result = res;
-          if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
-            {
-	      nis_freeresult (saved_res);
-	      ent->nis = 0;
-	      give_spwd_free (&ent->pwd);
-	      return niserr2nss (ent->result->status);
-            }
-        }
-      parse_res = _nss_nisplus_parse_spent (ent->result, result, buffer,
-					    buflen, errnop);
-      if (parse_res == -1)
-	{
-	  ent->first = saved_first;
-	  nis_freeresult (ent->result);
-	  ent->result = saved_res;
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      else
-	{
-	  if (!saved_first)
-	    nis_freeresult (saved_res);
-	}
-      if (parse_res &&
-          in_blacklist (result->sp_namp, strlen (result->sp_namp), ent))
-        parse_res = 0; /* if result->pw_name in blacklist,search next entry */
-    }
-  while (!parse_res);
-
-  copy_spwd_changes (result, &ent->pwd, p2, p2len);
-
-  return NSS_STATUS_SUCCESS;
-}
-
 
 static enum nss_status
-getspent_next_nis (struct spwd *result, ent_t *ent,
+getspent_next_nss (struct spwd *result, ent_t *ent,
 		   char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  char *domain, *outkey, *outval, *p, *p2;
-  int outkeylen, outvallen, parse_res;
+  enum nss_status status;
+  char *p2;
   size_t p2len;
 
-  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
-    {
-      ent->nis = 0;
-      give_spwd_free (&ent->pwd);
-      return NSS_STATUS_UNAVAIL;
-    }
+  if (!nss_getspent_r)
+    return NSS_STATUS_UNAVAIL;
 
   p2len = spwd_need_buflen (&ent->pwd);
   if (p2len > buflen)
@@ -600,87 +380,11 @@
   buflen -= p2len;
   do
     {
-      bool_t saved_first;
-      char *saved_oldkey;
-      int saved_oldlen;
-
-      if (ent->first)
-	{
-	  if (yp_first (domain, "shadow.byname", &outkey, &outkeylen,
-			&outval, &outvallen) != YPERR_SUCCESS)
-	    {
-	      ent->nis = 0;
-	      give_spwd_free (&ent->pwd);
-	      return NSS_STATUS_UNAVAIL;
-	    }
-
-	  if (buflen < ((size_t) outvallen + 1))
-	    {
-	      free (outval);
-	      *errnop = ERANGE;
-	      return NSS_STATUS_TRYAGAIN;
-	    }
-
-	  saved_first = TRUE;
-	  saved_oldkey = ent->oldkey;
-	  saved_oldlen = ent->oldkeylen;
-	  ent->oldkey = outkey;
-	  ent->oldkeylen = outkeylen;
-	  ent->first = FALSE;
-	}
-      else
-	{
-	  if (yp_next (domain, "shadow.byname", ent->oldkey, ent->oldkeylen,
-		       &outkey, &outkeylen, &outval, &outvallen)
-	      != YPERR_SUCCESS)
-	    {
-	      ent->nis = 0;
-	      give_spwd_free (&ent->pwd);
-	      return NSS_STATUS_NOTFOUND;
-	    }
-
-	  if (buflen < ((size_t) outvallen + 1))
-	    {
-	      free (outval);
-	      *errnop = ERANGE;
-	      return NSS_STATUS_TRYAGAIN;
-	    }
-
-	  saved_first = FALSE;
-	  saved_oldkey = ent->oldkey;
-	  saved_oldlen = ent->oldkeylen;
-	  ent->oldkey = outkey;
-	  ent->oldkeylen = outkeylen;
-	}
-
-      /* Copy the found data to our buffer  */
-      p = strncpy (buffer, outval, buflen);
-
-      /* ...and free the data.  */
-      free (outval);
-
-      while (isspace (*p))
-	++p;
-      parse_res = _nss_files_parse_spent (p, result, data, buflen, errnop);
-      if (parse_res == -1)
-	{
-	  free (ent->oldkey);
-	  ent->oldkey = saved_oldkey;
-	  ent->oldkeylen = saved_oldlen;
-	  ent->first = saved_first;
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      else
-	{
-	  if (!saved_first)
-	    free (saved_oldkey);
-	}
-      if (parse_res &&
-          in_blacklist (result->sp_namp, strlen (result->sp_namp), ent))
-        parse_res = 0;
+      if ((status = nss_getspent_r (result, buffer, buflen, errnop)) !=
+          NSS_STATUS_SUCCESS)
+        return status;
     }
-  while (!parse_res);
+  while (in_blacklist (result->sp_namp, strlen (result->sp_namp), ent));
 
   copy_spwd_changes (result, &ent->pwd, p2, p2len);
 
@@ -689,15 +393,16 @@
 
 /* This function handle the +user entrys in /etc/shadow */
 static enum nss_status
-getspnam_plususer (const char *name, struct spwd *result, char *buffer,
-		   size_t buflen, int *errnop)
+getspnam_plususer (const char *name, struct spwd *result, ent_t *ent,
+		   char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
   struct spwd pwd;
-  int parse_res;
   char *p;
   size_t plen;
 
+  if (!nss_getspnam_r)
+    return NSS_STATUS_UNAVAIL;
+
   memset (&pwd, '\0', sizeof (struct spwd));
   pwd.sp_warn = -1;
   pwd.sp_inact = -1;
@@ -715,71 +420,16 @@
   p = buffer + (buflen - plen);
   buflen -= plen;
 
-  if (use_nisplus) /* Do the NIS+ query here */
-    {
-      nis_result *res;
-      char buf[strlen (name) + 24 + pwdtablelen];
-
-      sprintf(buf, "[name=%s],%s", name, pwdtable);
-      res = nis_list(buf, 0, NULL, NULL);
-      if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
-        {
-          enum nss_status status =  niserr2nss (res->status);
-
-          nis_freeresult (res);
-          return status;
-        }
-      parse_res = _nss_nisplus_parse_spent (res, result, buffer,
-					    buflen, errnop);
-      if (parse_res == -1)
-	{
-	  nis_freeresult (res);
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      nis_freeresult (res);
-    }
-  else /* Use NIS */
-    {
-      char *domain, *outval, *ptr;
-      int outvallen;
-
-      if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
-	return NSS_STATUS_NOTFOUND;
-
-      if (yp_match (domain, "shadow.byname", name, strlen (name),
-		    &outval, &outvallen)  != YPERR_SUCCESS)
-	return NSS_STATUS_NOTFOUND;
-
-      if (buflen < ((size_t) outvallen + 1))
-	{
-	  free (outval);
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
+  if (nss_getspnam_r (name, result, buffer, buflen, errnop) !=
+      NSS_STATUS_SUCCESS)
+    return NSS_STATUS_NOTFOUND;
 
-      ptr = strncpy (buffer, outval, buflen);
-      free (outval);
-      while (isspace (*ptr))
-        ptr++;
-      parse_res = _nss_files_parse_spent (ptr, result, data, buflen, errnop);
-      if (parse_res == -1)
-	return NSS_STATUS_TRYAGAIN;
-    }
+  if (in_blacklist (result->sp_namp, strlen (result->sp_namp), ent))
+    return NSS_STATUS_NOTFOUND;
 
-  if (parse_res)
-    {
-      copy_spwd_changes (result, &pwd, p, plen);
-      give_spwd_free (&pwd);
-      /* We found the entry.  */
-      return NSS_STATUS_SUCCESS;
-    }
-  else
-    {
-      /* Give buffer the old len back */
-      buflen += plen;
-      give_spwd_free (&pwd);
-    }
+  copy_spwd_changes (result, &pwd, p, plen);
+  give_spwd_free (&pwd);
+  /* We found the entry.  */
   return NSS_STATUS_RETURN;
 }
 
@@ -863,14 +513,9 @@
 	  ent->first = TRUE;
 	  copy_spwd_changes (&ent->pwd, result, NULL, 0);
 
-	  if (use_nisplus)
-	    status = getspent_next_nisplus_netgr (NULL, result, ent,
-						  &result->sp_namp[2],
-						  buffer, buflen, errnop);
-	  else
-	    status = getspent_next_nis_netgr (NULL, result, ent,
-					      &result->sp_namp[2],
-					      buffer, buflen, errnop);
+	  status = getspent_next_nss_netgr (NULL, result, ent,
+					    &result->sp_namp[2],
+					    buffer, buflen, errnop);
 	  if (status == NSS_STATUS_RETURN)
 	    continue;
 	  else
@@ -894,8 +539,9 @@
 	  /* Store the User in the blacklist for the "+" at the end of
 	     /etc/passwd */
 	  blacklist_store_name (&result->sp_namp[1], ent);
-          status = getspnam_plususer (&result->sp_namp[1], result, buffer,
-				      buflen, errnop);
+	  status = getspnam_plususer (&result->sp_namp[1], result, ent,
+					buffer, buflen, errnop);
+
           if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
             break;
           else
@@ -916,14 +562,11 @@
       /* +:... */
       if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0')
 	{
-	  ent->nis = TRUE;
+	  ent->files = FALSE;
 	  ent->first = TRUE;
 	  copy_spwd_changes (&ent->pwd, result, NULL, 0);
 
-	  if (use_nisplus)
-	    return getspent_next_nisplus (result, ent, buffer, buflen, errnop);
-	  else
-	    return getspent_next_nis (result, ent, buffer, buflen, errnop);
+	  return getspent_next_nss (result, ent, buffer, buflen, errnop);
 	}
     }
 
@@ -937,57 +580,46 @@
 {
   if (ent->netgroup)
     {
-      int status;
+      enum nss_status status;
 
       /* We are searching members in a netgroup */
       /* Since this is not the first call, we don't need the group name */
-      if (use_nisplus)
-	status = getspent_next_nisplus_netgr (NULL, pw, ent, NULL, buffer,
-					      buflen, errnop);
-      else
-	status = getspent_next_nis_netgr (NULL, pw, ent, NULL, buffer, buflen,
-					  errnop);
+      status = getspent_next_nss_netgr (NULL, pw, ent, NULL, buffer,
+					buflen, errnop);
+
       if (status == NSS_STATUS_RETURN)
 	return getspent_next_file (pw, ent, buffer, buflen, errnop);
       else
 	return status;
     }
   else
-    if (ent->nis)
-      {
-	if (use_nisplus)
-	  return getspent_next_nisplus (pw, ent, buffer, buflen, errnop);
-	else
-	  return getspent_next_nis (pw, ent, buffer, buflen, errnop);
-      }
-    else
+    if (ent->files)
       return getspent_next_file (pw, ent, buffer, buflen, errnop);
+    else
+      return getspent_next_nss (pw, ent, buffer, buflen, errnop);
 }
 
 enum nss_status
 _nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen,
 			int *errnop)
 {
-  enum nss_status status = NSS_STATUS_SUCCESS;
+  enum nss_status result = NSS_STATUS_SUCCESS;
 
   __libc_lock_lock (lock);
 
+  /* Be prepared that the setpwent function was not called before.  */
   if (ni == NULL)
-    {
-      __nss_database_lookup ("shadow_compat", "passwd_compat", "nis", &ni);
-      use_nisplus = (strcmp (ni->name, "nisplus") == 0);
-    }
+    init_nss_interface ();
 
-  /* Be prepared that the setspent function was not called before.  */
   if (ext_ent.stream == NULL)
-    status = internal_setspent (&ext_ent);
+    result = internal_setspent (&ext_ent, 1);
 
-  if (status == NSS_STATUS_SUCCESS)
-    status = internal_getspent_r (pwd, &ext_ent, buffer, buflen, errnop);
+  if (result == NSS_STATUS_SUCCESS)
+    result = internal_getspent_r (pwd, &ext_ent, buffer, buflen, errnop);
 
   __libc_lock_unlock (lock);
 
-  return status;
+  return result;
 }
 
 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
@@ -1046,6 +678,8 @@
 	}
 
       /* -@netgroup */
+      /* If the loaded NSS module does not support this service, add
+         all users from a +@netgroup entry to the blacklist, too.  */
       if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@'
 	  && result->sp_namp[2] != '\0')
 	{
@@ -1080,12 +714,8 @@
 
 	  do
 	    {
-	      if (use_nisplus)
-		status = getspent_next_nisplus_netgr (name, result, ent, buf,
-						      buffer, buflen, errnop);
-	      else
-		status = getspent_next_nis_netgr (name, result, ent, buf,
-						  buffer, buflen, errnop);
+	      status = getspent_next_nss_netgr (name, result, ent, buf,
+						buffer, buflen, errnop);
 	      if (status == NSS_STATUS_RETURN)
 		continue;
 
@@ -1114,8 +744,9 @@
 	    {
 	      enum nss_status status;
 
-	      status = getspnam_plususer (name, result, buffer, buflen,
-					  errnop);
+	      status = getspnam_plususer (name, result, ent,
+					  buffer, buflen, errnop);
+
 	      if (status == NSS_STATUS_RETURN)
 		/* We couldn't parse the entry */
 		return NSS_STATUS_NOTFOUND;
@@ -1129,7 +760,9 @@
 	{
 	  enum nss_status status;
 
-	  status = getspnam_plususer (name, result, buffer, buflen, errnop);
+	  status = getspnam_plususer (name, result, ent,
+				      buffer, buflen, errnop);
+
 	  if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
 	    return NSS_STATUS_NOTFOUND;
 	  else
@@ -1143,28 +776,30 @@
 _nss_compat_getspnam_r (const char *name, struct spwd *pwd,
 			char *buffer, size_t buflen, int *errnop)
 {
-  ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
+  enum nss_status result;
+  ent_t ent = {0, TRUE, 0, NULL, {NULL, 0, 0},
 	       {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
-  enum nss_status status;
 
   if (name[0] == '-' || name[0] == '+')
     return NSS_STATUS_NOTFOUND;
 
+  __libc_lock_lock (lock);
+
   if (ni == NULL)
-    {
-      __nss_database_lookup ("shadow_compat", "passwd_compat", "nis", &ni);
-      use_nisplus = (strcmp (ni->name, "nisplus") == 0);
-    }
+    init_nss_interface ();
+
+  __libc_lock_unlock (lock);
 
-  status = internal_setspent (&ent);
-  if (status != NSS_STATUS_SUCCESS)
-    return status;
+  result = internal_setspent (&ent, 0);
 
-  status = internal_getspnam_r (name, pwd, &ent, buffer, buflen, errnop);
+  if (result != NSS_STATUS_SUCCESS)
+    return result;
+
+  result = internal_getspnam_r (name, pwd, &ent, buffer, buflen, errnop);
 
   internal_endspent (&ent);
 
-  return status;
+  return result;
 }
 
 /* Support routines for remembering -@netgroup and -user entries.
--- nss/Versions
+++ nss/Versions	2003/05/20 08:49:17
@@ -9,7 +9,7 @@
   }
   GLIBC_PRIVATE {
     _nss_files_parse_grent; _nss_files_parse_pwent; _nss_files_parse_spent;
-    __nss_disable_nscd;
+    __nss_disable_nscd; __nss_lookup_function;
   }
 }
 


More information about the Libc-alpha mailing list