about summary refs log tree commit diff
path: root/nis
diff options
context:
space:
mode:
Diffstat (limited to 'nis')
-rw-r--r--nis/Banner2
-rw-r--r--nis/Makefile19
-rw-r--r--nis/TODO2
-rw-r--r--nis/lckcache.c181
-rw-r--r--nis/libnsl.map6
-rw-r--r--nis/nis_cache.c44
-rw-r--r--nis/nis_call.c546
-rw-r--r--nis/nis_intern.c145
-rw-r--r--nis/nis_intern.h23
-rw-r--r--nis/nis_lookup.c164
-rw-r--r--nis/nis_print.c56
-rw-r--r--nis/nis_subr.c44
-rw-r--r--nis/nis_table.c180
-rw-r--r--nis/nis_util.c99
-rw-r--r--nis/nisplus-parser.h34
-rw-r--r--nis/nss_compat/compat-grp.c120
-rw-r--r--nis/nss_compat/compat-pwd.c81
-rw-r--r--nis/nss_compat/compat-spwd.c78
-rw-r--r--nis/nss_nis/nis-publickey.c3
-rw-r--r--nis/nss_nisplus/nisplus-alias.c130
-rw-r--r--nis/nss_nisplus/nisplus-ethers.c148
-rw-r--r--nis/nss_nisplus/nisplus-grp.c243
-rw-r--r--nis/nss_nisplus/nisplus-hosts.c119
-rw-r--r--nis/nss_nisplus/nisplus-netgrp.c11
-rw-r--r--nis/nss_nisplus/nisplus-network.c268
-rw-r--r--nis/nss_nisplus/nisplus-parser.c337
-rw-r--r--nis/nss_nisplus/nisplus-proto.c226
-rw-r--r--nis/nss_nisplus/nisplus-publickey.c72
-rw-r--r--nis/nss_nisplus/nisplus-pwd.c197
-rw-r--r--nis/nss_nisplus/nisplus-rpc.c230
-rw-r--r--nis/nss_nisplus/nisplus-service.c253
-rw-r--r--nis/nss_nisplus/nisplus-spwd.c154
-rw-r--r--nis/rpcsvc/nis_cache.h47
-rw-r--r--nis/rpcsvc/nis_cache.x47
-rw-r--r--nis/rpcsvc/nislib.h6
35 files changed, 2545 insertions, 1770 deletions
diff --git a/nis/Banner b/nis/Banner
index b5aedc2b97..77ab77e8d2 100644
--- a/nis/Banner
+++ b/nis/Banner
@@ -1 +1 @@
-NIS(YP)/NIS+ NSS modules 0.11 by Thorsten Kukuk
+NIS(YP)/NIS+ NSS modules 0.12 by Thorsten Kukuk
diff --git a/nis/Makefile b/nis/Makefile
index 23a71446bb..c10c175e7d 100644
--- a/nis/Makefile
+++ b/nis/Makefile
@@ -17,12 +17,13 @@
 # Boston, MA 02111-1307, USA.
 
 #
-#	Makefile for NIS part.
+#	Makefile for NIS/NIS+ part.
 #
 subdir	:= nis
 
 headers			:= $(wildcard rpcsvc/*.[hx])
-distribute		:= nss-nis.h nss-nisplus.h nis_intern.h Banner
+distribute		:= nss-nis.h nss-nisplus.h nis_intern.h Banner \
+			nisplus-parser.h
 
 # These are the databases available for the nis (and perhaps later nisplus)
 # service.  This must be a superset of the services in nss.
@@ -44,15 +45,15 @@ vpath %.c $(subdir-dirs)
 libnsl-routines = yp_xdr ypclnt ypupdate_xdr \
                   nis_subr nis_local_names nis_free nis_file \
                   nis_print nis_error nis_call nis_lookup nis_clone\
-                  nis_table nis_xdr nis_intern nis_server nis_ping\
+                  nis_cache nis_table nis_xdr nis_server nis_ping\
 		  nis_checkpoint nis_mkdir nis_rmdir nis_getservlist\
-		  nis_verifygroup nis_ismember nis_addmember \
+		  nis_verifygroup nis_ismember nis_addmember nis_util\
 		  nis_removemember nis_creategroup nis_destroygroup\
 		  nis_print_group_entry nis_domain_of nis_domain_of_r\
-		  nis_modify nis_remove nis_add nis_defaults
+		  nis_modify nis_remove nis_add nis_defaults lckcache
 libnsl-map	= libnsl.map
 
-libnss_compat-routines	:= $(addprefix compat-,grp pwd spwd)
+libnss_compat-routines	:= $(addprefix compat-,grp pwd spwd) nisplus-parser
 libnss_compat-inhibit-o	= $(filter-out .so,$(object-suffixes))
 libnss_compat-map	:= libnss_compat.map
 
@@ -60,16 +61,14 @@ libnss_nis-routines	:= $(addprefix nis-,$(databases))
 libnss_nis-inhibit-o	= $(filter-out .so,$(object-suffixes))
 libnss_nis-map		:= libnss_nis.map
 
-libnss_nisplus-routines	:= $(addprefix nisplus-,$(databases))
+libnss_nisplus-routines	:= $(addprefix nisplus-,$(databases)) nisplus-parser
 libnss_nisplus-inhibit-o = $(filter-out .so,$(object-suffixes))
 libnss_nisplus-map	:= libnss_nisplus.map
 
 include ../Rules
 
 
-$(objpfx)libnss_compat.so: $(objpfx)libnsl.so$(libnsl.so-version) \
-			   $(common-objpfx)nss/libnss_files.so \
-			   $(common-objpfx)nis/libnss_nisplus.so
+$(objpfx)libnss_compat.so: $(objpfx)libnsl.so$(libnsl.so-version)
 $(objpfx)libnss_nis.so: $(objpfx)libnsl.so$(libnsl.so-version) \
 			$(common-objpfx)nss/libnss_files.so
 $(objpfx)libnss_nisplus.so: $(objpfx)libnsl.so$(libnsl.so-version)
diff --git a/nis/TODO b/nis/TODO
index f6d695956a..0fe695d78b 100644
--- a/nis/TODO
+++ b/nis/TODO
@@ -2,8 +2,6 @@
  * nis_addmember: Where checks for duplicate group members ? nisgrpadm or
 		  nis_addmember ?
 
- * nss_nisplus: When using parser form nss_files, rewrite parser
-
  * nis_table.c: nis_list(): 
 	Missing flags: FOLLOW_PATH, ALL_RESULTS
 	callback: Don't simulate it, use server callback thread
diff --git a/nis/lckcache.c b/nis/lckcache.c
new file mode 100644
index 0000000000..ead577372e
--- /dev/null
+++ b/nis/lckcache.c
@@ -0,0 +1,181 @@
+/* Handle locking of NIS+ cache file.
+   Copyright (C) 1996 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
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <fcntl.h>
+#include <bits/libc-lock.h>
+#include <shadow.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <rpcsvc/nis.h>
+#include <rpcsvc/nislib.h>
+#include <rpcsvc/nis_cache.h>
+
+/* How long to wait for getting the lock before returning with an
+   error.  */
+#define TIMEOUT 15 /* sec */
+
+
+/* File descriptor for lock file.  */
+static int lock_fd = -1;
+
+/* Prevent problems in multithreaded program by using mutex.  */
+__libc_lock_define_initialized (static, lock)
+
+
+/* Prototypes for local functions.  */
+static void noop_handler __P ((int __sig));
+
+
+/* We cannot simply return in error cases.  We have to close the file
+   and perhaps restore the signal handler.  */
+#define RETURN_CLOSE_FD(code)						      \
+  do {									      \
+    if ((code) < 0 && lock_fd >= 0)					      \
+      {									      \
+	close (lock_fd);						      \
+	lock_fd = -1;							      \
+      }									      \
+    __libc_lock_unlock (lock);						      \
+    return (code);							      \
+  } while (0)
+
+#define RETURN_RESTORE_HANDLER(code)					      \
+  do {									      \
+    /* Restore old action handler for alarm.  We don't need to know	      \
+       about the current one.  */					      \
+    sigaction (SIGALRM, &saved_act, NULL);				      \
+    RETURN_CLOSE_FD (code);						      \
+  } while (0)
+
+#define RETURN_CLEAR_ALARM(code)					      \
+  do {									      \
+    /* Clear alarm.  */							      \
+    alarm (0);								      \
+    /* Restore old set of handled signals.  We don't need to know	      \
+       about the current one.*/						      \
+    sigprocmask (SIG_SETMASK, &saved_set, NULL);			      \
+    RETURN_RESTORE_HANDLER (code);					      \
+  } while (0)
+
+
+int
+__nis_lock_cache (void)
+{
+  int flags;
+  sigset_t saved_set;			/* Saved set of caught signals.  */
+  struct sigaction saved_act;		/* Saved signal action.  */
+  sigset_t new_set;			/* New set of caught signals.  */
+  struct sigaction new_act;		/* New signal action.  */
+  struct flock fl;			/* Information struct for locking.  */
+  int result;
+
+  if (lock_fd != -1)
+    /* Still locked by own process.  */
+    return -1;
+
+  /* Prevent problems caused by multiple threads.  */
+  __libc_lock_lock (lock);
+
+  lock_fd = open (CACHELOCK, O_RDONLY|O_CREAT, 0666);
+  if (lock_fd == -1)
+    /* Cannot create lock file.  */
+    RETURN_CLOSE_FD (-1);
+
+  /* Make sure file gets correctly closed when process finished.  */
+  flags = fcntl (lock_fd, F_GETFD, 0);
+  if (flags == -1)
+    /* Cannot get file flags.  */
+    RETURN_CLOSE_FD (-1);
+  flags |= FD_CLOEXEC;		/* Close on exit.  */
+  if (fcntl (lock_fd, F_SETFD, flags) < 0)
+    /* Cannot set new flags.  */
+    RETURN_CLOSE_FD (-1);
+
+  /* Now we have to get exclusive write access.  Since multiple
+     process could try this we won't stop when it first fails.
+     Instead we set a timeout for the system call.  Once the timer
+     expires it is likely that there are some problems which cannot be
+     resolved by waiting.
+
+     It is important that we don't change the signal state.  We must
+     restore the old signal behaviour.  */
+  memset (&new_act, '\0', sizeof (struct sigaction));
+  new_act.sa_handler = noop_handler;
+  sigfillset (&new_act.sa_mask);
+  new_act.sa_flags = 0ul;
+
+  /* Install new action handler for alarm and save old.  */
+  if (sigaction (SIGALRM, &new_act, &saved_act) < 0)
+    /* Cannot install signal handler.  */
+    RETURN_CLOSE_FD (-1);
+
+  /* Now make sure the alarm signal is not blocked.  */
+  sigemptyset (&new_set);
+  sigaddset (&new_set, SIGALRM);
+  if (sigprocmask (SIG_UNBLOCK, &new_set, &saved_set) < 0)
+    RETURN_RESTORE_HANDLER (-1);
+
+  /* Start timer.  If we cannot get the lock in the specified time we
+     get a signal.  */
+  alarm (TIMEOUT);
+
+  /* Try to get the lock.  */
+  memset (&fl, '\0', sizeof (struct flock));
+  fl.l_type = F_RDLCK;
+  fl.l_whence = SEEK_SET;
+  result = fcntl (lock_fd, F_SETLK, &fl);
+
+  RETURN_CLEAR_ALARM (result);
+}
+
+
+int
+__nis_unlock_cache ()
+{
+  int result;
+
+  if (lock_fd == -1)
+    /* There is no lock set.  */
+    result = -1;
+  else
+    {
+      /* Prevent problems caused by multiple threads.  */
+      __libc_lock_lock (lock);
+
+      result = close (lock_fd);
+
+      /* Mark descriptor as unused.  */
+      lock_fd = -1;
+
+      /* Clear mutex.  */
+      __libc_lock_unlock (lock);
+    }
+
+  return result;
+}
+
+
+static void
+noop_handler (sig)
+     int sig;
+{
+  /* We simply return which makes the `fcntl' call return with an error.  */
+}
diff --git a/nis/libnsl.map b/nis/libnsl.map
index 36bb857093..cf22d27d2f 100644
--- a/nis/libnsl.map
+++ b/nis/libnsl.map
@@ -1,7 +1,10 @@
 GLIBC_2.0 {
   global:
     __nis_default_access; __nis_default_group; __nis_default_owner;
-    __nis_default_ttl;    __yp_check;          nis_add;
+    __nis_default_ttl;    __nis_finddirectory; __nis_lock_cache;
+    __nis_unlock_cache;   __nis_hash;
+
+    nis_add;
     nis_add_entry;        nis_addmember;       nis_checkpoint;
     nis_clone_directory;  nis_clone_entry;     nis_clone_group;
     nis_clone_link;       nis_clone_nis_attr;  nis_clone_objdata;
@@ -51,6 +54,7 @@ GLIBC_2.0 {
     xdr_ypresp_xfr;       xdr_ypstat;          xdr_ypupdate_args;
     xdr_ypxfrstat;        xdr_zotypes;
 
+    __yp_check;          
     yp_all;               yp_bind;             yp_first;
     yp_get_default_domain; yp_maplist;         yp_master;
     yp_match;             yp_next;             yp_order;
diff --git a/nis/nis_cache.c b/nis/nis_cache.c
new file mode 100644
index 0000000000..8e1d583003
--- /dev/null
+++ b/nis/nis_cache.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <rpcsvc/nis.h>
+#include <rpcsvc/nislib.h>
+#include <rpcsvc/nis_cache.h>
+#include <bits/libc-lock.h>
+
+#include "nis_intern.h"
+
+/* XXX Only dummy functions in the moment. The real implementation
+       will follow, if we have a working nis_cachemgr */
+directory_obj *
+__cache_search (const_nis_name name)
+{
+  return NULL;
+}
+
+nis_error 
+__cache_add (fd_result *fd)
+{
+  return NIS_FAIL;
+}
diff --git a/nis/nis_call.c b/nis/nis_call.c
index 08a20acd73..f25b8017a5 100644
--- a/nis/nis_call.c
+++ b/nis/nis_call.c
@@ -17,6 +17,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <fcntl.h>
 #include <string.h>
 #include <rpc/rpc.h>
 #include <rpc/auth.h>
@@ -26,8 +27,30 @@
 #include <arpa/inet.h>
 #include "nis_intern.h"
 
-static struct timeval TIMEOUT = {25, 0};
-static int const MAXTRIES = 3;
+static struct timeval TIMEOUT = {10, 0};
+
+struct dir_binding
+{
+  CLIENT *clnt;                  /* RPC CLIENT handle */
+  nis_server *server_val;        /* List of servers */
+  u_int server_len;              /* # of servers */
+  u_int server_used;             /* Which server we are bind in the moment ? */
+  u_int trys;                    /* How many server have we tried ? */
+  bool_t master_only;            /* Is only binded to the master */
+  bool_t use_auth;               /* Do we use AUTH ? */
+  bool_t use_udp;                /* Do we use UDP ? */
+  time_t create;                 /* Binding creation time */
+  struct sockaddr_in addr;       /* Server's IP address */
+  int socket;                    /* Server's local socket */
+  unsigned short port;           /* Local port */
+};
+typedef struct dir_binding dir_binding;
+
+static inline u_int
+__nis_ping (const nis_server *serv, u_int serv_len)
+{
+  return 0;
+}
 
 static unsigned long
 inetstr2int (const char *str)
@@ -53,110 +76,217 @@ inetstr2int (const char *str)
   return inet_addr (buffer);
 }
 
-static CLIENT *
-__nis_dobind (const nis_server *server, u_long flags)
+static void
+__bind_destroy (dir_binding *bind)
 {
-  struct sockaddr_in clnt_saddr;
-  int clnt_sock;
-  size_t i;
-  CLIENT *client = NULL;
-
-  memset (&clnt_saddr, '\0', sizeof clnt_saddr);
-  clnt_saddr.sin_family = AF_INET;
-  for (i = 0; i < server->ep.ep_len; i++)
+  if (bind->clnt != NULL)
     {
-      if (strcmp (server->ep.ep_val[i].family, "loopback") == 0)
+      if (bind->use_auth)
+	auth_destroy (bind->clnt->cl_auth);
+      clnt_destroy (bind->clnt);
+    }
+  free (bind->server_val);
+  free (bind);
+}
+
+static nis_error
+__bind_next (dir_binding *bind)
+{
+  if (bind->trys >= bind->server_len)
+    return NIS_FAIL;
+  
+  bind->server_used++;
+  if (bind->server_used >= bind->server_len)
+    bind->server_used = 0;
+
+  if (bind->clnt != NULL)
+    {
+      if (bind->use_auth)
+	auth_destroy (bind->clnt->cl_auth);
+      clnt_destroy (bind->clnt);
+      bind->clnt = NULL;
+    }
+  
+  return NIS_SUCCESS;
+}
+
+static nis_error
+__bind_connect (dir_binding *dbp)
+{
+  struct sockaddr_in check;
+  nis_server *serv;
+  int checklen;
+  u_int i;
+
+  if (dbp == NULL)
+    return NIS_FAIL;
+
+  serv = &dbp->server_val[dbp->server_used];
+
+  memset (&dbp->addr, '\0', sizeof (dbp->addr));
+  dbp->addr.sin_family = AF_INET;
+  for (i = 0; i < serv->ep.ep_len; ++i)
+    {
+      if (strcmp (serv->ep.ep_val[i].family, "inet") == 0)
 	{
-	  if (server->ep.ep_val[i].uaddr[i] == '-')
-	    clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+	  if (dbp->use_udp)
+	    {
+	      if (strcmp (serv->ep.ep_val[i].proto, "udp") == 0)
+		dbp->addr.sin_addr.s_addr =
+		  inetstr2int (serv->ep.ep_val[i].uaddr);
+	      else
+		continue;
+	    }
 	  else
-	    if (strcmp (server->ep.ep_val[i].proto, "udp") == 0)
-	      {
-		if ((flags & USE_DGRAM) == USE_DGRAM)
-		  clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-		else
-		  continue;
-	      }
-	    else
-	      if (strcmp (server->ep.ep_val[i].proto, "tcp") == 0)
-		{
-		  if ((flags & USE_DGRAM) == USE_DGRAM)
-		    continue;
-		  else
-		    clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-		}
+	    if (strcmp (serv->ep.ep_val[i].proto, "tcp") == 0)
+	      dbp->addr.sin_addr.s_addr =
+		inetstr2int (serv->ep.ep_val[i].uaddr);
 	}
       else
-	if (strcmp (server->ep.ep_val[i].family, "inet") == 0)
-	  {
-	    if (server->ep.ep_val[i].uaddr[i] == '-')
-	      clnt_saddr.sin_addr.s_addr =
-		inetstr2int (server->ep.ep_val[i].uaddr);
-	    else
-	      if (strcmp (server->ep.ep_val[i].proto, "udp") == 0)
-		{
-		  if ((flags & USE_DGRAM) == USE_DGRAM)
-		    clnt_saddr.sin_addr.s_addr =
-		      inetstr2int (server->ep.ep_val[i].uaddr);
-		  else
-		    continue;
-		}
-	      else
-		if (strcmp (server->ep.ep_val[i].proto, "tcp") == 0)
-		  {
-		    if ((flags & USE_DGRAM) == USE_DGRAM)
-		      continue;
-		    else
-		      clnt_saddr.sin_addr.s_addr =
-			inetstr2int (server->ep.ep_val[i].uaddr);
-		  }
-	  }
-	else
-	  continue;
-
-      clnt_sock = RPC_ANYSOCK;
-      if ((flags & USE_DGRAM) == USE_DGRAM)
-	client = clntudp_create (&clnt_saddr, NIS_PROG, NIS_VERSION,
-				 TIMEOUT, &clnt_sock);
-      else
-	client = clnttcp_create (&clnt_saddr, NIS_PROG, NIS_VERSION,
-				 &clnt_sock, 0, 0);
-
-      if (client == NULL)
 	continue;
-      if (clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
-		     (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS)
+    }
+  if (dbp->addr.sin_addr.s_addr == 0)
+    return NIS_FAIL;
+
+  dbp->socket = RPC_ANYSOCK;
+  if (dbp->use_udp)
+    dbp->clnt = clntudp_create (&dbp->addr, NIS_PROG, NIS_VERSION,
+				 TIMEOUT, &dbp->socket);
+  else
+    dbp->clnt = clnttcp_create (&dbp->addr, NIS_PROG, NIS_VERSION,
+				 &dbp->socket, 0, 0);
+  
+  if (dbp->clnt == NULL)
+    return NIS_RPCERROR;
+  
+  clnt_control (dbp->clnt, CLSET_TIMEOUT, (caddr_t)&TIMEOUT);
+  /* If the program exists, close the socket */
+  if (fcntl (dbp->socket, F_SETFD, 1) == -1)
+    perror (_("fcntl: F_SETFD"));
+  
+  if (dbp->use_auth)
+    {
+#if defined(HAVE_SECURE_RPC)
+      if (serv->key_type == NIS_PK_DH)
 	{
-	  clnt_destroy (client);
-	  continue;
+	  char netname[MAXNETNAMELEN+1];
+	  char *p;
+	  
+	  p = stpcpy (netname, "unix.");
+	  strncpy (p, serv->name,MAXNETNAMELEN-5);
+	  netname[MAXNETNAMELEN] = '\0';
+	  p = strchr (netname, '.');
+	  *p = '@';
+	  dbp->clnt->cl_auth =
+	    authdes_pk_create (netname, &serv->pkey, 300, NULL, NULL);
+	  if (!dbp->clnt->cl_auth)
+	    dbp->clnt->cl_auth = authunix_create_default ();
 	}
+      else
+#endif
+	dbp->clnt->cl_auth = authunix_create_default ();
+      dbp->use_auth = TRUE;
+    }
+  
+  /* Get port for sanity checks later */
+  checklen = sizeof (struct sockaddr_in);
+  memset (&check, 0, checklen);
+  if (dbp->use_udp)
+    bind (dbp->socket, (struct sockaddr *)&check, checklen);
+  check.sin_family = AF_INET;
+  if (!getsockname (dbp->socket, (struct sockaddr *)&check, &checklen))
+    dbp->port = check.sin_port;
+
+  dbp->create = time (NULL);
+
+  return NIS_SUCCESS;
+}
 
-      if ((flags & NO_AUTHINFO) != NO_AUTHINFO)
+static dir_binding *
+__bind_create (const nis_server *serv_val, u_int serv_len, u_long flags)
+{
+  dir_binding *dbp;
+  u_int i;
+  
+  dbp = calloc (1, sizeof (dir_binding));
+  if (dbp == NULL)
+    return NULL;
+  
+  dbp->server_len = serv_len;
+  dbp->server_val = calloc (1, sizeof (nis_server) * serv_len);
+  if (dbp->server_val == NULL)
+    {
+      free (dbp);
+      return NULL;
+    }
+  
+  for (i = 0; i < serv_len; ++i)
+    {
+      if (serv_val[i].name != NULL)
+	dbp->server_val[i].name = strdup (serv_val[i].name);
+      
+      dbp->server_val[i].ep.ep_len = serv_val[i].ep.ep_len;
+      if (dbp->server_val[i].ep.ep_len > 0)
 	{
-#if defined(HAVE_SECURE_RPC)
-	  if (server->key_type == NIS_PK_DH && getenv ("NO_SECURE_RPC") == NULL)
+	  unsigned long j;
+	  
+	  dbp->server_val[i].ep.ep_val =
+	    malloc (serv_val[i].ep.ep_len * sizeof (endpoint));
+	  for (j = 0; j < dbp->server_val[i].ep.ep_len; ++j)
 	    {
-	      char netname[MAXNETNAMELEN+1];
-	      char *p;
-
-	      p = stpcpy (netname, "unix.");
-	      strncpy (p, server->name,MAXNETNAMELEN-5);
-	      netname[MAXNETNAMELEN] = '\0';
-	      p = strchr (netname, '.');
-	      *p = '@';
-	      client->cl_auth =
-		authdes_pk_create (netname, &server->pkey, 300, NULL, NULL);
-	      if (!client->cl_auth)
-		client->cl_auth = authunix_create_default ();
+	      if (serv_val[i].ep.ep_val[j].uaddr)
+		dbp->server_val[i].ep.ep_val[j].uaddr =
+		  strdup (serv_val[i].ep.ep_val[j].uaddr);
+	      else
+		dbp->server_val[i].ep.ep_val[j].uaddr = NULL;
+	      if (serv_val[i].ep.ep_val[j].family)
+		dbp->server_val[i].ep.ep_val[j].family =
+		  strdup (serv_val[i].ep.ep_val[j].family);
+	      else
+		dbp->server_val[i].ep.ep_val[j].family = NULL;
+	      if (serv_val[i].ep.ep_val[j].proto)
+		dbp->server_val[i].ep.ep_val[j].proto =
+		  strdup (serv_val[i].ep.ep_val[j].proto);
+	      else
+		dbp->server_val[i].ep.ep_val[j].proto = NULL;
 	    }
-	  else
-#endif
-	    client->cl_auth = authunix_create_default ();
 	}
-      return client;
+      else
+	dbp->server_val[i].ep.ep_val = NULL;
+      dbp->server_val[i].key_type = serv_val[i].key_type;
+      dbp->server_val[i].pkey.n_len = serv_val[i].pkey.n_len;
+      if (serv_val[i].pkey.n_len > 0)
+	{
+	  dbp->server_val[i].pkey.n_bytes =
+	    malloc (serv_val[i].pkey.n_len);
+	  if (dbp->server_val[i].pkey.n_bytes == NULL)
+	    return NULL;
+	  memcpy (dbp->server_val[i].pkey.n_bytes, serv_val[i].pkey.n_bytes,
+		  serv_val[i].pkey.n_len);
+	}
+      else
+	dbp->server_val[i].pkey.n_bytes = NULL;
     }
+  
+  dbp->server_used = __nis_ping (dbp->server_val, dbp->server_len);
+  if (flags & USE_DGRAM)
+    dbp->use_udp = TRUE;
+  else
+    dbp->use_udp = FALSE;
 
-  return NULL;
+  if (flags & NO_AUTHINFO)
+    dbp->use_auth = FALSE;
+  else
+    dbp->use_auth = TRUE;
+
+  if (flags & MASTER_ONLY)
+    dbp->master_only = TRUE;
+  else
+    dbp->master_only = FALSE;
+
+  dbp->trys = 1;
+
+  return dbp;
 }
 
 nis_error
@@ -164,89 +294,84 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
 	       xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp,
 	       u_long flags)
 {
-  CLIENT *clnt;
-  int try, result;
-
-  try = 0;
-  result = NIS_NAMEUNREACHABLE;
-
-  if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1)
-    server_len = 1; /* The first entry is the master */
-
-  while (try < MAXTRIES && result != RPC_SUCCESS)
+  enum clnt_stat result;
+  nis_error retcode;
+  dir_binding *dbp;
+
+  if (flags & MASTER_ONLY) 
+    server_len = 1;
+  
+  dbp = __bind_create (server, server_len, flags);
+  while (__bind_connect (dbp) != NIS_SUCCESS)
     {
-      unsigned int i;
-
-      if ((flags & HARD_LOOKUP) == 0)
-	++try;
-
-      for (i = 0; i < server_len; i++)
+      if (__bind_next (dbp) != NIS_SUCCESS)
 	{
-	  if ((clnt = __nis_dobind (&server[i], flags)) == NULL)
-	    continue;
-
-	  result = clnt_call (clnt, prog, xargs, req, xres, resp, TIMEOUT);
-
-	  if (result != RPC_SUCCESS)
-	    {
-	      clnt_perror (clnt, "do_niscall: clnt_call");
-	      clnt_destroy (clnt);
-	      result = NIS_RPCERROR;
-	    }
-	  else
-	    clnt_destroy (clnt);
+	  __bind_destroy (dbp);
+	  return NIS_NAMEUNREACHABLE;
 	}
     }
 
-  return result;
-}
-
-static directory_obj *
-dir_lookup (const_nis_name name, nis_server *serv, u_long flags)
-{
-  CLIENT *clnt;
-  int try, result;
-  nis_result *res;
-  struct ns_request req;
-  directory_obj *dir;
-
-  res = calloc (1, sizeof (nis_result));
-  req.ns_name = (char *)name;
-  req.ns_object.ns_object_len = 0;
-  req.ns_object.ns_object_val = NULL;
-  try = 0;
-  result = NIS_NAMEUNREACHABLE;
-
-  while (try < MAXTRIES && result != RPC_SUCCESS)
+  do
     {
-      if ((clnt = __nis_dobind (serv, flags)) == NULL)
-	continue;
-
-      result = clnt_call (clnt, NIS_LOOKUP, (xdrproc_t) xdr_ns_request,
-			  (caddr_t) &req, (xdrproc_t) xdr_nis_result,
-			  (caddr_t) res, TIMEOUT);
-
+    again:
+      result = clnt_call (dbp->clnt, prog, xargs, req, xres, resp, TIMEOUT);
+      
       if (result != RPC_SUCCESS)
 	{
-	  clnt_perror (clnt, "do_niscall: clnt_call");
-	  clnt_destroy (clnt);
-	  result = NIS_RPCERROR;
+	  clnt_perror (dbp->clnt, "__do_niscall2: clnt_call");
+	  __bind_destroy (dbp);
+	  retcode = NIS_RPCERROR;
 	}
       else
-	clnt_destroy (clnt);
+	{
+	  switch (prog)
+	    {
+	    case NIS_LOOKUP:
+	    case NIS_ADD:
+	    case NIS_MODIFY:
+	    case NIS_REMOVE:
+	    case NIS_IBLIST:
+	    case NIS_IBADD:
+	    case NIS_IBMODIFY:
+	    case NIS_IBREMOVE:
+	    case NIS_IBFIRST:
+	    case NIS_IBNEXT:
+	      if ((((nis_result *)xres)->status != NIS_SUCCESS) &&
+		  (((nis_result *)xres)->status != NIS_S_SUCCESS))
+		if (__bind_next (dbp) == NIS_SUCCESS)
+		  goto again;
+	    case NIS_FINDDIRECTORY:
+	      if (((fd_result *)xres)->status != NIS_SUCCESS)
+		if (__bind_next (dbp) == NIS_SUCCESS)
+		  goto again;
+	      break;
+#if 0
+	    case NIS_STATUS: /* nis_taglist */
+	    case NIS_SERVSTATE:
+	      break;
+	    case NIS_DUMPLOG: /* log_result */
+	    case NIS_DUMP:
+	      break;
+	    case NIS_CHECKPOINT: /* cp_result */
+	      break;
+#endif
+	    default:
+	      break;
+	    }
+	  __bind_destroy (dbp);
+	  retcode = NIS_SUCCESS;
+	}
     }
-  if (result != RPC_SUCCESS || res->status != NIS_SUCCESS)
-    return NULL;
-
-  dir = nis_clone_directory (&res->objects.objects_val->DI_data, NULL);
-  nis_freeresult (res);
-
-  return dir;
+  while ((flags & HARD_LOOKUP) && retcode == NIS_RPCERROR);
+  
+  return retcode; 
 }
 
 static directory_obj *
 rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
 {
+  fd_result *fd_res;
+  XDR xdrs;
   char domain [strlen (name) + 3];
 
   nis_domain_of_r (name, domain, sizeof (domain));
@@ -287,8 +412,20 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
 	/* The root server of our domain is a replica of the parent
 	   domain ! (Now I understand why a root server must be a
 	   replica of the parent domain) */
-	obj = dir_lookup (ndomain, dir->do_servers.do_servers_val,
-			  flags);
+	fd_res = __nis_finddirectory (dir, ndomain);
+	if (fd_res->status != NIS_SUCCESS)
+	  {
+	    nis_free_directory (dir);
+	    xdr_free((xdrproc_t)xdr_fd_result, (caddr_t)fd_res);
+	    return NULL;
+	  }
+	__cache_add (fd_res);
+	obj = calloc(1, sizeof(directory_obj));
+	xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val,
+		      fd_res->dir_data.dir_data_len, XDR_DECODE);
+	xdr_directory_obj(&xdrs, obj);
+	xdr_destroy(&xdrs);
+	xdr_free((xdrproc_t)xdr_fd_result, (caddr_t)fd_res);
 	if (obj != NULL)
 	  {
 	    /* We have found a NIS+ server serving ndomain, now
@@ -303,15 +440,14 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
 	    return NULL;
 	  }
       }
-      break;
+    break;
     case LOWER_NAME:
       {
 	directory_obj *obj;
 	char leaf [strlen (name) + 3];
 	char ndomain [strlen (name) + 3];
-	u_int i;
 	char *cp;
-
+	
 	do
 	  {
 	    if (strlen (domain) == 0)
@@ -327,21 +463,30 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
 	cp = strchr (leaf, '\0');
 	*cp++ = '.';
 	strcpy (cp, domain);
-
-	for (i = 0; i < dir->do_servers.do_servers_len; ++i)
+	
+	fd_res = __nis_finddirectory (dir, leaf);
+	if (fd_res->status != NIS_SUCCESS)
 	  {
-	    obj = dir_lookup (leaf, &dir->do_servers.do_servers_val[i],
-			      flags);
-	    if (obj != NULL)
-	      {
-		/* We have found a NIS+ server serving ndomain, now
-		   let us search for "name" */
-		nis_free_directory (dir);
-		return rec_dirsearch (name, obj, flags);
-	      }
+	    nis_free_directory (dir);
+	    xdr_free((xdrproc_t)xdr_fd_result, (caddr_t)fd_res);
+	    return NULL;
+	  }
+	__cache_add (fd_res);
+	obj = calloc(1, sizeof(directory_obj));
+	xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val,
+		      fd_res->dir_data.dir_data_len, XDR_DECODE);
+	xdr_directory_obj(&xdrs, obj);
+	xdr_destroy(&xdrs);
+	xdr_free((xdrproc_t)xdr_fd_result, (caddr_t)fd_res);
+	if (obj != NULL)
+	  {
+	    /* We have found a NIS+ server serving ndomain, now
+	       let us search for "name" */
+	    nis_free_directory (dir);
+	    return rec_dirsearch (name, obj, flags);
 	  }
       }
-      break;
+    break;
     case BAD_NAME:
       nis_free_directory (dir);
       return NULL;
@@ -354,37 +499,44 @@ nis_error
 __do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs,
 	      caddr_t req, xdrproc_t xres, caddr_t resp, u_long flags)
 {
-  nis_error result;
+  nis_error retcode;
   directory_obj *dir = NULL;
-  const nis_server *server;
+  nis_server *server;
   u_int server_len;
 
+  if (name == NULL)
+    return NIS_BADNAME;
 
-  dir = readColdStartFile ();
-  if (dir == NULL) /* No /var/nis/NIS_COLD_START -> no NIS+ installed */
-    return NIS_UNAVAIL;
-
-  if (name != NULL)
+  if ((flags & NO_CACHE) !=  NO_CACHE)
+    dir = __cache_search (name);
+  
+  if (dir == NULL)
     {
+      dir = readColdStartFile ();
+      if (dir == NULL) /* No /var/nis/NIS_COLD_START->no NIS+ installed */
+	return NIS_UNAVAIL;
+      
       dir = rec_dirsearch (name, dir, flags);
       if (dir == NULL)
-	{
-	  if (nis_dir_cmp (nis_local_directory(), name) == NOT_SEQUENTIAL)
-	    return NIS_NAMEUNREACHABLE;
-	  else
-	    return NIS_NOTFOUND;
-	}
+	return NIS_NOTFOUND;
     }
-  server = dir->do_servers.do_servers_val;
-  server_len = dir->do_servers.do_servers_len;
 
-  if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1)
-    server_len = 1; /* The first entry is the master */
-
-  result = __do_niscall2 (server, server_len, prog, xargs, req, xres,
-			  resp, flags);
-  if (dir != NULL)
-    nis_free_directory (dir);
+  if (flags & MASTER_ONLY) 
+    {
+      server = dir->do_servers.do_servers_val;
+      server_len = 1;
+    }
+  else
+    {
+      server = dir->do_servers.do_servers_val;
+      server_len = dir->do_servers.do_servers_len;
+    }
+  
+  
+  retcode = __do_niscall2 (server, server_len, prog, xargs, req, xres, resp,
+			   flags);
+  
+  nis_free_directory (dir);
 
-  return result;
+  return retcode;
 }
diff --git a/nis/nis_intern.c b/nis/nis_intern.c
deleted file mode 100644
index 7bfa263070..0000000000
--- a/nis/nis_intern.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/* Copyright (c) 1997 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-#include <string.h>
-#include <rpcsvc/nis.h>
-#include <rpcsvc/nislib.h>
-#include "nis_intern.h"
-
-/* Nearly the same as nis_getnames, but nis_getnames stopped
-   when 2 points left */
-nis_name *
-__nis_expandname (const char *name)
-{
-  nis_name *getnames = NULL;
-  char local_domain[NIS_MAXNAMELEN + 1];
-  char *path, *cp;
-  int count, pos;
-
-  strncpy (local_domain, nis_local_directory (), NIS_MAXNAMELEN);
-  local_domain[NIS_MAXNAMELEN] = '\0';
-
-  count = 1;
-  if ((getnames = malloc ((count + 1) * sizeof (char *))) == NULL)
-    return NULL;
-
-  /* Do we have a fully qualified NIS+ name ? If yes, give it back */
-  if (name[strlen (name) - 1] == '.')
-    {
-      if ((getnames[0] = strdup (name)) == NULL)
-	{
-	  free (getnames);
-	  return NULL;
-	}
-      getnames[1] = NULL;
-
-      return getnames;
-    }
-
-  /* Get the search path, where we have to search "name" */
-  path = getenv ("NIS_PATH");
-  if (path == NULL)
-    path = strdupa ("$");
-  else
-    path = strdupa (path);
-
-  pos = 0;
-
-  cp = strtok (path, ":");
-  while (cp)
-    {
-      if (strcmp (cp, "$") == 0)
-	{
-	  char *cptr = local_domain;
-	  char *tmp;
-
-	  while (*cptr != '\0')
-	    {
-	      if (pos >= count)
-		{
-		  count += 5;
-		  getnames = realloc (getnames, (count + 1) * sizeof (char *));
-		}
-	      tmp = malloc (strlen (cptr) + strlen (local_domain) +
-			    strlen (name) + 2);
-	      if (tmp == NULL)
-		return NULL;
-
-	      getnames[pos] = tmp;
-	      tmp = stpcpy (tmp, name);
-	      if (*cptr != '.')
-		*tmp++ = '.';
-	      stpcpy (tmp, cptr);
-
-	      ++pos;
-
-	      ++cptr;
-	      while ((*cptr != '\0') && (*cptr != '.'))
-		++cptr;
-
-	      if ((*cptr == '.') && (cptr[1] != '\0'))
-		++cptr;
-	    }
-	}
-      else
-	{
-	  char *tmp;
-
-	  if (cp[strlen (cp) - 1] == '$')
-	    {
-	      tmp = malloc (strlen (cp) + strlen (local_domain) +
-			    strlen (name) + 2);
-	      if (tmp == NULL)
-		return NULL;
-
-	      getnames[pos] = tmp;
-	      tmp = stpcpy (tmp, name);
-	      *tmp++ = '.';
-	      tmp = stpcpy (tmp, cp);
-	      --tmp;
-	      if (tmp[- 1] != '.')
-		*tmp++ = '.';
-	      stpcpy (tmp, local_domain);
-	    }
-	  else
-	    {
-	      tmp = malloc (strlen (cp) + strlen (name) + 2);
-	      if (tmp == NULL)
-		return NULL;
-
-	      tmp = stpcpy (tmp, name);
-	      *tmp++ = '.';
-	      stpcpy (tmp, cp);
-	    }
-
-	  if (pos > count)
-	    {
-	      count += 5;
-	      getnames = realloc (getnames, (count + 1) * sizeof (char *));
-	    }
-	  getnames[pos] = tmp;
-	  pos++;
-	}
-      cp = strtok (NULL, ":");
-    }
-
-  getnames[pos] = NULL;
-
-  return getnames;
-}
diff --git a/nis/nis_intern.h b/nis/nis_intern.h
index 25c88a2b22..a7cb785e40 100644
--- a/nis/nis_intern.h
+++ b/nis/nis_intern.h
@@ -24,17 +24,22 @@
 
 __BEGIN_DECLS
 
-extern nis_error __do_niscall2 (const nis_server *server, u_int server_len,
-				u_long prog, xdrproc_t xargs, caddr_t req,
-				xdrproc_t xres, caddr_t resp, u_long flags);
-extern nis_error __do_niscall (const_nis_name name, u_long prog,
-			       xdrproc_t xargs, caddr_t req, xdrproc_t xres,
-			       caddr_t resp, u_long flags);
+extern nis_error __do_niscall2 __P ((const nis_server *serv, u_int serv_len,
+				     u_long prog, xdrproc_t xargs, caddr_t req,
+				     xdrproc_t xres, caddr_t resp, 
+				     u_long flags));
+extern nis_error __do_niscall __P ((const_nis_name name, u_long prog,
+				    xdrproc_t xargs, caddr_t req, 
+				    xdrproc_t xres, caddr_t resp,
+				    u_long flags));
 #if defined (HAVE_SECURE_RPC)
-extern AUTH *authdes_pk_create (const char *, const netobj *, u_int,
-				struct sockaddr *, des_block *);
+extern AUTH *authdes_pk_create __P ((const char *, const netobj *, u_int,
+				     struct sockaddr *, des_block *));
 #endif
-extern nis_name *__nis_expandname (const char *);
+
+/* NIS+ cache */
+extern directory_obj *__cache_search __P ((const_nis_name name));
+extern nis_error __cache_add __P ((fd_result *));
 
 __END_DECLS
 
diff --git a/nis/nis_lookup.c b/nis/nis_lookup.c
index 6f5b12b285..82db7b0b25 100644
--- a/nis/nis_lookup.c
+++ b/nis/nis_lookup.c
@@ -30,128 +30,94 @@ nis_lookup (const_nis_name name, const u_long flags)
   struct ns_request req;
   nis_name *names;
   nis_error status;
-  int is_link = 1;	 /* We should go at least once in the while loop */
   int count_links = 0;	 /* We will follow only 16 links in the deep */
-  int i;
+  int done = 0;
+  int name_nr = 0;
+  nis_name namebuf[2] = {NULL, NULL};
 
   res = calloc (1, sizeof (nis_result));
 
   if (flags & EXPAND_NAME)
     {
-      names = __nis_expandname (name);
+      names = nis_getnames (name);
       if (names == NULL)
 	{
 	  res->status = NIS_NAMEUNREACHABLE;
 	  return res;
 	}
-
-      i = 0;
-      while (names[i] != NULL && (i == 0 || res->status > 1))
-	{
-	  req.ns_name = names[i];
-
-	  while (is_link)
-	    {
-	      req.ns_object.ns_object_len = 0;
-	      req.ns_object.ns_object_val = NULL;
-	      memset (res, '\0', sizeof (nis_result));
-
-	      if ((status = __do_niscall (req.ns_name, NIS_LOOKUP,
-					  (xdrproc_t) xdr_ns_request,
-					  (caddr_t) & req,
-					  (xdrproc_t) xdr_nis_result,
-				      (caddr_t) res, flags)) != RPC_SUCCESS)
-		{
-		  res->status = status;
-		  nis_freenames (names);
-		  return res;
-		}
-
-	      if ((res->status == NIS_SUCCESS || res->status == NIS_S_SUCCESS)
-		  && (res->objects.objects_len > 0 &&
-		      res->objects.objects_val->zo_data.zo_type == LINK_OBJ))
-		is_link = 1;
-	      else
-		is_link = 0;
-
-	      if (is_link)
-		{
-		  if ((flags & FOLLOW_LINKS) == FOLLOW_LINKS)
-		    {
-		      if (count_links == 16)
-			{
-			  res->status = NIS_LINKNAMEERROR;
-			  return res;
-			}
-		      else
-			++count_links;
-
-		      req.ns_name = res->objects.objects_val->LI_data.li_name;
-		    }
-		  else
-		    {
-		      res->status = NIS_NOTSEARCHABLE;
-		      return res;
-		    }
-		}
-	    }
-
-	  ++i;
-	  if (res->status == NIS_NOT_ME)
-	    res->status = NIS_NOSUCHNAME;
-	}
-
-      nis_freenames (names);
     }
   else
     {
-      req.ns_name = (char *)name;
+      names = namebuf;
+      names[0] = (nis_name) name;
+    }
 
-      while (is_link)
+  req.ns_name = names[0];
+  while (!done)
+    {
+      req.ns_object.ns_object_len = 0;
+      req.ns_object.ns_object_val = NULL;
+      memset (res, '\0', sizeof (nis_result));
+
+      status = __do_niscall (req.ns_name, NIS_LOOKUP,
+			     (xdrproc_t) xdr_ns_request,
+			     (caddr_t) & req,
+			     (xdrproc_t) xdr_nis_result,
+			     (caddr_t) res, flags);
+      if (status != NIS_SUCCESS)
+	res->status = status;
+
+      switch (res->status)
 	{
-	  req.ns_object.ns_object_len = 0;
-	  req.ns_object.ns_object_val = NULL;
-	  memset (res, '\0', sizeof (nis_result));
-
-	  if ((status = __do_niscall (req.ns_name, NIS_LOOKUP,
-				      (xdrproc_t) xdr_ns_request,
-				      (caddr_t) &req,
-				      (xdrproc_t) xdr_nis_result,
-				      (caddr_t) res, flags)) != RPC_SUCCESS)
+	case NIS_PARTIAL:
+	case NIS_SUCCESS:
+	case NIS_S_SUCCESS:
+	  if (__type_of(NIS_RES_OBJECT (res)) == LINK_OBJ &&
+	      flags & FOLLOW_LINKS) /* We are following links */
 	    {
-	      res->status = status;
-	      return res;
+	      /* if we hit the link limit, bail */
+	      if (count_links > NIS_MAXLINKS)
+		{
+		  res->status = NIS_LINKNAMEERROR;
+		  ++done;
+		  break;
+		}
+	      if (count_links)
+		free (req.ns_name);
+	      ++count_links;
+	      req.ns_name = strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
+	      nis_freeresult (res);
+	      res = calloc (1, sizeof (nis_result));
 	    }
-
-	  if ((res->status == NIS_SUCCESS || res->status == NIS_S_SUCCESS) &&
-	      (res->objects.objects_len > 0 &&
-	       res->objects.objects_val->zo_data.zo_type == LINK_OBJ))
-	    is_link = 1;
 	  else
-	    is_link = 0;
-
-	  if (is_link)
+	    ++done;
+	  break;
+	case NIS_CBRESULTS:
+	  /* XXX Implement CALLBACK here ! */
+	  ++done;
+	  break;
+	default:
+	  /* Try the next domainname if we don't follow a link */
+	  if (count_links)
 	    {
-	      if ((flags & FOLLOW_LINKS) == FOLLOW_LINKS)
-		{
-		  if (count_links == 16)
-		    {
-		      res->status = NIS_LINKNAMEERROR;
-		      return res;
-		    }
-		  else
-		    ++count_links;
-
-		  req.ns_name = res->objects.objects_val->LI_data.li_name;
-		}
-	      else
-		{
-		  res->status = NIS_NOTSEARCHABLE;
-		  return res;
-		}
+	      free (req.ns_name);
+	      res->status = NIS_LINKNAMEERROR;
+	      ++done;
+	      break;
 	    }
+	  ++name_nr;
+	  if (names[name_nr] == NULL)
+	    {
+	      ++done;
+	      break;
+	    }
+	  req.ns_name = names[name_nr];
+	  break;
 	}
     }
 
+  if (names != namebuf)
+    nis_freenames (names);
+
   return res;
 }
diff --git a/nis/nis_print.c b/nis/nis_print.c
index f829994245..1914840e86 100644
--- a/nis/nis_print.c
+++ b/nis/nis_print.c
@@ -77,6 +77,41 @@ nis_flags2str (const u_long flags)
   return buf;
 }
 
+static void
+nis_print_objtype (enum zotypes type)
+{
+  switch (type)
+    {
+    case BOGUS_OBJ:
+      fputs (_("BOGUS OBJECT\n"), stdout);
+      break;
+    case NO_OBJ:
+      fputs (_("NO OBJECT\n"), stdout);
+      break;
+    case DIRECTORY_OBJ:
+      fputs (_("DIRECTORY\n"), stdout);
+      break;
+    case GROUP_OBJ:
+      fputs (_("GROUP\n"), stdout);
+      break;
+    case TABLE_OBJ:
+      fputs (_("TABLE\n"), stdout);
+      break;
+    case ENTRY_OBJ:
+      fputs (_("ENTRY\n"), stdout);
+      break;
+    case LINK_OBJ:
+      fputs (_("LINK\n"), stdout);
+      break;
+    case PRIVATE_OBJ:
+      fputs (_("PRIVATE\n"), stdout);
+      break;
+    default:
+      fputs (_("(Unknown object)\n"), stdout);
+      break;
+    }
+}
+
 void
 nis_print_rights (const u_long access)
 {
@@ -218,9 +253,10 @@ nis_print_table (const table_obj *obj)
 void
 nis_print_link (const link_obj *obj)
 {
-  printf (_("Type : %d\n"), obj->li_rtype);
-  printf (_("Name : %s\n"), obj->li_name);
-  printf (_("Attributes : %d\n"), obj->li_attrs.li_attrs_len);
+  fputs (_("Linked Object Type : "), stdout);
+  nis_print_objtype (obj->li_rtype);
+  printf (_("Linked to : %s\n"), obj->li_name);
+  /* XXX Print the attributs here, if they exists */
 }
 
 void
@@ -255,41 +291,29 @@ nis_print_object (const nis_object * obj)
   printf (_("Creation Time : %s"), ctime (&obj->zo_oid.ctime));
   printf (_("Mod. Time     : %s"), ctime (&obj->zo_oid.mtime));
   fputs (_("Object Type   : "), stdout);
+  nis_print_objtype (obj->zo_data.zo_type);
   switch (obj->zo_data.zo_type)
     {
-    case BOGUS_OBJ:
-      fputs (_("BOGUS OBJECT\n"), stdout);
-      break;
-    case NO_OBJ:
-      fputs (_("NO OBJECT\n"), stdout);
-      break;
     case DIRECTORY_OBJ:
-      fputs (_("DIRECTORY\n"), stdout);
       nis_print_directory (&obj->zo_data.objdata_u.di_data);
       break;
     case GROUP_OBJ:
-      fputs (_("GROUP\n"), stdout);
       nis_print_group (&obj->zo_data.objdata_u.gr_data);
       break;
     case TABLE_OBJ:
-      fputs (_("TABLE\n"), stdout);
       nis_print_table (&obj->zo_data.objdata_u.ta_data);
       break;
     case ENTRY_OBJ:
-      fputs (_("ENTRY\n"), stdout);
       nis_print_entry (&obj->zo_data.objdata_u.en_data);
       break;
     case LINK_OBJ:
-      fputs (_("LINK\n"), stdout);
       nis_print_link (&obj->zo_data.objdata_u.li_data);
       break;
     case PRIVATE_OBJ:
-      fputs (_("PRIVATE\n"), stdout);
       printf (_("    Data Length = %u\n"),
 	      obj->zo_data.objdata_u.po_data.po_data_len);
       break;
     default:
-      fputs (_("(Unknown object)\n"), stdout);
       break;
     }
 }
diff --git a/nis/nis_subr.c b/nis/nis_subr.c
index 780c27f7b5..fcd1903638 100644
--- a/nis/nis_subr.c
+++ b/nis/nis_subr.c
@@ -116,8 +116,7 @@ nis_getnames (const_nis_name name)
   nis_name *getnames = NULL;
   char local_domain[NIS_MAXNAMELEN + 1];
   char *path, *cp;
-  int count, pos;
-
+  int count, pos, have_point;
 
   strncpy (local_domain, nis_local_directory (), NIS_MAXNAMELEN);
   local_domain[NIS_MAXNAMELEN] = '\0';
@@ -146,6 +145,8 @@ nis_getnames (const_nis_name name)
   else
     path = strdupa (path);
 
+  have_point = (strchr (name, '.') != NULL);
+
   pos = 0;
 
   cp = strtok (path, ":");
@@ -156,7 +157,7 @@ nis_getnames (const_nis_name name)
 	  char *cptr = local_domain;
 	  char *tmp;
 
-	  while (count_dots (cptr) >= 2)
+	  while ((have_point && *cptr != '\0') || (count_dots (cptr) >= 2))
 	    {
 	      if (pos >= count)
 		{
@@ -171,13 +172,18 @@ nis_getnames (const_nis_name name)
 	      getnames[pos] = tmp;
 	      tmp = stpcpy (tmp, name);
 	      *tmp++ = '.';
-	      stpcpy (tmp, cptr);
+	      if (cptr[1] != '\0')
+		stpcpy (tmp, cptr);
+	      else
+		++cptr;
 
 	      ++pos;
 
-	      while (*cptr != '.')
+	      while (*cptr != '.' && *cptr != '\0')
+		++cptr;
+	      if (cptr[0] != '\0' && cptr[1] != '\0')
+		/* If we have only ".", don't remove the "." */
 		++cptr;
-	      ++cptr;
 	    }
 	}
       else
@@ -186,31 +192,35 @@ nis_getnames (const_nis_name name)
 
 	  if (cp[strlen (cp) - 1] == '$')
 	    {
+	      char *p;
+
 	      tmp = malloc (strlen (cp) + strlen (local_domain) +
 			    strlen (name) + 2);
 	      if (tmp == NULL)
 		return NULL;
 
-	      tmp = stpcpy (tmp, name);
-	      *tmp++ = '.';
-	      tmp = stpcpy (tmp, cp);
-	      --tmp;
-	      if (tmp[-1] != '.')
-		*tmp++ = '.';
-	      stpcpy (tmp, local_domain);
+	      p = stpcpy (tmp, name);
+	      *p++ = '.';
+	      p = stpcpy (p, cp);
+	      --p;
+	      if (p[-1] != '.')
+		*p++ = '.';
+	      stpcpy (p, local_domain);
 	    }
 	  else
 	    {
+	      char *p;
+
 	      tmp = malloc (strlen (cp) + strlen (name) + 2);
 	      if (tmp == NULL)
 		return NULL;
 
-	      tmp = stpcpy (tmp, name);
-	      *tmp++ = '.';
-	      stpcpy (tmp, cp);
+	      p = stpcpy (tmp, name);
+	      *p++ = '.';
+	      stpcpy (p, cp);
 	    }
 
-	  if (pos > count)
+	  if (pos >= count)
 	    {
 	      count += 5;
 	      getnames = realloc (getnames, (count + 1) * sizeof (char *));
diff --git a/nis/nis_table.c b/nis/nis_table.c
index 4cfd734173..16fd1e68ec 100644
--- a/nis/nis_table.c
+++ b/nis/nis_table.c
@@ -145,18 +145,6 @@ __create_ib_request (const_nis_name name, struct ib_request *ibreq,
 	     &ibreq->ibr_srch.ibr_srch_val);
   if (ibreq->ibr_name == NULL)
     return NULL;
-  if ((flags & EXPAND_NAME) == EXPAND_NAME)
-    {
-      nis_name *names;
-
-      names = __nis_expandname (ibreq->ibr_name);
-      free (ibreq->ibr_name);
-      ibreq->ibr_name = NULL;
-      if (names == NULL)
-	return NULL;
-      ibreq->ibr_name = strdup (names[0]);
-      nis_freenames (names);
-    }
 
   ibreq->ibr_flags = (flags & (RETURN_RESULT | ADD_OVERWRITE | REM_MULTIPLE |
 			       MOD_SAMEOBJ | ADD_RESERVED | REM_RESERVED |
@@ -181,9 +169,12 @@ nis_list (const_nis_name name, u_long flags,
 {
   nis_result *res = NULL;
   struct ib_request ibreq;
-  int result;
-  int count_links = 0;		/* We will only follow 16 links! */
-  int is_link = 1;		/* We should go at least once in the while loop */
+  int status;
+  int count_links = 0;	    /* We will only follow 16 links! */
+  int done = 0;
+  nis_name *names;
+  nis_name namebuf[2] = {NULL, NULL};
+  int name_nr = 0;
 
   res = calloc (1, sizeof (nis_result));
 
@@ -193,56 +184,95 @@ nis_list (const_nis_name name, u_long flags,
       return res;
     }
 
-  while (is_link)
+  if (flags & EXPAND_NAME)
     {
-      memset (res, '\0', sizeof (nis_result));
-
-      if ((result = __do_niscall (ibreq.ibr_name, NIS_IBLIST,
-				  (xdrproc_t) xdr_ib_request,
-				  (caddr_t) &ibreq, (xdrproc_t) xdr_nis_result,
-				  (caddr_t) res, flags)) != RPC_SUCCESS)
+      names = nis_getnames (ibreq.ibr_name);
+      free (ibreq.ibr_name);
+      ibreq.ibr_name = NULL;
+      if (names == NULL)
 	{
-	  res->status = result;
-	  nis_free_request (&ibreq);
+	  res->status = NIS_BADNAME;
 	  return res;
 	}
+      ibreq.ibr_name = strdup (names[name_nr]);
+    }
+  else
+    names = namebuf;
 
-      nis_free_request (&ibreq);
+  while (!done)
+    {
+      memset (res, '\0', sizeof (nis_result));
 
-      if ((res->status == NIS_SUCCESS || res->status == NIS_S_SUCCESS) &&
-	  (res->objects.objects_len > 0 &&
-	   res->objects.objects_val->zo_data.zo_type == LINK_OBJ))
-	is_link = 1;
-      else
-	is_link = 0;
+      status = __do_niscall (ibreq.ibr_name, NIS_IBLIST,
+			     (xdrproc_t) xdr_ib_request,
+			     (caddr_t) &ibreq, (xdrproc_t) xdr_nis_result,
+			     (caddr_t) res, flags);
+      if (status != NIS_SUCCESS)
+	res->status = status;
 
-      if (is_link)
+      switch (res->status)
 	{
-	  if ((flags & FOLLOW_LINKS) == FOLLOW_LINKS)
+	case NIS_PARTIAL:
+	case NIS_SUCCESS:
+	case NIS_S_SUCCESS:
+	  if (__type_of(NIS_RES_OBJECT (res)) == LINK_OBJ &&
+	      flags & FOLLOW_LINKS) /* We are following links */
 	    {
-	      if (count_links == 16)
+	      /* if we hit the link limit, bail */
+	      if (count_links > NIS_MAXLINKS)
 		{
 		  res->status = NIS_LINKNAMEERROR;
-		  return res;
-		}
-	      else
-		++count_links;
-
-	      if (__create_ib_request (res->objects.objects_val->LI_data.li_name,
-				       &ibreq, flags) == NULL)
-		{
-		  res->status = NIS_BADNAME;
-		  return res;
+		  ++done;
+		  break;
 		}
+	      if (count_links)
+		free (ibreq.ibr_name);
+	      ++count_links;
+	      free (ibreq.ibr_name);
+	      ibreq.ibr_name = strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
+	      if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
+		if (ibreq.ibr_srch.ibr_srch_len == 0)
+		  {
+		    ibreq.ibr_srch.ibr_srch_len =
+		      NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len;
+		    ibreq.ibr_srch.ibr_srch_val =
+		      NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
+		  }
+	      nis_freeresult (res);
+	      res = calloc (1, sizeof (nis_result));
 	    }
 	  else
+	    ++done;
+	  break;
+	case NIS_CBRESULTS:
+	  /* XXX Implement CALLBACK here ! */
+	  ++done;
+	  break;
+	default:
+	  /* Try the next domainname if we don't follow a link */
+	  if (count_links)
+	    {
+	      free (ibreq.ibr_name);
+	      res->status = NIS_LINKNAMEERROR;
+	      ++done;
+	      break;
+	    }
+	  ++name_nr;
+	  if (names[name_nr] == NULL)
 	    {
-	      res->status = NIS_NOTSEARCHABLE;
-	      return res;
+	      ++done;
+	      break;
 	    }
+	  ibreq.ibr_name = names[name_nr];
+	  break;
 	}
     }
 
+  if (names != namebuf)
+    nis_freenames (names);
+
+  nis_free_request (&ibreq);
+
   if (callback != NULL &&
       (res->status == NIS_SUCCESS || res->status == NIS_S_SUCCESS))
     {
@@ -279,34 +309,34 @@ nis_add_entry (const_nis_name name, const nis_object *obj,
   ibreq.ibr_obj.ibr_obj_val = nis_clone_object (obj, NULL);
   ibreq.ibr_obj.ibr_obj_len = 1;
 
-  p1 = ibreq.ibr_obj.ibr_obj_val[0].zo_name;
+  p1 = ibreq.ibr_obj.ibr_obj_val->zo_name;
   if (p1 == NULL || strlen (p1) == 0)
-    ibreq.ibr_obj.ibr_obj_val[0].zo_name =
+    ibreq.ibr_obj.ibr_obj_val->zo_name =
       nis_leaf_of_r (name, buf1, sizeof (buf1));
 
-  p2 = ibreq.ibr_obj.ibr_obj_val[0].zo_owner;
+  p2 = ibreq.ibr_obj.ibr_obj_val->zo_owner;
   if (p2 == NULL || strlen (p2) == 0)
-    ibreq.ibr_obj.ibr_obj_val[0].zo_owner = nis_local_principal ();
+    ibreq.ibr_obj.ibr_obj_val->zo_owner = nis_local_principal ();
 
-  p3 = ibreq.ibr_obj.ibr_obj_val[0].zo_group;
+  p3 = ibreq.ibr_obj.ibr_obj_val->zo_group;
   if (p3 == NULL || strlen (p3) == 0)
-    ibreq.ibr_obj.ibr_obj_val[0].zo_group = nis_local_group ();
+    ibreq.ibr_obj.ibr_obj_val->zo_group = nis_local_group ();
 
-  p4 = ibreq.ibr_obj.ibr_obj_val[0].zo_domain;
-  ibreq.ibr_obj.ibr_obj_val[0].zo_domain =
+  p4 = ibreq.ibr_obj.ibr_obj_val->zo_domain;
+  ibreq.ibr_obj.ibr_obj_val->zo_domain =
     nis_domain_of_r (name, buf4, sizeof (buf4));
 
   if ((status = __do_niscall (ibreq.ibr_name, NIS_IBADD,
 			      (xdrproc_t) xdr_ib_request,
 			      (caddr_t) &ibreq,
 			      (xdrproc_t) xdr_nis_result,
-			      (caddr_t) res, 0)) != RPC_SUCCESS)
+			      (caddr_t) res, 0)) != NIS_SUCCESS)
     res->status = status;
 
-  ibreq.ibr_obj.ibr_obj_val[0].zo_name = p1;
-  ibreq.ibr_obj.ibr_obj_val[0].zo_owner = p2;
-  ibreq.ibr_obj.ibr_obj_val[0].zo_group = p3;
-  ibreq.ibr_obj.ibr_obj_val[0].zo_domain = p4;
+  ibreq.ibr_obj.ibr_obj_val->zo_name = p1;
+  ibreq.ibr_obj.ibr_obj_val->zo_owner = p2;
+  ibreq.ibr_obj.ibr_obj_val->zo_group = p3;
+  ibreq.ibr_obj.ibr_obj_val->zo_domain = p4;
 
   nis_free_request (&ibreq);
 
@@ -336,33 +366,33 @@ nis_modify_entry (const_nis_name name, const nis_object *obj,
   ibreq.ibr_obj.ibr_obj_val = nis_clone_object (obj, NULL);
   ibreq.ibr_obj.ibr_obj_len = 1;
 
-  p1 = ibreq.ibr_obj.ibr_obj_val[0].zo_name;
+  p1 = ibreq.ibr_obj.ibr_obj_val->zo_name;
   if (p1 == NULL || strlen (p1) == 0)
-    ibreq.ibr_obj.ibr_obj_val[0].zo_name =
+    ibreq.ibr_obj.ibr_obj_val->zo_name =
       nis_leaf_of_r (name, buf1, sizeof (buf1));
 
-  p2 = ibreq.ibr_obj.ibr_obj_val[0].zo_owner;
+  p2 = ibreq.ibr_obj.ibr_obj_val->zo_owner;
   if (p2 == NULL || strlen (p2) == 0)
-    ibreq.ibr_obj.ibr_obj_val[0].zo_owner = nis_local_principal ();
+    ibreq.ibr_obj.ibr_obj_val->zo_owner = nis_local_principal ();
 
-  p3 = ibreq.ibr_obj.ibr_obj_val[0].zo_group;
+  p3 = ibreq.ibr_obj.ibr_obj_val->zo_group;
   if (p3 == NULL || strlen (p3) == 0)
-    ibreq.ibr_obj.ibr_obj_val[0].zo_group = nis_local_group ();
+    ibreq.ibr_obj.ibr_obj_val->zo_group = nis_local_group ();
 
-  p4 = ibreq.ibr_obj.ibr_obj_val[0].zo_domain;
-  ibreq.ibr_obj.ibr_obj_val[0].zo_domain =
+  p4 = ibreq.ibr_obj.ibr_obj_val->zo_domain;
+  ibreq.ibr_obj.ibr_obj_val->zo_domain =
     nis_domain_of_r (name, buf4, sizeof (buf4));
 
   if ((status = __do_niscall (ibreq.ibr_name, NIS_IBMODIFY,
 			      (xdrproc_t) xdr_ib_request,
 			      (caddr_t) & ibreq, (xdrproc_t) xdr_nis_result,
-			      (caddr_t) res, 0)) != RPC_SUCCESS)
+			      (caddr_t) res, 0)) != NIS_SUCCESS)
     res->status = status;
 
-  ibreq.ibr_obj.ibr_obj_val[0].zo_name = p1;
-  ibreq.ibr_obj.ibr_obj_val[0].zo_owner = p2;
-  ibreq.ibr_obj.ibr_obj_val[0].zo_group = p3;
-  ibreq.ibr_obj.ibr_obj_val[0].zo_domain = p4;
+  ibreq.ibr_obj.ibr_obj_val->zo_name = p1;
+  ibreq.ibr_obj.ibr_obj_val->zo_owner = p2;
+  ibreq.ibr_obj.ibr_obj_val->zo_group = p3;
+  ibreq.ibr_obj.ibr_obj_val->zo_domain = p4;
 
   nis_free_request (&ibreq);
 
@@ -395,7 +425,7 @@ nis_remove_entry (const_nis_name name, const nis_object *obj,
   if ((status = __do_niscall (ibreq.ibr_name, NIS_IBREMOVE,
 			      (xdrproc_t) xdr_ib_request,
 			      (caddr_t) & ibreq, (xdrproc_t) xdr_nis_result,
-			      (caddr_t) res, 0)) != RPC_SUCCESS)
+			      (caddr_t) res, 0)) != NIS_SUCCESS)
     res->status = status;
 
   nis_free_request (&ibreq);
@@ -421,7 +451,7 @@ nis_first_entry (const_nis_name name)
   if ((status = __do_niscall (ibreq.ibr_name, NIS_IBFIRST,
 			      (xdrproc_t) xdr_ib_request,
 			      (caddr_t) &ibreq, (xdrproc_t) xdr_nis_result,
-			      (caddr_t) res, 0)) != RPC_SUCCESS)
+			      (caddr_t) res, 0)) != NIS_SUCCESS)
     res->status = status;
 
   nis_free_request (&ibreq);
@@ -460,7 +490,7 @@ nis_next_entry (const_nis_name name, const netobj *cookie)
   if ((status = __do_niscall (ibreq.ibr_name, NIS_IBNEXT,
 			      (xdrproc_t) xdr_ib_request,
 			      (caddr_t) &ibreq, (xdrproc_t) xdr_nis_result,
-			      (caddr_t) res, 0)) != RPC_SUCCESS)
+			      (caddr_t) res, 0)) != NIS_SUCCESS)
     res->status = status;
 
   nis_free_request (&ibreq);
diff --git a/nis/nis_util.c b/nis/nis_util.c
new file mode 100644
index 0000000000..4e39d6fb6a
--- /dev/null
+++ b/nis/nis_util.c
@@ -0,0 +1,99 @@
+/* Copyright (c) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <string.h>
+#include <rpcsvc/nis.h>
+#include "nis_intern.h"
+
+fd_result *
+__nis_finddirectory (directory_obj *dir, const_nis_name name)
+{
+  fd_args fd_args;
+  fd_result *fd_res;
+
+  fd_args.dir_name = strdup (name);
+  fd_args.requester = nis_local_host();
+  fd_res = calloc (1, sizeof (fd_result));
+      
+  if (__do_niscall2 (dir->do_servers.do_servers_val, 
+		     dir->do_servers.do_servers_len, NIS_FINDDIRECTORY,
+		     (xdrproc_t) xdr_fd_args,
+		     (caddr_t) &fd_args, (xdrproc_t) xdr_fd_result,
+		     (caddr_t) fd_res, NO_AUTHINFO|USE_DGRAM) != NIS_SUCCESS)
+    fd_res->status = NIS_RPCERROR;
+  
+  return fd_res;
+}
+
+/* This is from libc/db/hash/hash_func.c, hash3 is static there */
+/*
+ * This is INCREDIBLY ugly, but fast.  We break the string up into 8 byte
+ * units.  On the first time through the loop we get the "leftover bytes"
+ * (strlen % 8).  On every other iteration, we perform 8 HASHC's so we handle
+ * all 8 bytes.  Essentially, this saves us 7 cmp & branch instructions.  If
+ * this routine is heavily used enough, it's worth the ugly coding.
+ *
+ * OZ's original sdbm hash
+ */
+unsigned long
+__nis_hash (const void *keyarg, register size_t len)
+{
+  register const u_char *key;
+  register size_t loop;
+  register u_int32_t h;
+  
+#define HASHC   h = *key++ + 65599 * h
+  
+  h = 0;
+  key = keyarg;
+  if (len > 0) 
+    {
+      loop = (len + 8 - 1) >> 3;
+      switch (len & (8 - 1)) 
+	{
+	case 0:
+	  do {
+	    HASHC;
+	    /* FALLTHROUGH */
+	  case 7:
+	    HASHC;
+	    /* FALLTHROUGH */
+	  case 6:
+	    HASHC;
+	    /* FALLTHROUGH */
+	  case 5:
+	    HASHC;
+	    /* FALLTHROUGH */
+	  case 4:
+	    HASHC;
+	    /* FALLTHROUGH */
+	  case 3:
+	    HASHC;
+	    /* FALLTHROUGH */
+	  case 2:
+	    HASHC;
+	    /* FALLTHROUGH */
+	  case 1:
+	    HASHC;
+	  } while (--loop);
+	}
+    }
+  return (h);
+}
+
diff --git a/nis/nisplus-parser.h b/nis/nisplus-parser.h
new file mode 100644
index 0000000000..b24ca46507
--- /dev/null
+++ b/nis/nisplus-parser.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef __NISPLUS_PARSER_H_
+#define __NISPLUS_PARSER_H_ 1
+
+#include <pwd.h>
+#include <grp.h>
+#include <shadow.h>
+
+extern int _nss_nisplus_parse_pwent (nis_result *, struct passwd *,
+				     char *, size_t);
+extern int _nss_nisplus_parse_grent (nis_result *, u_long, struct group *,
+				     char *, size_t);
+extern int _nss_nisplus_parse_spent (nis_result *, struct spwd *,
+				     char *, size_t);
+
+#endif
diff --git a/nis/nss_compat/compat-grp.c b/nis/nss_compat/compat-grp.c
index 40a190eea7..59165ea590 100644
--- a/nis/nss_compat/compat-grp.c
+++ b/nis/nss_compat/compat-grp.c
@@ -30,9 +30,12 @@
 #include <nsswitch.h>
 
 #include "nss-nisplus.h"
+#include "nisplus-parser.h"
 
 static service_user *ni = NULL;
 static bool_t use_nisplus = FALSE; /* default: group_compat: nis */
+static nis_name grptable = NULL; /* Name of the group table */
+static size_t grptablelen = 0;
 
 /* Get the declaration of the parser function.  */
 #define ENTNAME grent
@@ -57,14 +60,12 @@ struct ent_t
     char *oldkey;
     int oldkeylen;
     nis_result *result;
-    nis_name *names;
-    u_long names_nr;
     FILE *stream;
     struct blacklist_t blacklist;
 };
 typedef struct ent_t ent_t;
 
-static ent_t ext_ent = {0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0}};
+static ent_t ext_ent = {0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0}};
 
 /* Protect global state against multiple changers.  */
 __libc_lock_define_initialized (static, lock)
@@ -72,8 +73,31 @@ __libc_lock_define_initialized (static, lock)
 /* Prototypes for local functions.  */
 static void blacklist_store_name (const char *, ent_t *);
 static int in_blacklist (const char *, int, ent_t *);
-extern int _nss_nisplus_parse_grent (nis_result *, struct group *,
-				     char *, size_t);
+
+static enum nss_status
+_nss_first_init (void)
+{
+  if (ni == NULL)
+    {
+      __nss_database_lookup ("group_compat", NULL, "nis", &ni);
+      use_nisplus = (strcmp (ni->name, "nisplus") == 0);
+    }
+
+  if (grptable == NULL)
+    {
+      char buf [20 + strlen (nis_local_directory ())];
+      char *p;
+
+      p = stpcpy (buf, "group.org_dir.");
+      p = stpcpy (p, nis_local_directory ());
+      grptable = strdup (buf);
+      if (grptable == NULL)
+        return NSS_STATUS_TRYAGAIN;
+      grptablelen = strlen (grptable);
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
 
 static enum nss_status
 internal_setgrent (ent_t *ent)
@@ -82,6 +106,9 @@ internal_setgrent (ent_t *ent)
 
   ent->nis = ent->nis_first = 0;
 
+  if (_nss_first_init () != NSS_STATUS_SUCCESS)
+    return NSS_STATUS_UNAVAIL;
+
   if (ent->oldkey != NULL)
     {
       free (ent->oldkey);
@@ -95,12 +122,6 @@ internal_setgrent (ent_t *ent)
       ent->result = NULL;
     }
 
-  if (ent->names != NULL)
-    {
-      nis_freenames (ent->names);
-      ent->names = NULL;
-    }
-  ent->names_nr = 0;
   ent->blacklist.current = 0;
   if (ent->blacklist.data != NULL)
     ent->blacklist.data[0] = '\0';
@@ -126,12 +147,6 @@ _nss_compat_setgrent (void)
 
   __libc_lock_lock (lock);
 
-  if (ni == NULL)
-    {
-      __nss_database_lookup ("group_compat", NULL, "nis", &ni);
-      use_nisplus = (strcmp (ni->name, "nisplus") == 0);
-    }
-
   result = internal_setgrent (&ext_ent);
 
   __libc_lock_unlock (lock);
@@ -164,12 +179,6 @@ internal_endgrent (ent_t *ent)
       ent->result = NULL;
     }
 
-  if (ent->names != NULL)
-    {
-      nis_freenames (ent->names);
-      ent->names = NULL;
-    }
-  ent->names_nr = 0;
   ent->blacklist.current = 0;
   if (ent->blacklist.data != NULL)
     ent->blacklist.data[0] = '\0';
@@ -263,22 +272,11 @@ getgrent_next_nisplus (struct group *result, ent_t *ent, char *buffer,
 {
   int parse_res;
 
-  if (ent->names == NULL)
-    {
-      ent->names = nis_getnames ("group.org_dir");
-      if (ent->names == NULL || ent->names[0] == NULL)
-        {
-          ent->nis = 0;
-          return NSS_STATUS_UNAVAIL;
-        }
-    }
-
   do
     {
       if (ent->nis_first)
         {
-	next_name:
-          ent->result = nis_first_entry(ent->names[ent->names_nr]);
+          ent->result = nis_first_entry(grptable);
           if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
             {
               ent->nis = 0;
@@ -290,27 +288,16 @@ getgrent_next_nisplus (struct group *result, ent_t *ent, char *buffer,
         {
           nis_result *res;
 
-          res = nis_next_entry(ent->names[ent->names_nr],
-                               &ent->result->cookie);
+          res = nis_next_entry(grptable, &ent->result->cookie);
           nis_freeresult (ent->result);
           ent->result = res;
           if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
             {
-              if ((ent->result->status == NIS_NOTFOUND) &&
-                  ent->names[ent->names_nr + 1] != NULL)
-                {
-                  nis_freeresult (ent->result);
-                  ent->names_nr += 1;
-                  goto next_name;
-                }
-              else
-                {
-                  ent->nis = 0;
-                  return niserr2nss (ent->result->status);
-                }
+	      ent->nis = 0;
+	      return niserr2nss (ent->result->status);
             }
         }
-      parse_res = _nss_nisplus_parse_grent (ent->result, result, buffer,
+      parse_res = _nss_nisplus_parse_grent (ent->result, 0, result, buffer,
                                             buflen);
       if (parse_res &&
           in_blacklist (result->gr_name, strlen (result->gr_name), ent))
@@ -332,11 +319,10 @@ getgrent_next_file_plusgroup (struct group *result, char *buffer,
   if (use_nisplus) /* Do the NIS+ query here */
     {
       nis_result *res;
-      char buf[strlen (result->gr_name) + 24];
+      char buf[strlen (result->gr_name) + 24 + grptablelen];
 
-      sprintf(buf, "[name=%s],group.org_dir",
-              &result->gr_name[1]);
-      res = nis_list(buf, EXPAND_NAME, NULL, NULL);
+      sprintf(buf, "[name=%s],%s", &result->gr_name[1], 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);
@@ -344,7 +330,7 @@ getgrent_next_file_plusgroup (struct group *result, char *buffer,
           nis_freeresult (res);
           return status;
         }
-      parse_res = _nss_nisplus_parse_grent (res, result, buffer, buflen);
+      parse_res = _nss_nisplus_parse_grent (res, 0, result, buffer, buflen);
       nis_freeresult (res);
     }
   else /* Use NIS */
@@ -470,12 +456,6 @@ _nss_compat_getgrent_r (struct group *grp, char *buffer, size_t buflen)
 
   __libc_lock_lock (lock);
 
-  if (ni == NULL)
-    {
-      __nss_database_lookup ("group_compat", NULL, "nis", &ni);
-      use_nisplus = (strcmp (ni->name, "nisplus") == 0);
-    }
-
   /* Be prepared that the setgrent function was not called before.  */
   if (ext_ent.stream == NULL)
     status = internal_setgrent (&ext_ent);
@@ -493,7 +473,7 @@ enum nss_status
 _nss_compat_getgrnam_r (const char *name, struct group *grp,
 			char *buffer, size_t buflen)
 {
-  ent_t ent = {0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0}};
+  ent_t ent = {0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0}};
   enum nss_status status;
 
   if (name[0] == '-' || name[0] == '+')
@@ -501,15 +481,10 @@ _nss_compat_getgrnam_r (const char *name, struct group *grp,
 
   __libc_lock_lock (lock);
 
-  if (ni == NULL)
-    {
-      __nss_database_lookup ("group_compat", NULL, "nis", &ni);
-      use_nisplus = (strcmp (ni->name, "nisplus") == 0);
-    }
+  status = internal_setgrent (&ent);
 
   __libc_lock_unlock (lock);
 
-  status = internal_setgrent (&ent);
   if (status != NSS_STATUS_SUCCESS)
     return status;
 
@@ -527,20 +502,15 @@ enum nss_status
 _nss_compat_getgrgid_r (gid_t gid, struct group *grp,
 			char *buffer, size_t buflen)
 {
-  ent_t ent = {0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0}};
+  ent_t ent = {0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0}};
   enum nss_status status;
 
   __libc_lock_lock (lock);
 
-  if (ni == NULL)
-    {
-      __nss_database_lookup ("group_compat", NULL, "nis", &ni);
-      use_nisplus = (strcmp (ni->name, "nisplus") == 0);
-    }
+  status = internal_setgrent (&ent);
 
   __libc_lock_unlock (lock);
 
-  status = internal_setgrent (&ent);
   if (status != NSS_STATUS_SUCCESS)
     return status;
 
diff --git a/nis/nss_compat/compat-pwd.c b/nis/nss_compat/compat-pwd.c
index d0d230bb1e..0d0f2a6c33 100644
--- a/nis/nss_compat/compat-pwd.c
+++ b/nis/nss_compat/compat-pwd.c
@@ -32,9 +32,12 @@
 
 #include "netgroup.h"
 #include "nss-nisplus.h"
+#include "nisplus-parser.h"
 
 static service_user *ni = NULL;
 static bool_t use_nisplus = FALSE; /* default: passwd_compat: nis */
+static nis_name pwdtable = NULL; /* Name of the pwd table */
+static size_t pwdtablelen = 0;
 
 /* Get the declaration of the parser function.  */
 #define ENTNAME pwent
@@ -60,8 +63,6 @@ struct ent_t
     char *oldkey;
     int oldkeylen;
     nis_result *result;
-    nis_name *names;
-    u_long names_nr;
     FILE *stream;
     struct blacklist_t blacklist;
     struct passwd pwd;
@@ -69,7 +70,7 @@ struct ent_t
   };
 typedef struct ent_t ent_t;
 
-static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0},
+static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
 			{NULL, NULL, 0, 0, NULL, NULL, NULL}};
 
 /* Protect global state against multiple changers.  */
@@ -78,8 +79,7 @@ __libc_lock_define_initialized (static, lock)
 /* Prototypes for local functions.  */
 static void blacklist_store_name (const char *, ent_t *);
 static int in_blacklist (const char *, int, ent_t *);
-extern int _nss_nisplus_parse_pwent (nis_result *, struct passwd *,
-				     char *, size_t);
+
 static void
 give_pwd_free (struct passwd *pwd)
 {
@@ -209,12 +209,19 @@ internal_setpwent (ent_t *ent)
       ent->result = NULL;
     }
 
-  if (ent->names != NULL)
+  if (pwdtable == NULL)
     {
-      nis_freenames (ent->names);
-      ent->names = NULL;
+      char buf [20 + strlen (nis_local_directory ())];
+      char *p;
+
+      p = stpcpy (buf, "passwd.org_dir.");
+      p = stpcpy (p, nis_local_directory ());
+      pwdtable = strdup (buf);
+      if (pwdtable == NULL)
+	return NSS_STATUS_TRYAGAIN;
+      pwdtablelen = strlen (pwdtable);
     }
-  ent->names_nr = 0;
+
   ent->blacklist.current = 0;
   if (ent->blacklist.data != NULL)
     ent->blacklist.data[0] = '\0';
@@ -280,13 +287,6 @@ internal_endpwent (ent_t *ent)
       ent->result = NULL;
     }
 
-  if (ent->names != NULL)
-    {
-      nis_freenames (ent->names);
-      ent->names = NULL;
-    }
-  ent->names_nr = 0;
-
   ent->blacklist.current = 0;
   if (ent->blacklist.data != NULL)
     ent->blacklist.data[0] = '\0';
@@ -435,9 +435,9 @@ getpwent_next_nisplus_netgr (struct passwd *result, ent_t *ent, char *group,
       p2 = buffer + (buflen - p2len);
       buflen -= p2len;
       {
-	char buf[strlen (user) + 30];
-	sprintf(buf, "[name=%s],passwd.org_dir", user);
-	nisres = nis_list(buf, EXPAND_NAME, NULL, NULL);
+	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)
 	{
@@ -475,16 +475,6 @@ getpwent_next_nisplus (struct passwd *result, ent_t *ent, char *buffer,
   size_t p2len;
   char *p2;
 
-  if (ent->names == NULL)
-    {
-      ent->names = nis_getnames ("passwd.org_dir");
-      if (ent->names == NULL || ent->names[0] == NULL)
-	{
-	  ent->nis = 0;
-	  return NSS_STATUS_UNAVAIL;
-	}
-    }
-
   p2len = pwd_need_buflen (&ent->pwd);
   if (p2len > buflen)
     {
@@ -497,8 +487,7 @@ getpwent_next_nisplus (struct passwd *result, ent_t *ent, char *buffer,
     {
       if (ent->first)
 	{
-	next_name:
-	  ent->result = nis_first_entry(ent->names[ent->names_nr]);
+	  ent->result = nis_first_entry(pwdtable);
           if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
 	    {
 	      ent->nis = 0;
@@ -511,25 +500,14 @@ getpwent_next_nisplus (struct passwd *result, ent_t *ent, char *buffer,
 	{
 	  nis_result *res;
 
-	  res = nis_next_entry(ent->names[ent->names_nr],
-			       &ent->result->cookie);
+	  res = nis_next_entry(pwdtable, &ent->result->cookie);
 	  nis_freeresult (ent->result);
 	  ent->result = res;
 	  if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
 	    {
-	      if ((ent->result->status == NIS_NOTFOUND) &&
-		  ent->names[ent->names_nr + 1] != NULL)
-		{
-		  nis_freeresult (ent->result);
-		  ent->names_nr += 1;
-		  goto next_name;
-		}
-	      else
-		{
-		  ent->nis = 0;
-		  give_pwd_free (&ent->pwd);
-		  return niserr2nss (ent->result->status);
-		}
+	      ent->nis = 0;
+	      give_pwd_free (&ent->pwd);
+	      return niserr2nss (ent->result->status);
 	    }
 	}
       parse_res = _nss_nisplus_parse_pwent (ent->result, result, buffer,
@@ -648,11 +626,10 @@ getpwent_next_file_plususer (struct passwd *result, char *buffer,
   if (use_nisplus) /* Do the NIS+ query here */
     {
       nis_result *res;
-      char buf[strlen (result->pw_name) + 24];
+      char buf[strlen (result->pw_name) + 24 + pwdtablelen];
 
-      sprintf(buf, "[name=%s],passwd.org_dir",
-	      &result->pw_name[1]);
-      res = nis_list(buf, EXPAND_NAME, NULL, NULL);
+      sprintf(buf, "[name=%s],%s", &result->pw_name[1], 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);
@@ -869,7 +846,7 @@ enum nss_status
 _nss_compat_getpwnam_r (const char *name, struct passwd *pwd,
 			char *buffer, size_t buflen)
 {
-  ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0},
+  ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
 	       {NULL, NULL, 0, 0, NULL, NULL, NULL}};
   enum nss_status status;
 
@@ -904,7 +881,7 @@ enum nss_status
 _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd,
 			char *buffer, size_t buflen)
 {
-  ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0},
+  ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
 	       {NULL, NULL, 0, 0, NULL, NULL, NULL}};
   enum nss_status status;
 
diff --git a/nis/nss_compat/compat-spwd.c b/nis/nss_compat/compat-spwd.c
index 066f707ebb..4199baf202 100644
--- a/nis/nss_compat/compat-spwd.c
+++ b/nis/nss_compat/compat-spwd.c
@@ -32,9 +32,12 @@
 
 #include "netgroup.h"
 #include "nss-nisplus.h"
+#include "nisplus-parser.h"
 
 static service_user *ni = NULL;
 static bool_t use_nisplus = FALSE; /* default: passwd_compat: nis */
+static nis_name pwdtable = NULL; /* Name of the password table */
+static size_t pwdtablelen = 0;
 
 /* Get the declaration of the parser function.  */
 #define ENTNAME spent
@@ -60,8 +63,6 @@ struct ent_t
     char *oldkey;
     int oldkeylen;
     nis_result *result;
-    nis_name *names;
-    u_long names_nr;
     FILE *stream;
     struct blacklist_t blacklist;
     struct spwd pwd;
@@ -69,7 +70,7 @@ struct ent_t
   };
 typedef struct ent_t ent_t;
 
-static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0},
+static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
 			{NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
 
 /* Protect global state against multiple changers.  */
@@ -78,8 +79,7 @@ __libc_lock_define_initialized (static, lock)
 /* Prototypes for local functions.  */
 static void blacklist_store_name (const char *, ent_t *);
 static int in_blacklist (const char *, int, ent_t *);
-extern int _nss_nisplus_parse_spent (nis_result *, struct spwd *,
-				     char *, size_t);
+
 static void
 give_spwd_free (struct spwd *pwd)
 {
@@ -160,12 +160,19 @@ internal_setspent (ent_t *ent)
       nis_freeresult (ent->result);
       ent->result = NULL;
     }
-  if (ent->names != NULL)
+
+  if (pwdtable == NULL)
     {
-      nis_freenames (ent->names);
-      ent->names = NULL;
+      char buf [20 + strlen (nis_local_directory ())];
+      char *p;
+
+      p = stpcpy (buf, "passwd.org_dir.");
+      p = stpcpy (p, nis_local_directory ());
+      pwdtable = strdup (buf);
+      if (pwdtable == NULL)
+        return NSS_STATUS_TRYAGAIN;
+      pwdtablelen = strlen (pwdtable);
     }
-  ent->names_nr = 0;
 
   ent->blacklist.current = 0;
   if (ent->blacklist.data != NULL)
@@ -234,12 +241,6 @@ internal_endspent (ent_t *ent)
       nis_freeresult (ent->result);
       ent->result = NULL;
     }
-  if (ent->names != NULL)
-    {
-      nis_freenames (ent->names);
-      ent->names = NULL;
-    }
-  ent->names_nr = 0;
 
   ent->blacklist.current = 0;
   if (ent->blacklist.data != NULL)
@@ -387,9 +388,9 @@ getspent_next_nisplus_netgr (struct spwd *result, ent_t *ent, char *group,
       p2 = buffer + (buflen - p2len);
       buflen -= p2len;
       {
-        char buf[strlen (user) + 30];
-        sprintf(buf, "[name=%s],passwd.org_dir", user);
-        nisres = nis_list(buf, EXPAND_NAME, NULL, NULL);
+        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)
         {
@@ -427,16 +428,6 @@ getspent_next_nisplus (struct spwd *result, ent_t *ent, char *buffer,
   size_t p2len;
   char *p2;
 
-  if (ent->names == NULL)
-    {
-      ent->names = nis_getnames ("passwd.org_dir");
-      if (ent->names == NULL || ent->names[0] == NULL)
-        {
-          ent->nis = 0;
-          return NSS_STATUS_UNAVAIL;
-        }
-    }
-
   p2len = spwd_need_buflen (&ent->pwd);
   if (p2len > buflen)
     {
@@ -449,8 +440,7 @@ getspent_next_nisplus (struct spwd *result, ent_t *ent, char *buffer,
     {
       if (ent->first)
         {
-        next_name:
-          ent->result = nis_first_entry(ent->names[ent->names_nr]);
+          ent->result = nis_first_entry(pwdtable);
           if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
             {
               ent->nis = 0;
@@ -463,25 +453,14 @@ getspent_next_nisplus (struct spwd *result, ent_t *ent, char *buffer,
         {
           nis_result *res;
 
-          res = nis_next_entry(ent->names[ent->names_nr],
-                               &ent->result->cookie);
+          res = nis_next_entry(pwdtable, &ent->result->cookie);
           nis_freeresult (ent->result);
           ent->result = res;
           if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
             {
-              if ((ent->result->status == NIS_NOTFOUND) &&
-                  ent->names[ent->names_nr + 1] != NULL)
-                {
-                  nis_freeresult (ent->result);
-                  ent->names_nr += 1;
-                  goto next_name;
-                }
-              else
-                {
-                  ent->nis = 0;
-                  give_spwd_free (&ent->pwd);
-                  return niserr2nss (ent->result->status);
-                }
+	      ent->nis = 0;
+	      give_spwd_free (&ent->pwd);
+	      return niserr2nss (ent->result->status);
             }
         }
       parse_res = _nss_nisplus_parse_spent (ent->result, result, buffer,
@@ -601,11 +580,10 @@ getspent_next_file_plususer (struct spwd *result, char *buffer,
   if (use_nisplus) /* Do the NIS+ query here */
     {
       nis_result *res;
-      char buf[strlen (result->sp_namp) + 24];
+      char buf[strlen (result->sp_namp) + 24 + pwdtablelen];
 
-      sprintf(buf, "[name=%s],passwd.org_dir",
-              &result->sp_namp[1]);
-      res = nis_list(buf, EXPAND_NAME, NULL, NULL);
+      sprintf(buf, "[name=%s],%s", &result->sp_namp[1], pwdtable);
+      res = nis_list(buf, 0, NULL, NULL);
       if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
         {
           enum nss_status status =  niserr2nss (res->status);
@@ -821,7 +799,7 @@ enum nss_status
 _nss_compat_getspnam_r (const char *name, struct spwd *pwd,
 			char *buffer, size_t buflen)
 {
-  ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0},
+  ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
 	       {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
   enum nss_status status;
 
diff --git a/nis/nss_nis/nis-publickey.c b/nis/nss_nis/nis-publickey.c
index 52d1783d63..ade09c4127 100644
--- a/nis/nss_nis/nis-publickey.c
+++ b/nis/nss_nis/nis-publickey.c
@@ -22,7 +22,6 @@
 #include <errno.h>
 #include <string.h>
 #include <syslog.h>
-#include <bits/libc-lock.h>
 #include <rpc/rpc.h>
 #include <rpcsvc/yp.h>
 #include <rpcsvc/ypclnt.h>
@@ -40,7 +39,7 @@ _nss_nis_getpublickey (const char *netname, char *pkey)
   enum nss_status retval;
   char *domain, *result;
   int len;
-
+  
   pkey[0] = 0;
 
   if (netname == NULL)
diff --git a/nis/nss_nisplus/nisplus-alias.c b/nis/nss_nisplus/nisplus-alias.c
index 1784778ca0..660ba3c34a 100644
--- a/nis/nss_nisplus/nisplus-alias.c
+++ b/nis/nss_nisplus/nisplus-alias.c
@@ -31,27 +31,47 @@
 __libc_lock_define_initialized (static, lock)
 
 static nis_result *result = NULL;
-static nis_name *names = NULL;
+static u_long next_entry = 0;
+static nis_name tablename_val = NULL;
+static u_long tablename_len = 0;
 
 #define NISENTRYVAL(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
 
 #define NISENTRYLEN(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
+        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
+
+static enum nss_status
+_nss_create_tablename (void)
+{
+  if (tablename_val == NULL)
+    {
+      char buf [40 + strlen (nis_local_directory ())];
+      char *p;
+
+      p = stpcpy (buf, "mail_aliases.org_dir.");
+      p = stpcpy (p, nis_local_directory ());
+      tablename_val = strdup (buf);
+      if (tablename_val == NULL)
+        return NSS_STATUS_TRYAGAIN;
+      tablename_len = strlen (tablename_val);
+    }
+  return NSS_STATUS_SUCCESS;
+}
 
 static int
-_nss_nisplus_parse_aliasent (nis_result *result, struct aliasent *alias,
-			  char *buffer, size_t buflen)
+_nss_nisplus_parse_aliasent (nis_result *result, unsigned long entry,
+			     struct aliasent *alias, char *buffer,
+			     size_t buflen)
 {
   if (result == NULL)
     return 0;
 
   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
-      result->objects.objects_len != 1 ||
-      result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
-      strcmp(result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
+      __type_of (&result->objects.objects_val[entry]) != ENTRY_OBJ ||
+      strcmp(result->objects.objects_val[entry].EN_data.en_type,
 	     "mail_aliases") != 0 ||
-      result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 2)
+      result->objects.objects_val[entry].EN_data.en_cols.en_cols_len < 2)
     return 0;
   else
     {
@@ -62,7 +82,7 @@ _nss_nisplus_parse_aliasent (nis_result *result, struct aliasent *alias,
       char *line;
       char *cp;
 
-      if (NISENTRYLEN(0, 1, result) >= buflen)
+      if (NISENTRYLEN(entry, 1, result) >= buflen)
 	{
 	  /* The line is too long for our buffer.  */
 	no_more_room:
@@ -71,19 +91,20 @@ _nss_nisplus_parse_aliasent (nis_result *result, struct aliasent *alias,
 	}
       else
 	{
-	  strncpy (buffer, NISENTRYVAL(0, 1, result), NISENTRYLEN(0, 1, result));
-	  buffer[NISENTRYLEN(0, 1, result)] = '\0';
+	  strncpy (buffer, NISENTRYVAL(entry, 1, result),
+		   NISENTRYLEN(entry, 1, result));
+	  buffer[NISENTRYLEN(entry, 1, result)] = '\0';
 	}
 
-      if (NISENTRYLEN(0, 0, result) >= room_left)
+      if (NISENTRYLEN(entry, 0, result) >= room_left)
 	goto no_more_room;
 
       alias->alias_local = 0;
       alias->alias_members_len = 0;
       *first_unused = '\0';
       ++first_unused;
-      strcpy (first_unused, NISENTRYVAL(0, 0, result));
-      first_unused[NISENTRYLEN(0, 0, result)] = '\0';
+      strcpy (first_unused, NISENTRYVAL(entry, 0, result));
+      first_unused[NISENTRYLEN(entry, 0, result)] = '\0';
       alias->alias_name = first_unused;
 
       /* Terminate the line for any case.  */
@@ -129,23 +150,38 @@ _nss_nisplus_parse_aliasent (nis_result *result, struct aliasent *alias,
     }
 }
 
-enum nss_status
-_nss_nisplus_setaliasent (void)
+static enum nss_status
+internal_setaliasent (void)
 {
-  __libc_lock_lock (lock);
-
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
+
+  if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+    return NSS_STATUS_UNAVAIL;
+
+  next_entry = 0;
+  result = nis_list(tablename_val, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
     {
-      nis_freenames (names);
-      names = NULL;
+      nis_freeresult (result);
+      result = NULL;
     }
+  return niserr2nss (result->status);
+}
+
+enum nss_status
+_nss_nisplus_setaliasent (void)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_setaliasent ();
 
   __libc_lock_unlock (lock);
 
-  return NSS_STATUS_SUCCESS;
+  return status;
 }
 
 enum nss_status
@@ -156,11 +192,7 @@ _nss_nisplus_endaliasent (void)
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
+  next_entry = 0;
 
   __libc_lock_unlock (lock);
 
@@ -173,31 +205,18 @@ internal_nisplus_getaliasent_r (struct aliasent *alias,
 {
   int parse_res;
 
+  if (result == NULL)
+    internal_setaliasent ();
+
   /* Get the next entry until we found a correct one. */
   do
     {
-      if (result == NULL)
-	{
-	  names = nis_getnames("mail_aliases.org_dir");
-	  if (names == NULL || names[0] == NULL)
-	    return NSS_STATUS_UNAVAIL;
-
-	  result = nis_first_entry(names[0]);
-	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-	    return niserr2nss (result->status);
-	}
-      else
-	{
-	  nis_result *res2;
-
-	  res2 = nis_next_entry(names[0], &result->cookie);
-	  nis_freeresult (result);
-	  result = res2;
-	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-	    return niserr2nss (result->status);
-	}
+      if (next_entry >= result->objects.objects_len)
+	return NSS_STATUS_NOTFOUND;
 
-      parse_res = _nss_nisplus_parse_aliasent (result, alias, buffer, buflen);
+      parse_res = _nss_nisplus_parse_aliasent (result, next_entry, alias,
+					       buffer, buflen);
+      ++next_entry;
     } while (!parse_res);
 
   return NSS_STATUS_SUCCESS;
@@ -224,21 +243,26 @@ _nss_nisplus_getaliasbyname_r (const char *name, struct aliasent *alias,
 {
   int parse_res;
 
+  if (tablename_val == NULL)
+    if (_nss_create_tablename() != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
+
   if (name == NULL || strlen(name) > 8)
     return NSS_STATUS_NOTFOUND;
   else
     {
       nis_result *result;
-      char buf[strlen (name) + 30];
+      char buf[strlen (name) + 30 + tablename_len];
 
-      sprintf(buf, "[name=%s],mail_aliases.org_dir", name);
+      sprintf(buf, "[name=%s],%s", name, tablename_val);
 
-      result = nis_list(buf, EXPAND_NAME, NULL, NULL);
+      result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
       if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	return niserr2nss (result->status);
 
-      parse_res = _nss_nisplus_parse_aliasent (result, alias, buffer, buflen);
+      parse_res = _nss_nisplus_parse_aliasent (result, 0, alias,
+					       buffer, buflen);
 
       if (parse_res)
 	return NSS_STATUS_SUCCESS;
diff --git a/nis/nss_nisplus/nisplus-ethers.c b/nis/nss_nisplus/nisplus-ethers.c
index d83c7b2e11..7c07833ef4 100644
--- a/nis/nss_nisplus/nisplus-ethers.c
+++ b/nis/nss_nisplus/nisplus-ethers.c
@@ -33,7 +33,8 @@
 __libc_lock_define_initialized (static, lock)
 
 static nis_result *result = NULL;
-static nis_name *names = NULL;
+static nis_name tablename_val = NULL;
+static u_long tablename_len = 0;
 
 /* Because the `ethers' lookup does not fit so well in the scheme so
    we define a dummy struct here which helps us to use the available
@@ -45,32 +46,6 @@ struct etherent
 };
 struct etherent_data {};
 
-#define ENTNAME         etherent
-#define DATABASE        "ethers"
-#include "../../nss/nss_files/files-parse.c"
-LINE_PARSER
-("#",
- /* Read the ethernet address: 6 x 8bit hexadecimal number.  */
- {
-   size_t cnt;
-
-   for (cnt = 0; cnt < 6; ++cnt)
-     {
-       unsigned int number;
-
-       if (cnt < 5)
-         INT_FIELD (number, ISCOLON , 0, 16, (unsigned int))
-       else
-         INT_FIELD (number, isspace, 0, 16, (unsigned int))
-
-       if (number > 0xff)
-         return 0;
-       result->e_addr.ether_addr_octet[cnt] = number;
-     }
- };
- STRING_FIELD (result->e_name, isspace, 1);
- )
-
 #define NISENTRYVAL(idx,col,res) \
         ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
 
@@ -83,21 +58,18 @@ _nss_nisplus_parse_etherent (nis_result *result, struct etherent *ether,
 {
   char *p = buffer;
   size_t room_left = buflen;
-  struct parser_data *data = (void *) buffer;
 
   if (result == NULL)
     return 0;
 
   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
       result->objects.objects_len != 1 ||
-      result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
-      strcmp(result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
+      __type_of (NIS_RES_OBJECT (result)) != ENTRY_OBJ ||
+      strcmp(NIS_RES_OBJECT (result)->EN_data.en_type,
              "ethers_tbl") != 0 ||
-      result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 2)
+      NIS_RES_OBJECT(result)->EN_data.en_cols.en_cols_len < 2)
     return 0;
 
-  memset (p, '\0', room_left);
-
   /* Generate the ether entry format and use the normal parser */
   if (NISENTRYLEN (0, 0, result) +1 > room_left)
     {
@@ -106,32 +78,47 @@ _nss_nisplus_parse_etherent (nis_result *result, struct etherent *ether,
     }
   strncpy (p, NISENTRYVAL (0, 0, result), NISENTRYLEN (0, 0, result));
   room_left -= (NISENTRYLEN (0, 0, result) +1);
+  ether->e_name = p;
+
+  ether->e_addr = *ether_aton (NISENTRYVAL (0, 1, result));
+
+  return 1;
+}
 
-  if (NISENTRYLEN (0, 1, result) +1 > room_left)
+static enum nss_status
+_nss_create_tablename (void)
+{
+  if (tablename_val == NULL)
     {
-      __set_errno (ERANGE);
-      return 0;
-    }
-  strcat (p, "\t");
-  strncat (p, NISENTRYVAL (0, 1, result), NISENTRYLEN (0, 1, result));
-  room_left -= (NISENTRYLEN (0, 1, result) + 1);
+      char buf [40 + strlen (nis_local_directory ())];
+      char *p;
 
-  return _nss_files_parse_etherent (p,ether, data, buflen);
+      p = stpcpy (buf, "ethers.org_dir.");
+      p = stpcpy (p, nis_local_directory ());
+      tablename_val = strdup (buf);
+      if (tablename_val == NULL)
+        return NSS_STATUS_TRYAGAIN;
+      tablename_len = strlen (tablename_val);
+    }
+  return NSS_STATUS_SUCCESS;
 }
 
+
 enum nss_status
 _nss_nisplus_setetherent (void)
 {
+  enum nss_status status;
+
+  status = NSS_STATUS_SUCCESS;
+
   __libc_lock_lock (lock);
 
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
+
+  if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+    status = NSS_STATUS_UNAVAIL;
 
   __libc_lock_unlock (lock);
 
@@ -146,11 +133,6 @@ _nss_nisplus_endetherent (void)
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
 
   __libc_lock_unlock (lock);
 
@@ -163,16 +145,16 @@ internal_nisplus_getetherent_r (struct etherent *ether, char *buffer,
 {
   int parse_res;
 
+  if (tablename_val == NULL)
+    if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
+
   /* Get the next entry until we found a correct one. */
   do
     {
       if (result == NULL)
 	{
-	  names = nis_getnames("ethers.org_dir");
-	  if (names == NULL || names[0] == NULL)
-	    return NSS_STATUS_UNAVAIL;
-
-	  result = nis_first_entry(names[0]);
+	  result = nis_first_entry(tablename_val);
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    return niserr2nss (result->status);
 	}
@@ -180,7 +162,7 @@ internal_nisplus_getetherent_r (struct etherent *ether, char *buffer,
 	{
 	  nis_result *res2;
 
-	  res2 = nis_next_entry(names[0], &result->cookie);
+	  res2 = nis_next_entry(tablename_val, &result->cookie);
 	  nis_freeresult (result);
 	  result = res2;
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
@@ -214,16 +196,20 @@ _nss_nisplus_gethostton_r (const char *name, struct etherent *eth,
 {
   int parse_res;
 
+  if (tablename_val == NULL)
+    if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
+
   if (name == NULL)
     return NSS_STATUS_NOTFOUND;
   else
     {
       nis_result *result;
-      char buf[strlen (name) + 255];
+      char buf[strlen (name) + 40 + tablename_len];
 
-      sprintf(buf, "[name=%s],ethers.org_dir", name);
+      sprintf(buf, "[name=%s],%s", name, tablename_val);
 
-      result = nis_list(buf, EXPAND_NAME, NULL, NULL);
+      result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
       if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
         return niserr2nss (result->status);
@@ -245,34 +231,40 @@ _nss_nisplus_getntohost_r (const struct ether_addr *addr,
 			   struct etherent *eth,
 			   char *buffer, size_t buflen)
 {
-  int parse_res;
-  nis_result *result;
-  char buf[255];
+  if (tablename_val == NULL)
+    if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
 
   if (addr == NULL)
     {
       __set_errno (EINVAL);
       return NSS_STATUS_UNAVAIL;
     }
+  else
+    {
+      int parse_res;
+      nis_result *result;
+      char buf[255 + tablename_len];
 
-  memset (&buf, '\0', sizeof (buf));
-  snprintf(buf, sizeof (buf), "[addr=%x:%x:%x:%x:%x:%x],ethers.org_dir",
-	   addr->ether_addr_octet[0], addr->ether_addr_octet[1],
-	   addr->ether_addr_octet[2], addr->ether_addr_octet[3],
-	   addr->ether_addr_octet[4], addr->ether_addr_octet[5]);
+      memset (&buf, '\0', sizeof (buf));
+      snprintf(buf, sizeof (buf), "[addr=%x:%x:%x:%x:%x:%x],ethers.org_dir",
+	       addr->ether_addr_octet[0], addr->ether_addr_octet[1],
+	       addr->ether_addr_octet[2], addr->ether_addr_octet[3],
+	       addr->ether_addr_octet[4], addr->ether_addr_octet[5]);
 
-  result = nis_list(buf, EXPAND_NAME, NULL, NULL);
+      result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
-  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-    return niserr2nss (result->status);
+      if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+	return niserr2nss (result->status);
 
-  parse_res = _nss_nisplus_parse_etherent (result, eth, buffer, buflen);
+      parse_res = _nss_nisplus_parse_etherent (result, eth, buffer, buflen);
 
-  if (parse_res)
-    return NSS_STATUS_SUCCESS;
+      if (parse_res)
+	return NSS_STATUS_SUCCESS;
 
-  if (!parse_res && errno == ERANGE)
-    return NSS_STATUS_TRYAGAIN;
-  else
-    return NSS_STATUS_NOTFOUND;
+      if (!parse_res && errno == ERANGE)
+	return NSS_STATUS_TRYAGAIN;
+      else
+	return NSS_STATUS_NOTFOUND;
+    }
 }
diff --git a/nis/nss_nisplus/nisplus-grp.c b/nis/nss_nisplus/nisplus-grp.c
index bf851e0cea..f759f61ca0 100644
--- a/nis/nss_nisplus/nisplus-grp.c
+++ b/nis/nss_nisplus/nisplus-grp.c
@@ -27,143 +27,66 @@
 #include <rpcsvc/nislib.h>
 
 #include "nss-nisplus.h"
+#include "nisplus-parser.h"
 
 __libc_lock_define_initialized (static, lock);
 
 static nis_result *result = NULL;
-static nis_name *names = NULL;
+static unsigned long next_entry = 0;
+static nis_name tablename_val = NULL;
+static u_long tablename_len = 0;
 
-#define NISENTRYVAL(idx,col,res) \
-((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
-
-#define NISENTRYLEN(idx,col,res) \
-  ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
-
-int
-_nss_nisplus_parse_grent (nis_result * result, struct group *gr,
-			  char *buffer, size_t buflen)
+static enum nss_status
+_nss_create_tablename (void)
 {
-  char *first_unused = buffer;
-  size_t room_left = buflen;
-  char *line;
-  int count;
-
-  if (result == NULL)
-    return 0;
-
-  if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
-      result->objects.objects_len != 1 ||
-      result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
-      strcmp (result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
-	      "group_tbl") != 0 ||
-      result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 4)
-    return 0;
-
-  if (NISENTRYLEN (0, 0, result) >= room_left)
+  if (tablename_val == NULL)
     {
-      /* The line is too long for our buffer.  */
-    no_more_room:
-      __set_errno (ERANGE);
-      return 0;
+      char buf [40 + strlen (nis_local_directory ())];
+      char *p;
+
+      p = stpcpy (buf, "group.org_dir.");
+      p = stpcpy (p, nis_local_directory ());
+      tablename_val = strdup (buf);
+      if (tablename_val == NULL)
+        return NSS_STATUS_TRYAGAIN;
+      tablename_len = strlen (tablename_val);
     }
+  return NSS_STATUS_SUCCESS;
+}
 
-  strncpy (first_unused, NISENTRYVAL (0, 0, result),
-	   NISENTRYLEN (0, 0, result));
-  first_unused[NISENTRYLEN (0, 0, result)] = '\0';
-  gr->gr_name = first_unused;
-  room_left -= (strlen (first_unused) + 1);
-  first_unused += strlen (first_unused) + 1;
-
-  if (NISENTRYLEN (0, 1, result) >= room_left)
-    goto no_more_room;
-
-  strncpy (first_unused, NISENTRYVAL (0, 1, result),
-	   NISENTRYLEN (0, 1, result));
-  first_unused[NISENTRYLEN (0, 1, result)] = '\0';
-  gr->gr_passwd = first_unused;
-  room_left -= (strlen (first_unused) + 1);
-  first_unused += strlen (first_unused) + 1;
-
-  if (NISENTRYLEN (0, 2, result) >= room_left)
-    goto no_more_room;
-
-  strncpy (first_unused, NISENTRYVAL (0, 2, result),
-	   NISENTRYLEN (0, 2, result));
-  first_unused[NISENTRYLEN (0, 2, result)] = '\0';
-  gr->gr_gid = atoi (first_unused);
-  room_left -= (strlen (first_unused) + 1);
-  first_unused += strlen (first_unused) + 1;
-
-  if (NISENTRYLEN (0, 3, result) >= room_left)
-    goto no_more_room;
-
-  strncpy (first_unused, NISENTRYVAL (0, 3, result),
-	   NISENTRYLEN (0, 3, result));
-  first_unused[NISENTRYLEN (0, 3, result)] = '\0';
-  line = first_unused;
-  room_left -= (strlen (line) + 1);
-  first_unused += strlen (line) + 1;
-  /* Adjust the pointer so it is aligned for
-     storing pointers.  */
-  first_unused += __alignof__ (char *) - 1;
-  first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
-  gr->gr_mem = (char **) first_unused;
-
-  count = 0;
-  while (*line != '\0')
-    {
-      /* Skip leading blanks.  */
-      while (isspace (*line))
-	++line;
-
-      if (*line == '\0')
-	break;
-
-      if (room_left < sizeof (char *))
-	  goto no_more_room;
-      room_left -= sizeof (char *);
-      gr->gr_mem[count] = line;
+static enum nss_status
+internal_setgrent (void)
+{
+  if (result)
+    nis_freeresult (result);
+  result = NULL;
+  next_entry = 0;
 
-      while (*line != '\0' && *line != ',' && !isspace(*line))
-	++line;
+  if (tablename_val == NULL)
+    if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
 
-      if (line != gr->gr_mem[count])
-	{
-	  if (*line != '\0')
-	    {
-	      *line = '\0';
-	      ++line;
-	    }
-	  ++count;
-	}
-      else
-	gr->gr_mem[count] = NULL;
+  result = nis_list (tablename_val, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+    {
+      nis_freeresult (result);
+      result = NULL;
     }
-  if (room_left < sizeof (char *))
-      goto no_more_room;
-  room_left -= sizeof (char *);
-  gr->gr_mem[count] = NULL;
-
-  return 1;
+  return niserr2nss (result->status);
 }
 
 enum nss_status
 _nss_nisplus_setgrent (void)
 {
+  enum nss_status status;
+
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
+  status = internal_setgrent ();
 
   __libc_lock_unlock (lock);
 
-  return NSS_STATUS_SUCCESS;
+  return status;
 }
 
 enum nss_status
@@ -174,11 +97,6 @@ _nss_nisplus_endgrent (void)
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
 
   __libc_lock_unlock (lock);
 
@@ -190,31 +108,18 @@ internal_nisplus_getgrent_r (struct group *gr, char *buffer, size_t buflen)
 {
   int parse_res;
 
+  if (result == NULL)
+    internal_setgrent ();
+
   /* Get the next entry until we found a correct one. */
   do
     {
-      if (result == NULL)
-	{
-	  names = nis_getnames ("group.org_dir");
-	  if (names == NULL || names[0] == NULL)
-	    return NSS_STATUS_UNAVAIL;
-
-	  result = nis_first_entry (names[0]);
-	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-	    return niserr2nss (result->status);
-	}
-      else
-	{
-	  nis_result *res;
-
-	  res = nis_next_entry (names[0], &result->cookie);
-	  nis_freeresult (result);
-	  result = res;
-	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-	    return niserr2nss (result->status);
-	}
+      if (next_entry >= result->objects.objects_len)
+	return NSS_STATUS_NOTFOUND;
 
-      parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen);
+      parse_res = _nss_nisplus_parse_grent (result, next_entry, gr,
+					    buffer, buflen);
+      ++next_entry;
     }
   while (!parse_res);
 
@@ -241,16 +146,20 @@ _nss_nisplus_getgrnam_r (const char *name, struct group *gr,
 {
   int parse_res;
 
+  if (tablename_val == NULL)
+    if (_nss_create_tablename() != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
+
   if (name == NULL || strlen (name) > 8)
     return NSS_STATUS_NOTFOUND;
   else
     {
       nis_result *result;
-      char buf[strlen (name) + 24];
+      char buf[strlen (name) + 24 + tablename_len];
 
-      sprintf (buf, "[name=%s],group.org_dir", name);
+      sprintf (buf, "[name=%s],%s", name, tablename_val);
 
-      result = nis_list (buf, EXPAND_NAME, NULL, NULL);
+      result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
 
       if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	{
@@ -260,7 +169,7 @@ _nss_nisplus_getgrnam_r (const char *name, struct group *gr,
 	  return status;
 	}
 
-      parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen);
+      parse_res = _nss_nisplus_parse_grent (result, 0, gr, buffer, buflen);
 
       nis_freeresult (result);
 
@@ -278,31 +187,37 @@ enum nss_status
 _nss_nisplus_getgrgid_r (const gid_t gid, struct group *gr,
 			 char *buffer, size_t buflen)
 {
-  int parse_res;
-  nis_result *result;
-  char buf[36];
+  if (tablename_val == NULL)
+    if (_nss_create_tablename() != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
 
-  sprintf (buf, "[gid=%d],group.org_dir", gid);
+  {
+    int parse_res;
+    nis_result *result;
+    char buf[36 + tablename_len];
 
-  result = nis_list (buf, EXPAND_NAME, NULL, NULL);
+    sprintf (buf, "[gid=%d],%s", gid, tablename_val);
 
-  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-    {
-      enum nss_status status = niserr2nss (result->status);
+    result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
-      nis_freeresult (result);
-      return status;
-    }
+    if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+      {
+	enum nss_status status = niserr2nss (result->status);
+
+	nis_freeresult (result);
+	return status;
+      }
 
-  parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen);
+    parse_res = _nss_nisplus_parse_grent (result, 0, gr, buffer, buflen);
 
-  nis_freeresult (result);
+    nis_freeresult (result);
 
-  if (parse_res)
-    return NSS_STATUS_SUCCESS;
+    if (parse_res)
+      return NSS_STATUS_SUCCESS;
 
-  if (!parse_res && errno == ERANGE)
-    return NSS_STATUS_TRYAGAIN;
-  else
-    return NSS_STATUS_NOTFOUND;
+    if (!parse_res && errno == ERANGE)
+      return NSS_STATUS_TRYAGAIN;
+    else
+      return NSS_STATUS_NOTFOUND;
+  }
 }
diff --git a/nis/nss_nisplus/nisplus-hosts.c b/nis/nss_nisplus/nisplus-hosts.c
index ee87a78225..19f9161076 100644
--- a/nis/nss_nisplus/nisplus-hosts.c
+++ b/nis/nss_nisplus/nisplus-hosts.c
@@ -33,13 +33,14 @@
 __libc_lock_define_initialized (static, lock)
 
 static nis_result *result = NULL;
-static nis_name *names = NULL;
+static nis_name tablename_val = NULL;
+static u_long tablename_len = 0;
 
 #define NISENTRYVAL(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
 
 #define NISENTRYLEN(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
+        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
 
 /* Get implementation for some internal functions. */
 #include "../../resolv/mapv4v6addr.h"
@@ -57,10 +58,10 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host,
     return 0;
 
   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
-      result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
-      strcmp(result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
-             "hosts_tbl") != 0 ||
-      result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 4)
+      __type_of (result->objects.objects_val) != ENTRY_OBJ ||
+      strcmp(result->objects.objects_val[0].EN_data.en_type,
+	     "hosts_tbl") != 0 ||
+      result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 4)
     return 0;
 
   if (room_left < NISENTRYLEN (0, 2, result) + 1)
@@ -162,37 +163,58 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host,
       host->h_aliases[i] = line;
 
       while (*line != '\0' && *line != ' ')
-	line++;
+	++line;
 
-      if (line != host->h_aliases[i])
-            {
-              *line = '\0';
-              line++;
-              i++;
-            }
+      if (*line == ' ')
+	{
+	  *line = '\0';
+	  ++line;
+	  ++i;
+	}
+      else
+	host->h_aliases[i+1] = NULL;
     }
 
   return 1;
 
 }
 
+static enum nss_status
+_nss_create_tablename (void)
+{
+  if (tablename_val == NULL)
+    {
+      char buf [40 + strlen (nis_local_directory ())];
+      char *p;
+
+      p = stpcpy (buf, "hosts.org_dir.");
+      p = stpcpy (p, nis_local_directory ());
+      tablename_val = strdup (buf);
+      if (tablename_val == NULL)
+        return NSS_STATUS_TRYAGAIN;
+      tablename_len = strlen (tablename_val);
+    }
+  return NSS_STATUS_SUCCESS;
+}
+
 enum nss_status
 _nss_nisplus_sethostent (void)
 {
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
   __libc_lock_lock (lock);
 
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
+
+  if (tablename_val == NULL)
+    if (_nss_create_tablename() != NSS_STATUS_SUCCESS)
+      status = NSS_STATUS_UNAVAIL;
 
   __libc_lock_unlock (lock);
 
-  return NSS_STATUS_SUCCESS;
+  return status;
 }
 
 enum nss_status
@@ -203,11 +225,6 @@ _nss_nisplus_endhostent (void)
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
 
   __libc_lock_unlock (lock);
 
@@ -225,11 +242,11 @@ internal_nisplus_gethostent_r (struct hostent *host, char *buffer,
     {
       if (result == NULL)
 	{
-	  names = nis_getnames("hosts.org_dir");
-	  if (names == NULL || names[0] == NULL)
-	    return NSS_STATUS_UNAVAIL;
+	  if (tablename_val == NULL)
+	    if (_nss_create_tablename() != NSS_STATUS_SUCCESS)
+	      return NSS_STATUS_UNAVAIL;
 
-	  result = nis_first_entry(names[0]);
+	  result = nis_first_entry(tablename_val);
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
             {
               int retval;
@@ -248,7 +265,7 @@ internal_nisplus_gethostent_r (struct hostent *host, char *buffer,
 	{
 	  nis_result *res2;
 
-	  res2 = nis_next_entry(names[0], &result->cookie);
+	  res2 = nis_next_entry(tablename_val, &result->cookie);
 	  nis_freeresult (result);
 	  result = res2;
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
@@ -302,6 +319,13 @@ _nss_nisplus_gethostbyname2_r (const char *name, int af, struct hostent *host,
 {
   int parse_res, retval;
 
+  if (tablename_val == NULL)
+    if (_nss_create_tablename() != NSS_STATUS_SUCCESS)
+      {
+	*herrnop = NETDB_INTERNAL;
+	return NSS_STATUS_UNAVAIL;
+      }
+
   if (name == NULL)
     {
       __set_errno (EINVAL);
@@ -311,28 +335,27 @@ _nss_nisplus_gethostbyname2_r (const char *name, int af, struct hostent *host,
   else
     {
       nis_result *result;
-      char buf[strlen (name) + 255];
+      char buf[strlen (name) + 255 + tablename_len];
 
       /* Search at first in the alias list, and use the correct name
 	 for the next search */
-      sprintf(buf, "[name=%s],hosts.org_dir", name);
-      result = nis_list(buf, EXPAND_NAME, NULL, NULL);
+      sprintf(buf, "[name=%s],%s", name, tablename_val);
+      result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
       /* If we do not find it, try it as original name. But if the
 	 database is correct, we should find it in the first case, too */
-      if ((result->status != NIS_SUCCESS &&
-	   result->status != NIS_S_SUCCESS) ||
-	  result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
-	  strcmp(result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
+      if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
+	  __type_of (result->objects.objects_val) != ENTRY_OBJ ||
+	  strcmp(result->objects.objects_val->EN_data.en_type,
 		 "hosts_tbl") != 0 ||
-	  result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len
-	  < 3)
-	sprintf(buf, "[cname=%s],hosts.org_dir", name);
+	  result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
+	sprintf(buf, "[cname=%s],%s", name, tablename_val);
       else
-	sprintf(buf, "[cname=%s],hosts.org_dir", NISENTRYVAL(0, 0, result));
+	sprintf(buf, "[cname=%s],%s", NISENTRYVAL(0, 0, result),
+		tablename_val);
 
       nis_freeresult (result);
-      result = nis_list(buf, EXPAND_NAME, NULL, NULL);
+      result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
       retval = niserr2nss (result->status);
       if (retval != NSS_STATUS_SUCCESS)
@@ -385,17 +408,21 @@ _nss_nisplus_gethostbyaddr_r (const char *addr, int addrlen, int type,
 			      struct hostent *host, char *buffer,
 			      size_t buflen, int *herrnop)
 {
+  if (tablename_val == NULL)
+    if (_nss_create_tablename() != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
+
   if (addr == NULL)
     return NSS_STATUS_NOTFOUND;
   else
     {
       nis_result *result;
-      char buf[1025];
+      char buf[255 + tablename_len];
       int retval, parse_res;
 
-      snprintf(buf, sizeof (buf) -1, "[addr=%s],hosts.org_dir",
-	       inet_ntoa (*(struct in_addr *)addr));
-      result = nis_list(buf, EXPAND_NAME, NULL, NULL);
+      snprintf(buf, sizeof (buf) -1, "[addr=%s],%s",
+	       inet_ntoa (*(struct in_addr *)addr), tablename_val);
+      result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
       retval = niserr2nss (result->status);
       if (retval != NSS_STATUS_SUCCESS)
diff --git a/nis/nss_nisplus/nisplus-netgrp.c b/nis/nss_nisplus/nisplus-netgrp.c
index 5907882725..670d0bb4ed 100644
--- a/nis/nss_nisplus/nisplus-netgrp.c
+++ b/nis/nss_nisplus/nisplus-netgrp.c
@@ -36,10 +36,10 @@ static unsigned long data_size = 0;
 static unsigned long position = 0;
 
 #define NISENTRYVAL(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
 
 #define NISENTRYLEN(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
+        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
 
 static enum nss_status
 _nss_nisplus_parse_netgroup (struct __netgrent *result, char *buffer,
@@ -49,8 +49,7 @@ _nss_nisplus_parse_netgroup (struct __netgrent *result, char *buffer,
 
   /* Some sanity checks.  */
   if (data == NULL || data_size == 0)
-    /* User bug.  setnetgrent() wasn't called before.  */
-    abort ();
+    return NSS_STATUS_NOTFOUND;
 
   if (position == data_size)
     return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
@@ -154,9 +153,9 @@ _nss_nisplus_setnetgrent (char *group)
       position = 0;
     }
 
-  sprintf(buf, "[name=%s],netgroup.org_dir", group);
+  sprintf (buf, "[name=%s],netgroup.org_dir", group);
 
-  data = nis_list(buf, EXPAND_NAME, NULL, NULL);
+  data = nis_list (buf, EXPAND_NAME, NULL, NULL);
 
   if (niserr2nss (data->status) != NSS_STATUS_SUCCESS)
     {
diff --git a/nis/nss_nisplus/nisplus-network.c b/nis/nss_nisplus/nisplus-network.c
index 8d6e08b2c6..9a46397149 100644
--- a/nis/nss_nisplus/nisplus-network.c
+++ b/nis/nss_nisplus/nisplus-network.c
@@ -29,109 +29,160 @@
 
 #include "nss-nisplus.h"
 
-/* Get the declaration of the parser function.  */
-#define ENTNAME netent
-#define DATABASE "networks"
-#define TRAILING_LIST_MEMBER            n_aliases
-#define TRAILING_LIST_SEPARATOR_P       isspace
-#include "../nss/nss_files/files-parse.c"
-LINE_PARSER
-("#",
- {
-   char *addr;
-
-   STRING_FIELD (result->n_name, isspace, 1);
-
-   STRING_FIELD (addr, isspace, 1);
-   result->n_net = inet_network (addr);
-
- })
-
 __libc_lock_define_initialized (static, lock)
 
 static nis_result *result = NULL;
-static nis_name *names = NULL;
+static nis_name tablename_val = NULL;
+static u_long tablename_len = 0;
 
 #define NISENTRYVAL(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
 
 #define NISENTRYLEN(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
+        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
 
 
 static int
 _nss_nisplus_parse_netent (nis_result *result, struct netent *network,
 			    char *buffer, size_t buflen)
 {
-  char *p = buffer;
+  char *first_unused = buffer;
   size_t room_left = buflen;
   unsigned int i;
-  struct parser_data *data = (void *) buffer;
+  char *p, *line;
 
   if (result == NULL)
     return 0;
 
   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
-      result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
-      strcmp(result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
+      __type_of (result->objects.objects_val) != ENTRY_OBJ ||
+      strcmp(result->objects.objects_val[0].EN_data.en_type,
              "networks_tbl") != 0 ||
-      result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 3)
+      result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 3)
     return 0;
 
-  /* Generate the network entry format and use the normal parser */
-  if (NISENTRYLEN (0, 0, result) +1 > room_left)
+  if (NISENTRYLEN(0, 0, result) >= room_left)
     {
+      /* The line is too long for our buffer.  */
+    no_more_room:
       __set_errno (ERANGE);
       return 0;
     }
 
-  memset (p, '\0', room_left);
+  strncpy (first_unused, NISENTRYVAL(0, 0, result),
+           NISENTRYLEN (0, 0, result));
+  first_unused[NISENTRYLEN(0, 0, result)] = '\0';
+  network->n_name = first_unused;
+  room_left -= (strlen (first_unused) +1);
+  first_unused += strlen (first_unused) +1;
+  network->n_addrtype = 0;
+  network->n_net = inet_network (NISENTRYVAL (0, 2, result));
+  p = first_unused;
+
+  line = p;
+  for (i = 0; i < result->objects.objects_len; i++)
+    {
+      if (strcmp (NISENTRYVAL (i, 1, result), network->n_name) != 0)
+        {
+          if (NISENTRYLEN (i, 1, result) + 2 > room_left)
+            {
+              __set_errno (ERANGE);
+              return 0;
+            }
+          p = stpcpy(p, " ");
+          p = stpncpy (p, NISENTRYVAL (i, 1, result),
+                       NISENTRYLEN (i, 1, result));
+          *p = '\0';
+          room_left -= (NISENTRYLEN (i, 1, result) + 1);
+        }
+    }
+  ++p;
+  first_unused = p;
+
+  /* Adjust the pointer so it is aligned for
+     storing pointers.  */
+  first_unused += __alignof__ (char *) - 1;
+  first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
+  network->n_aliases = (char **) first_unused;
+  if (room_left < 2 * sizeof (char *))
+    goto no_more_room;
+  room_left -= (2 * sizeof (char *));
+  network->n_aliases[0] = NULL;
+
+    i = 0;
+  while (*line != '\0')
+    {
+      /* Skip leading blanks.  */
+      while (isspace (*line))
+        line++;
 
-  strncpy (p, NISENTRYVAL (0, 0, result), NISENTRYLEN (0, 0, result));
-  room_left -= (NISENTRYLEN (0, 0, result) +1);
+      if (*line == '\0')
+        break;
 
-  if (NISENTRYLEN (0, 2, result) +1 > room_left)
-    {
-      __set_errno (ERANGE);
-      return 0;
+      if (room_left < sizeof (char *))
+        {
+          __set_errno (ERANGE);
+          return 0;
+        }
+
+      room_left -= sizeof (char *);
+      network->n_aliases[i] = line;
+
+      while (*line != '\0' && *line != ' ')
+        ++line;
+
+      if (line != network->n_aliases[i])
+        {
+          if (*line != '\0')
+            {
+              *line = '\0';
+              ++line;
+            }
+          ++i;
+        }
+      else
+        network->n_aliases[i] = NULL;
     }
-  strcat (p, "\t");
-  strncat (p, NISENTRYVAL (0, 2, result), NISENTRYLEN (0, 2, result));
-  room_left -= (NISENTRYLEN (0, 2, result) + 1);
-                                        /* + 1: We overwrite the last \0 */
 
-  for (i = 1; i < result->objects.objects_len; i++)
+  return 1;
+}
+
+static enum nss_status
+_nss_create_tablename (void)
+{
+  if (tablename_val == NULL)
     {
-      if (NISENTRYLEN (i, 1, result) +1 > room_left)
-	{
-	  __set_errno (ERANGE);
-	  return 0;
-	}
-      strcat (p, " ");
-      strncat (p, NISENTRYVAL (i, 1, result), NISENTRYLEN (i, 1, result));
-      room_left -= (NISENTRYLEN (i, 1, result) + 1);
+      char buf [40 + strlen (nis_local_directory ())];
+      char *p;
+
+      p = stpcpy (buf, "networks.org_dir.");
+      p = stpcpy (p, nis_local_directory ());
+      tablename_val = strdup (buf);
+      if (tablename_val == NULL)
+        return NSS_STATUS_TRYAGAIN;
+      tablename_len = strlen (tablename_val);
     }
-
-  return _nss_files_parse_netent (p, network, data, buflen);
+  return NSS_STATUS_SUCCESS;
 }
 
 enum nss_status
 _nss_nisplus_setnetent (void)
 {
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
   __libc_lock_lock (lock);
 
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
+
+  if (tablename_val == NULL)
+    if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+      status = NSS_STATUS_UNAVAIL;
 
   __libc_lock_unlock (lock);
 
-  return NSS_STATUS_SUCCESS;
+  return status;
 }
 
 enum nss_status
@@ -142,11 +193,6 @@ _nss_nisplus_endnetent (void)
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
 
   __libc_lock_unlock (lock);
 
@@ -164,11 +210,11 @@ internal_nisplus_getnetent_r (struct netent *network, char *buffer,
     {
       if (result == NULL)
 	{
-	  names = nis_getnames("networks.org_dir");
-	  if (names == NULL || names[0] == NULL)
-	    return NSS_STATUS_UNAVAIL;
+	  if (tablename_val == NULL)
+	    if (_nss_create_tablename() != NSS_STATUS_SUCCESS)
+	      return NSS_STATUS_UNAVAIL;
 
-	  result = nis_first_entry(names[0]);
+	  result = nis_first_entry(tablename_val);
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    {
 	      int retval;
@@ -178,15 +224,17 @@ internal_nisplus_getnetent_r (struct netent *network, char *buffer,
 		{
 		  *herrnop = NETDB_INTERNAL;
 		  __set_errno (EAGAIN);
+		  return retval;
 		}
-	      return retval;
+	      else
+		return retval;
 	    }
 	}
       else
 	{
 	  nis_result *res;
 
-	  res = nis_next_entry(names[0], &result->cookie);
+	  res = nis_next_entry(tablename_val, &result->cookie);
 	  nis_freeresult (result);
 	  result = res;
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
@@ -236,6 +284,10 @@ _nss_nisplus_getnetbyname_r (const char *name, struct netent *network,
 {
   int parse_res, retval;
 
+  if (tablename_val == NULL)
+    if (_nss_create_tablename() != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
+
   if (name == NULL)
     {
       __set_errno (EINVAL);
@@ -245,28 +297,28 @@ _nss_nisplus_getnetbyname_r (const char *name, struct netent *network,
   else
     {
       nis_result *result;
-      char buf[strlen (name) + 255];
-
+      char buf[strlen (name) + 255 + tablename_len];
 
       /* Search at first in the alias list, and use the correct name
 	 for the next search */
-      sprintf(buf, "[name=%s],networks.org_dir", name);
-      result = nis_list(buf, EXPAND_NAME, NULL, NULL);
+      sprintf(buf, "[name=%s],%s", name, tablename_val);
+      result = nis_list(buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
 
       /* If we do not find it, try it as original name. But if the
 	 database is correct, we should find it in the first case, too */
       if ((result->status != NIS_SUCCESS &&
 	   result->status != NIS_S_SUCCESS) ||
-	  result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
-	  strcmp(result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
+	  __type_of (result->objects.objects_val) != ENTRY_OBJ ||
+	  strcmp(result->objects.objects_val[0].EN_data.en_type,
 		 "networks_tbl") != 0 ||
-	  result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 3)
-	sprintf(buf, "[cname=%s],networks.org_dir", name);
+	  result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 3)
+	sprintf(buf, "[cname=%s],%s", name, tablename_val);
       else
-	sprintf(buf, "[cname=%s],networks.org_dir", NISENTRYVAL(0, 0, result));
+	sprintf(buf, "[cname=%s],%s", NISENTRYVAL(0, 0, result),
+		tablename_val);
 
       nis_freeresult (result);
-      result = nis_list(buf, EXPAND_NAME, NULL, NULL);
+      result = nis_list(buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
 
       retval = niserr2nss (result->status);
       if (retval != NSS_STATUS_SUCCESS)
@@ -301,39 +353,45 @@ _nss_nisplus_getnetbyaddr_r (const unsigned long addr, const int type,
 			     struct netent *network,
 			     char *buffer, size_t buflen, int *herrnop)
 {
-  int parse_res, retval;
-  nis_result *result;
-  char buf[1024];
-  struct in_addr in;
+  if (tablename_val == NULL)
+    if (_nss_create_tablename() != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
 
-  in = inet_makeaddr (addr, 0);
-  snprintf(buf, sizeof (buf) - 1, "[addr=%s],networks.org_dir",
-	   inet_ntoa (in));
+  {
+    int parse_res, retval;
+    nis_result *result;
+    char buf[1024 + tablename_len];
+    struct in_addr in;
 
-  result = nis_list(buf, EXPAND_NAME, NULL, NULL);
+    in = inet_makeaddr (addr, 0);
+    snprintf(buf, sizeof (buf) - 1, "[addr=%s],%s",
+	     inet_ntoa (in), tablename_len);
 
-  retval = niserr2nss (result->status);
-  if (retval != NSS_STATUS_SUCCESS)
-    {
-      if (retval == NSS_STATUS_TRYAGAIN)
-	{
-	  __set_errno (EAGAIN);
-	  *herrnop = NETDB_INTERNAL;
-	}
-      nis_freeresult (result);
-      return retval;
-    }
+    result = nis_list(buf, EXPAND_NAME, NULL, NULL);
 
-  parse_res = _nss_nisplus_parse_netent (result, network, buffer, buflen);
+    retval = niserr2nss (result->status);
+    if (retval != NSS_STATUS_SUCCESS)
+      {
+	if (retval == NSS_STATUS_TRYAGAIN)
+	  {
+	    __set_errno (EAGAIN);
+	    *herrnop = NETDB_INTERNAL;
+	  }
+	nis_freeresult (result);
+	return retval;
+      }
 
-  nis_freeresult (result);
+    parse_res = _nss_nisplus_parse_netent (result, network, buffer, buflen);
 
-  if (parse_res)
-    return NSS_STATUS_SUCCESS;
+    nis_freeresult (result);
 
-  *herrnop = NETDB_INTERNAL;
-  if (!parse_res && errno == ERANGE)
-    return NSS_STATUS_TRYAGAIN;
-  else
-    return NSS_STATUS_NOTFOUND;
+    if (parse_res)
+      return NSS_STATUS_SUCCESS;
+
+    *herrnop = NETDB_INTERNAL;
+    if (!parse_res && errno == ERANGE)
+      return NSS_STATUS_TRYAGAIN;
+    else
+      return NSS_STATUS_NOTFOUND;
+  }
 }
diff --git a/nis/nss_nisplus/nisplus-parser.c b/nis/nss_nisplus/nisplus-parser.c
new file mode 100644
index 0000000000..bb6bba1e3e
--- /dev/null
+++ b/nis/nss_nisplus/nisplus-parser.c
@@ -0,0 +1,337 @@
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <pwd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <rpcsvc/nis.h>
+
+#include "nisplus-parser.h"
+
+#define NISENTRYVAL(idx,col,res) \
+        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+
+#define NISENTRYLEN(idx,col,res) \
+        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
+
+
+int
+_nss_nisplus_parse_pwent (nis_result *result, struct passwd *pw,
+			  char *buffer, size_t buflen)
+{
+  char *first_unused = buffer;
+  size_t room_left = buflen;
+
+  if (result == NULL)
+    return 0;
+
+  if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
+      result->objects.objects_len != 1 ||
+      __type_of (result->objects.objects_val) != ENTRY_OBJ ||
+      strcmp(result->objects.objects_val->EN_data.en_type,
+	     "passwd_tbl") != 0 ||
+      result->objects.objects_val->EN_data.en_cols.en_cols_len < 7)
+    return 0;
+
+  if (NISENTRYLEN (0, 0, result) >= room_left)
+    {
+      /* The line is too long for our buffer.  */
+    no_more_room:
+      __set_errno (ERANGE);
+      return 0;
+    }
+
+  strncpy (first_unused, NISENTRYVAL(0, 0, result),
+	   NISENTRYLEN (0, 0, result));
+  first_unused[NISENTRYLEN(0, 0, result)] = '\0';
+  pw->pw_name = first_unused;
+  room_left -= (strlen (first_unused) +1);
+  first_unused += strlen (first_unused) +1;
+
+  if (NISENTRYLEN(0, 1, result) >= room_left)
+    goto no_more_room;
+
+  strncpy (first_unused, NISENTRYVAL(0, 1, result),
+	   NISENTRYLEN (0, 1, result));
+  first_unused[NISENTRYLEN(0, 1, result)] = '\0';
+  pw->pw_passwd = first_unused;
+  room_left -= (strlen (first_unused) +1);
+  first_unused += strlen (first_unused) +1;
+
+  if (NISENTRYLEN(0, 2, result) >= room_left)
+    goto no_more_room;
+
+  strncpy (first_unused, NISENTRYVAL (0, 2, result),
+	   NISENTRYLEN (0, 2, result));
+  first_unused[NISENTRYLEN(0, 2, result)] = '\0';
+  pw->pw_uid = atoi (first_unused);
+  room_left -= (strlen (first_unused) +1);
+  first_unused += strlen (first_unused) +1;
+
+  if (NISENTRYLEN(0, 3, result) >= room_left)
+    goto no_more_room;
+
+  strncpy (first_unused, NISENTRYVAL(0, 3, result),
+	   NISENTRYLEN (0, 3, result));
+  first_unused[NISENTRYLEN(0, 3, result)] = '\0';
+  pw->pw_gid = atoi (first_unused);
+  room_left -= (strlen (first_unused) +1);
+  first_unused += strlen (first_unused) +1;
+
+  if (NISENTRYLEN(0, 4, result) >= room_left)
+    goto no_more_room;
+
+  strncpy (first_unused, NISENTRYVAL(0, 4, result),
+	   NISENTRYLEN (0, 4, result));
+  first_unused[NISENTRYLEN(0, 4, result)] = '\0';
+  pw->pw_gecos = first_unused;
+  room_left -= (strlen (first_unused) +1);
+  first_unused += strlen (first_unused) +1;
+
+  if (NISENTRYLEN(0, 5, result) >= room_left)
+    goto no_more_room;
+
+  strncpy (first_unused, NISENTRYVAL (0, 5, result),
+	   NISENTRYLEN (0, 5, result));
+  first_unused[NISENTRYLEN(0, 5, result)] = '\0';
+  pw->pw_dir = first_unused;
+  room_left -= (strlen (first_unused) +1);
+  first_unused += strlen (first_unused) +1;
+
+  if (NISENTRYLEN(0, 6, result) >= room_left)
+    goto no_more_room;
+
+  strncpy (first_unused, NISENTRYVAL (0, 6, result),
+	   NISENTRYLEN (0, 6, result));
+  first_unused[NISENTRYLEN (0, 6, result)] = '\0';
+  pw->pw_shell = first_unused;
+  room_left -= (strlen (first_unused) +1);
+  first_unused += strlen (first_unused) +1;
+
+  return 1;
+}
+
+int
+_nss_nisplus_parse_grent (nis_result *result, u_long entry,
+			  struct group *gr, char *buffer, size_t buflen)
+{
+  char *first_unused = buffer;
+  size_t room_left = buflen;
+  char *line;
+  int count;
+
+  if (result == NULL)
+    return 0;
+
+  if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
+      __type_of(result->objects.objects_val) != ENTRY_OBJ ||
+      strcmp (result->objects.objects_val[entry].EN_data.en_type,
+	      "group_tbl") != 0 ||
+      result->objects.objects_val[entry].EN_data.en_cols.en_cols_len < 4)
+    return 0;
+
+  if (NISENTRYLEN (entry, 0, result) >= room_left)
+    {
+      /* The line is too long for our buffer.  */
+    no_more_room:
+      __set_errno (ERANGE);
+      return 0;
+    }
+
+  strncpy (first_unused, NISENTRYVAL (entry, 0, result),
+	   NISENTRYLEN (entry, 0, result));
+  first_unused[NISENTRYLEN (entry, 0, result)] = '\0';
+  gr->gr_name = first_unused;
+  room_left -= (strlen (first_unused) + 1);
+  first_unused += strlen (first_unused) + 1;
+
+  if (NISENTRYLEN (entry, 1, result) >= room_left)
+    goto no_more_room;
+
+  strncpy (first_unused, NISENTRYVAL (entry, 1, result),
+	   NISENTRYLEN (entry, 1, result));
+  first_unused[NISENTRYLEN (entry, 1, result)] = '\0';
+  gr->gr_passwd = first_unused;
+  room_left -= (strlen (first_unused) + 1);
+  first_unused += strlen (first_unused) + 1;
+
+  if (NISENTRYLEN (entry, 2, result) >= room_left)
+    goto no_more_room;
+
+  strncpy (first_unused, NISENTRYVAL (entry, 2, result),
+	   NISENTRYLEN (entry, 2, result));
+  first_unused[NISENTRYLEN (entry, 2, result)] = '\0';
+  gr->gr_gid = atoi (first_unused);
+  room_left -= (strlen (first_unused) + 1);
+  first_unused += strlen (first_unused) + 1;
+
+  if (NISENTRYLEN (entry, 3, result) >= room_left)
+    goto no_more_room;
+
+  strncpy (first_unused, NISENTRYVAL (entry, 3, result),
+	   NISENTRYLEN (entry, 3, result));
+  first_unused[NISENTRYLEN (entry, 3, result)] = '\0';
+  line = first_unused;
+  room_left -= (strlen (line) + 1);
+  first_unused += strlen (line) + 1;
+  /* Adjust the pointer so it is aligned for
+     storing pointers.  */
+  first_unused += __alignof__ (char *) - 1;
+  first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
+  gr->gr_mem = (char **) first_unused;
+
+  count = 0;
+  while (*line != '\0')
+    {
+      /* Skip leading blanks.  */
+      while (isspace (*line))
+	++line;
+
+      if (*line == '\0')
+	break;
+
+      if (room_left < sizeof (char *))
+	  goto no_more_room;
+      room_left -= sizeof (char *);
+      gr->gr_mem[count] = line;
+
+      while (*line != '\0' && *line != ',' && !isspace(*line))
+	++line;
+
+      if (line != gr->gr_mem[count])
+	{
+	  if (*line != '\0')
+	    {
+	      *line = '\0';
+	      ++line;
+	    }
+	  ++count;
+	}
+      else
+	gr->gr_mem[count] = NULL;
+    }
+  if (room_left < sizeof (char *))
+      goto no_more_room;
+  room_left -= sizeof (char *);
+  gr->gr_mem[count] = NULL;
+
+  return 1;
+}
+
+int
+_nss_nisplus_parse_spent (nis_result *result, struct spwd *sp,
+			  char *buffer, size_t buflen)
+{
+  char *first_unused = buffer;
+  size_t room_left = buflen;
+  
+  if (result == NULL)
+    return 0;
+
+  if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
+      result->objects.objects_len != 1 ||
+      __type_of(result->objects.objects_val) != ENTRY_OBJ ||
+      strcmp (result->objects.objects_val->EN_data.en_type,
+	      "passwd_tbl") != 0 ||
+      result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 8)
+    return 0;
+
+  if (NISENTRYLEN(0, 0, result) >= room_left)
+    {
+      /* The line is too long for our buffer.  */
+    no_more_room:
+      __set_errno (ERANGE);
+      return 0;
+    }
+
+  strncpy (first_unused, NISENTRYVAL (0, 0, result),
+	   NISENTRYLEN (0, 0, result));
+  first_unused[NISENTRYLEN(0, 0, result)] = '\0';
+  sp->sp_namp = first_unused;
+  room_left -= (strlen (first_unused) +1);
+  first_unused += strlen (first_unused) +1;
+
+  if (NISENTRYLEN(0, 1, result) >= room_left)
+    goto no_more_room;
+
+  strncpy (first_unused, NISENTRYVAL (0, 1, result),
+	   NISENTRYLEN (0, 1, result));
+  first_unused[NISENTRYLEN(0, 1, result)] = '\0';
+  sp->sp_pwdp = first_unused;
+  room_left -= (strlen (first_unused) +1);
+  first_unused += strlen (first_unused) +1;
+
+  sp->sp_lstchg = sp->sp_min = sp->sp_max = sp->sp_warn = sp->sp_inact =
+    sp->sp_expire = sp->sp_flag = -1;
+
+  if (NISENTRYLEN (0, 7, result) > 0)
+    {
+      char *line, *cp;
+
+      line = NISENTRYVAL (0, 7, result);
+      cp = strchr (line, ':');
+      if (cp == NULL)
+	return 0;
+      *cp++ = '\0';
+      sp->sp_lstchg = atol (line);
+
+      line = cp;
+      cp = strchr (line, ':');
+      if (cp == NULL)
+	return 0;
+      *cp++ = '\0';
+      sp->sp_min = atol(line);
+
+      line = cp;
+      cp = strchr (line, ':');
+      if (cp == NULL)
+	return 0;
+      *cp++ = '\0';
+      sp->sp_max = atol(line);
+
+      line = cp;
+      cp = strchr (line, ':');
+      if (cp == NULL)
+	return 0;
+      *cp++ = '\0';
+      sp->sp_warn = atol(line);
+
+      line = cp;
+      cp = strchr (line, ':');
+      if (cp == NULL)
+	return 0;
+      *cp++ = '\0';
+      sp->sp_inact = atol(line);
+
+      line = cp;
+      cp = strchr (line, ':');
+      if (cp == NULL)
+	return 0;
+      *cp++ = '\0';
+      sp->sp_expire = atol(line);
+
+      line = cp;
+      if (line == NULL)
+	return 0;
+      sp->sp_flag = atol(line);
+    }
+
+  return 1;
+}
diff --git a/nis/nss_nisplus/nisplus-proto.c b/nis/nss_nisplus/nisplus-proto.c
index ee0341d0b9..1ee9a8944b 100644
--- a/nis/nss_nisplus/nisplus-proto.c
+++ b/nis/nss_nisplus/nisplus-proto.c
@@ -31,97 +31,146 @@
 __libc_lock_define_initialized (static, lock)
 
 static nis_result *result = NULL;
-static nis_name *names = NULL;
-
-#define ENTNAME         protoent
-#define DATABASE        "protocols"
-#define TRAILING_LIST_MEMBER            p_aliases
-#define TRAILING_LIST_SEPARATOR_P       isspace
-#include "../../nss/nss_files/files-parse.c"
-LINE_PARSER
-("#",
- STRING_FIELD (result->p_name, isspace, 1);
- INT_FIELD (result->p_proto, isspace, 1, 10,);
-)
+static nis_name tablename_val = NULL;
+static u_long tablename_len = 0;
 
 #define NISENTRYVAL(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
 
 #define NISENTRYLEN(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
+        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
 
 static int
 _nss_nisplus_parse_protoent (nis_result * result, struct protoent *proto,
 			     char *buffer, size_t buflen)
 {
-  char *p = buffer;
+  char *first_unused = buffer;
   size_t room_left = buflen;
   unsigned int i;
-  struct parser_data *data = (void *) buffer;
+  char *p, *line;
 
   if (result == NULL)
     return 0;
 
   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
-      result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
-   strcmp (result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
-	   "protocols_tbl") != 0 ||
-      result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 3)
+      __type_of (NIS_RES_OBJECT (result)) != ENTRY_OBJ ||
+      strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "protocols_tbl") != 0
+      || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 3)
     return 0;
 
-  memset (p, '\0', room_left);
-
   /* Generate the protocols entry format and use the normal parser */
   if (NISENTRYLEN (0, 0, result) + 1 > room_left)
     {
+    no_more_room:
       __set_errno (ERANGE);
       return 0;
     }
-  strncpy (p, NISENTRYVAL (0, 0, result), NISENTRYLEN (0, 0, result));
-  room_left -= (NISENTRYLEN (0, 0, result) + 1);
+  strncpy (first_unused, NISENTRYVAL (0, 0, result),
+           NISENTRYLEN (0, 0, result));
+  first_unused[NISENTRYLEN (0, 0, result)] = '\0';
+  proto->p_name = first_unused;
+  room_left -= (strlen (first_unused) +1);
+  first_unused += strlen (first_unused) +1;
+
 
   if (NISENTRYLEN (0, 2, result) + 1 > room_left)
+    goto no_more_room;
+  proto->p_proto = atoi (NISENTRYVAL (0, 2, result));
+  p = first_unused;
+
+  line = p;
+  for (i = 0; i < result->objects.objects_len; i++)
     {
-      __set_errno (ERANGE);
-      return 0;
+      if (strcmp (NISENTRYVAL (i, 1, result), proto->p_name) != 0)
+        {
+          if (NISENTRYLEN (i, 1, result) + 2 > room_left)
+            goto no_more_room;
+          p = stpcpy(p, " ");
+          p = stpncpy (p, NISENTRYVAL (i, 1, result),
+                       NISENTRYLEN (i, 1, result));
+          *p = '\0';
+          room_left -= (NISENTRYLEN (i, 1, result) + 1);
+        }
     }
-  strcat (p, "\t");
-  strncat (p, NISENTRYVAL (0, 2, result), NISENTRYLEN (0, 2, result));
-  room_left -= (NISENTRYLEN (0, 2, result) + 1);
-  /* + 1: We overwrite the last \0 */
-
-  for (i = 1; i < result->objects.objects_len; i++)
+  ++p;
+  first_unused = p;
+
+  /* Adjust the pointer so it is aligned for
+     storing pointers.  */
+  first_unused += __alignof__ (char *) - 1;
+  first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
+  proto->p_aliases = (char **) first_unused;
+  if (room_left < sizeof (char *))
+    goto no_more_room;
+  room_left -= (sizeof (char *));
+  proto->p_aliases[0] = NULL;
+
+  i = 0;
+  while (*line != '\0')
     {
-      if (NISENTRYLEN (i, 1, result) + 1 > room_left)
-	{
-	  __set_errno (ERANGE);
-	  return 0;
-	}
-      strcat (p, " ");
-      strncat (p, NISENTRYVAL (i, 1, result), NISENTRYLEN (i, 1, result));
-      room_left -= (NISENTRYLEN (i, 1, result) + 1);
+      /* Skip leading blanks.  */
+      while (isspace (*line))
+        line++;
+      if (*line == '\0')
+        break;
+
+      if (room_left < sizeof (char *))
+        goto no_more_room;
+
+      room_left -= sizeof (char *);
+      proto->p_aliases[i] = line;
+
+      while (*line != '\0' && *line != ' ')
+        ++line;
+
+      if (*line == ' ')
+        {
+          *line = '\0';
+          ++line;
+          ++i;
+        }
+      else
+        proto->p_aliases[i+1] = NULL;
     }
 
-  return _nss_files_parse_protoent (p, proto, data, buflen);
+  return 1;
+}
+
+static enum nss_status
+_nss_create_tablename (void)
+{
+  if (tablename_val == NULL)
+    {
+      char buf [40 + strlen (nis_local_directory ())];
+      char *p;
+
+      p = stpcpy (buf, "protocols.org_dir.");
+      p = stpcpy (p, nis_local_directory ());
+      tablename_val = strdup (buf);
+      if (tablename_val == NULL)
+        return NSS_STATUS_TRYAGAIN;
+      tablename_len = strlen (tablename_val);
+    }
+  return NSS_STATUS_SUCCESS;
 }
 
 enum nss_status
 _nss_nisplus_setprotoent (void)
 {
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
   __libc_lock_lock (lock);
 
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
+
+  if (tablename_val == NULL)
+    status = _nss_create_tablename ();
 
   __libc_lock_unlock (lock);
 
-  return NSS_STATUS_SUCCESS;
+  return status;
 }
 
 enum nss_status
@@ -132,11 +181,6 @@ _nss_nisplus_endprotoent (void)
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
 
   __libc_lock_unlock (lock);
 
@@ -154,11 +198,11 @@ internal_nisplus_getprotoent_r (struct protoent *proto, char *buffer,
     {
       if (result == NULL)
 	{
-	  names = nis_getnames ("protocols.org_dir");
-	  if (names == NULL || names[0] == NULL)
-	    return NSS_STATUS_UNAVAIL;
+	  if (tablename_val == NULL)
+	    if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+	      return NSS_STATUS_UNAVAIL;
 
-	  result = nis_first_entry (names[0]);
+	  result = nis_first_entry (tablename_val);
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    return niserr2nss (result->status);
 	}
@@ -166,7 +210,7 @@ internal_nisplus_getprotoent_r (struct protoent *proto, char *buffer,
 	{
 	  nis_result *res;
 
-	  res = nis_next_entry (names[0], &result->cookie);
+	  res = nis_next_entry (tablename_val, &result->cookie);
 	  nis_freeresult (result);
 	  result = res;
 
@@ -202,32 +246,37 @@ _nss_nisplus_getprotobyname_r (const char *name, struct protoent *proto,
 {
   int parse_res;
 
+  if (tablename_val == NULL)
+    if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
+
   if (name == NULL)
     return NSS_STATUS_NOTFOUND;
   else
     {
       nis_result *result;
-      char buf[strlen (name) + 255];
+      char buf[strlen (name) + 255 + tablename_len];
 
       /* Search at first in the alias list, and use the correct name
          for the next search */
-      sprintf (buf, "[name=%s],protocols.org_dir", name);
-      result = nis_list (buf, EXPAND_NAME, NULL, NULL);
+      sprintf (buf, "[name=%s],%s", name, tablename_val);
+      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
       /* If we do not find it, try it as original name. But if the
          database is correct, we should find it in the first case, too */
       if ((result->status != NIS_SUCCESS &&
 	   result->status != NIS_S_SUCCESS) ||
-	  result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
-	  strcmp (result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
+	  __type_of (result->objects.objects_val) != ENTRY_OBJ ||
+	  strcmp (result->objects.objects_val->EN_data.en_type,
 		  "protocols_tbl") != 0 ||
-	  result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 3)
-	sprintf (buf, "[cname=%s],protocols.org_dir", name);
+	  result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
+	sprintf (buf, "[cname=%s],%s", name, tablename_val);
       else
-	sprintf (buf, "[cname=%s],protocols.org_dir", NISENTRYVAL (0, 0, result));
+	sprintf (buf, "[cname=%s],%s", NISENTRYVAL (0, 0, result),
+		 tablename_val);
 
       nis_freeresult (result);
-      result = nis_list (buf, EXPAND_NAME, NULL, NULL);
+      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
       if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	{
@@ -255,30 +304,35 @@ enum nss_status
 _nss_nisplus_getprotobynumber_r (const int number, struct protoent *proto,
 				 char *buffer, size_t buflen)
 {
-  int parse_res;
-  nis_result *result;
-  char buf[46];
-
-  snprintf (buf, sizeof (buf), "[number=%d],protocols.org_dir", number);
+  if (tablename_val == NULL)
+    if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
+  {
+    int parse_res;
+    nis_result *result;
+    char buf[46 + tablename_len];
 
-  result = nis_list (buf, EXPAND_NAME, NULL, NULL);
+    snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val);
 
-  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-    {
-      enum nss_status status = niserr2nss (result->status);
+    result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
 
-      nis_freeresult (result);
-      return status;
-    }
+    if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+      {
+	enum nss_status status = niserr2nss (result->status);
 
-  parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen);
+	nis_freeresult (result);
+	return status;
+      }
 
-  nis_freeresult (result);
-  if (parse_res)
-    return NSS_STATUS_SUCCESS;
+    parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen);
 
-  if (!parse_res && errno == ERANGE)
-    return NSS_STATUS_TRYAGAIN;
-  else
-    return NSS_STATUS_NOTFOUND;
+    nis_freeresult (result);
+    if (parse_res)
+      return NSS_STATUS_SUCCESS;
+
+    if (!parse_res && errno == ERANGE)
+      return NSS_STATUS_TRYAGAIN;
+    else
+      return NSS_STATUS_NOTFOUND;
+  }
 }
diff --git a/nis/nss_nisplus/nisplus-publickey.c b/nis/nss_nisplus/nisplus-publickey.c
index 91cfba730e..4c596b8ada 100644
--- a/nis/nss_nisplus/nisplus-publickey.c
+++ b/nis/nss_nisplus/nisplus-publickey.c
@@ -61,10 +61,10 @@ _nss_nisplus_getpublickey (const char *netname, char *pkey)
 	    netname, domain);
 
   if (buf[strlen (buf)-1] != '.')
-    strcat(buf, ".");
+    strcat (buf, ".");
 
-  res = nis_list(buf, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
-		 NULL, NULL);
+  res = nis_list (buf, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
+		  NULL, NULL);
 
   retval = niserr2nss (res->status);
 
@@ -192,7 +192,7 @@ parse_grp_str (const char *s, gid_t *gidp, int *gidlenp, gid_t *gidlist)
       return NSS_STATUS_NOTFOUND;
     }
 
-  *gidp = (atoi (s));
+  *gidp = atoi (s);
 
   gidlen = 0;
 
@@ -238,7 +238,7 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
   /* XXX but we cant, for now. XXX */
   res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
 		  NULL, NULL);
-  switch(res->status)
+  switch (res->status)
     {
     case NIS_SUCCESS:
     case NIS_S_SUCCESS:
@@ -274,10 +274,10 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
 	      netname, domain);
     }
 
-  len = ENTRY_LEN(res->objects.objects_val, 0);
-  strncpy(principal, ENTRY_VAL(res->objects.objects_val, 0), len);
+  len = ENTRY_LEN (res->objects.objects_val, 0);
+  strncpy (principal, ENTRY_VAL (res->objects.objects_val, 0), len);
   principal[len] = '\0';
-  nis_freeresult(res);
+  nis_freeresult (res);
 
   if (principal[0] == '\0')
     return NSS_STATUS_UNAVAIL;
@@ -287,45 +287,45 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
    *      LOCAL entry in **local** cred table.
    */
   domain = nis_local_directory ();
-  if ((strlen(principal)+strlen(domain)+45) >
+  if ((strlen (principal)+strlen (domain)+45) >
       (size_t) NIS_MAXNAMELEN)
     {
       syslog (LOG_ERR, _("netname2user: principal name '%s' too long"),
 	      principal);
       return NSS_STATUS_UNAVAIL;
     }
-  sprintf(sname, "[cname=%s,auth_type=LOCAL],cred.org_dir.%s",
+  sprintf (sname, "[cname=%s,auth_type=LOCAL],cred.org_dir.%s",
 	  principal, domain);
   if (sname[strlen(sname) - 1] != '.')
     strcat(sname, ".");
 
   /* must use authenticated call here */
   /* XXX but we cant, for now. XXX */
-  res = nis_list(sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
-		 NULL, NULL);
-  switch(res->status) {
-  case NIS_NOTFOUND:
-  case NIS_PARTIAL:
-  case NIS_NOSUCHNAME:
-  case NIS_NOSUCHTABLE:
-    nis_freeresult (res);
-    return NSS_STATUS_NOTFOUND;
-  case NIS_S_NOTFOUND:
-  case NIS_TRYAGAIN:
-    syslog (LOG_ERR,
-	    "netname2user: (nis+ lookup): %s\n",
-	    nis_sperrno (res->status));
-    nis_freeresult (res);
-    return NSS_STATUS_TRYAGAIN;
-  case NIS_SUCCESS:
-  case NIS_S_SUCCESS:
-    break;   /* go and do something useful */
-  default:
-    syslog (LOG_ERR, "netname2user: (nis+ lookup): %s\n",
-	    nis_sperrno (res->status));
-    nis_freeresult (res);
-    return NSS_STATUS_UNAVAIL;
-  }
+  res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
+		  NULL, NULL);
+  switch(res->status)
+    {
+    case NIS_NOTFOUND:
+    case NIS_PARTIAL:
+    case NIS_NOSUCHNAME:
+    case NIS_NOSUCHTABLE:
+      nis_freeresult (res);
+      return NSS_STATUS_NOTFOUND;
+    case NIS_S_NOTFOUND:
+    case NIS_TRYAGAIN:
+      syslog (LOG_ERR, "netname2user: (nis+ lookup): %s\n",
+	      nis_sperrno (res->status));
+      nis_freeresult (res);
+      return NSS_STATUS_TRYAGAIN;
+    case NIS_SUCCESS:
+    case NIS_S_SUCCESS:
+      break;   /* go and do something useful */
+    default:
+      syslog (LOG_ERR, "netname2user: (nis+ lookup): %s\n",
+	      nis_sperrno (res->status));
+      nis_freeresult (res);
+      return NSS_STATUS_UNAVAIL;
+    }
 
   if (res->objects.objects_len > 1)
     {
@@ -339,7 +339,7 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
 	     netname, domain);
     }
   /* Fetch the uid */
-  *uidp = (atoi (ENTRY_VAL (res->objects.objects_val, 2)));
+  *uidp = atoi (ENTRY_VAL (res->objects.objects_val, 2));
 
   if (*uidp == 0)
     {
diff --git a/nis/nss_nisplus/nisplus-pwd.c b/nis/nss_nisplus/nisplus-pwd.c
index 89b0eff7a7..459a1a4380 100644
--- a/nis/nss_nisplus/nisplus-pwd.c
+++ b/nis/nss_nisplus/nisplus-pwd.c
@@ -30,127 +30,48 @@
 __libc_lock_define_initialized (static, lock)
 
 static nis_result *result = NULL;
-static nis_name *names = NULL;
+static nis_name tablename_val = NULL;
+static u_long tablename_len = 0;
 
-#define NISENTRYVAL(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+extern int _nss_nisplus_parse_pwent (nis_result *res, struct passwd *pw,
+				     char *buffer, size_t buflen);
 
-#define NISENTRYLEN(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
-
-int
-_nss_nisplus_parse_pwent (nis_result *result, struct passwd *pw,
-			  char *buffer, size_t buflen)
+static enum nss_status
+_nss_create_tablename (void)
 {
-  char *first_unused = buffer;
-  size_t room_left = buflen;
-
-  if (result == NULL)
-    return 0;
-
-  if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
-      result->objects.objects_len != 1 ||
-      result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
-      strcmp(result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
-	     "passwd_tbl") != 0 ||
-      result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 7)
-    return 0;
-
-  if (NISENTRYLEN(0, 0, result) >= room_left)
+  if (tablename_val == NULL)
     {
-      /* The line is too long for our buffer.  */
-    no_more_room:
-      __set_errno (ERANGE);
-      return 0;
+      char buf [40 + strlen (nis_local_directory ())];
+      char *p;
+
+      p = stpcpy (buf, "passwd.org_dir.");
+      p = stpcpy (p, nis_local_directory ());
+      tablename_val = strdup (buf);
+      if (tablename_val == NULL)
+        return NSS_STATUS_TRYAGAIN;
+      tablename_len = strlen (tablename_val);
     }
-
-  strncpy (first_unused, NISENTRYVAL(0, 0, result),
-	   NISENTRYLEN (0, 0, result));
-  first_unused[NISENTRYLEN(0, 0, result)] = '\0';
-  pw->pw_name = first_unused;
-  room_left -= (strlen (first_unused) +1);
-  first_unused += strlen (first_unused) +1;
-
-  if (NISENTRYLEN(0, 1, result) >= room_left)
-    goto no_more_room;
-
-  strncpy (first_unused, NISENTRYVAL(0, 1, result),
-	   NISENTRYLEN (0, 1, result));
-  first_unused[NISENTRYLEN(0, 1, result)] = '\0';
-  pw->pw_passwd = first_unused;
-  room_left -= (strlen (first_unused) +1);
-  first_unused += strlen (first_unused) +1;
-
-  if (NISENTRYLEN(0, 2, result) >= room_left)
-    goto no_more_room;
-
-  strncpy (first_unused, NISENTRYVAL (0, 2, result),
-	   NISENTRYLEN (0, 2, result));
-  first_unused[NISENTRYLEN(0, 2, result)] = '\0';
-  pw->pw_uid = atoi (first_unused);
-  room_left -= (strlen (first_unused) +1);
-  first_unused += strlen (first_unused) +1;
-
-  if (NISENTRYLEN(0, 3, result) >= room_left)
-    goto no_more_room;
-
-  strncpy (first_unused, NISENTRYVAL(0, 3, result),
-	   NISENTRYLEN (0, 3, result));
-  first_unused[NISENTRYLEN(0, 3, result)] = '\0';
-  pw->pw_gid = atoi (first_unused);
-  room_left -= (strlen (first_unused) +1);
-  first_unused += strlen (first_unused) +1;
-
-  if (NISENTRYLEN(0, 4, result) >= room_left)
-    goto no_more_room;
-
-  strncpy (first_unused, NISENTRYVAL(0, 4, result),
-	   NISENTRYLEN (0, 4, result));
-  first_unused[NISENTRYLEN(0, 4, result)] = '\0';
-  pw->pw_gecos = first_unused;
-  room_left -= (strlen (first_unused) +1);
-  first_unused += strlen (first_unused) +1;
-
-  if (NISENTRYLEN(0, 5, result) >= room_left)
-    goto no_more_room;
-
-  strncpy (first_unused, NISENTRYVAL (0, 5, result),
-	   NISENTRYLEN (0, 5, result));
-  first_unused[NISENTRYLEN(0, 5, result)] = '\0';
-  pw->pw_dir = first_unused;
-  room_left -= (strlen (first_unused) +1);
-  first_unused += strlen (first_unused) +1;
-
-  if (NISENTRYLEN(0, 6, result) >= room_left)
-    goto no_more_room;
-
-  strncpy (first_unused, NISENTRYVAL (0, 6, result),
-	   NISENTRYLEN (0, 6, result));
-  first_unused[NISENTRYLEN (0, 6, result)] = '\0';
-  pw->pw_shell = first_unused;
-  room_left -= (strlen (first_unused) +1);
-  first_unused += strlen (first_unused) +1;
-
-  return 1;
+  return NSS_STATUS_SUCCESS;
 }
 
+
 enum nss_status
 _nss_nisplus_setpwent (void)
 {
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
   __libc_lock_lock (lock);
 
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
+
+  if (tablename_val == NULL)
+    status = _nss_create_tablename ();
 
   __libc_lock_unlock (lock);
 
-  return NSS_STATUS_SUCCESS;
+  return status;
 }
 
 enum nss_status
@@ -161,11 +82,6 @@ _nss_nisplus_endpwent (void)
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
 
   __libc_lock_unlock (lock);
 
@@ -182,11 +98,11 @@ internal_nisplus_getpwent_r (struct passwd *pw, char *buffer, size_t buflen)
     {
       if (result == NULL)
 	{
-	  names = nis_getnames ("passwd.org_dir");
-	  if (names == NULL || names[0] == NULL)
-	    return NSS_STATUS_UNAVAIL;
+          if (tablename_val == NULL)
+            if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+              return NSS_STATUS_UNAVAIL;
 
-	  result = nis_first_entry(names[0]);
+	  result = nis_first_entry(tablename_val);
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    return niserr2nss (result->status);
 	}
@@ -194,7 +110,7 @@ internal_nisplus_getpwent_r (struct passwd *pw, char *buffer, size_t buflen)
 	{
 	  nis_result *res;
 
-	  res = nis_next_entry(names[0], &result->cookie);
+	  res = nis_next_entry(tablename_val, &result->cookie);
 	  nis_freeresult (result);
 	  result = res;
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
@@ -227,16 +143,20 @@ _nss_nisplus_getpwnam_r (const char *name, struct passwd *pw,
 {
   int parse_res;
 
+  if (tablename_val == NULL)
+    if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
+
   if (name == NULL || strlen (name) > 8)
     return NSS_STATUS_NOTFOUND;
   else
     {
       nis_result *result;
-      char buf[strlen (name) + 24];
+      char buf[strlen (name) + 24 + tablename_len];
 
-      sprintf(buf, "[name=%s],passwd.org_dir", name);
+      sprintf(buf, "[name=%s],%s", name, tablename_val);
 
-      result = nis_list(buf, EXPAND_NAME, NULL, NULL);
+      result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
       if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	{
@@ -264,30 +184,35 @@ enum nss_status
 _nss_nisplus_getpwuid_r (const uid_t uid, struct passwd *pw,
 		     char *buffer, size_t buflen)
 {
-  int parse_res;
-  nis_result *result;
-  char buf[100];
-
-  sprintf(buf, "[uid=%d],passwd.org_dir", uid);
+  if (tablename_val == NULL)
+    if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
+  {
+    int parse_res;
+    nis_result *result;
+    char buf[100 + tablename_len];
 
-  result = nis_list(buf, EXPAND_NAME, NULL, NULL);
+    sprintf(buf, "[uid=%d],%s", uid, tablename_val);
 
-  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-   {
-     enum nss_status status = niserr2nss (result->status);
+    result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
-     nis_freeresult (result);
-     return status;
-   }
+    if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+      {
+	enum nss_status status = niserr2nss (result->status);
 
-  parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen);
+	nis_freeresult (result);
+	return status;
+      }
 
-  nis_freeresult (result);
-  if (parse_res)
-    return NSS_STATUS_SUCCESS;
+    parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen);
 
-  if (!parse_res && errno == ERANGE)
-    return NSS_STATUS_TRYAGAIN;
-  else
-    return NSS_STATUS_NOTFOUND;
+    nis_freeresult (result);
+    if (parse_res)
+      return NSS_STATUS_SUCCESS;
+
+    if (!parse_res && errno == ERANGE)
+      return NSS_STATUS_TRYAGAIN;
+    else
+      return NSS_STATUS_NOTFOUND;
+  }
 }
diff --git a/nis/nss_nisplus/nisplus-rpc.c b/nis/nss_nisplus/nisplus-rpc.c
index 180e9169f2..cebd5d7183 100644
--- a/nis/nss_nisplus/nisplus-rpc.c
+++ b/nis/nss_nisplus/nisplus-rpc.c
@@ -31,98 +31,148 @@
 __libc_lock_define_initialized (static, lock)
 
 static nis_result *result = NULL;
-static nis_name *names = NULL;
-
-#define ENTNAME         rpcent
-#define DATABASE        "rpc"
-#define TRAILING_LIST_MEMBER            r_aliases
-#define TRAILING_LIST_SEPARATOR_P       isspace
-#include "../../nss/nss_files/files-parse.c"
-LINE_PARSER
-("#",
- STRING_FIELD (result->r_name, isspace, 1);
- INT_FIELD (result->r_number, isspace, 1, 10,);
- )
+static nis_name tablename_val = NULL;
+static u_long tablename_len = 0;
 
 #define NISENTRYVAL(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
 
 #define NISENTRYLEN(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
+        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
 
 static int
 _nss_nisplus_parse_rpcent (nis_result *result, struct rpcent *rpc,
 			   char *buffer, size_t buflen)
 {
-  char *p = buffer;
+  char *first_unused = buffer;
   size_t room_left = buflen;
   unsigned int i;
-  struct parser_data *data = (void *) buffer;
+  char *p, *line;
+
 
   if (result == NULL)
     return 0;
 
   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
-      result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
-      strcmp(result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
+      __type_of (result->objects.objects_val) != ENTRY_OBJ ||
+      strcmp(result->objects.objects_val[0].EN_data.en_type,
              "rpc_tbl") != 0 ||
-      result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 3)
+      result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 3)
     return 0;
 
-  memset (p, '\0', room_left);
-
-  /* Generate the rpc entry format and use the normal parser */
-  if (NISENTRYLEN (0, 0, result) +1 > room_left)
+  if (NISENTRYLEN (0, 0, result) >= room_left)
     {
+    no_more_room:
       __set_errno (ERANGE);
       return 0;
     }
-  strncpy (p, NISENTRYVAL (0, 0, result), NISENTRYLEN (0, 0, result));
-  room_left -= (NISENTRYLEN (0, 0, result) +1);
-
-  if (NISENTRYLEN (0, 2, result) +1 > room_left)
+  strncpy (first_unused, NISENTRYVAL (0, 0, result),
+           NISENTRYLEN (0, 0, result));
+  first_unused[NISENTRYLEN (0, 0, result)] = '\0';
+  rpc->r_name = first_unused;
+  room_left -= (strlen (first_unused) +1);
+  first_unused += strlen (first_unused) +1;
+  rpc->r_number = atoi (NISENTRYVAL (0, 2, result));
+  p = first_unused;
+
+  line = p;
+  for (i = 0; i < result->objects.objects_len; i++)
     {
-      __set_errno (ERANGE);
-      return 0;
+      if (strcmp (NISENTRYVAL (i, 1, result), rpc->r_name) != 0)
+        {
+          if (NISENTRYLEN (i, 1, result) + 2 > room_left)
+	    goto no_more_room;
+          p = stpcpy(p, " ");
+          p = stpncpy (p, NISENTRYVAL (i, 1, result),
+                       NISENTRYLEN (i, 1, result));
+          *p = '\0';
+          room_left -= (NISENTRYLEN (i, 1, result) + 1);
+        }
     }
-  strcat (p, "\t");
-  strncat (p, NISENTRYVAL (0, 2, result), NISENTRYLEN (0, 2, result));
-  room_left -= (NISENTRYLEN (0, 2, result) + 1);
-                                       /* + 1: We overwrite the last \0 */
-
-  for (i = 0; i < result->objects.objects_len; i++)
-    /* XXX should we start with i = 0 or with i = 1 ? */
+  ++p;
+  first_unused = p;
+
+  /* Adjust the pointer so it is aligned for
+     storing pointers.  */
+  first_unused += __alignof__ (char *) - 1;
+  first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
+  rpc->r_aliases = (char **) first_unused;
+  if (room_left < sizeof (char *))
+    goto no_more_room;
+  room_left -= (sizeof (char *));
+  rpc->r_aliases[0] = NULL;
+
+  i = 0;
+  while (*line != '\0')
     {
-      if (NISENTRYLEN (i, 1, result) +1 > room_left)
+      /* Skip leading blanks.  */
+      while (isspace (*line))
+        line++;
+
+      if (*line == '\0')
+        break;
+
+      if (room_left < sizeof (char *))
+	goto no_more_room;
+
+      room_left -= sizeof (char *);
+      rpc->r_aliases[i] = line;
+
+      while (*line != '\0' && *line != ' ')
+        ++line;
+
+      if (line != rpc->r_aliases[i])
         {
-          __set_errno (ERANGE);
-          return 0;
+          if (*line != '\0')
+            {
+              *line = '\0';
+              ++line;
+            }
+          ++i;
         }
-      strcat (p, " ");
-      strncat (p, NISENTRYVAL (i, 1, result), NISENTRYLEN (i, 1, result));
-      room_left -= (NISENTRYLEN (i, 1, result) + 1);
+      else
+        rpc->r_aliases[i] = NULL;
     }
 
-  return _nss_files_parse_rpcent (p, rpc, data, buflen);
+  return 1;
 }
 
+static enum nss_status
+_nss_create_tablename (void)
+{
+  if (tablename_val == NULL)
+    {
+      char buf [40 + strlen (nis_local_directory ())];
+      char *p;
+
+      p = stpcpy (buf, "rpc.org_dir.");
+      p = stpcpy (p, nis_local_directory ());
+      tablename_val = strdup (buf);
+      if (tablename_val == NULL)
+        return NSS_STATUS_TRYAGAIN;
+      tablename_len = strlen (tablename_val);
+    }
+  return NSS_STATUS_SUCCESS;
+}
+
+
 enum nss_status
 _nss_nisplus_setrpcent (void)
 {
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
   __libc_lock_lock (lock);
 
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
+
+  if (tablename_val == NULL)
+    status = _nss_create_tablename ();
 
   __libc_lock_unlock (lock);
 
-  return NSS_STATUS_SUCCESS;
+  return status;
 }
 
 enum nss_status
@@ -133,11 +183,6 @@ _nss_nisplus_endrpcent (void)
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
 
   __libc_lock_unlock (lock);
 
@@ -155,11 +200,11 @@ internal_nisplus_getrpcent_r (struct rpcent *rpc, char *buffer,
     {
       if (result == NULL)
 	{
-	  names = nis_getnames ("rpc.org_dir");
-	  if (names == NULL || names[0] == NULL)
-	    return NSS_STATUS_UNAVAIL;
+          if (tablename_val == NULL)
+            if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+              return NSS_STATUS_UNAVAIL;
 
-	  result = nis_first_entry(names[0]);
+	  result = nis_first_entry(tablename_val);
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    return niserr2nss (result->status);
 	}
@@ -167,7 +212,7 @@ internal_nisplus_getrpcent_r (struct rpcent *rpc, char *buffer,
 	{
 	  nis_result *res;
 
-	  res = nis_next_entry (names[0], &result->cookie);
+	  res = nis_next_entry (tablename_val, &result->cookie);
 	  nis_freeresult (result);
 	  result = res;
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
@@ -201,32 +246,37 @@ _nss_nisplus_getrpcbyname_r (const char *name, struct rpcent *rpc,
 {
   int parse_res;
 
+  if (tablename_val == NULL)
+    if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
+
   if (name == NULL)
     return NSS_STATUS_NOTFOUND;
   else
     {
       nis_result *result;
-      char buf[strlen (name) + 255];
+      char buf[strlen (name) + 255 + tablename_len];
 
       /* Search at first in the alias list, and use the correct name
          for the next search */
-      sprintf (buf, "[name=%s],rpc.org_dir", name);
-      result = nis_list (buf, EXPAND_NAME, NULL, NULL);
+      sprintf (buf, "[name=%s],%s", name, tablename_val);
+      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
       /* If we do not find it, try it as original name. But if the
          database is correct, we should find it in the first case, too */
       if ((result->status != NIS_SUCCESS &&
            result->status != NIS_S_SUCCESS) ||
-          result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
-          strcmp (result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
+          __type_of (result->objects.objects_val) != ENTRY_OBJ ||
+          strcmp (result->objects.objects_val->EN_data.en_type,
 		  "rpc_tbl") != 0 ||
-          result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 3)
-        sprintf (buf, "[cname=%s],rpc.org_dir", name);
+          result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
+        sprintf (buf, "[cname=%s],%s", name, tablename_val);
       else
-        sprintf (buf, "[cname=%s],rpc.org_dir", NISENTRYVAL(0, 0, result));
+        sprintf (buf, "[cname=%s],%s", NISENTRYVAL(0, 0, result),
+		 tablename_val);
 
       nis_freeresult (result);
-      result = nis_list(buf, EXPAND_NAME, NULL, NULL);
+      result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS , NULL, NULL);
 
       if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	{
@@ -254,31 +304,37 @@ enum nss_status
 _nss_nisplus_getrpcbynumber_r (const int number, struct rpcent *rpc,
 				char *buffer, size_t buflen)
 {
-  int parse_res;
-  nis_result *result;
-  char buf[100];
+  if (tablename_val == NULL)
+    if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
 
-  snprintf (buf, sizeof (buf), "[number=%d],rpc.org_dir", number);
+  {
+    int parse_res;
+    nis_result *result;
+    char buf[100 + tablename_len];
 
-  result = nis_list(buf, EXPAND_NAME, NULL, NULL);
+    snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val);
 
-  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-    {
-      enum nss_status status = niserr2nss (result->status);
+    result = nis_list(buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
 
-      nis_freeresult (result);
-      return status;
-    }
+    if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+      {
+	enum nss_status status = niserr2nss (result->status);
 
-  parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen);
+	nis_freeresult (result);
+	return status;
+      }
 
-  nis_freeresult (result);
+    parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen);
 
-  if (parse_res)
-    return NSS_STATUS_SUCCESS;
+    nis_freeresult (result);
 
-  if (!parse_res && errno == ERANGE)
-    return NSS_STATUS_TRYAGAIN;
-  else
-    return NSS_STATUS_NOTFOUND;
+    if (parse_res)
+      return NSS_STATUS_SUCCESS;
+
+    if (!parse_res && errno == ERANGE)
+      return NSS_STATUS_TRYAGAIN;
+    else
+      return NSS_STATUS_NOTFOUND;
+  }
 }
diff --git a/nis/nss_nisplus/nisplus-service.c b/nis/nss_nisplus/nisplus-service.c
index 6cad42d4f6..50bc7e24c1 100644
--- a/nis/nss_nisplus/nisplus-service.c
+++ b/nis/nss_nisplus/nisplus-service.c
@@ -31,107 +31,154 @@
 __libc_lock_define_initialized (static, lock);
 
 static nis_result *result = NULL;
-static nis_name *names = NULL;
-
-#define ENTNAME         servent
-#define DATABASE        "services"
-#define TRAILING_LIST_MEMBER            s_aliases
-#define TRAILING_LIST_SEPARATOR_P       isspace
-#include "../../nss/nss_files/files-parse.c"
-#define ISSLASH(c) ((c) == '/')
-LINE_PARSER
-("#",
- STRING_FIELD (result->s_name, isspace, 1);
- INT_FIELD (result->s_port, ISSLASH, 10, 0, htons);
- STRING_FIELD (result->s_proto, isspace, 1);
- )
-
+static nis_name tablename_val = NULL;
+static u_long tablename_len = 0;
 
 #define NISENTRYVAL(idx,col,res) \
-  ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+  ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
 
 #define NISENTRYLEN(idx,col,res) \
-    ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
+    ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
 
 static int
 _nss_nisplus_parse_servent (nis_result *result, struct servent *serv,
 			    char *buffer, size_t buflen)
 {
-  char *p = buffer;
+  char *first_unused = buffer;
   size_t room_left = buflen;
   unsigned int i;
-  struct parser_data *data = (void *) buffer;
+  char *p, *line;
 
   if (result == NULL)
     return 0;
 
   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
-      result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
-   strcmp (result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
-	   "services_tbl") != 0 ||
-      result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 4)
+      __type_of (result->objects.objects_val) != ENTRY_OBJ ||
+      strcmp (result->objects.objects_val->EN_data.en_type,
+	      "services_tbl") != 0 ||
+      result->objects.objects_val->EN_data.en_cols.en_cols_len < 4)
     return 0;
 
-  memset (p, '\0', room_left);
-
-  /* Generate the services entry format and use the normal parser */
-  if (NISENTRYLEN (0, 0, result) + 1 > room_left)
+  if (NISENTRYLEN (0, 0, result) >= room_left)
     {
+    no_more_room:
       __set_errno (ERANGE);
       return 0;
     }
-  strncpy (p, NISENTRYVAL (0, 0, result), NISENTRYLEN (0, 0, result));
-  room_left -= (NISENTRYLEN (0, 0, result) + 1);
-
-  if (NISENTRYLEN (0, 3, result) + 1 > room_left)
+  strncpy (first_unused, NISENTRYVAL (0, 0, result),
+           NISENTRYLEN (0, 0, result));
+  first_unused[NISENTRYLEN (0, 0, result)] = '\0';
+  serv->s_name = first_unused;
+  room_left -= (strlen (first_unused) +1);
+  first_unused += strlen (first_unused) +1;
+
+  if (NISENTRYLEN (0, 2, result) >= room_left)
+    goto no_more_room;
+  strncpy (first_unused, NISENTRYVAL (0, 2, result),
+           NISENTRYLEN (0, 2, result));
+  first_unused[NISENTRYLEN (0, 2, result)] = '\0';
+  serv->s_proto = first_unused;
+  room_left -= (strlen (first_unused) +1);
+  first_unused += strlen (first_unused) +1;
+
+  serv->s_port = atoi (NISENTRYVAL (0, 3, result));
+  p = first_unused;
+
+  line = p;
+  for (i = 0; i < result->objects.objects_len; i++)
     {
-      __set_errno (ERANGE);
-      return 0;
+      if (strcmp (NISENTRYVAL (i, 1, result), serv->s_name) != 0)
+        {
+          if (NISENTRYLEN (i, 1, result) + 2 > room_left)
+            goto no_more_room;
+          p = stpcpy(p, " ");
+          p = stpncpy (p, NISENTRYVAL (i, 1, result),
+                       NISENTRYLEN (i, 1, result));
+          *p = '\0';
+          room_left -= (NISENTRYLEN (i, 1, result) + 1);
+        }
     }
-  strcat (p, "\t");
-  strncat (p, NISENTRYVAL (0, 3, result), NISENTRYLEN (0, 3, result));
-  room_left -= (NISENTRYLEN (0, 3, result) + 1);
-  if (NISENTRYLEN (0, 2, result) + 1 > room_left)
+  ++p;
+  first_unused = p;
+
+  /* Adjust the pointer so it is aligned for
+     storing pointers.  */
+  first_unused += __alignof__ (char *) - 1;
+  first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
+  serv->s_aliases = (char **) first_unused;
+  if (room_left < sizeof (char *))
+    goto no_more_room;
+  room_left -= (sizeof (char *));
+  serv->s_aliases[0] = NULL;
+
+  i = 0;
+  while (*line != '\0')
     {
-      __set_errno (ERANGE);
-      return 0;
-    }
-  strcat (p, "/");
-  strncat (p, NISENTRYVAL (0, 2, result), NISENTRYLEN (0, 2, result));
-  room_left -= (NISENTRYLEN (0, 2, result) + 1);
+      /* Skip leading blanks.  */
+      while (isspace (*line))
+        line++;
 
-  for (i = 1; i < result->objects.objects_len; i++)
-    {
-      if (NISENTRYLEN (i, 1, result) + 1 > room_left)
-	{
-	  __set_errno (ERANGE);
-	  return 0;
+      if (*line == '\0')
+        break;
+
+      if (room_left < sizeof (char *))
+        goto no_more_room;
+
+      room_left -= sizeof (char *);
+      serv->s_aliases[i] = line;
+
+      while (*line != '\0' && *line != ' ')
+        ++line;
+
+      if (*line == ' ')
+        {
+	  *line = '\0';
+	  ++line;
+          ++i;
 	}
-      strcat (p, " ");
-      strcat (p, NISENTRYVAL (i, 1, result));
-      room_left -= (NISENTRYLEN (i, 1, result) + 1);
+      else
+        serv->s_aliases[i+1] = NULL;
     }
 
-  return _nss_files_parse_servent (p, serv, data, buflen);
+  return 1;
+}
+
+static enum nss_status
+_nss_create_tablename (void)
+{
+  if (tablename_val == NULL)
+    {
+      char buf [40 + strlen (nis_local_directory ())];
+      char *p;
+
+      p = stpcpy (buf, "services.org_dir.");
+      p = stpcpy (p, nis_local_directory ());
+      tablename_val = strdup (buf);
+      if (tablename_val == NULL)
+        return NSS_STATUS_TRYAGAIN;
+      tablename_len = strlen (tablename_val);
+    }
+  return NSS_STATUS_SUCCESS;
 }
 
+
 enum nss_status
 _nss_nisplus_setservent (void)
 {
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
   __libc_lock_lock (lock);
 
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
+
+  if (tablename_val == NULL)
+    status = _nss_create_tablename ();
 
   __libc_lock_unlock (lock);
 
-  return NSS_STATUS_SUCCESS;
+  return status;
 }
 
 enum nss_status
@@ -142,11 +189,6 @@ _nss_nisplus_endservent (void)
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
 
   __libc_lock_unlock (lock);
 
@@ -164,11 +206,11 @@ internal_nisplus_getservent_r (struct servent *serv, char *buffer,
     {
       if (result == NULL)
 	{
-	  names = nis_getnames ("services.org_dir");
-	  if (names == NULL || names[0] == NULL)
-	    return NSS_STATUS_UNAVAIL;
+          if (tablename_val == NULL)
+            if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+              return NSS_STATUS_UNAVAIL;
 
-	  result = nis_first_entry (names[0]);
+	  result = nis_first_entry (tablename_val);
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    return niserr2nss (result->status);
 	}
@@ -176,7 +218,7 @@ internal_nisplus_getservent_r (struct servent *serv, char *buffer,
 	{
 	  nis_result *res;
 
-	  res = nis_next_entry (names[0], &result->cookie);
+	  res = nis_next_entry (tablename_val, &result->cookie);
 	  nis_freeresult (result);
 	  result = res;
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
@@ -212,6 +254,10 @@ _nss_nisplus_getservbyname_r (const char *name, const char *protocol,
 {
   int parse_res;
 
+  if (tablename_val == NULL)
+    if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
+
   if (name == NULL || protocol == NULL)
     {
       __set_errno (EINVAL);
@@ -220,29 +266,30 @@ _nss_nisplus_getservbyname_r (const char *name, const char *protocol,
   else
     {
       nis_result *result;
-      char buf[strlen (name) + 255];
+      char buf[strlen (name) + 255 + tablename_len];
 
       /* Search at first in the alias list, and use the correct name
          for the next search */
-      sprintf (buf, "[name=%s,proto=%s],services.org_dir", name,
-	       protocol);
-      result = nis_list (buf, EXPAND_NAME, NULL, NULL);
+      sprintf (buf, "[name=%s,proto=%s],%s", name, protocol,
+	       tablename_val);
+      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
       /* If we do not find it, try it as original name. But if the
          database is correct, we should find it in the first case, too */
       if ((result->status != NIS_SUCCESS &&
 	   result->status != NIS_S_SUCCESS) ||
-	  result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
-	  strcmp (result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
+	  __type_of (result->objects.objects_val) != ENTRY_OBJ ||
+	  strcmp (result->objects.objects_val->EN_data.en_type,
 		  "services_tbl") != 0 ||
-	  result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 4)
-	sprintf (buf, "[cname=%s,proto=%s],services.org_dir", name, protocol);
+	  result->objects.objects_val->EN_data.en_cols.en_cols_len < 4)
+	sprintf (buf, "[cname=%s,proto=%s],%s", name, protocol,
+		 tablename_val);
       else
-	sprintf (buf, "[cname=%s,proto=%s],services.org_dir",
-		 NISENTRYVAL (0, 0, result), protocol);
+	sprintf (buf, "[cname=%s,proto=%s],%s",
+		 NISENTRYVAL (0, 0, result), protocol, tablename_val);
 
       nis_freeresult (result);
-      result = nis_list (buf, EXPAND_NAME, NULL, NULL);
+      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
       if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	{
@@ -271,38 +318,44 @@ _nss_nisplus_getservbynumber_r (const int number, const char *protocol,
 				struct servent *serv,
 				char *buffer, size_t buflen)
 {
-  int parse_res;
-  nis_result *result;
-  char buf[60 + strlen (protocol)];
+  if (tablename_val == NULL)
+    if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
 
   if (protocol == NULL)
     {
       __set_errno (EINVAL);
       return NSS_STATUS_NOTFOUND;
     }
+  else
+    {
+      int parse_res;
+      nis_result *result;
+      char buf[60 + strlen (protocol) + tablename_len];
 
-  snprintf (buf, sizeof (buf), "[number=%d,proto=%s],services.org_dir",
-	    number, protocol);
+      snprintf (buf, sizeof (buf), "[number=%d,proto=%s],%s",
+		number, protocol, tablename_val);
 
-  result = nis_list (buf, EXPAND_NAME, NULL, NULL);
+      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
-  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-    {
-      enum nss_status status = niserr2nss (result->status);
+      if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+	{
+	  enum nss_status status = niserr2nss (result->status);
 
-      nis_freeresult (result);
-      return status;
-    }
+	  nis_freeresult (result);
+	  return status;
+	}
 
-  parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen);
+      parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen);
 
-  nis_freeresult (result);
+      nis_freeresult (result);
 
-  if (parse_res)
-    return NSS_STATUS_SUCCESS;
+      if (parse_res)
+	return NSS_STATUS_SUCCESS;
 
-  if (!parse_res && errno == ERANGE)
-    return NSS_STATUS_TRYAGAIN;
-  else
-    return NSS_STATUS_NOTFOUND;
+      if (!parse_res && errno == ERANGE)
+	return NSS_STATUS_TRYAGAIN;
+      else
+	return NSS_STATUS_NOTFOUND;
+    }
 }
diff --git a/nis/nss_nisplus/nisplus-spwd.c b/nis/nss_nisplus/nisplus-spwd.c
index e6ff674f30..81bde4e689 100644
--- a/nis/nss_nisplus/nisplus-spwd.c
+++ b/nis/nss_nisplus/nisplus-spwd.c
@@ -26,132 +26,45 @@
 #include <rpcsvc/nislib.h>
 
 #include "nss-nisplus.h"
+#include "nisplus-parser.h"
 
 __libc_lock_define_initialized (static, lock)
 
 static nis_result *result = NULL;
-static nis_name *names = NULL;
+static nis_name tablename_val = NULL;
+static u_long tablename_len = 0;
 
-#define NISENTRYVAL(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
-
-#define NISENTRYLEN(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
-
-int
-_nss_nisplus_parse_spent (nis_result *result, struct spwd *sp,
-			  char *buffer, size_t buflen)
+static enum nss_status
+_nss_create_tablename (void)
 {
-  char *first_unused = buffer;
-  size_t room_left = buflen;
-
-  if (result == NULL)
-    return 0;
-
-  if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
-      result->objects.objects_len != 1 ||
-      result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
-      strcmp (result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
-	      "passwd_tbl") != 0 ||
-      result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 8)
-    return 0;
-
-  if (NISENTRYLEN(0, 0, result) >= room_left)
-    {
-      /* The line is too long for our buffer.  */
-    no_more_room:
-      __set_errno (ERANGE);
-      return 0;
-    }
-
-  strncpy (first_unused, NISENTRYVAL (0, 0, result),
-	   NISENTRYLEN (0, 0, result));
-  first_unused[NISENTRYLEN(0, 0, result)] = '\0';
-  sp->sp_namp = first_unused;
-  room_left -= (strlen (first_unused) +1);
-  first_unused += strlen (first_unused) +1;
-
-  if (NISENTRYLEN(0, 1, result) >= room_left)
-    goto no_more_room;
-
-  strncpy (first_unused, NISENTRYVAL (0, 1, result),
-	   NISENTRYLEN (0, 1, result));
-  first_unused[NISENTRYLEN(0, 1, result)] = '\0';
-  sp->sp_pwdp = first_unused;
-  room_left -= (strlen (first_unused) +1);
-  first_unused += strlen (first_unused) +1;
-
-  sp->sp_lstchg = sp->sp_min = sp->sp_max = sp->sp_warn = sp->sp_inact =
-    sp->sp_expire = sp->sp_flag = -1;
-
-  if (NISENTRYVAL (0, 7, result) != NULL)
+  if (tablename_val == NULL)
     {
-      char *line, *cp;
-
-      line = NISENTRYVAL (0, 7, result);
-      cp = strchr (line, ':');
-      if (cp == NULL)
-	return 0;
-      *cp++ = '\0';
-      sp->sp_lstchg = atol (line);
-
-      line = cp;
-      cp = strchr (line, ':');
-      if (cp == NULL)
-	return 0;
-      *cp++ = '\0';
-      sp->sp_min = atol(line);
-
-      line = cp;
-      cp = strchr (line, ':');
-      if (cp == NULL)
-	return 0;
-      *cp++ = '\0';
-      sp->sp_max = atol(line);
-
-      line = cp;
-      cp = strchr (line, ':');
-      if (cp == NULL)
-	return 0;
-      *cp++ = '\0';
-      sp->sp_warn = atol(line);
-
-      line = cp;
-      cp = strchr (line, ':');
-      if (cp == NULL)
-	return 0;
-      *cp++ = '\0';
-      sp->sp_inact = atol(line);
-
-      line = cp;
-      cp = strchr (line, ':');
-      if (cp == NULL)
-	return 0;
-      *cp++ = '\0';
-      sp->sp_expire = atol(line);
-
-      line = cp;
-      if (line == NULL)
-	return 0;
-      sp->sp_flag = atol(line);
+      char buf [40 + strlen (nis_local_directory ())];
+      char *p;
+
+      p = stpcpy (buf, "passwd.org_dir.");
+      p = stpcpy (p, nis_local_directory ());
+      tablename_val = strdup (buf);
+      if (tablename_val == NULL)
+        return NSS_STATUS_TRYAGAIN;
+      tablename_len = strlen (tablename_val);
     }
-
-  return 1;
+  return NSS_STATUS_SUCCESS;
 }
 
 enum nss_status
 _nss_nisplus_setspent (void)
 {
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
   __libc_lock_lock (lock);
 
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
+
+  if (tablename_val == NULL)
+    status = _nss_create_tablename ();
 
   __libc_lock_unlock (lock);
 
@@ -166,11 +79,6 @@ _nss_nisplus_endspent (void)
   if (result)
     nis_freeresult (result);
   result = NULL;
-  if (names)
-    {
-      nis_freenames (names);
-      names = NULL;
-    }
 
   __libc_lock_unlock (lock);
 
@@ -187,11 +95,11 @@ internal_nisplus_getspent_r (struct spwd *sp, char *buffer, size_t buflen)
     {
       if (result == NULL)
 	{
-	  names = nis_getnames ("passwd.org_dir");
-	  if (names == NULL || names[0] == NULL)
-	    return NSS_STATUS_UNAVAIL;
+          if (tablename_val == NULL)
+            if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+              return NSS_STATUS_UNAVAIL;
 
-	  result = nis_first_entry (names[0]);
+	  result = nis_first_entry (tablename_val);
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    return niserr2nss (result->status);
 	}
@@ -199,7 +107,7 @@ internal_nisplus_getspent_r (struct spwd *sp, char *buffer, size_t buflen)
 	{
 	  nis_result *res;
 
-	  res = nis_next_entry (names[0], &result->cookie);
+	  res = nis_next_entry (tablename_val, &result->cookie);
 	  nis_freeresult (result);
 	  result = res;
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
@@ -232,16 +140,20 @@ _nss_nisplus_getspnam_r (const char *name, struct spwd *sp,
 {
   int parse_res;
 
+  if (tablename_val == NULL)
+    if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
+      return NSS_STATUS_UNAVAIL;
+
   if (name == NULL || strlen (name) > 8)
     return NSS_STATUS_NOTFOUND;
   else
     {
       nis_result *result;
-      char buf[strlen (name) + 24];
+      char buf[strlen (name) + 24 + tablename_len];
 
-      sprintf (buf, "[name=%s],passwd.org_dir", name);
+      sprintf (buf, "[name=%s],%s", name, tablename_val);
 
-      result = nis_list (buf, EXPAND_NAME, NULL, NULL);
+      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
       if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	{
diff --git a/nis/rpcsvc/nis_cache.h b/nis/rpcsvc/nis_cache.h
new file mode 100644
index 0000000000..ca91a22cd4
--- /dev/null
+++ b/nis/rpcsvc/nis_cache.h
@@ -0,0 +1,47 @@
+#ifndef __RPCSVC_NIS_CACHE_H_
+#define __RPCSVC_NIS_CACHE_H_
+
+#include <features.h>
+#include <rpc/rpc.h>
+#include <rpc/types.h>
+#include <rpcsvc/nis.h>
+
+__BEGIN_DECLS
+
+/* default cache file */
+#define CACHEFILE "/var/nis/NIS_SHARED_DIRCACHE" 
+
+/* clients have to read-lock the cache file, and SVR4 locking requires that */
+/*   the file be writable, but we don't want a world-writable cache file.   */
+/*   So... everyone agrees to use a different, world-writable file for the  */
+/*   locking operations, but the data is in CACHEFILE.                      */
+#define CACHELOCK "/usr/tmp/.NIS_DIR_CACHELOCK"
+
+/* the file containing one trusted XDR'ed directory object.
+ * This has to be present for the system to work.
+ */
+#define COLD_START_FILE "/var/nis/NIS_COLD_START"
+
+enum pc_status {HIT, MISS, NEAR_MISS};
+
+#define CACHEPROG ((u_long)100301)
+#define CACHE_VER_1 ((u_long)1)
+
+#define NIS_CACHE_ADD_ENTRY ((u_long)1)
+#define NIS_CACHE_REMOVE_ENTRY ((u_long)2)
+#define NIS_CACHE_READ_COLDSTART ((u_long)3)
+#define NIS_CACHE_REFRESH_ENTRY ((u_long)4)
+
+extern void *nis_cache_add_entry_1 __P ((fd_result *, CLIENT *));
+extern void *nis_cache_add_entry_1_svc __P ((fd_result *, struct svc_req *));
+extern void *nis_cache_remove_entry_1 __P ((directory_obj *, CLIENT *));
+extern void *nis_cache_remove_entry_1_svc __P ((directory_obj *,
+						struct svc_req *));
+extern void *nis_cache_read_coldstart_1 __P ((void *, CLIENT *));
+extern void *nis_cache_read_coldstart_1_svc __P ((void *, struct svc_req *));
+extern void *nis_cache_refresh_entry_1 __P ((char **, CLIENT *));
+extern void *nis_cache_refresh_entry_1_svc __P ((char **, struct svc_req *));
+
+__END_DECLS
+
+#endif /* !_RPCSVC_NIS_CACHE_H_ */
diff --git a/nis/rpcsvc/nis_cache.x b/nis/rpcsvc/nis_cache.x
new file mode 100644
index 0000000000..91870d8a48
--- /dev/null
+++ b/nis/rpcsvc/nis_cache.x
@@ -0,0 +1,47 @@
+/*
+ *	nis_cache.x
+ *
+ *	Copyright (c) 1988-1992 Sun Microsystems Inc
+ *	All Rights Reserved.
+ */
+
+%#pragma ident	"@(#)nis_cache.x	1.8	92/07/14 SMI"
+
+
+#ifdef RPC_HDR
+%#include <rpc/types.h>
+%#include <rpcsvc/nis.h>
+%
+%/* default cache file */
+%#define CACHEFILE "/var/nis/NIS_SHARED_DIRCACHE" 
+%
+%/* clients have to read-lock the cache file, and SVR4 locking requires that */
+%/*   the file be writable, but we don't want a world-writable cache file.   */
+%/*   So... everyone agrees to use a different, world-writable file for the  */
+%/*   locking operations, but the data is in CACHEFILE.                      */
+%#define CACHELOCK "/usr/tmp/.NIS_DIR_CACHELOCK"
+%
+%/* the file containing one trusted XDR'ed directory object.
+% * This has to be present for the system to work.
+% */
+%#define COLD_START_FILE "/var/nis/NIS_COLD_START"
+%
+%enum pc_status {HIT, MISS, NEAR_MISS};
+%
+%extern int __nis_debuglevel;
+%
+%
+#endif
+
+#ifdef RPC_CLNT
+%#include "../gen/nis_clnt.h"
+#endif
+
+program CACHEPROG {
+	version CACHE_VER_1 {
+		void NIS_CACHE_ADD_ENTRY(fd_result) = 1;
+		void NIS_CACHE_REMOVE_ENTRY(directory_obj) = 2;
+		void NIS_CACHE_READ_COLDSTART(void) = 3;
+		void NIS_CACHE_REFRESH_ENTRY(string<>) = 4;
+	} = 1;
+} = 100301;
diff --git a/nis/rpcsvc/nislib.h b/nis/rpcsvc/nislib.h
index cbd8fbde51..73b3804e85 100644
--- a/nis/rpcsvc/nislib.h
+++ b/nis/rpcsvc/nislib.h
@@ -254,10 +254,14 @@ extern nis_name __nis_default_owner __P ((char *));
 extern nis_name __nis_default_group __P ((char *));
 extern u_long __nis_default_ttl __P ((char *));
 extern u_long __nis_default_access __P ((char *, u_long));
-extern fd_result *__nis_finddirectory __P ((directory_obj *, nis_name));
+extern fd_result *__nis_finddirectory __P ((directory_obj *, const_nis_name));
+extern u_long __nis_hash __P ((const void *keyarg, register size_t len));
 extern log_result *__nis_dumplog __P ((nis_server *,nis_name, u_long));
 extern log_result *__nis_dump __P ((nis_server *, nis_name,
 				    int (*)(nis_name, nis_object *, void *)));
+/* NIS+ cache locking */
+extern int __nis_lock_cache __P ((void));
+extern int __nis_unlock_cache __P ((void));
 
 __END_DECLS