about summary refs log tree commit diff
path: root/nis
diff options
context:
space:
mode:
Diffstat (limited to 'nis')
-rw-r--r--nis/Makefile6
-rw-r--r--nis/Versions9
-rw-r--r--nis/libnsl.h40
-rw-r--r--nis/nis_addmember.c30
-rw-r--r--nis/nis_call.c566
-rw-r--r--nis/nis_callback.c65
-rw-r--r--nis/nis_checkpoint.c5
-rw-r--r--nis/nis_clone_dir.c27
-rw-r--r--nis/nis_clone_obj.c6
-rw-r--r--nis/nis_clone_res.c29
-rw-r--r--nis/nis_creategroup.c18
-rw-r--r--nis/nis_defaults.c127
-rw-r--r--nis/nis_domain_of.c16
-rw-r--r--nis/nis_domain_of_r.c9
-rw-r--r--nis/nis_error.c97
-rw-r--r--nis/nis_error.h48
-rw-r--r--nis/nis_file.c93
-rw-r--r--nis/nis_getservlist.c57
-rw-r--r--nis/nis_intern.h3
-rw-r--r--nis/nis_ismember.c5
-rw-r--r--nis/nis_local_names.c6
-rw-r--r--nis/nis_lookup.c109
-rw-r--r--nis/nis_ping.c11
-rw-r--r--nis/nis_print_group_entry.c14
-rw-r--r--nis/nis_removemember.c74
-rw-r--r--nis/nis_subr.c105
-rw-r--r--nis/nis_table.c380
-rw-r--r--nis/nis_xdr.c524
-rw-r--r--nis/nis_xdr.h35
-rw-r--r--nis/nisplus-parser.h18
-rw-r--r--nis/nss12
-rw-r--r--nis/nss-default.c127
-rw-r--r--nis/nss-nis.c87
-rw-r--r--nis/nss-nis.h32
-rw-r--r--nis/nss-nisplus.h6
-rw-r--r--nis/nss_compat/compat-grp.c48
-rw-r--r--nis/nss_compat/compat-initgroups.c6
-rw-r--r--nis/nss_compat/compat-pwd.c83
-rw-r--r--nis/nss_compat/compat-spwd.c73
-rw-r--r--nis/nss_nis/nis-alias.c76
-rw-r--r--nis/nss_nis/nis-ethers.c75
-rw-r--r--nis/nss_nis/nis-grp.c256
-rw-r--r--nis/nss_nis/nis-hosts.c136
-rw-r--r--nis/nss_nis/nis-initgroups.c121
-rw-r--r--nis/nss_nis/nis-netgrp.c30
-rw-r--r--nis/nss_nis/nis-network.c115
-rw-r--r--nis/nss_nis/nis-proto.c60
-rw-r--r--nis/nss_nis/nis-publickey.c106
-rw-r--r--nis/nss_nis/nis-pwd.c350
-rw-r--r--nis/nss_nis/nis-rpc.c169
-rw-r--r--nis/nss_nis/nis-service.c254
-rw-r--r--nis/nss_nis/nis-spwd.c66
-rw-r--r--nis/nss_nisplus/nisplus-alias.c257
-rw-r--r--nis/nss_nisplus/nisplus-ethers.c251
-rw-r--r--nis/nss_nisplus/nisplus-grp.c380
-rw-r--r--nis/nss_nisplus/nisplus-hosts.c371
-rw-r--r--nis/nss_nisplus/nisplus-initgroups.c150
-rw-r--r--nis/nss_nisplus/nisplus-netgrp.c30
-rw-r--r--nis/nss_nisplus/nisplus-network.c318
-rw-r--r--nis/nss_nisplus/nisplus-parser.c252
-rw-r--r--nis/nss_nisplus/nisplus-proto.c323
-rw-r--r--nis/nss_nisplus/nisplus-publickey.c62
-rw-r--r--nis/nss_nisplus/nisplus-pwd.c388
-rw-r--r--nis/nss_nisplus/nisplus-rpc.c336
-rw-r--r--nis/nss_nisplus/nisplus-service.c341
-rw-r--r--nis/nss_nisplus/nisplus-spwd.c151
-rw-r--r--nis/rpcsvc/nislib.h8
-rw-r--r--nis/yp_xdr.c8
-rw-r--r--nis/ypclnt.c311
-rw-r--r--nis/ypupdate_xdr.c2
70 files changed, 5093 insertions, 3666 deletions
diff --git a/nis/Makefile b/nis/Makefile
index fa5c4dfd30..8083ee8044 100644
--- a/nis/Makefile
+++ b/nis/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1996, 1997, 1998, 2001, 2004 Free Software Foundation, Inc.
+# Copyright (C) 1996,1997,1998,2001,2004,2006 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
@@ -54,7 +54,7 @@ libnsl-routines = yp_xdr ypclnt ypupdate_xdr \
 		  nis_print_group_entry nis_domain_of nis_domain_of_r\
 		  nis_modify nis_remove nis_add nis_defaults\
 		  nis_findserv nis_callback nis_clone_dir nis_clone_obj\
-		  nis_clone_res
+		  nis_clone_res nss-default
 
 libnss_compat-routines	:= $(addprefix compat-,grp pwd spwd initgroups)
 libnss_compat-inhibit-o	= $(filter-out .os,$(object-suffixes))
@@ -64,7 +64,7 @@ libnss_nis-routines	:= $(addprefix nis-,$(databases)) nis-initgroups \
 libnss_nis-inhibit-o	= $(filter-out .os,$(object-suffixes))
 
 libnss_nisplus-routines	:= $(addprefix nisplus-,$(databases)) nisplus-parser \
-			   nss-nisplus
+			   nss-nisplus nisplus-initgroups
 libnss_nisplus-inhibit-o = $(filter-out .os,$(object-suffixes))
 
 include ../Rules
diff --git a/nis/Versions b/nis/Versions
index d6b6a972f6..be4453e285 100644
--- a/nis/Versions
+++ b/nis/Versions
@@ -57,6 +57,10 @@ libnsl {
   GLIBC_2.2 {
     xdr_ypall;
   }
+  GLIBC_PRIVATE {
+    _nsl_default_nss; __prepare_niscall; __follow_path; __do_niscall3;
+    __create_ib_request; _xdr_ib_request; _xdr_nis_result;
+  }
 }
 
 libnss_compat {
@@ -117,11 +121,10 @@ libnss_nisplus {
     _nss_nisplus_getservbyname_r; _nss_nisplus_getservbynumber_r;
     _nss_nisplus_getservent_r; _nss_nisplus_getspent_r;
     _nss_nisplus_getspnam_r; _nss_nisplus_netname2user;
-    _nss_nisplus_parse_grent; _nss_nisplus_parse_pwent;
-    _nss_nisplus_parse_spent; _nss_nisplus_setaliasent;
+    _nss_nisplus_setaliasent;
     _nss_nisplus_setetherent; _nss_nisplus_setgrent; _nss_nisplus_sethostent;
     _nss_nisplus_setnetent; _nss_nisplus_setnetgrent; _nss_nisplus_setprotoent;
     _nss_nisplus_setpwent; _nss_nisplus_setrpcent; _nss_nisplus_setservent;
-    _nss_nisplus_setspent;
+    _nss_nisplus_setspent; _nss_nisplus_initgroups_dyn;
   }
 }
diff --git a/nis/libnsl.h b/nis/libnsl.h
new file mode 100644
index 0000000000..c6ceb321d7
--- /dev/null
+++ b/nis/libnsl.h
@@ -0,0 +1,40 @@
+/* Copyright (C) 2005, 2006 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 Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <rpcsvc/nis.h>
+
+#define NSS_FLAG_NETID_AUTHORITATIVE	1
+#define NSS_FLAG_SERVICES_AUTHORITATIVE	2
+#define NSS_FLAG_SETENT_BATCH_READ	4
+
+
+/* Get current set of default flags.  */
+extern int _nsl_default_nss (void);
+
+/* Set up everything for a call to __do_niscall3.  */
+extern nis_error __prepare_niscall (const_nis_name name, directory_obj **dirp,
+				    dir_binding *bptrp, unsigned int flags);
+libnsl_hidden_proto (__prepare_niscall)
+
+extern struct ib_request *__create_ib_request (const_nis_name name,
+					       unsigned int flags);
+libnsl_hidden_proto (__create_ib_request)
+
+extern nis_error __follow_path (char **tablepath, char **tableptr,
+				struct ib_request *ibreq, dir_binding *bptr);
+libnsl_hidden_proto (__follow_path)
diff --git a/nis/nis_addmember.c b/nis/nis_addmember.c
index bbe1c23977..5e342ad0d0 100644
--- a/nis/nis_addmember.c
+++ b/nis/nis_addmember.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998, 1999, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 1998, 1999, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -28,13 +28,12 @@ nis_addmember (const_nis_name member, const_nis_name group)
     {
       size_t grouplen = strlen (group);
       char buf[grouplen + 14 + NIS_MAXNAMELEN];
-      char leafbuf[grouplen + 2];
       char domainbuf[grouplen + 2];
       nis_result *res, *res2;
       nis_error status;
       char *cp, *cp2;
 
-      cp = stpcpy (buf, nis_leaf_of_r (group, leafbuf, sizeof (leafbuf) - 1));
+      cp = rawmemchr (nis_leaf_of_r (group, buf, sizeof (buf) - 1), '\0');
       cp = stpcpy (cp, ".groups_dir");
       cp2 = nis_domain_of_r (group, domainbuf, sizeof (domainbuf) - 1);
       if (cp2 != NULL && cp2[0] != '\0')
@@ -42,30 +41,35 @@ nis_addmember (const_nis_name member, const_nis_name group)
 	  *cp++ = '.';
           stpcpy (cp, cp2);
         }
-      res = nis_lookup (buf, FOLLOW_LINKS|EXPAND_NAME);
+      res = nis_lookup (buf, FOLLOW_LINKS | EXPAND_NAME);
       if (NIS_RES_STATUS (res) != NIS_SUCCESS)
 	{
 	  status = NIS_RES_STATUS (res);
 	  nis_freeresult (res);
 	  return status;
 	}
-      if ((NIS_RES_NUMOBJ (res)  != 1) ||
-          (__type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ))
+      if (NIS_RES_NUMOBJ (res) != 1
+	  || __type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ)
 	{
 	  nis_freeresult (res);
 	  return NIS_INVALIDOBJ;
 	}
 
-      NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val
+      u_int gr_members_len
+	= NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len;
+
+      nis_name *new_gr_members_val
 	= realloc (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val,
-		   (NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len + 1)
-		   * sizeof (char *));
-      if (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val == NULL)
+		   (gr_members_len + 1) * sizeof (nis_name));
+      if (new_gr_members_val == NULL)
 	goto nomem_out;
-      NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val[NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len] = strdup (member);
-      if (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val[NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len] == NULL)
+
+      NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val
+	= new_gr_members_val;
+
+      new_gr_members_val[gr_members_len] = strdup (member);
+      if (new_gr_members_val[gr_members_len] == NULL)
 	{
-	  free (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val);
 	nomem_out:
 	  nis_freeresult (res);
 	  return NIS_NOMEMORY;
diff --git a/nis/nis_call.c b/nis/nis_call.c
index 14041a160c..c571e8f367 100644
--- a/nis/nis_call.c
+++ b/nis/nis_call.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1997, 1998, 2001, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 2001, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -25,11 +26,15 @@
 #include <rpc/auth.h>
 #include <rpcsvc/nis.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <bits/libc-lock.h>
 
 #include "nis_xdr.h"
 #include "nis_intern.h"
+#include <libnsl.h>
 
 static const struct timeval RPCTIMEOUT = {10, 0};
 static const struct timeval UDPTIMEOUT = {5, 0};
@@ -37,28 +42,19 @@ static const struct timeval UDPTIMEOUT = {5, 0};
 extern u_short __pmap_getnisport (struct sockaddr_in *address, u_long program,
 				  u_long version, u_int protocol);
 
-unsigned long
+unsigned long int
 inetstr2int (const char *str)
 {
-  char buffer[strlen (str) + 3];
-  size_t buflen;
-  size_t i, j;
-
-  buflen = stpcpy (buffer, str) - buffer;
-
-  j = 0;
-  for (i = 0; i < buflen; ++i)
-    if (buffer[i] == '.')
+  size_t j = 0;
+  for (size_t i = 0; str[i] != '\0'; ++i)
+    if (str[i] == '.' && __builtin_expect (++j == 4, 0))
       {
-	++j;
-	if (j == 4)
-	  {
-	    buffer[i] = '\0';
-	    break;
-	  }
+	char buffer[i + 1];
+	buffer[i] = '\0';
+	return inet_addr (memcpy (buffer, str, i));
       }
 
-  return inet_addr (buffer);
+  return inet_addr (str);
 }
 
 void
@@ -76,8 +72,6 @@ libnsl_hidden_def (__nisbind_destroy)
 nis_error
 __nisbind_next (dir_binding *bind)
 {
-  u_int j;
-
   if (bind->clnt != NULL)
     {
       if (bind->use_auth)
@@ -89,7 +83,7 @@ __nisbind_next (dir_binding *bind)
   if (bind->trys >= bind->server_len)
     return NIS_FAIL;
 
-  for (j = bind->current_ep + 1;
+  for (u_int j = bind->current_ep + 1;
        j < bind->server_val[bind->server_used].ep.ep_len; ++j)
     if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].family,
 		"inet") == 0)
@@ -104,7 +98,7 @@ __nisbind_next (dir_binding *bind)
   if (bind->server_used >= bind->server_len)
     bind->server_used = 0;
 
-  for (j = 0; j < bind->server_val[bind->server_used].ep.ep_len; ++j)
+  for (u_int j = 0; j < bind->server_val[bind->server_used].ep.ep_len; ++j)
     if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].family,
 		"inet") == 0)
       if (bind->server_val[bind->server_used].ep.ep_val[j].proto[0] == '-')
@@ -117,10 +111,79 @@ __nisbind_next (dir_binding *bind)
 }
 libnsl_hidden_def (__nisbind_next)
 
+static struct ckey_cache_entry
+{
+  struct in_addr inaddr;
+  in_port_t port;
+  unsigned int protocol;
+  des_block ckey;
+} *ckey_cache;
+static size_t ckey_cache_size;
+static size_t ckey_cache_allocated;
+static pid_t ckey_cache_pid;
+static uid_t ckey_cache_euid;
+__libc_lock_define_initialized (static, ckey_cache_lock)
+
+static bool_t
+get_ckey (des_block *ckey, struct sockaddr_in *addr, unsigned int protocol)
+{
+  size_t i;
+  pid_t pid = getpid ();
+  uid_t euid = geteuid ();
+  bool_t ret = FALSE;
+
+  __libc_lock_lock (ckey_cache_lock);
+
+  if (ckey_cache_pid != pid || ckey_cache_euid != euid)
+    {
+      ckey_cache_size = 0;
+      ckey_cache_pid = pid;
+      ckey_cache_euid = euid;
+    }
+
+  for (i = 0; i < ckey_cache_size; ++i)
+    if (ckey_cache[i].port == addr->sin_port
+	&& ckey_cache[i].protocol == protocol
+	&& memcmp (&ckey_cache[i].inaddr, &addr->sin_addr,
+		   sizeof (addr->sin_addr)) == 0)
+      {
+	*ckey = ckey_cache[i].ckey;
+	ret = TRUE;
+	break;
+      }
+
+  if (!ret && key_gendes (ckey) >= 0)
+    {
+      ret = TRUE;
+      /* Don't grow the cache indefinitely.  */
+      if (ckey_cache_size == 256)
+	ckey_cache_size = 0;
+      if (ckey_cache_size == ckey_cache_allocated)
+	{
+	  size_t size = ckey_cache_allocated ? ckey_cache_allocated * 2 : 16;
+	  struct ckey_cache_entry *new_cache
+	    = realloc (ckey_cache, size * sizeof (*ckey_cache));
+	  if (new_cache != NULL)
+	    {
+	      ckey_cache = new_cache;
+	      ckey_cache_allocated = size;
+	    }
+	}
+      ckey_cache[ckey_cache_size].inaddr = addr->sin_addr;
+      ckey_cache[ckey_cache_size].port = addr->sin_port;
+      ckey_cache[ckey_cache_size].protocol = protocol;
+      ckey_cache[ckey_cache_size++].ckey = *ckey;
+    }
+
+  __libc_lock_unlock (ckey_cache_lock);
+  return ret;
+}
+
 nis_error
 __nisbind_connect (dir_binding *dbp)
 {
   nis_server *serv;
+  u_short port;
 
   if (dbp == NULL)
     return NIS_FAIL;
@@ -133,14 +196,17 @@ __nisbind_connect (dir_binding *dbp)
   dbp->addr.sin_addr.s_addr =
     inetstr2int (serv->ep.ep_val[dbp->current_ep].uaddr);
 
-  if (dbp->addr.sin_addr.s_addr == 0)
+  if (dbp->addr.sin_addr.s_addr == INADDR_NONE)
     return NIS_FAIL;
 
   /* Check, if the host is online and rpc.nisd is running. Much faster
      then the clnt*_create functions: */
-  if (__pmap_getnisport (&dbp->addr, NIS_PROG, NIS_VERSION, IPPROTO_UDP) == 0)
+  port = __pmap_getnisport (&dbp->addr, NIS_PROG, NIS_VERSION,
+			    dbp->use_udp ? IPPROTO_UDP : IPPROTO_TCP);
+  if (port == 0)
     return NIS_RPCERROR;
 
+  dbp->addr.sin_port = htons (port);
   dbp->socket = RPC_ANYSOCK;
   if (dbp->use_udp)
     dbp->clnt = clntudp_create (&dbp->addr, NIS_PROG, NIS_VERSION,
@@ -163,23 +229,21 @@ __nisbind_connect (dir_binding *dbp)
 	{
 	  char netname[MAXNETNAMELEN + 1];
 	  char *p;
+	  des_block ckey;
 
-	  p = stpcpy (netname, "unix.");
+	  p = stpcpy (netname, "unix@");
 	  strncpy (p, serv->name, MAXNETNAMELEN - 5);
 	  netname[MAXNETNAMELEN] = '\0';
-	  // XXX What is this supposed to do?  If we really want to replace
-	  // XXX the first dot, then we might as well use unix@ as the
-	  // XXX prefix string.  --drepper
-	  p = strchr (netname, '.');
-	  *p = '@';
-	  dbp->clnt->cl_auth =
-	    authdes_pk_create (netname, &serv->pkey, 300, NULL, NULL);
+	  dbp->clnt->cl_auth = NULL;
+	  if (get_ckey (&ckey, &dbp->addr,
+			dbp->use_udp ? IPPROTO_UDP : IPPROTO_TCP))
+	    dbp->clnt->cl_auth =
+	      authdes_pk_create (netname, &serv->pkey, 300, NULL, &ckey);
 	  if (!dbp->clnt->cl_auth)
 	    dbp->clnt->cl_auth = authunix_create_default ();
 	}
       else
 	dbp->clnt->cl_auth = authunix_create_default ();
-      dbp->use_auth = TRUE;
     }
 
   return NIS_SUCCESS;
@@ -188,7 +252,8 @@ libnsl_hidden_def (__nisbind_connect)
 
 nis_error
 __nisbind_create (dir_binding *dbp, const nis_server *serv_val,
-		  unsigned int serv_len, unsigned int flags)
+		  unsigned int serv_len, unsigned int server_used,
+		  unsigned int current_ep, unsigned int flags)
 {
   dbp->clnt = NULL;
 
@@ -214,10 +279,15 @@ __nisbind_create (dir_binding *dbp, const nis_server *serv_val,
   dbp->trys = 1;
 
   dbp->class = -1;
-  if (__nis_findfastest (dbp) < 1)
+  if (server_used == ~0)
     {
-      __nisbind_destroy (dbp);
-      return NIS_NAMEUNREACHABLE;
+      if (__nis_findfastest (dbp) < 1)
+	return NIS_NAMEUNREACHABLE;
+    }
+  else
+    {
+      dbp->server_used = server_used;
+      dbp->current_ep = current_ep;
     }
 
   return NIS_SUCCESS;
@@ -269,6 +339,7 @@ __do_niscall3 (dir_binding *dbp, u_long prog, xdrproc_t xargs, caddr_t req,
 		  || ((nis_result *)resp)->status == NIS_NOSUCHNAME
 		  || ((nis_result *)resp)->status == NIS_NOT_ME)
 		{
+		next_server:
 		  if (__nisbind_next (dbp) == NIS_SUCCESS)
 		    {
 		      while (__nisbind_connect (dbp) != NIS_SUCCESS)
@@ -286,38 +357,14 @@ __do_niscall3 (dir_binding *dbp, u_long prog, xdrproc_t xargs, caddr_t req,
 	      if (((fd_result *)resp)->status == NIS_SYSTEMERROR
 		  || ((fd_result *)resp)->status == NIS_NOSUCHNAME
 		  || ((fd_result *)resp)->status == NIS_NOT_ME)
-		{
-		  if (__nisbind_next (dbp) == NIS_SUCCESS)
-		    {
-		      while (__nisbind_connect (dbp) != NIS_SUCCESS)
-			{
-			  if (__nisbind_next (dbp) != NIS_SUCCESS)
-			    return NIS_SUCCESS;
-			}
-		    }
-		  else
-		    break; /* No more servers to search in */
-		  goto again;
-		}
+		goto next_server;
 	      break;
 	    case NIS_DUMPLOG: /* log_result */
 	    case NIS_DUMP:
 	      if (((log_result *)resp)->lr_status == NIS_SYSTEMERROR
 		  || ((log_result *)resp)->lr_status == NIS_NOSUCHNAME
 		  || ((log_result *)resp)->lr_status == NIS_NOT_ME)
-		{
-		  if (__nisbind_next (dbp) == NIS_SUCCESS)
-		    {
-		      while (__nisbind_connect (dbp) != NIS_SUCCESS)
-			{
-			  if (__nisbind_next (dbp) != NIS_SUCCESS)
-			    return NIS_SUCCESS;
-			}
-		    }
-		  else
-		    break; /* No more servers to search in */
-		  goto again;
-		}
+		goto next_server;
 	      break;
 	    default:
 	      break;
@@ -329,6 +376,8 @@ __do_niscall3 (dir_binding *dbp, u_long prog, xdrproc_t xargs, caddr_t req,
 
   return retcode;
 }
+libnsl_hidden_def (__do_niscall3)
+
 
 nis_error
 __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
@@ -341,7 +390,7 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
   if (flags & MASTER_ONLY)
     server_len = 1;
 
-  status = __nisbind_create (&dbp, server, server_len, flags);
+  status = __nisbind_create (&dbp, server, server_len, ~0, ~0, flags);
   if (status != NIS_SUCCESS)
     return status;
 
@@ -373,14 +422,18 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, nis_error *status)
     case HIGHER_NAME:
       { /* We need data from a parent domain */
 	directory_obj *obj;
-	char ndomain [strlen (name) + 3];
-
-	nis_domain_of_r (dir->do_name, ndomain, sizeof (ndomain));
+	const char *ndomain = __nis_domain_of (dir->do_name);
 
 	/* 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) */
 	fd_res = __nis_finddirectory (dir, ndomain);
+	if (fd_res == NULL)
+	  {
+	    nis_free_directory (dir);
+	    *status = NIS_NOMEMORY;
+	    return NULL;
+	  }
 	*status = fd_res->status;
 	if (fd_res->status != NIS_SUCCESS)
 	  {
@@ -388,36 +441,33 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, nis_error *status)
 	    __free_fdresult (fd_res);
 	    return dir;
 	  }
+	nis_free_directory (dir);
 	obj = calloc (1, sizeof (directory_obj));
+	if (obj == NULL)
+	  {
+	    __free_fdresult (fd_res);
+	    *status = NIS_NOMEMORY;
+	    return NULL;
+	  }
 	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);
 	__free_fdresult (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, status);
-	  }
-	else
-	  {
-	    /* Ups, very bad. Are we already the root server ? */
-	    nis_free_directory (dir);
-	    return NULL;
-	  }
+
+	/* We have found a NIS+ server serving ndomain, now
+	   let us search for "name" */
+	return rec_dirsearch (name, obj, status);
       }
-    break;
+      break;
     case LOWER_NAME:
       {
 	directory_obj *obj;
 	size_t namelen = strlen (name);
 	char leaf[namelen + 3];
 	char domain[namelen + 3];
-	char ndomain[namelen + 3];
+	const char *ndomain;
 	char *cp;
-	u_int run = 0;
 
 	strcpy (domain, name);
 
@@ -429,23 +479,22 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, nis_error *status)
 		return NULL;
 	      }
 	    nis_leaf_of_r (domain, leaf, sizeof (leaf));
-	    nis_domain_of_r (domain, ndomain, sizeof (ndomain));
-	    strcpy (domain, ndomain);
-	    ++run;
+	    ndomain = __nis_domain_of (domain);
+	    memmove (domain, ndomain, strlen (ndomain) + 1);
 	  }
 	while (nis_dir_cmp (domain, dir->do_name) != SAME_NAME);
 
-	if (run == 1)
-	  {
-	    /* We have found the directory above. Use it. */
-	    return dir;
-	  }
-
-	cp = strchr (leaf, '\0');
+	cp = rawmemchr (leaf, '\0');
 	*cp++ = '.';
 	strcpy (cp, domain);
 
 	fd_res = __nis_finddirectory (dir, leaf);
+	if (fd_res == NULL)
+	  {
+	    nis_free_directory (dir);
+	    *status = NIS_NOMEMORY;
+	    return NULL;
+	  }
 	*status = fd_res->status;
 	if (fd_res->status != NIS_SUCCESS)
 	  {
@@ -453,21 +502,24 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, nis_error *status)
 	    __free_fdresult (fd_res);
 	    return dir;
 	  }
-	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);
-	__free_fdresult (fd_res);
-	if (obj != NULL)
+	nis_free_directory (dir);
+	obj = calloc (1, sizeof(directory_obj));
+	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, status);
+	    __free_fdresult (fd_res);
+	    *status = NIS_NOMEMORY;
+	    return NULL;
 	  }
+	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);
+	__free_fdresult (fd_res);
+	/* We have found a NIS+ server serving ndomain, now
+	   let us search for "name" */
+	return rec_dirsearch (name, obj, status);
       }
-    break;
+      break;
     case BAD_NAME:
       nis_free_directory (dir);
       *status = NIS_BADNAME;
@@ -486,24 +538,26 @@ first_shoot (const_nis_name name, directory_obj *dir)
   directory_obj *obj = NULL;
   fd_result *fd_res;
   XDR xdrs;
-  char domain[strlen (name) + 3];
 
   if (nis_dir_cmp (name, dir->do_name) == SAME_NAME)
     return dir;
 
-  nis_domain_of_r (name, domain, sizeof (domain));
-
-  if (nis_dir_cmp (domain, dir->do_name) == SAME_NAME)
-    return dir;
-
-  fd_res = __nis_finddirectory (dir, domain);
+  fd_res = __nis_finddirectory (dir, name);
+  if (fd_res == NULL)
+    return NULL;
   if (fd_res->status == NIS_SUCCESS
       && (obj = calloc (1, sizeof (directory_obj))) != NULL)
     {
-      xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val,
-		    fd_res->dir_data.dir_data_len, XDR_DECODE);
+      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);
+
+      if (strcmp (dir->do_name, obj->do_name) != 0)
+	{
+	  nis_free_directory (obj);
+	  obj = NULL;
+	}
     }
 
   __free_fdresult (fd_res);
@@ -514,87 +568,271 @@ first_shoot (const_nis_name name, directory_obj *dir)
   return obj;
 }
 
+static struct nis_server_cache
+{
+  int search_parent;
+  int uses;
+  unsigned int size;
+  unsigned int server_used;
+  unsigned int current_ep;
+  time_t expires;
+  char name[];
+} *nis_server_cache[16];
+static time_t nis_cold_start_mtime;
+__libc_lock_define_initialized (static, nis_server_cache_lock)
+
+static directory_obj *
+nis_server_cache_search (const_nis_name name, int search_parent,
+			 unsigned int *server_used, unsigned int *current_ep,
+			 struct timeval *now)
+{
+  directory_obj *ret = NULL;
+  int i;
+  char *addr;
+  XDR xdrs;
+  struct stat64 st;
+
+  if (stat64 ("/var/nis/NIS_COLD_START", &st) < 0)
+    st.st_mtime = nis_cold_start_mtime + 1;
+
+  __libc_lock_lock (nis_server_cache_lock);
+
+  for (i = 0; i < 16; ++i)
+    if (nis_server_cache[i] == NULL)
+      continue;
+    else if (st.st_mtime != nis_cold_start_mtime
+	     || now->tv_sec > nis_server_cache[i]->expires)
+      {
+	free (nis_server_cache[i]);
+	nis_server_cache[i] = NULL;
+      }
+    else if (nis_server_cache[i]->search_parent == search_parent
+	     && strcmp (nis_server_cache[i]->name, name) == 0)
+      {
+	ret = calloc (1, sizeof (directory_obj));
+	if (ret == NULL)
+	  break;
+
+	addr = rawmemchr (nis_server_cache[i]->name, '\0') + 8;
+	addr = (char *) ((uintptr_t) addr & ~(uintptr_t) 7);
+	xdrmem_create (&xdrs, addr, nis_server_cache[i]->size, XDR_DECODE);
+	if (!_xdr_directory_obj (&xdrs, ret))
+	  {
+	    xdr_destroy (&xdrs);
+	    free (ret);
+	    ret = NULL;
+	    free (nis_server_cache[i]);
+	    nis_server_cache[i] = NULL;
+	    break;
+	  }
+	xdr_destroy (&xdrs);
+	*server_used = nis_server_cache[i]->server_used;
+	*current_ep = nis_server_cache[i]->current_ep;
+	break;
+      }
+
+  nis_cold_start_mtime = st.st_mtime;
+
+  __libc_lock_unlock (nis_server_cache_lock);
+  return ret;
+}
+
+static void
+nis_server_cache_add (const_nis_name name, int search_parent,
+		      directory_obj *dir, unsigned int server_used,
+		      unsigned int current_ep, struct timeval *now)
+{
+  struct nis_server_cache **loc;
+  struct nis_server_cache *new;
+  struct nis_server_cache *old;
+  int i;
+  char *addr;
+  unsigned int size;
+  XDR xdrs;
+
+  if (dir == NULL)
+    return;
+
+  size = xdr_sizeof ((xdrproc_t) _xdr_directory_obj, (char *) dir);
+  new = calloc (1, sizeof (*new) + strlen (name) + 8 + size);
+  if (new == NULL)
+    return;
+  new->search_parent = search_parent;
+  new->uses = 1;
+  new->expires = now->tv_sec + dir->do_ttl;
+  new->size = size;
+  new->server_used = server_used;
+  new->current_ep = current_ep;
+  addr = stpcpy (new->name, name) + 8;
+  addr = (char *) ((uintptr_t) addr & ~(uintptr_t) 7);
+
+  xdrmem_create(&xdrs, addr, size, XDR_ENCODE);
+  if (!_xdr_directory_obj (&xdrs, dir))
+    {
+      xdr_destroy (&xdrs);
+      free (new);
+      return;
+    }
+  xdr_destroy (&xdrs);
+
+  __libc_lock_lock (nis_server_cache_lock);
+
+  /* Choose which entry should be evicted from the cache.  */
+  loc = &nis_server_cache[0];
+  if (*loc != NULL)
+    for (i = 1; i < 16; ++i)
+      if (nis_server_cache[i] == NULL)
+	{
+	  loc = &nis_server_cache[i];
+	  break;
+	}
+      else if ((*loc)->uses > nis_server_cache[i]->uses
+	       || ((*loc)->uses == nis_server_cache[i]->uses
+		   && (*loc)->expires > nis_server_cache[i]->expires))
+	loc = &nis_server_cache[i];
+  old = *loc;
+  *loc = new;
+
+  __libc_lock_unlock (nis_server_cache_lock);
+  free (old);
+}
+
 nis_error
-__nisfind_server (const_nis_name name, directory_obj **dir)
+__nisfind_server (const_nis_name name, int search_parent,
+		  directory_obj **dir, dir_binding *dbp, unsigned int flags)
 {
+  nis_error result = NIS_SUCCESS;
+  nis_error status;
+  directory_obj *obj;
+  struct timeval now;
+  unsigned int server_used = ~0;
+  unsigned int current_ep = ~0;
+
   if (name == NULL)
     return NIS_BADNAME;
 
-#if 0
-  /* Search in local cache. In the moment, we ignore the fastest server */
-  if (!(flags & NO_CACHE))
-    dir = __nis_cache_search (name, flags, &cinfo);
-#endif
+  if (*dir != NULL)
+    return NIS_SUCCESS;
 
-  if (*dir == NULL)
-    {
-      nis_error status;
-      directory_obj *obj;
+  (void) gettimeofday (&now, NULL);
 
-      *dir = readColdStartFile ();
-      if (*dir == NULL) /* No /var/nis/NIS_COLD_START->no NIS+ installed */
-	return NIS_UNAVAIL;
+  if ((flags & NO_CACHE) == 0)
+    *dir = nis_server_cache_search (name, search_parent, &server_used,
+				    &current_ep, &now);
+  if (*dir != NULL)
+    {
+      unsigned int server_len = (*dir)->do_servers.do_servers_len;
+      if (flags & MASTER_ONLY)
+	{
+	  server_len = 1;
+	  if (server_used != 0)
+	    {
+	      server_used = ~0;
+	      current_ep = ~0;
+	    }
+	}
+      result = __nisbind_create (dbp, (*dir)->do_servers.do_servers_val,
+				 server_len, server_used, current_ep, flags);
+      if (result != NIS_SUCCESS)
+	{
+	  nis_free_directory (*dir);
+	  *dir = NULL;
+	}
+      return result;
+    }
 
-      /* Try at first, if servers in "dir" know our object */
-      obj = first_shoot (name, *dir);
+  *dir = readColdStartFile ();
+  if (*dir == NULL)
+    /* No /var/nis/NIS_COLD_START->no NIS+ installed.  */
+    return NIS_UNAVAIL;
+
+  /* Try at first, if servers in "dir" know our object */
+  const char *search_name = name;
+  if (search_parent)
+    search_name = __nis_domain_of (name);
+  obj = first_shoot (search_name, *dir);
+  if (obj == NULL)
+    {
+      obj = rec_dirsearch (search_name, *dir, &status);
       if (obj == NULL)
+	result = status;
+    }
+
+  if (result == NIS_SUCCESS)
+    {
+      unsigned int server_len = obj->do_servers.do_servers_len;
+      if (flags & MASTER_ONLY)
+	server_len = 1;
+      result = __nisbind_create (dbp, obj->do_servers.do_servers_val,
+				 server_len, ~0, ~0, flags);
+      if (result == NIS_SUCCESS)
 	{
-	  *dir = rec_dirsearch (name, *dir, &status);
-	  if (*dir == NULL)
-	    return status;
+	  if ((flags & MASTER_ONLY) == 0
+	      || obj->do_servers.do_servers_len == 1)
+	    {
+	      server_used = dbp->server_used;
+	      current_ep = dbp->current_ep;
+	    }
+	  if ((flags & NO_CACHE) == 0)
+	    nis_server_cache_add (name, search_parent, obj,
+				  server_used, current_ep, &now);
 	}
       else
-	*dir = obj;
+	{
+	  nis_free_directory (obj);
+	  obj = NULL;
+	}
     }
 
-  return NIS_SUCCESS;
+  *dir = obj;
+
+  return result;
 }
 
+
+nis_error
+__prepare_niscall (const_nis_name name, directory_obj **dirp,
+		   dir_binding *bptrp, unsigned int flags)
+{
+  nis_error retcode = __nisfind_server (name, 1, dirp, bptrp, flags);
+  if (__builtin_expect (retcode != NIS_SUCCESS, 0))
+    return retcode;
+
+  do
+    if (__nisbind_connect (bptrp) == NIS_SUCCESS)
+      return NIS_SUCCESS;
+  while (__nisbind_next (bptrp) == NIS_SUCCESS);
+
+  __nisbind_destroy (bptrp);
+  memset (bptrp, '\0', sizeof (*bptrp));
+
+  retcode = NIS_NAMEUNREACHABLE;
+  nis_free_directory (*dirp);
+  *dirp = NULL;
+
+  return retcode;
+}
+libnsl_hidden_def (__prepare_niscall)
+
+
 nis_error
 __do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs,
 	      caddr_t req, xdrproc_t xres, caddr_t resp, unsigned int flags,
 	      nis_cb *cb)
 {
-  nis_error retcode;
   dir_binding bptr;
   directory_obj *dir = NULL;
-  nis_server *server;
-  u_int server_len;
   int saved_errno = errno;
 
-  retcode = __nisfind_server (name, &dir);
-  if (retcode != NIS_SUCCESS)
-    return retcode;
-
-  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 = __nisbind_create (&bptr, server, server_len, flags);
+  nis_error retcode = __prepare_niscall (name, &dir, &bptr, flags);
   if (retcode == NIS_SUCCESS)
     {
-      while (__nisbind_connect (&bptr) != NIS_SUCCESS)
-	{
-	  if (__nisbind_next (&bptr) != NIS_SUCCESS)
-	    {
-	      nis_free_directory (dir);
-	      __nisbind_destroy (&bptr);
-	      return NIS_NAMEUNREACHABLE;
-	    }
-	}
       retcode = __do_niscall3 (&bptr, prog, xargs, req, xres, resp, flags, cb);
 
       __nisbind_destroy (&bptr);
-    }
 
-  nis_free_directory (dir);
+      nis_free_directory (dir);
+    }
 
   __set_errno (saved_errno);
 
diff --git a/nis/nis_callback.c b/nis/nis_callback.c
index b867b39ab7..e0acd9683a 100644
--- a/nis/nis_callback.c
+++ b/nis/nis_callback.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1997,1998,1999,2000,2005,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
 
@@ -197,22 +197,18 @@ internal_nis_do_callback (struct dir_binding *bptr, netobj *cookie,
 			  struct nis_cb *cb)
 {
   struct timeval TIMEOUT = {25, 0};
-  bool_t cb_is_running = FALSE;
+  bool_t cb_is_running;
 
   data = cb;
 
   for (;;)
     {
-      struct pollfd *my_pollfd;
+      struct pollfd my_pollfd[svc_max_pollfd];
       int i;
 
       if (svc_max_pollfd == 0 && svc_pollfd == NULL)
         return NIS_CBERROR;
 
-      my_pollfd = malloc (sizeof (struct pollfd) * svc_max_pollfd);
-      if (__builtin_expect (my_pollfd == NULL, 0))
-	return NIS_NOMEMORY;
-
       for (i = 0; i < svc_max_pollfd; ++i)
         {
           my_pollfd[i].fd = svc_pollfd[i].fd;
@@ -220,20 +216,17 @@ internal_nis_do_callback (struct dir_binding *bptr, netobj *cookie,
           my_pollfd[i].revents = 0;
         }
 
-      switch (i = __poll (my_pollfd, svc_max_pollfd, 25*1000))
+      switch (i = TEMP_FAILURE_RETRY (__poll (my_pollfd, svc_max_pollfd,
+					      25*1000)))
         {
 	case -1:
-	  free (my_pollfd);
-	  if (errno == EINTR)
-	    continue;
 	  return NIS_CBERROR;
 	case 0:
-	  free (my_pollfd);
 	  /* See if callback 'thread' in the server is still alive. */
-	  memset ((char *) &cb_is_running, 0, sizeof (cb_is_running));
+	  cb_is_running = FALSE;
 	  if (clnt_call (bptr->clnt, NIS_CALLBACK, (xdrproc_t) xdr_netobj,
 			 (caddr_t) cookie, (xdrproc_t) xdr_bool,
-			 (caddr_t) & cb_is_running, TIMEOUT) != RPC_SUCCESS)
+			 (caddr_t) &cb_is_running, TIMEOUT) != RPC_SUCCESS)
 	    cb_is_running = FALSE;
 
 	  if (cb_is_running == FALSE)
@@ -244,7 +237,6 @@ internal_nis_do_callback (struct dir_binding *bptr, netobj *cookie,
 	  break;
 	default:
 	  svc_getreq_poll (my_pollfd, i);
-	  free (my_pollfd);
 	  if (data->nomore)
 	    return data->result;
 	}
@@ -274,16 +266,15 @@ __nis_create_callback (int (*callback) (const_nis_name, const nis_object *,
   struct nis_cb *cb;
   int sock = RPC_ANYSOCK;
   struct sockaddr_in sin;
-  int len = sizeof (struct sockaddr_in);
-  char addr[NIS_MAXNAMELEN + 1];
+  socklen_t len = sizeof (struct sockaddr_in);
   unsigned short port;
+  int nomsg = 0;
 
-  cb = (struct nis_cb *) calloc (1, sizeof (struct nis_cb));
+  cb = (struct nis_cb *) calloc (1,
+				 sizeof (struct nis_cb) + sizeof (nis_server));
   if (__builtin_expect (cb == NULL, 0))
     goto failed;
-  cb->serv = (nis_server *) calloc (1, sizeof (nis_server));
-  if (__builtin_expect (cb->serv == NULL, 0))
-    goto failed;
+  cb->serv = (nis_server *) (cb + 1);
   cb->serv->name = strdup (nis_local_principal ());
   if (__builtin_expect (cb->serv->name == NULL, 0))
     goto failed;
@@ -326,15 +317,20 @@ __nis_create_callback (int (*callback) (const_nis_name, const nis_object *,
   cb->serv->ep.ep_val[0].proto = strdup ((flags & USE_DGRAM) ? "udp" : "tcp");
   if (__builtin_expect (cb->serv->ep.ep_val[0].proto == NULL, 0))
     goto failed;
-  cb->xprt = (flags & USE_DGRAM) ? svcudp_bufcreate (sock, 100, 8192) :
-				   svctcp_create (sock, 100, 8192);
+  cb->xprt = ((flags & USE_DGRAM)
+	      ? svcudp_bufcreate (sock, 100, 8192)
+	      : svctcp_create (sock, 100, 8192));
+  if (cb->xprt == NULL)
+    {
+      nomsg = 1;
+      goto failed;
+    }
   cb->sock = cb->xprt->xp_sock;
   if (!svc_register (cb->xprt, CB_PROG, CB_VERS, cb_prog_1, 0))
     {
       xprt_unregister (cb->xprt);
       svc_destroy (cb->xprt);
       xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
-      free (cb->serv);
       free (cb);
       syslog (LOG_ERR, "NIS+: failed to register callback dispatcher");
       return NULL;
@@ -345,30 +341,30 @@ __nis_create_callback (int (*callback) (const_nis_name, const nis_object *,
       xprt_unregister (cb->xprt);
       svc_destroy (cb->xprt);
       xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
-      free (cb->serv);
       free (cb);
       syslog (LOG_ERR, "NIS+: failed to read local socket info");
       return NULL;
     }
   port = ntohs (sin.sin_port);
   get_myaddress (&sin);
-  snprintf (addr, sizeof (addr), "%s.%d.%d", inet_ntoa (sin.sin_addr),
-	    (port & 0xFF00) >> 8, port & 0x00FF);
-  cb->serv->ep.ep_val[0].uaddr = strdup (addr);
+
+  if (asprintf (&cb->serv->ep.ep_val[0].uaddr, "%s.%d.%d",
+		inet_ntoa (sin.sin_addr), (port & 0xFF00) >> 8, port & 0x00FF)
+      < 0)
+    goto failed;
 
   return cb;
 
  failed:
   if (cb)
     {
-      if (cb->serv)
-	{
-	  xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
-	  free (cb->serv);
-	}
+      if (cb->xprt)
+	svc_destroy (cb->xprt);
+      xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
       free (cb);
     }
-  syslog (LOG_ERR, "NIS+: out of memory allocating callback");
+  if (!nomsg)
+    syslog (LOG_ERR, "NIS+: out of memory allocating callback");
   return NULL;
 }
 
@@ -379,7 +375,6 @@ __nis_destroy_callback (struct nis_cb *cb)
   svc_destroy (cb->xprt);
   close (cb->sock);
   xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
-  free (cb->serv);
   free (cb);
 
   return NIS_SUCCESS;
diff --git a/nis/nis_checkpoint.c b/nis/nis_checkpoint.c
index 0146d53054..23c4707b6f 100644
--- a/nis/nis_checkpoint.c
+++ b/nis/nis_checkpoint.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998, 1999 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 1998, 1999, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -24,7 +24,7 @@
 #include "nis_intern.h"
 
 nis_result *
-nis_checkpoint(const_nis_name dirname)
+nis_checkpoint (const_nis_name dirname)
 {
   nis_result *res;
 
@@ -48,7 +48,6 @@ nis_checkpoint(const_nis_name dirname)
       if (__type_of (NIS_RES_OBJECT (res2)) != NIS_DIRECTORY_OBJ)
 	{
 	  nis_freeresult (res2);
-	  nis_freeresult (res);
 	  NIS_RES_STATUS (res) = NIS_INVALIDOBJ;
 	  return res;
 	}
diff --git a/nis/nis_clone_dir.c b/nis/nis_clone_dir.c
index 0271db1790..f94a1eeb74 100644
--- a/nis/nis_clone_dir.c
+++ b/nis/nis_clone_dir.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 1998, 2005, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -26,18 +26,27 @@
 directory_obj *
 nis_clone_directory (const directory_obj *src, directory_obj *dest)
 {
-  unsigned char *addr;
+  char *addr;
   unsigned int size;
   XDR xdrs;
-  directory_obj *res;
 
   if (src == NULL)
-    return (NULL);
+    return NULL;
 
   size = xdr_sizeof ((xdrproc_t)_xdr_directory_obj, (char *)src);
   if ((addr = calloc(1, size)) == NULL)
     return NULL;
 
+  xdrmem_create(&xdrs, addr, size, XDR_ENCODE);
+  if (!_xdr_directory_obj (&xdrs, (directory_obj *)src))
+    {
+      xdr_destroy (&xdrs);
+      free (addr);
+      return NULL;
+    }
+  xdr_destroy (&xdrs);
+
+  directory_obj *res;
   if (dest == NULL)
     {
       if ((res = calloc (1, sizeof (directory_obj))) == NULL)
@@ -49,18 +58,12 @@ nis_clone_directory (const directory_obj *src, directory_obj *dest)
   else
     res = dest;
 
-  xdrmem_create(&xdrs, addr, size, XDR_ENCODE);
-  if (!_xdr_directory_obj (&xdrs, (directory_obj *)src))
-    {
-      xdr_destroy (&xdrs);
-      free (addr);
-      return NULL;
-    }
-  xdr_destroy (&xdrs);
   xdrmem_create (&xdrs, addr, size, XDR_DECODE);
   if (!_xdr_directory_obj (&xdrs, res))
     {
       xdr_destroy (&xdrs);
+      if (res != dest)
+	free (res);
       free (addr);
       return NULL;
     }
diff --git a/nis/nis_clone_obj.c b/nis/nis_clone_obj.c
index 0b163fe662..4d88200284 100644
--- a/nis/nis_clone_obj.c
+++ b/nis/nis_clone_obj.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 1998, 2004, 2005 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -26,8 +26,8 @@
 nis_object *
 nis_clone_object (const nis_object *src, nis_object *dest)
 {
-  unsigned char *addr;
-  unsigned long size;
+  char *addr;
+  unsigned int size;
   XDR xdrs;
   nis_object *res = NULL;
 
diff --git a/nis/nis_clone_res.c b/nis/nis_clone_res.c
index 135f397911..021f7cb4f4 100644
--- a/nis/nis_clone_res.c
+++ b/nis/nis_clone_res.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 1998, 2005, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -26,10 +26,9 @@
 nis_result *
 nis_clone_result (const nis_result *src, nis_result *dest)
 {
-  unsigned char *addr;
+  char *addr;
   unsigned int size;
   XDR xdrs;
-  nis_result *res;
 
   if (src == NULL)
     return (NULL);
@@ -38,6 +37,16 @@ nis_clone_result (const nis_result *src, nis_result *dest)
   if ((addr = calloc(1, size)) == NULL)
     return NULL;
 
+  xdrmem_create (&xdrs, addr, size, XDR_ENCODE);
+  if (!_xdr_nis_result (&xdrs, (nis_result *)src))
+    {
+      xdr_destroy (&xdrs);
+      free (addr);
+      return NULL;
+    }
+  xdr_destroy (&xdrs);
+
+  nis_result *res;
   if (dest == NULL)
     {
       if ((res = calloc (1, sizeof (nis_result))) == NULL)
@@ -49,18 +58,12 @@ nis_clone_result (const nis_result *src, nis_result *dest)
   else
     res = dest;
 
-  xdrmem_create(&xdrs, addr, size, XDR_ENCODE);
-  if (!_xdr_nis_result (&xdrs, (nis_result *)src))
-    {
-      xdr_destroy (&xdrs);
-      free (addr);
-      return NULL;
-    }
-  xdr_destroy (&xdrs);
-  xdrmem_create(&xdrs, addr, size, XDR_DECODE);
-  if (!_xdr_nis_result(&xdrs, res))
+  xdrmem_create (&xdrs, addr, size, XDR_DECODE);
+  if (!_xdr_nis_result (&xdrs, res))
     {
       xdr_destroy (&xdrs);
+      if (res != dest)
+	free (res);
       free (addr);
       return NULL;
     }
diff --git a/nis/nis_creategroup.c b/nis/nis_creategroup.c
index 3786461d64..0e9e13d5e5 100644
--- a/nis/nis_creategroup.c
+++ b/nis/nis_creategroup.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 1998, 1999, 2000, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
 
@@ -46,18 +46,24 @@ nis_creategroup (const_nis_name group, unsigned int flags)
       else
 	return NIS_BADNAME;
 
-      obj = malloc (sizeof (nis_object));
+      obj = calloc (1, sizeof (nis_object));
       if (__builtin_expect (obj == NULL, 0))
 	return NIS_NOMEMORY;
 
       obj->zo_oid.ctime = obj->zo_oid.mtime = time (NULL);
       obj->zo_name = strdup (leafbuf);
-      obj->zo_owner = strdup (__nis_default_owner (NULL));
-      obj->zo_group = strdup (__nis_default_group (NULL));
+      obj->zo_owner = __nis_default_owner (NULL);
+      obj->zo_group = __nis_default_group (NULL);
       obj->zo_domain = strdup (domainbuf);
       if (obj->zo_name == NULL || obj->zo_owner == NULL
 	  || obj->zo_group == NULL || obj->zo_domain == NULL)
-	return NIS_NOMEMORY;
+	{
+	  free (obj->zo_group);
+	  free (obj->zo_owner);
+	  free (obj->zo_name);
+	  free (obj);
+	  return NIS_NOMEMORY;
+	}
       obj->zo_access = __nis_default_access (NULL, 0);
       obj->zo_ttl = 60 * 60;
       obj->zo_data.zo_type = NIS_GROUP_OBJ;
@@ -66,11 +72,11 @@ nis_creategroup (const_nis_name group, unsigned int flags)
       obj->zo_data.objdata_u.gr_data.gr_members.gr_members_val = NULL;
 
       res = nis_add (buf, obj);
+      nis_free_object (obj);
       if (res == NULL)
 	return NIS_NOMEMORY;
       status = NIS_RES_STATUS (res);
       nis_freeresult (res);
-      nis_free_object (obj);
 
       return status;
     }
diff --git a/nis/nis_defaults.c b/nis/nis_defaults.c
index f13578635a..ed79b59ec6 100644
--- a/nis/nis_defaults.c
+++ b/nis/nis_defaults.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 1998, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -17,6 +17,7 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -30,45 +31,36 @@
 ** Some functions for parsing the -D param and NIS_DEFAULTS Environ
 */
 static nis_name
-searchgroup (char *str)
+searchXYX (char *str, const char *what)
 {
-  char *cptr;
-  int i;
+  assert (strlen (what) == 6);
+  assert (strncmp (str, what, 6) == 0);
+  str += 6;			/* Points to the begin of the parameters.  */
+
+  int i = 0;
+  while (str[i] != '\0' && str[i] != ':')
+    ++i;
+  if (i == 0)			/* only "<WHAT>=" ? */
+    return strdup ("");
 
-  cptr = strstr (str, "group=");
-  if (cptr == NULL)
-    return NULL;
+  return strndup (str, i);
+}
 
-  cptr += 6;			/* points to the begin of the group string */
-  i = 0;
-  while (cptr[i] != '\0' && cptr[i] != ':')
-    i++;
-  if (i == 0)			/* only "group=" ? */
-    return (nis_name) "";
 
-  return strndup (cptr, i);
+static nis_name
+searchgroup (char *str)
+{
+  return searchXYX (str, "group=");
 }
 
+
 static nis_name
 searchowner (char *str)
 {
-  char *cptr;
-  int i;
-
-  cptr = strstr (str, "owner=");
-  if (cptr == NULL)
-    return NULL;
-
-  cptr += 6;			/* points to the begin of the owner string */
-  i = 0;
-  while (cptr[i] != '\0' && cptr[i] != ':')
-    i++;
-  if (i == 0)			/* only "owner=" ? */
-    return strdup ("");
-
-  return strndup (cptr, i);
+  return searchXYX (str, "owner=");
 }
 
+
 static uint32_t
 searchttl (char *str)
 {
@@ -358,86 +350,61 @@ searchaccess (char *str, unsigned int access)
   return result;
 }
 
+
 nis_name
 __nis_default_owner (char *defaults)
 {
-  char default_owner[NIS_MAXNAMELEN + 1];
-  char *cptr, *dptr;
+  char *default_owner = NULL;
 
-  strcpy (default_owner, nis_local_principal ());
+  char *cptr = defaults;
+  if (cptr == NULL)
+    cptr = getenv ("NIS_DEFAULTS");
 
-  if (defaults != NULL)
+  if (cptr != NULL)
     {
-      dptr = strstr (defaults, "owner=");
+      char *dptr = strstr (cptr, "owner=");
       if (dptr != NULL)
 	{
-	  char *p = searchowner (defaults);
-	  if (strlen (p) <= NIS_MAXNAMELEN)
-	    strcpy (default_owner, p);
+	  char *p = searchowner (dptr);
+	  if (p == NULL)
+	    return NULL;
+	  default_owner = strdupa (p);
 	  free (p);
 	}
     }
-  else
-    {
-      cptr = getenv ("NIS_DEFAULTS");
-      if (cptr != NULL)
-	{
-	  dptr = strstr (cptr, "owner=");
-	  if (dptr != NULL)
-	    {
-	      char *p = searchowner (cptr);
-	      if (strlen (p) <= NIS_MAXNAMELEN)
-		strcpy (default_owner, p);
-	      free (p);
-	    }
-	}
-    }
 
-  return strdup (default_owner);
+  return strdup (default_owner ?: nis_local_principal ());
 }
 libnsl_hidden_def (__nis_default_owner)
 
+
 nis_name
 __nis_default_group (char *defaults)
 {
-  char default_group[NIS_MAXNAMELEN + 1];
-  char *cptr, *dptr;
+  char *default_group = NULL;
 
-  strcpy (default_group, nis_local_group ());
+  char *cptr = defaults;
+  if (cptr == NULL)
+    cptr = getenv ("NIS_DEFAULTS");
 
-  if (defaults != NULL)
+  if (cptr != NULL)
     {
-      dptr = strstr (defaults, "group=");
+      char *dptr = strstr (cptr, "group=");
       if (dptr != NULL)
 	{
-	  char *p = searchgroup (defaults);
-
-	  if (strlen (p) <= NIS_MAXNAMELEN)
-	    strcpy (default_group, p);
+	  char *p = searchgroup (dptr);
+	  if (p == NULL)
+	    return NULL;
+	  default_group = strdupa (p);
 	  free (p);
 	}
     }
-  else
-    {
-      cptr = getenv ("NIS_DEFAULTS");
-      if (cptr != NULL)
-	{
-	  dptr = strstr (cptr, "group=");
-	  if (dptr != NULL)
-	    {
-	      char *p = searchgroup (cptr);
-
-	      if (strlen (p) <= NIS_MAXNAMELEN)
-		strcpy (default_group, p);
-	      free (p);
-	    }
-	}
-    }
 
-  return strdup (default_group);
+  return strdup (default_group ?: nis_local_group ());
 }
 libnsl_hidden_def (__nis_default_group)
 
+
 uint32_t
 __nis_default_ttl (char *defaults)
 {
@@ -480,7 +447,7 @@ __nis_default_access (char *param, unsigned int defaults)
     {
       cptr = getenv ("NIS_DEFAULTS");
       if (cptr != NULL && strstr (cptr, "access=") != NULL)
-	result = searchaccess (getenv ("NIS_DEFAULTS"), result);
+	result = searchaccess (cptr, result);
     }
 
   return result;
diff --git a/nis/nis_domain_of.c b/nis/nis_domain_of.c
index eca2066aa3..4d6b48640e 100644
--- a/nis/nis_domain_of.c
+++ b/nis/nis_domain_of.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -26,3 +26,17 @@ nis_domain_of (const_nis_name name)
 
   return nis_domain_of_r (name, result, NIS_MAXNAMELEN);
 }
+
+const_nis_name
+__nis_domain_of (const_nis_name name)
+{
+  const_nis_name cptr = strchr (name, '.');
+
+  if (cptr++ == NULL)
+    return "";
+
+  if (*cptr == '\0')
+    return ".";
+
+  return cptr;
+}
diff --git a/nis/nis_domain_of_r.c b/nis/nis_domain_of_r.c
index 1fedcfe074..e2db146038 100644
--- a/nis/nis_domain_of_r.c
+++ b/nis/nis_domain_of_r.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -29,6 +29,7 @@ nis_domain_of_r (const_nis_name name, char *buffer, size_t buflen)
 
   if (buffer == NULL)
     {
+    erange:
       __set_errno (ERANGE);
       return NULL;
     }
@@ -44,7 +45,11 @@ nis_domain_of_r (const_nis_name name, char *buffer, size_t buflen)
   cptr_len = strlen (cptr);
 
   if (cptr_len == 0)
-    return strcpy (buffer, ".");
+    {
+      if (buflen < 2)
+	goto erange;
+      return strcpy (buffer, ".");
+    }
 
   if (__builtin_expect (cptr_len >= buflen, 0))
     {
diff --git a/nis/nis_error.c b/nis/nis_error.c
index 147f88ce15..d92ad03604 100644
--- a/nis/nis_error.c
+++ b/nis/nis_error.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998, 1999, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1997,1998,1999,2004,2005,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -24,65 +24,41 @@
 #include <rpcsvc/nis.h>
 
 
-static const char *nis_errlist[] =
+#define MF(line) MF1 (line)
+#define MF1(line) str##line
+static const union msgstr_t
 {
-  N_("Success"),
-  N_("Probable success"),
-  N_("Not found"),
-  N_("Probably not found"),
-  N_("Cache expired"),
-  N_("NIS+ servers unreachable"),
-  N_("Unknown object"),
-  N_("Server busy, try again"),
-  N_("Generic system error"),
-  N_("First/next chain broken"),
-  N_("Permission denied"),
-  N_("Not owner"),
-  N_("Name not served by this server"),
-  N_("Server out of memory"),
-  N_("Object with same name exists"),
-  N_("Not master server for this domain"),
-  N_("Invalid object for operation"),
-  N_("Malformed name, or illegal name"),
-  N_("Unable to create callback"),
-  N_("Results sent to callback proc"),
-  N_("Not found, no such name"),
-  N_("Name/entry isn't unique"),
-  N_("Modification failed"),
-  N_("Database for table does not exist"),
-  N_("Entry/table type mismatch"),
-  N_("Link points to illegal name"),
-  N_("Partial success"),
-  N_("Too many attributes"),
-  N_("Error in RPC subsystem"),
-  N_("Missing or malformed attribute"),
-  N_("Named object is not searchable"),
-  N_("Error while talking to callback proc"),
-  N_("Non NIS+ namespace encountered"),
-  N_("Illegal object type for operation"),
-  N_("Passed object is not the same object on server"),
-  N_("Modify operation failed"),
-  N_("Query illegal for named table"),
-  N_("Attempt to remove a non-empty table"),
-  N_("Error in accessing NIS+ cold start file.  Is NIS+ installed?"),
-  N_("Full resync required for directory"),
-  N_("NIS+ operation failed"),
-  N_("NIS+ service is unavailable or not installed"),
-  N_("Yes, 42 is the meaning of life"),
-  N_("Unable to authenticate NIS+ server"),
-  N_("Unable to authenticate NIS+ client"),
-  N_("No file space on server"),
-  N_("Unable to create process on server"),
-  N_("Master server busy, full dump rescheduled.")
-};
+  struct
+  {
+#define S(s) char MF(__LINE__)[sizeof (s)];
+#include "nis_error.h"
+#undef S
+  };
+  char str[0];
+} msgstr =
+  {
+    {
+#define S(s) s,
+#include "nis_error.h"
+#undef S
+    }
+  };
+
+static const unsigned short int msgidx[] =
+  {
+#define S(s) offsetof (union msgstr_t, MF (__LINE__)),
+#include "nis_error.h"
+#undef S
+  };
+
 
 const char *
 nis_sperrno (const nis_error status)
 {
-  if (status >= (sizeof (nis_errlist) / sizeof (nis_errlist[0])))
+  if (status >= sizeof (msgidx) / sizeof (msgidx[0]))
     return "???";
   else
-    return gettext (nis_errlist[status]);
+    return gettext (msgstr.str + msgidx[status]);
 }
 libnsl_hidden_def (nis_sperrno)
 
@@ -102,26 +78,21 @@ char *
 nis_sperror_r (const nis_error status, const char *label,
 	       char *buffer, size_t buflen)
 {
-  const char *cptr;
-
-  cptr = nis_sperrno (status);
-
-  if ((strlen (cptr) + strlen (label) + 3) > buflen)
+  if (snprintf (buffer, buflen, "%s: %s", label, nis_sperrno (status))
+      >= buflen)
     {
-      errno = ERANGE;
+      __set_errno (ERANGE);
       return NULL;
     }
 
-    sprintf (buffer, "%s: %s", label, cptr);
-
-    return buffer;
+  return buffer;
 }
 libnsl_hidden_def (nis_sperror_r)
 
 char *
 nis_sperror (const nis_error status, const char *label)
 {
-  static char buffer[NIS_MAXNAMELEN +1];
+  static char buffer[NIS_MAXNAMELEN + 1];
 
   return nis_sperror_r (status, label, buffer, sizeof (buffer));
 }
diff --git a/nis/nis_error.h b/nis/nis_error.h
new file mode 100644
index 0000000000..add1316d9f
--- /dev/null
+++ b/nis/nis_error.h
@@ -0,0 +1,48 @@
+S(N_("Success"))
+S(N_("Probable success"))
+S(N_("Not found"))
+S(N_("Probably not found"))
+S(N_("Cache expired"))
+S(N_("NIS+ servers unreachable"))
+S(N_("Unknown object"))
+S(N_("Server busy, try again"))
+S(N_("Generic system error"))
+S(N_("First/next chain broken"))
+S(N_("Permission denied"))
+S(N_("Not owner"))
+S(N_("Name not served by this server"))
+S(N_("Server out of memory"))
+S(N_("Object with same name exists"))
+S(N_("Not master server for this domain"))
+S(N_("Invalid object for operation"))
+S(N_("Malformed name, or illegal name"))
+S(N_("Unable to create callback"))
+S(N_("Results sent to callback proc"))
+S(N_("Not found, no such name"))
+S(N_("Name/entry isn't unique"))
+S(N_("Modification failed"))
+S(N_("Database for table does not exist"))
+S(N_("Entry/table type mismatch"))
+S(N_("Link points to illegal name"))
+S(N_("Partial success"))
+S(N_("Too many attributes"))
+S(N_("Error in RPC subsystem"))
+S(N_("Missing or malformed attribute"))
+S(N_("Named object is not searchable"))
+S(N_("Error while talking to callback proc"))
+S(N_("Non NIS+ namespace encountered"))
+S(N_("Illegal object type for operation"))
+S(N_("Passed object is not the same object on server"))
+S(N_("Modify operation failed"))
+S(N_("Query illegal for named table"))
+S(N_("Attempt to remove a non-empty table"))
+S(N_("Error in accessing NIS+ cold start file.  Is NIS+ installed?"))
+S(N_("Full resync required for directory"))
+S(N_("NIS+ operation failed"))
+S(N_("NIS+ service is unavailable or not installed"))
+S(N_("Yes, 42 is the meaning of life"))
+S(N_("Unable to authenticate NIS+ server"))
+S(N_("Unable to authenticate NIS+ client"))
+S(N_("No file space on server"))
+S(N_("Unable to create process on server"))
+S(N_("Master server busy, full dump rescheduled."))
diff --git a/nis/nis_file.c b/nis/nis_file.c
index 1f2295787c..566f30c48c 100644
--- a/nis/nis_file.c
+++ b/nis/nis_file.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998, 1999, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 1998, 1999, 2004, 2005 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
 
@@ -23,27 +23,30 @@
 #include <rpcsvc/nis.h>
 #include "nis_xdr.h"
 
-static const char cold_start_file[] = "/var/nis/NIS_COLD_START";
+typedef bool_t (*iofct_t) (XDR *, void *);
+typedef void (*freefct_t) (void *);
 
-directory_obj *
-readColdStartFile (void)
+
+static void *
+read_nis_obj (const char *name, iofct_t readfct, freefct_t freefct,
+	      size_t objsize)
 {
-  FILE *in = fopen (cold_start_file, "rc");
+  FILE *in = fopen (name, "rc");
   if (in == NULL)
     return NULL;
 
-  directory_obj *obj = calloc (1, sizeof (directory_obj));
+  void *obj = calloc (1, objsize);
 
   if (obj != NULL)
     {
       XDR xdrs;
       xdrstdio_create (&xdrs, in, XDR_DECODE);
-      bool_t status = _xdr_directory_obj (&xdrs, obj);
+      bool_t status = readfct (&xdrs, obj);
       xdr_destroy (&xdrs);
 
       if (!status)
 	{
-	  nis_free_directory (obj);
+	  freefct (obj);
 	  obj = NULL;
 	}
     }
@@ -52,75 +55,49 @@ readColdStartFile (void)
 
   return obj;
 }
-libnsl_hidden_def (readColdStartFile)
 
-bool_t
-writeColdStartFile (const directory_obj *obj)
+static bool_t
+write_nis_obj (const char *name, const void *obj, iofct_t writefct)
 {
-  XDR xdrs;
-  FILE *out;
-  bool_t status;
-
-  out = fopen (cold_start_file, "wb");
+  FILE *out = fopen (name, "w");
   if (out == NULL)
     return FALSE;
 
+  XDR xdrs;
   xdrstdio_create (&xdrs, out, XDR_ENCODE);
-  status = _xdr_directory_obj (&xdrs, (directory_obj *) obj);
+  bool_t status = writefct (&xdrs, (void *) obj);
   xdr_destroy (&xdrs);
   fclose (out);
 
   return status;
 }
 
-nis_object *
-nis_read_obj (const char *name)
-{
-  XDR xdrs;
-  FILE *in;
-  bool_t status;
-  nis_object *obj;
 
-  in = fopen (name, "rb");
-  if (in == NULL)
-    return NULL;
+static const char cold_start_file[] = "/var/nis/NIS_COLD_START";
 
-  obj = calloc (1, sizeof (nis_object));
-  if (obj == NULL)
-    {
-      fclose (in);
-      return NULL;
-    }
+directory_obj *
+readColdStartFile (void)
+{
+  return read_nis_obj (cold_start_file, (iofct_t) _xdr_directory_obj,
+		       (freefct_t) nis_free_directory, sizeof (directory_obj));
+}
+libnsl_hidden_def (readColdStartFile)
 
-  xdrstdio_create (&xdrs, in, XDR_DECODE);
-  status =_xdr_nis_object (&xdrs, obj);
-  xdr_destroy (&xdrs);
-  fclose (in);
+bool_t
+writeColdStartFile (const directory_obj *obj)
+{
+  return write_nis_obj (cold_start_file, obj, (iofct_t) _xdr_directory_obj);
+}
 
-  if (status)
-    return obj;
-  else
-    {
-      nis_free_object (obj);
-      return NULL;
-    }
+nis_object *
+nis_read_obj (const char *name)
+{
+  return read_nis_obj (name, (iofct_t) _xdr_nis_object,
+		       (freefct_t) nis_free_object, sizeof (nis_object));
 }
 
 bool_t
 nis_write_obj (const char *name, const nis_object *obj)
 {
-  XDR xdrs;
-  FILE *out;
-  bool_t status;
-
-  out = fopen (name, "wb");
-  if (out == NULL)
-    return FALSE;
-
-  xdrstdio_create (&xdrs, out, XDR_ENCODE);
-  status = _xdr_nis_object (&xdrs, (nis_object *) obj);
-  xdr_destroy (&xdrs);
-  fclose (out);
-
-  return status;
+  return write_nis_obj (name, obj, (iofct_t) _xdr_nis_object);
 }
diff --git a/nis/nis_getservlist.c b/nis/nis_getservlist.c
index 315960c8e8..e57649d526 100644
--- a/nis/nis_getservlist.c
+++ b/nis/nis_getservlist.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 1998, 1999, 2000, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -40,7 +40,10 @@ nis_getservlist (const_nis_name dir)
 	malloc (sizeof (nis_server *) *
 		(NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_len + 1));
       if (__builtin_expect (serv == NULL, 0))
-	return NULL;
+	{
+	  nis_freeresult (res);
+	  return NULL;
+	}
 
       for (i = 0; i < NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_len;
 	   ++i)
@@ -49,13 +52,41 @@ nis_getservlist (const_nis_name dir)
 	    &NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_val[i];
 	  serv[i] = calloc (1, sizeof (nis_server));
 	  if (__builtin_expect (serv[i] == NULL, 0))
-	    return NULL;
+	    {
+	    free_all:
+	      while (i-- > 0)
+		{
+		  free (serv[i]->pkey.n_bytes);
+		  if (serv[i]->ep.ep_val != NULL)
+		    {
+		      unsigned long int j;
+		      for (j = 0; j < serv[i]->ep.ep_len; ++j)
+			{
+			  free (serv[i]->ep.ep_val[j].proto);
+			  free (serv[i]->ep.ep_val[j].family);
+			  free (serv[i]->ep.ep_val[j].uaddr);
+			}
+		      free (serv[i]->ep.ep_val);
+		    }
+		  free (serv[i]->name);
+		  free (serv[i]);
+		}
+
+	      free (serv);
+
+	      nis_freeresult (res);
+
+	      return NULL;
+	    }
 
 	  if (server->name != NULL)
 	    {
 	      serv[i]->name = strdup (server->name);
 	      if (__builtin_expect (serv[i]->name == NULL, 0))
-		return NULL;
+		{
+		  ++i;
+		  goto free_all;
+		}
 	    }
 
           serv[i]->ep.ep_len = server->ep.ep_len;
@@ -66,7 +97,10 @@ nis_getservlist (const_nis_name dir)
               serv[i]->ep.ep_val =
 		malloc (server->ep.ep_len * sizeof (endpoint));
 	      if (__builtin_expect (serv[i]->ep.ep_val == NULL, 0))
-		return NULL;
+		{
+		  ++i;
+		  goto free_all;
+		}
 
               for (j = 0; j < serv[i]->ep.ep_len; ++j)
                 {
@@ -87,20 +121,20 @@ nis_getservlist (const_nis_name dir)
 		    serv[i]->ep.ep_val[j].proto = NULL;
                 }
             }
-          else
-	    serv[i]->ep.ep_val = NULL;
+
           serv[i]->key_type = server->key_type;
           serv[i]->pkey.n_len = server->pkey.n_len;
           if (server->pkey.n_len > 0)
             {
               serv[i]->pkey.n_bytes = malloc (server->pkey.n_len);
               if (__builtin_expect (serv[i]->pkey.n_bytes == NULL, 0))
-                return NULL;
+		{
+		  ++i;
+		  goto free_all;
+		}
               memcpy (serv[i]->pkey.n_bytes, server->pkey.n_bytes,
                       server->pkey.n_len);
             }
-          else
-            serv[i]->pkey.n_bytes = NULL;
         }
       serv[i] = NULL;
     }
@@ -111,8 +145,7 @@ nis_getservlist (const_nis_name dir)
 	serv[0] = NULL;
     }
 
-  if (res != NULL)
-    nis_freeresult (res);
+  nis_freeresult (res);
 
   return serv;
 }
diff --git a/nis/nis_intern.h b/nis/nis_intern.h
index 29a80a9188..c805920aec 100644
--- a/nis/nis_intern.h
+++ b/nis/nis_intern.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+/* Copyright (c) 1997,1998,1999,2000,2001,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
 
@@ -66,6 +66,7 @@ extern nis_error __do_niscall3 (dir_binding *dbp, u_long prog,
 				xdrproc_t xargs, caddr_t req,
 				xdrproc_t xres, caddr_t resp,
 				unsigned int flags, nis_cb *cb);
+libnsl_hidden_proto (__do_niscall3)
 
 extern u_short __pmap_getnisport (struct sockaddr_in *address, u_long program,
 				  u_long version, u_int protocol);
diff --git a/nis/nis_ismember.c b/nis/nis_ismember.c
index f3f9bc9540..178b4890ef 100644
--- a/nis/nis_ismember.c
+++ b/nis/nis_ismember.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998, 1999 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 1998, 1999, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
 
@@ -47,8 +47,7 @@ internal_ismember (const_nis_name principal, const_nis_name group)
   res = nis_lookup (buf, EXPAND_NAME|FOLLOW_LINKS);
   if (res == NULL || NIS_RES_STATUS (res) != NIS_SUCCESS)
     {
-      if (res)
-	nis_freeresult (res);
+      nis_freeresult (res);
       return 0;
     }
 
diff --git a/nis/nis_local_names.c b/nis/nis_local_names.c
index 30fd208b75..e9aea12a86 100644
--- a/nis/nis_local_names.c
+++ b/nis/nis_local_names.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 1998, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -63,7 +63,7 @@ nis_local_directory (void)
 	__nisdomainname[0] = '\0';
       else
 	{
-	  char *cp = strchr (__nisdomainname, '\0');
+	  char *cp = rawmemchr (__nisdomainname, '\0');
 
 	  /* Missing trailing dot? */
 	  if (cp[-1] != '.')
@@ -154,7 +154,7 @@ nis_local_host (void)
 	__nishostname[0] = '\0';
       else
 	{
-	  char *cp = strchr (__nishostname, '\0');
+	  char *cp = rawmemchr (__nishostname, '\0');
 	  int len = cp - __nishostname;
 
 	  /* Hostname already fully qualified? */
diff --git a/nis/nis_lookup.c b/nis/nis_lookup.c
index 0b97e67a61..9677b4d3d1 100644
--- a/nis/nis_lookup.c
+++ b/nis/nis_lookup.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1997, 1998, 1999, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1997-1999, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1997.
 
@@ -21,6 +22,8 @@
 #include <rpcsvc/nis.h>
 #include "nis_xdr.h"
 #include "nis_intern.h"
+#include <libnsl.h>
+
 
 nis_result *
 nis_lookup (const_nis_name name, const unsigned int flags)
@@ -61,36 +64,16 @@ nis_lookup (const_nis_name name, const unsigned int flags)
       req.ns_object.ns_object_len = 0;
       req.ns_object.ns_object_val = NULL;
 
-      status = __nisfind_server (req.ns_name, &dir);
-      if (status != NIS_SUCCESS)
+      status = __prepare_niscall (req.ns_name, &dir, &bptr, flags);
+      if (__builtin_expect (status != NIS_SUCCESS, 0))
 	{
 	  NIS_RES_STATUS (res) = status;
-	  return res;
-	}
-
-      status = __nisbind_create (&bptr, dir->do_servers.do_servers_val,
-				 dir->do_servers.do_servers_len, flags);
-      if (status != NIS_SUCCESS)
-	{
-	  NIS_RES_STATUS (res) = status;
-	  nis_free_directory (dir);
-	  return res;
-	}
-
-      while (__nisbind_connect (&bptr) != NIS_SUCCESS)
-	{
-	  if (__nisbind_next (&bptr) != NIS_SUCCESS)
-	    {
-	      __nisbind_destroy (&bptr);
-	      nis_free_directory (dir);
-	      NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
-	      return res;
-	    }
+	  goto out;
 	}
 
       do
 	{
-	  static struct timeval RPCTIMEOUT = {10, 0};
+	  static const struct timeval RPCTIMEOUT = {10, 0};
 	  enum clnt_stat result;
 
 	again:
@@ -107,11 +90,9 @@ nis_lookup (const_nis_name name, const unsigned int flags)
 
 	      if (NIS_RES_STATUS (res) == NIS_SUCCESS)
 		{
-		    if (__type_of(NIS_RES_OBJECT (res)) == NIS_LINK_OBJ &&
-			flags & FOLLOW_LINKS) /* We are following links */
+		    if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ
+			&& (flags & FOLLOW_LINKS)) /* We are following links */
 		      {
-			if (count_links)
-			  free (req.ns_name);
 			/* if we hit the link limit, bail */
 			if (count_links > NIS_MAXLINKS)
 			  {
@@ -120,55 +101,68 @@ nis_lookup (const_nis_name name, const unsigned int flags)
 			  }
 			++count_links;
 			req.ns_name =
-			  strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
-			if (req.ns_name == NULL)
-			  return NULL;
+			  strdupa (NIS_RES_OBJECT (res)->LI_data.li_name);
 
-			nis_freeresult (res);
-			res = calloc (1, sizeof (nis_result));
-			if (res == NULL)
-			  {
-			    __nisbind_destroy (&bptr);
-			    return NULL;
-			  }
+			/* The following is a non-obvious optimization.  A
+			   nis_freeresult call would call xdr_free as the
+			   following code.  But it also would unnecessarily
+			   free the result structure.  We avoid this here
+			   along with the necessary tests.  */
+			xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
+			memset (res, '\0', sizeof (*res));
 
 			link_first_try = 1; /* Try at first the old binding */
 			goto again;
 		      }
 		}
 	      else
-		if ((NIS_RES_STATUS (res) == NIS_SYSTEMERROR) ||
-		    (NIS_RES_STATUS (res) == NIS_NOSUCHNAME) ||
-		    (NIS_RES_STATUS (res) == NIS_NOT_ME))
+		if (NIS_RES_STATUS (res) == NIS_SYSTEMERROR
+		    || NIS_RES_STATUS (res) == NIS_NOSUCHNAME
+		    || NIS_RES_STATUS (res) == NIS_NOT_ME)
 		  {
 		    if (link_first_try)
 		      {
 			__nisbind_destroy (&bptr);
 			nis_free_directory (dir);
+			/* Otherwise __nisfind_server will not do anything.  */
+			dir = NULL;
 
-			if (__nisfind_server (req.ns_name, &dir) != NIS_SUCCESS)
-			  return res;
-
-			if (__nisbind_create (&bptr,
-					      dir->do_servers.do_servers_val,
-					      dir->do_servers.do_servers_len,
-					      flags) != NIS_SUCCESS)
-			  {
-			    nis_free_directory (dir);
-			    return res;
-			  }
+			if (__nisfind_server (req.ns_name, 1, &dir, &bptr,
+					      flags & ~MASTER_ONLY)
+			    != NIS_SUCCESS)
+			  goto out;
 		      }
 		    else
 		      if (__nisbind_next (&bptr) != NIS_SUCCESS)
-			break; /* No more servers to search */
+			{
+			  /* No more servers to search.  Try parent.  */
+			  const char *ndomain = __nis_domain_of (req.ns_name);
+			  req.ns_name = strdupa (ndomain);
+			  if (strcmp (req.ns_name, ".") == 0)
+			    {
+			      NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
+			      goto out;
+			    }
+
+			  __nisbind_destroy (&bptr);
+			  nis_free_directory (dir);
+			  dir = NULL;
+			  status = __prepare_niscall (req.ns_name, &dir,
+						      &bptr, flags);
+			  if (__builtin_expect (status != NIS_SUCCESS, 0))
+			    {
+			      NIS_RES_STATUS (res) = status;
+			      goto out;
+			    }
+			  goto again;
+			}
 
 		    while (__nisbind_connect (&bptr) != NIS_SUCCESS)
 		      {
 			if (__nisbind_next (&bptr) != NIS_SUCCESS)
 			  {
-			    __nisbind_destroy (&bptr);
 			    nis_free_directory (dir);
-			    return res;
+			    goto out;
 			  }
 		      }
 		    goto again;
@@ -185,7 +179,7 @@ nis_lookup (const_nis_name name, const unsigned int flags)
       if (status != NIS_SUCCESS)
 	{
 	  NIS_RES_STATUS (res) = status;
-	  return res;
+	  goto out;
 	}
 
       switch (NIS_RES_STATUS (res))
@@ -217,6 +211,7 @@ nis_lookup (const_nis_name name, const unsigned int flags)
 	}
     }
 
+ out:
   if (names != namebuf)
     nis_freenames (names);
 
diff --git a/nis/nis_ping.c b/nis/nis_ping.c
index d9924f9279..81afc5e8e3 100644
--- a/nis/nis_ping.c
+++ b/nis/nis_ping.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998, 1999 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 1998, 1999, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
 
@@ -39,8 +39,7 @@ nis_ping (const_nis_name dirname, unsigned int utime,
       res = nis_lookup (dirname, MASTER_ONLY);
       if (res == NULL || NIS_RES_STATUS (res) != NIS_SUCCESS)
 	{
-	  if (res)
-	    nis_freeresult (res);
+	  nis_freeresult (res);
 	  return;
 	}
       obj = res->objects.objects_val;
@@ -51,8 +50,7 @@ nis_ping (const_nis_name dirname, unsigned int utime,
   /* Check if obj is really a diryectory object */
   if (__type_of (obj) != NIS_DIRECTORY_OBJ)
     {
-      if (res != NULL)
-	nis_freeresult (res);
+      nis_freeresult (res);
       return;
     }
 
@@ -68,6 +66,5 @@ nis_ping (const_nis_name dirname, unsigned int utime,
 		   NIS_PING, (xdrproc_t) _xdr_ping_args,
 		   (caddr_t) &args, (xdrproc_t) xdr_void,
 		   (caddr_t) NULL, 0, NULL);
-  if (res)
-    nis_freeresult (res);
+  nis_freeresult (res);
 }
diff --git a/nis/nis_print_group_entry.c b/nis/nis_print_group_entry.c
index 6f0ba8fbd4..91e6399b90 100644
--- a/nis/nis_print_group_entry.c
+++ b/nis/nis_print_group_entry.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998, 2000, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -45,12 +45,16 @@ nis_print_group_entry (const_nis_name group)
 	}
       res = nis_lookup (buf, FOLLOW_LINKS | EXPAND_NAME);
 
-      if (NIS_RES_STATUS(res) != NIS_SUCCESS)
+      if (res == NULL)
 	return;
 
-      if ((NIS_RES_NUMOBJ (res) != 1) ||
-	  (__type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ))
-	return;
+      if (NIS_RES_STATUS (res) != NIS_SUCCESS
+	  || NIS_RES_NUMOBJ (res) != 1
+	  || __type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ)
+	{
+	  nis_freeresult (res);
+	  return;
+	}
 
       char *mem_exp[NIS_RES_NUMOBJ (res)];
       char *mem_imp[NIS_RES_NUMOBJ (res)];
diff --git a/nis/nis_removemember.c b/nis/nis_removemember.c
index b9e27ab48c..2e45b4fb79 100644
--- a/nis/nis_removemember.c
+++ b/nis/nis_removemember.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998, 1999, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1997,1998,1999,2004,2005,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -28,15 +28,12 @@ nis_removemember (const_nis_name member, const_nis_name group)
     {
       size_t grouplen = strlen (group);
       char buf[grouplen + 14 + NIS_MAXNAMELEN];
-      char leafbuf[grouplen + 2];
       char domainbuf[grouplen + 2];
-      nis_name *newmem;
       nis_result *res, *res2;
       nis_error status;
       char *cp, *cp2;
-      unsigned long int i, j, k;
 
-      cp = stpcpy (buf, nis_leaf_of_r (group, leafbuf, sizeof (leafbuf) - 1));
+      cp = rawmemchr (nis_leaf_of_r (group, buf, sizeof (buf) - 1), '\0');
       cp = stpcpy (cp, ".groups_dir");
       cp2 = nis_domain_of_r (group, domainbuf, sizeof (domainbuf) - 1);
       if (cp2 != NULL && cp2[0] != '\0')
@@ -44,60 +41,41 @@ nis_removemember (const_nis_name member, const_nis_name group)
           cp = stpcpy (cp, ".");
           stpcpy (cp, cp2);
         }
-      res = nis_lookup (buf, FOLLOW_LINKS|EXPAND_NAME);
-      if (res == NULL || NIS_RES_STATUS (res) != NIS_SUCCESS)
+      res = nis_lookup (buf, FOLLOW_LINKS | EXPAND_NAME);
+      if (res == NULL)
+	return NIS_NOMEMORY;
+      if (NIS_RES_STATUS (res) != NIS_SUCCESS)
         {
-	  if (res)
-	    {
-	      status = NIS_RES_STATUS (res);
-	      nis_freeresult (res);
-	    }
-	  else
-	    return NIS_NOMEMORY;
+	  status = NIS_RES_STATUS (res);
+	  nis_freeresult (res);
           return status;
         }
 
-      if ((res->objects.objects_len != 1) ||
-          (__type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ))
+      if (NIS_RES_NUMOBJ (res) != 1
+	  || __type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ)
 	{
 	  nis_freeresult (res);
 	  return NIS_INVALIDOBJ;
 	}
 
-      newmem =
-	calloc (NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len,
-		sizeof (char *));
-      if (newmem == NULL)
-	return NIS_NOMEMORY;
+      nis_name *gr_members_val
+	= NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_val;
+      u_int gr_members_len
+	= NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len;
 
-      k = NIS_RES_OBJECT (res)[0].GR_data.gr_members.gr_members_len;
-      j = 0;
-      for (i = 0; i < NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len;
-	   ++i)
-	{
-	  if (strcmp (NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_val[i],
-		      member) != 0)
-	    {
-	      newmem[j] = NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_val[i];
-	      ++j;
-	    }
-	  else
-	    {
-	      free (NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_val[i]);
-	      --k;
-	    }
-	}
-      free (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val);
-      assert (k <= NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len);
-      /* This realloc() call always decreases the size.  This cannot
-	 fail.  We still have the test but do not recover memory
-	 (i.e., we overwrite the input pointer).  */
-      newmem = realloc (newmem, k * sizeof (char*));
-      if (newmem == NULL)
-	return NIS_NOMEMORY;
+      u_int j = 0;
+      for (u_int i = 0; i < gr_members_len; ++i)
+	if (strcmp (gr_members_val[i], member) != 0)
+	  gr_members_val[j++] = gr_members_val[i];
+	else
+	  free (gr_members_val[i]);
 
-      NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val = newmem;
-      NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len = k;
+      /* There is no need to reallocate the gr_members_val array.  We
+	 just adjust the size to match the number of strings still in
+	 it.  Yes, xdr_array will use mem_free with a size parameter
+	 but this is mapped to a simple free call which determines the
+	 size of the block by itself.  */
+      NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len = j;
 
       cp = stpcpy (buf, NIS_RES_OBJECT (res)->zo_name);
       *cp++ = '.';
diff --git a/nis/nis_subr.c b/nis/nis_subr.c
index 4c4ef8b5b4..c68189e541 100644
--- a/nis/nis_subr.c
+++ b/nis/nis_subr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1999, 2000, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1997,1999,2000,2004,2005,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -39,22 +39,13 @@ nis_leaf_of_r (const_nis_name name, char *buffer, size_t buflen)
   while (name[i] != '.' && name[i] != '\0')
     i++;
 
-  if (i > buflen - 1)
+  if (__builtin_expect (i >= buflen, 0))
     {
       __set_errno (ERANGE);
       return NULL;
     }
 
-  if (i > 0)
-    {
-      if ((size_t)i >= buflen)
-	{
-	  __set_errno (ERANGE);
-	  return NULL;
-	}
-
-      *((char *) __mempcpy (buffer, name, i)) = '\0';
-    }
+  *((char *) __mempcpy (buffer, name, i)) = '\0';
 
   return buffer;
 }
@@ -98,13 +89,12 @@ nis_name_of_r (const_nis_name name, char *buffer, size_t buflen)
 }
 libnsl_hidden_def (nis_name_of_r)
 
-static int
+static int __always_inline
 count_dots (const_nis_name str)
 {
   int count = 0;
-  size_t l = strlen (str);
 
-  for (size_t i = 0; i < l; ++i)
+  for (size_t i = 0; str[i] != '\0'; ++i)
     if (str[i] == '.')
       ++count;
 
@@ -117,25 +107,23 @@ count_dots (const_nis_name str)
 nis_name *
 nis_getnames (const_nis_name name)
 {
-  nis_name *getnames = NULL;
-  char local_domain[NIS_MAXNAMELEN + 1];
+  const char *local_domain = nis_local_directory ();
+  size_t local_domain_len = strlen (local_domain);
+  size_t name_len = strlen (name);
   char *path;
-  char *cp;
-  int count;
   int pos = 0;
-  int have_point;
   char *saveptr;
+  int have_point;
+  const char *cp;
+  const char *cp2;
 
-  strncpy (local_domain, nis_local_directory (), NIS_MAXNAMELEN);
-  local_domain[NIS_MAXNAMELEN] = '\0';
-
-  count = 1;
-  getnames = malloc ((count + 1) * sizeof (char *));
+  int count = 2;
+  nis_name *getnames = malloc ((count + 1) * sizeof (char *));
   if (__builtin_expect (getnames == NULL, 0))
       return NULL;
 
   /* Do we have a fully qualified NIS+ name ? If yes, give it back */
-  if (name[strlen (name) - 1] == '.')
+  if (name[name_len - 1] == '.')
     {
       if ((getnames[0] = strdup (name)) == NULL)
 	{
@@ -151,6 +139,44 @@ nis_getnames (const_nis_name name)
       return getnames;
     }
 
+  /* If the passed NAME is shared a suffix (the latter of course with
+     a final dot) with each other we pass back NAME with a final
+     dot.  */
+  if (local_domain_len > 2)
+    {
+      have_point = 0;
+      cp = &local_domain[local_domain_len - 2];
+      cp2 = &name[name_len - 1];
+
+      while (*cp == *cp2)
+	{
+	  if (*cp == '.')
+	    have_point = 1;
+	  --cp;
+	  --cp2;
+	  if (cp < local_domain)
+	    {
+	      have_point = cp2 < name || *cp2 == '.';
+	      break;
+	    }
+	  if (cp2 < name)
+	    {
+	      have_point = *cp == '.';
+	      break;
+	    }
+	}
+
+      if (have_point)
+	{
+	  getnames[0] = malloc (name_len + 2);
+	  if (getnames[0] == NULL)
+	    goto free_null;
+
+	  strcpy (stpcpy (getnames[0], name), ".");
+	  ++pos;
+	}
+    }
+
   /* Get the search path, where we have to search "name" */
   path = getenv ("NIS_PATH");
   if (path == NULL)
@@ -158,17 +184,17 @@ nis_getnames (const_nis_name name)
   else
     path = strdupa (path);
 
-  have_point = (strchr (name, '.') != NULL);
+  have_point = strchr (name, '.') != NULL;
 
   cp = __strtok_r (path, ":", &saveptr);
   while (cp)
     {
       if (strcmp (cp, "$") == 0)
 	{
-	  char *cptr = local_domain;
+	  const char *cptr = local_domain;
 	  char *tmp;
 
-	  while ((have_point && *cptr != '\0') || (count_dots (cptr) >= 2))
+	  while (*cptr != '\0' && count_dots (cptr) >= 2)
 	    {
 	      if (pos >= count)
 		{
@@ -179,8 +205,7 @@ nis_getnames (const_nis_name name)
 		    goto free_null;
 		  getnames = newp;
 		}
-	      tmp = malloc (strlen (cptr) + strlen (local_domain) +
-			    strlen (name) + 2);
+	      tmp = malloc (strlen (cptr) + local_domain_len + name_len + 2);
 	      if (__builtin_expect (tmp == NULL, 0))
 		goto free_null;
 
@@ -210,7 +235,7 @@ nis_getnames (const_nis_name name)
 	    {
 	      char *p;
 
-	      tmp = malloc (cplen + strlen (local_domain) + strlen (name) + 2);
+	      tmp = malloc (cplen + local_domain_len + name_len + 2);
 	      if (__builtin_expect (tmp == NULL, 0))
 		goto free_null;
 
@@ -226,13 +251,16 @@ nis_getnames (const_nis_name name)
 	    {
 	      char *p;
 
-	      tmp = malloc (cplen + strlen (name) + 2);
+	      tmp = malloc (cplen + name_len + 3);
 	      if (__builtin_expect (tmp == NULL, 0))
 		goto free_null;
 
-	      p = __stpcpy (tmp, name);
+	      p = __mempcpy (tmp, name, name_len);
 	      *p++ = '.';
-	      memcpy (p, cp, cplen + 1);
+	      p = __mempcpy (p, cp, cplen);
+	      if (p[-1] != '.')
+		*p++ = '.';
+	      *p = '\0';
 	    }
 
 	  if (pos >= count)
@@ -250,6 +278,13 @@ nis_getnames (const_nis_name name)
       cp = __strtok_r (NULL, ":", &saveptr);
     }
 
+  if (pos == 0
+      && __asprintf (&getnames[pos++], "%s%s%s%s",
+		     name, name[name_len - 1] == '.' ? "" : ".",
+		     local_domain,
+		     local_domain[local_domain_len - 1] == '.' ? "" : ".") < 0)
+    goto free_null;
+
   getnames[pos] = NULL;
 
   return getnames;
diff --git a/nis/nis_table.c b/nis/nis_table.c
index 13acdfdf50..70b4701419 100644
--- a/nis/nis_table.c
+++ b/nis/nis_table.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 1997, 1998, 1999, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1997-1999, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
 
@@ -17,21 +18,21 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <assert.h>
 #include <string.h>
 #include <rpcsvc/nis.h>
 
 #include "nis_xdr.h"
 #include "nis_intern.h"
+#include "libnsl.h"
 
 
-static struct ib_request *
+struct ib_request *
 __create_ib_request (const_nis_name name, unsigned int flags)
 {
-  struct ib_request *ibreq = calloc (1, sizeof (ib_request));
-  char buf[strlen (name) + 1];
+  struct ib_request *ibreq = calloc (1, sizeof (struct ib_request));
   nis_attr *search_val = NULL;
   size_t search_len = 0;
-  char *cptr;
   size_t size = 0;
 
   if (ibreq == NULL)
@@ -39,18 +40,26 @@ __create_ib_request (const_nis_name name, unsigned int flags)
 
   ibreq->ibr_flags = flags;
 
-  cptr = strcpy (buf, name);
+  char *cptr = strdupa (name);
 
   /* Not of "[key=value,key=value,...],foo.." format? */
   if (cptr[0] != '[')
-    return (ibreq->ibr_name = strdup (cptr)) == NULL ? NULL : ibreq;
+    {
+      ibreq->ibr_name = strdup (cptr);
+      if (ibreq->ibr_name == NULL)
+	{
+	  free (ibreq);
+	  return NULL;
+	}
+      return ibreq;
+    }
 
   /* "[key=value,...],foo" format */
   ibreq->ibr_name = strchr (cptr, ']');
   if (ibreq->ibr_name == NULL || ibreq->ibr_name[1] != ',')
     {
-      ibreq->ibr_name = NULL; /* Or the xdr_* functions will dump */
-      nis_free_request (ibreq);
+      /* The object has not really been built yet so we use free.  */
+      free (ibreq);
       return NULL;
     }
 
@@ -85,21 +94,22 @@ __create_ib_request (const_nis_name name, unsigned int flags)
       if (cptr != NULL)
 	*cptr++ = '\0';
 
-      if (!val)
+      if (__builtin_expect (val == NULL, 0))
 	{
 	  nis_free_request (ibreq);
 	  return NULL;
 	}
       *val++ = '\0';
-      if ((search_len + 1) >= size)
+      if (search_len + 1 >= size)
         {
           size += 1;
-          search_val = realloc (search_val, size * sizeof (nis_attr));
-	  if (search_val == NULL)
+	  nis_attr *newp = realloc (search_val, size * sizeof (nis_attr));
+	  if (newp == NULL)
 	    goto free_null;
+	  search_val = newp;
 	}
       search_val[search_len].zattr_ndx = strdup (key);
-      if ((search_val[search_len].zattr_ndx) == NULL)
+      if (search_val[search_len].zattr_ndx == NULL)
 	goto free_null;
 
       search_val[search_len].zattr_val.zattr_val_len = strlen (val) + 1;
@@ -118,18 +128,18 @@ __create_ib_request (const_nis_name name, unsigned int flags)
 
   return ibreq;
 }
+libnsl_hidden_def (__create_ib_request)
 
-static struct timeval RPCTIMEOUT = {10, 0};
+static const struct timeval RPCTIMEOUT = {10, 0};
 
 static char *
-__get_tablepath (char *name, dir_binding *bptr)
+get_tablepath (char *name, dir_binding *bptr)
 {
   enum clnt_stat result;
-  nis_result *res = calloc (1, sizeof (nis_result));
+  nis_result res;
   struct ns_request req;
 
-  if (res == NULL)
-    return NULL;
+  memset (&res, '\0', sizeof (res));
 
   req.ns_name = name;
   req.ns_object.ns_object_len = 0;
@@ -137,21 +147,54 @@ __get_tablepath (char *name, dir_binding *bptr)
 
   result = clnt_call (bptr->clnt, NIS_LOOKUP, (xdrproc_t) _xdr_ns_request,
 		      (caddr_t) &req, (xdrproc_t) _xdr_nis_result,
-		      (caddr_t) res, RPCTIMEOUT);
+		      (caddr_t) &res, RPCTIMEOUT);
 
-  if (result == RPC_SUCCESS && NIS_RES_STATUS (res) == NIS_SUCCESS &&
-      __type_of (NIS_RES_OBJECT (res)) == NIS_TABLE_OBJ)
-    {
-      char *cptr = strdup (NIS_RES_OBJECT (res)->TA_data.ta_path);
-      nis_freeresult (res);
-      return cptr;
-    }
+  const char *cptr;
+  if (result == RPC_SUCCESS && NIS_RES_STATUS (&res) == NIS_SUCCESS
+      && __type_of (NIS_RES_OBJECT (&res)) == NIS_TABLE_OBJ)
+    cptr = NIS_RES_OBJECT (&res)->TA_data.ta_path;
   else
+    cptr = "";
+
+  char *str = strdup (cptr);
+
+  if (result == RPC_SUCCESS)
+    xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &res);
+
+  return str;
+}
+
+
+nis_error
+__follow_path (char **tablepath, char **tableptr, struct ib_request *ibreq,
+	       dir_binding *bptr)
+{
+  if (*tablepath == NULL)
     {
-      nis_freeresult (res);
-      return strdup ("");
+      *tablepath = get_tablepath (ibreq->ibr_name, bptr);
+      if (*tablepath == NULL)
+	return NIS_NOMEMORY;
+
+      *tableptr = *tablepath;
     }
+  if (*tableptr == NULL)
+    return NIS_NOTFOUND;
+
+  char *newname = strsep (tableptr, ":");
+  if (newname[0] == '\0')
+    return NIS_NOTFOUND;
+
+  newname = strdup (newname);
+  if (newname == NULL)
+    return NIS_NOMEMORY;
+
+  free (ibreq->ibr_name);
+  ibreq->ibr_name = newname;
+
+  return NIS_SUCCESS;
 }
+libnsl_hidden_def (__follow_path)
+
 
 nis_result *
 nis_list (const_nis_name name, unsigned int flags,
@@ -160,7 +203,7 @@ nis_list (const_nis_name name, unsigned int flags,
 			   const void *userdata),
 	  const void *userdata)
 {
-  nis_result *res = calloc (1, sizeof (nis_result));
+  nis_result *res = malloc (sizeof (nis_result));
   ib_request *ibreq;
   int status;
   enum clnt_stat clnt_status;
@@ -170,23 +213,29 @@ nis_list (const_nis_name name, unsigned int flags,
   nis_name namebuf[2] = {NULL, NULL};
   int name_nr = 0;
   nis_cb *cb = NULL;
-  char *tableptr, *tablepath = NULL;
-  int have_tablepath = 0;
+  char *tableptr;
+  char *tablepath = NULL;
   int first_try = 0; /* Do we try the old binding at first ? */
+  nis_result *allres = NULL;
 
   if (res == NULL)
     return NULL;
 
   if (name == NULL)
     {
-      NIS_RES_STATUS (res) = NIS_BADNAME;
+      status = NIS_BADNAME;
+    err_out:
+      nis_freeresult (allres);
+      memset (res, '\0', sizeof (nis_result));
+      NIS_RES_STATUS (res) = status;
       return res;
     }
 
-  if ((ibreq = __create_ib_request (name, flags)) == NULL)
+  ibreq = __create_ib_request (name, flags);
+  if (ibreq == NULL)
     {
-      NIS_RES_STATUS (res) = NIS_BADNAME;
-      return res;
+      status = NIS_BADNAME;
+      goto err_out;
     }
 
   if ((flags & EXPAND_NAME)
@@ -198,15 +247,16 @@ nis_list (const_nis_name name, unsigned int flags,
       if (names == NULL)
 	{
 	  nis_free_request (ibreq);
-	  NIS_RES_STATUS (res) = NIS_BADNAME;
-	  return res;
+	  status = NIS_BADNAME;
+	  goto err_out;
 	}
       ibreq->ibr_name = strdup (names[name_nr]);
       if (ibreq->ibr_name == NULL)
 	{
+	  nis_freenames (names);
 	  nis_free_request (ibreq);
-	  NIS_RES_STATUS (res) = NIS_NOMEMORY;
-	  return res;
+	  status = NIS_NOMEMORY;
+	  goto err_out;
 	}
     }
   else
@@ -224,36 +274,25 @@ nis_list (const_nis_name name, unsigned int flags,
 
       memset (res, '\0', sizeof (nis_result));
 
-      status = __nisfind_server (ibreq->ibr_name, &dir);
+      status = __nisfind_server (ibreq->ibr_name,
+				 ibreq->ibr_srch.ibr_srch_val != NULL,
+				 &dir, &bptr, flags & ~MASTER_ONLY);
       if (status != NIS_SUCCESS)
-        {
-	  nis_free_request (ibreq);
-          NIS_RES_STATUS (res) = status;
-          return res;
-        }
-
-      status = __nisbind_create (&bptr, dir->do_servers.do_servers_val,
-                                 dir->do_servers.do_servers_len, flags);
-      if (status != NIS_SUCCESS)
-        {
-	  nis_free_request (ibreq);
+	{
           NIS_RES_STATUS (res) = status;
-          nis_free_directory (dir);
-          return res;
-        }
+          goto fail3;
+	}
 
       while (__nisbind_connect (&bptr) != NIS_SUCCESS)
-	if (__nisbind_next (&bptr) != NIS_SUCCESS)
+	if (__builtin_expect (__nisbind_next (&bptr) != NIS_SUCCESS, 0))
 	  {
-	    __nisbind_destroy (&bptr);
-	    nis_free_directory (dir);
-	    nis_free_request (ibreq);
 	    NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
-	    return res;
+	    goto fail;
 	  }
 
       if (callback != NULL)
 	{
+	  assert (cb == NULL);
 	  cb = __nis_create_callback (callback, userdata, flags);
 	  ibreq->ibr_cbhost.ibr_cbhost_len = 1;
 	  ibreq->ibr_cbhost.ibr_cbhost_val = cb->serv;
@@ -265,7 +304,7 @@ nis_list (const_nis_name name, unsigned int flags,
 			       (xdrproc_t) _xdr_nis_result,
 			       (caddr_t) res, RPCTIMEOUT);
 
-      if (clnt_status != RPC_SUCCESS)
+      if (__builtin_expect (clnt_status != RPC_SUCCESS, 0))
 	NIS_RES_STATUS (res) = NIS_RPCERROR;
       else
 	switch (NIS_RES_STATUS (res))
@@ -273,13 +312,13 @@ nis_list (const_nis_name name, unsigned int flags,
 	  case NIS_PARTIAL:
 	  case NIS_SUCCESS:
 	  case NIS_S_SUCCESS:
-	    if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ &&
-		flags & FOLLOW_LINKS)		/* We are following links.  */
+	    if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ
+		&& (flags & FOLLOW_LINKS))	/* We are following links.  */
 	      {
 		free (ibreq->ibr_name);
 		ibreq->ibr_name = NULL;
 		/* If we hit the link limit, bail.  */
-		if (count_links > NIS_MAXLINKS)
+		if (__builtin_expect (count_links > NIS_MAXLINKS, 0))
 		  {
 		    NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
 		    ++done;
@@ -290,8 +329,22 @@ nis_list (const_nis_name name, unsigned int flags,
 		  strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
 		if (ibreq->ibr_name == NULL)
 		  {
-		    nis_free_request (ibreq);
 		    NIS_RES_STATUS (res) = NIS_NOMEMORY;
+		  fail:
+		    __nisbind_destroy (&bptr);
+		    nis_free_directory (dir);
+		  fail3:
+		    free (tablepath);
+		    if (cb)
+		      {
+			__nis_destroy_callback (cb);
+			ibreq->ibr_cbhost.ibr_cbhost_len = 0;
+			ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
+		      }
+		    if (names != namebuf)
+		      nis_freenames (names);
+		    nis_free_request (ibreq);
+		    nis_freeresult (allres);
 		    return res;
 		  }
 		if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
@@ -302,63 +355,88 @@ nis_list (const_nis_name name, unsigned int flags,
 		      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));
-		if (res == NULL)
-		  {
-		    if (have_tablepath)
-		      free (tablepath);
-		    __nisbind_destroy (&bptr);
-		    nis_free_directory (dir);
-		    return NULL;
-		  }
+		/* The following is a non-obvious optimization.  A
+		   nis_freeresult call would call xdr_free as the
+		   following code.  But it also would unnecessarily
+		   free the result structure.  We avoid this here
+		   along with the necessary tests.  */
+		xdr_free ((xdrproc_t) _xdr_nis_result, (char *)res);
+		memset (res, '\0', sizeof (*res));
 		first_try = 1; /* Try at first the old binding */
 		goto again;
 	      }
-	    else if ((flags & FOLLOW_PATH) &&
-		     NIS_RES_STATUS (res) == NIS_PARTIAL)
+	    else if ((flags & FOLLOW_PATH)
+		     && NIS_RES_STATUS (res) == NIS_PARTIAL)
 	      {
-		if (!have_tablepath)
+		clnt_status = __follow_path (&tablepath, &tableptr, ibreq,
+					     &bptr);
+		if (clnt_status != NIS_SUCCESS)
 		  {
-		    tablepath = __get_tablepath (ibreq->ibr_name, &bptr);
-		    tableptr = tablepath;
-		    have_tablepath = 1;
+		    NIS_RES_STATUS (res) = clnt_status;
+		    ++done;
 		  }
-		if (tableptr == NULL)
+		else
 		  {
-		    ++done;
-		    break;
+		    /* The following is a non-obvious optimization.  A
+		       nis_freeresult call would call xdr_free as the
+		       following code.  But it also would unnecessarily
+		       free the result structure.  We avoid this here
+		       along with the necessary tests.  */
+		    xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
+		    memset (res, '\0', sizeof (*res));
+		    first_try = 1;
+		    goto again;
 		  }
-		free (ibreq->ibr_name);
-		ibreq->ibr_name = strsep (&tableptr, ":");
-		if (ibreq->ibr_name == NULL || ibreq->ibr_name[0] == '\0')
+	      }
+	    else if ((flags & (FOLLOW_PATH | ALL_RESULTS))
+		     == (FOLLOW_PATH | ALL_RESULTS))
+	      {
+		if (allres == NULL)
 		  {
-		    ibreq->ibr_name = strdup ("");
-		    if (ibreq->ibr_name == NULL)
+		    allres = res;
+		    res = malloc (sizeof (nis_result));
+		    if (res == NULL)
 		      {
-			nis_free_request (ibreq);
+			res = allres;
+			allres = NULL;
 			NIS_RES_STATUS (res) = NIS_NOMEMORY;
-			return res;
+			goto fail;
 		      }
-		    ++done;
+		    NIS_RES_STATUS (res) = NIS_RES_STATUS (allres);
 		  }
 		else
 		  {
-		    ibreq->ibr_name = strdup (ibreq->ibr_name);
-		    nis_freeresult (res);
-		    res = calloc (1, sizeof (nis_result));
-		    if (res == NULL || ibreq->ibr_name == NULL)
+		    nis_object *objects_val
+		      = realloc (NIS_RES_OBJECT (allres),
+				 (NIS_RES_NUMOBJ (allres)
+				  + NIS_RES_NUMOBJ (res))
+				 * sizeof (nis_object));
+		    if (objects_val == NULL)
 		      {
-			free (res);
-			nis_free_request (ibreq);
-			if (have_tablepath)
-			  free (tablepath);
-			__nisbind_destroy (&bptr);
-			nis_free_directory (dir);
-			return NULL;
+			NIS_RES_STATUS (res) = NIS_NOMEMORY;
+			goto fail;
 		      }
-		    first_try = 1;
-		    goto again;
+		    NIS_RES_OBJECT (allres) = objects_val;
+		    memcpy (NIS_RES_OBJECT (allres) + NIS_RES_NUMOBJ (allres),
+			    NIS_RES_OBJECT (res),
+			    NIS_RES_NUMOBJ (res) * sizeof (nis_object));
+		    NIS_RES_NUMOBJ (allres) += NIS_RES_NUMOBJ (res);
+		    NIS_RES_NUMOBJ (res) = 0;
+		    free (NIS_RES_OBJECT (res));
+		    NIS_RES_OBJECT (res) = NULL;
+		    NIS_RES_STATUS (allres) = NIS_RES_STATUS (res);
+		    xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
+		  }
+		clnt_status = __follow_path (&tablepath, &tableptr, ibreq,
+					     &bptr);
+		if (clnt_status != NIS_SUCCESS)
+		  {
+		    /* Prepare for the nis_freeresult call.  */
+		    memset (res, '\0', sizeof (*res));
+
+		    if (clnt_status == NIS_NOMEMORY)
+		      NIS_RES_STATUS (allres) = clnt_status;
+		    ++done;
 		  }
 	      }
 	    else
@@ -374,32 +452,10 @@ nis_list (const_nis_name name, unsigned int flags,
 		  ++done;
 		else
 		  {
-		    if (!have_tablepath)
-		      {
-			tablepath = __get_tablepath (ibreq->ibr_name, &bptr);
-			tableptr = tablepath;
-			have_tablepath = 1;
-		      }
-		    if (tableptr == NULL)
-		      {
-			++done;
-			break;
-		      }
-		    free (ibreq->ibr_name);
-		    ibreq->ibr_name = strsep (&tableptr, ":");
-		    if (ibreq->ibr_name == NULL || ibreq->ibr_name[0] == '\0')
-		      {
-			ibreq->ibr_name = strdup ("");
-			++done;
-		      }
-		    else
-		      ibreq->ibr_name = strdup (ibreq->ibr_name);
-		    if (ibreq->ibr_name == NULL)
-		      {
-			nis_free_request (ibreq);
-			NIS_RES_STATUS (res) = NIS_NOMEMORY;
-			return res;
-		      }
+		    NIS_RES_STATUS (res)
+		      = __follow_path (&tablepath, &tableptr, ibreq, &bptr);
+		    if (NIS_RES_STATUS (res) != NIS_SUCCESS)
+		      ++done;
 		  }
 	      }
 	    break;
@@ -432,7 +488,7 @@ nis_list (const_nis_name name, unsigned int flags,
 		/* Try the next domainname if we don't follow a link.  */
 		free (ibreq->ibr_name);
 		ibreq->ibr_name = NULL;
-		if (count_links)
+		if (__builtin_expect (count_links, 0))
 		  {
 		    NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
 		    ++done;
@@ -447,9 +503,8 @@ nis_list (const_nis_name name, unsigned int flags,
 		ibreq->ibr_name = strdup (names[name_nr]);
 		if (ibreq->ibr_name == NULL)
 		  {
-		    nis_free_request (ibreq);
 		    NIS_RES_STATUS (res) = NIS_NOMEMORY;
-		    return res;
+		    goto fail;
 		  }
 		first_try = 1; /* Try old binding at first */
 		goto again;
@@ -463,17 +518,26 @@ nis_list (const_nis_name name, unsigned int flags,
 	  __nis_destroy_callback (cb);
 	  ibreq->ibr_cbhost.ibr_cbhost_len = 0;
 	  ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
+	  cb = NULL;
 	}
 
       __nisbind_destroy (&bptr);
       nis_free_directory (dir);
     }
 
+  free (tablepath);
+
   if (names != namebuf)
     nis_freenames (names);
 
   nis_free_request (ibreq);
 
+  if (allres)
+    {
+      nis_freeresult (res);
+      return allres;
+    }
+
   return res;
 }
 libnsl_hidden_def (nis_list)
@@ -481,15 +545,7 @@ libnsl_hidden_def (nis_list)
 nis_result *
 nis_add_entry (const_nis_name name, const nis_object *obj2, unsigned int flags)
 {
-  nis_object obj;
-  nis_result *res;
-  nis_error status;
-  ib_request *ibreq;
-  size_t namelen = strlen (name);
-  char buf1[namelen + 20];
-  char buf4[namelen + 20];
-
-  res = calloc (1, sizeof (nis_result));
+  nis_result *res = calloc (1, sizeof (nis_result));
   if (res == NULL)
     return NULL;
 
@@ -499,14 +555,20 @@ nis_add_entry (const_nis_name name, const nis_object *obj2, unsigned int flags)
       return res;
     }
 
-  if ((ibreq = __create_ib_request (name, flags)) == NULL)
+  ib_request *ibreq = __create_ib_request (name, flags);
+  if (ibreq == NULL)
     {
       NIS_RES_STATUS (res) = NIS_BADNAME;
       return res;
     }
 
+  nis_object obj;
   memcpy (&obj, obj2, sizeof (nis_object));
 
+  size_t namelen = strlen (name);
+  char buf1[namelen + 20];
+  char buf4[namelen + 20];
+
   if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
     obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1));
 
@@ -527,11 +589,12 @@ nis_add_entry (const_nis_name name, const nis_object *obj2, unsigned int flags)
     }
   ibreq->ibr_obj.ibr_obj_len = 1;
 
-  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, NULL)) != NIS_SUCCESS)
+  nis_error 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, NULL);
+  if (__builtin_expect (status != NIS_SUCCESS, 0))
     NIS_RES_STATUS (res) = status;
 
   nis_free_request (ibreq);
@@ -555,7 +618,8 @@ nis_modify_entry (const_nis_name name, const nis_object *obj2,
   if (res == NULL)
     return NULL;
 
-  if (( ibreq =__create_ib_request (name, flags)) == NULL)
+  ibreq = __create_ib_request (name, flags);
+  if (ibreq == NULL)
     {
       NIS_RES_STATUS (res) = NIS_BADNAME;
       return res;
@@ -583,10 +647,11 @@ nis_modify_entry (const_nis_name name, const nis_object *obj2,
     }
   ibreq->ibr_obj.ibr_obj_len = 1;
 
-  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, NULL)) != NIS_SUCCESS)
+  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, NULL);
+  if (__builtin_expect (status != NIS_SUCCESS, 0))
     NIS_RES_STATUS (res) = status;
 
   nis_free_request (ibreq);
@@ -612,7 +677,8 @@ nis_remove_entry (const_nis_name name, const nis_object *obj,
       return res;
     }
 
-  if ((ibreq =__create_ib_request (name, flags)) == NULL)
+  ibreq = __create_ib_request (name, flags);
+  if (ibreq == NULL)
     {
       NIS_RES_STATUS (res) = NIS_BADNAME;
       return res;
@@ -670,7 +736,7 @@ nis_first_entry (const_nis_name name)
 			 (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
 			 (caddr_t) res, 0, NULL);
 
-  if (status != NIS_SUCCESS)
+  if (__builtin_expect (status != NIS_SUCCESS, 0))
     NIS_RES_STATUS (res) = status;
 
   nis_free_request (ibreq);
@@ -713,7 +779,7 @@ nis_next_entry (const_nis_name name, const netobj *cookie)
 			 (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
 			 (caddr_t) res, 0, NULL);
 
-  if (status != NIS_SUCCESS)
+  if (__builtin_expect (status != NIS_SUCCESS, 0))
     NIS_RES_STATUS (res) = status;
 
   if (cookie != NULL)
diff --git a/nis/nis_xdr.c b/nis/nis_xdr.c
index 2a75505b31..0c6452a6a7 100644
--- a/nis/nis_xdr.c
+++ b/nis/nis_xdr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 1998, 2005, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -28,383 +28,415 @@
 static bool_t
 xdr_nis_attr (XDR *xdrs, nis_attr *objp)
 {
-  if (!xdr_string (xdrs, &objp->zattr_ndx, ~0))
-    return FALSE;
-  if (!xdr_bytes (xdrs, (char **) &objp->zattr_val.zattr_val_val,
-		  (u_int *) & objp->zattr_val.zattr_val_len, ~0))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_string (xdrs, &objp->zattr_ndx, ~0);
+  if (__builtin_expect (res, TRUE))
+    res = xdr_bytes (xdrs, (char **) &objp->zattr_val.zattr_val_val,
+		     &objp->zattr_val.zattr_val_len, ~0);
+  return res;
+}
+
+static __always_inline bool_t
+xdr_nis_name (XDR *xdrs, nis_name *objp)
+{
+  return xdr_string (xdrs, objp, ~0);
 }
 
 bool_t
 _xdr_nis_name (XDR *xdrs, nis_name *objp)
 {
-  if (!xdr_string (xdrs, objp, ~0))
-    return FALSE;
-  return TRUE;
+  return xdr_nis_name (xdrs, objp);
 }
 
-static bool_t
+static __always_inline bool_t
 xdr_zotypes (XDR *xdrs, zotypes *objp)
 {
-  if (!xdr_enum (xdrs, (enum_t *) objp))
-    return FALSE;
-  return TRUE;
+  return xdr_enum (xdrs, (enum_t *) objp);
 }
 
-static bool_t
+static __always_inline bool_t
 xdr_nstype (XDR *xdrs, nstype *objp)
 {
-  if (!xdr_enum (xdrs, (enum_t *) objp))
-    return FALSE;
-  return TRUE;
+  return xdr_enum (xdrs, (enum_t *) objp);
 }
 
 static bool_t
 xdr_oar_mask (XDR *xdrs, oar_mask *objp)
 {
-  if (!xdr_u_int (xdrs, &objp->oa_rights))
-    return FALSE;
-  if (!xdr_zotypes (xdrs, &objp->oa_otype))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_u_int (xdrs, &objp->oa_rights);
+  if (__builtin_expect (res, TRUE))
+    res = xdr_zotypes (xdrs, &objp->oa_otype);
+  return res;
 }
 
 static bool_t
 xdr_endpoint (XDR *xdrs, endpoint *objp)
 {
-  if (!xdr_string (xdrs, &objp->uaddr, ~0))
-    return FALSE;
-  if (!xdr_string (xdrs, &objp->family, ~0))
-    return FALSE;
-  if (!xdr_string (xdrs, &objp->proto, ~0))
-    return FALSE;
-  return TRUE;
+  bool_t res =  xdr_string (xdrs, &objp->uaddr, ~0);
+  if (__builtin_expect (res, TRUE))
+    {
+      res = xdr_string (xdrs, &objp->family, ~0);
+      if (__builtin_expect (res, 1))
+	res = xdr_string (xdrs, &objp->proto, ~0);
+    }
+  return res;
 }
 
 bool_t
 _xdr_nis_server (XDR *xdrs, nis_server *objp)
 {
-  if (!_xdr_nis_name (xdrs, &objp->name))
-    return FALSE;
-  if (!xdr_array (xdrs, (char **) &objp->ep.ep_val, (u_int *) &objp->ep.ep_len,
-		  ~0, sizeof (endpoint), (xdrproc_t) xdr_endpoint))
-    return FALSE;
-  if (!xdr_u_int (xdrs, &objp->key_type))
-    return FALSE;
-  if (!xdr_netobj (xdrs, &objp->pkey))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_nis_name (xdrs, &objp->name);
+  if (__builtin_expect (res, TRUE))
+    {
+      res = xdr_array (xdrs, (char **) &objp->ep.ep_val, &objp->ep.ep_len,
+		       ~0, sizeof (endpoint), (xdrproc_t) xdr_endpoint);
+      if (__builtin_expect (res, TRUE))
+	{
+	  res = xdr_u_int (xdrs, &objp->key_type);
+	  if (__builtin_expect (res, TRUE))
+	    res = xdr_netobj (xdrs, &objp->pkey);
+	}
+    }
+  return res;
 }
 
 bool_t
 _xdr_directory_obj (XDR *xdrs, directory_obj *objp)
 {
-  if (!_xdr_nis_name (xdrs, &objp->do_name))
-    return FALSE;
-  if (!xdr_nstype (xdrs, &objp->do_type))
-    return FALSE;
-  if (!xdr_array (xdrs, (char **) &objp->do_servers.do_servers_val,
-		  (u_int *) & objp->do_servers.do_servers_len, ~0,
-		  sizeof (nis_server), (xdrproc_t) _xdr_nis_server))
-    return FALSE;
-
-  if (!xdr_uint32_t (xdrs, &objp->do_ttl))
-    return FALSE;
-  if (!xdr_array (xdrs, (char **) &objp->do_armask.do_armask_val,
-		  (u_int *) & objp->do_armask.do_armask_len, ~0,
-		  sizeof (oar_mask), (xdrproc_t) xdr_oar_mask))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_nis_name (xdrs, &objp->do_name);
+  if (__builtin_expect (res, TRUE))
+    {
+      res = xdr_nstype (xdrs, &objp->do_type);
+      if (__builtin_expect (res, TRUE))
+	{
+	  res = xdr_array (xdrs, (char **) &objp->do_servers.do_servers_val,
+			   &objp->do_servers.do_servers_len, ~0,
+			   sizeof (nis_server), (xdrproc_t) _xdr_nis_server);
+	  if (__builtin_expect (res, TRUE))
+	    {
+	      res = xdr_uint32_t (xdrs, &objp->do_ttl);
+	      if (__builtin_expect (res, TRUE))
+		res = xdr_array (xdrs,
+				 (char **) &objp->do_armask.do_armask_val,
+				 &objp->do_armask.do_armask_len, ~0,
+				 sizeof (oar_mask), (xdrproc_t) xdr_oar_mask);
+	    }
+	}
+    }
+  return res;
 }
 
 static bool_t
 xdr_entry_col (XDR *xdrs, entry_col *objp)
 {
-  if (!xdr_u_int (xdrs, &objp->ec_flags))
-    return FALSE;
-  if (!xdr_bytes (xdrs, (char **) &objp->ec_value.ec_value_val,
-		  (u_int *) &objp->ec_value.ec_value_len, ~0))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_u_int (xdrs, &objp->ec_flags);
+  if (__builtin_expect (res, TRUE))
+    res = xdr_bytes (xdrs, (char **) &objp->ec_value.ec_value_val,
+		     &objp->ec_value.ec_value_len, ~0);
+  return res;
 }
 
 static bool_t
 xdr_entry_obj (XDR *xdrs, entry_obj *objp)
 {
-  if (!xdr_string (xdrs, &objp->en_type, ~0))
-    return FALSE;
-  if (!xdr_array (xdrs, (char **) &objp->en_cols.en_cols_val,
-		  (u_int *) &objp->en_cols.en_cols_len, ~0,
-		  sizeof (entry_col), (xdrproc_t) xdr_entry_col))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_string (xdrs, &objp->en_type, ~0);
+  if (__builtin_expect (res, TRUE))
+    res = xdr_array (xdrs, (char **) &objp->en_cols.en_cols_val,
+		     &objp->en_cols.en_cols_len, ~0,
+		     sizeof (entry_col), (xdrproc_t) xdr_entry_col);
+  return res;
 }
 
 static bool_t
 xdr_group_obj (XDR *xdrs, group_obj *objp)
 {
-  if (!xdr_u_int (xdrs, &objp->gr_flags))
-    return FALSE;
-  if (!xdr_array (xdrs, (char **) &objp->gr_members.gr_members_val,
-		  (u_int *) &objp->gr_members.gr_members_len, ~0,
-		  sizeof (nis_name), (xdrproc_t) _xdr_nis_name))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_u_int (xdrs, &objp->gr_flags);
+  if (__builtin_expect (res, TRUE))
+    res = xdr_array (xdrs, (char **) &objp->gr_members.gr_members_val,
+		     &objp->gr_members.gr_members_len, ~0,
+		     sizeof (nis_name), (xdrproc_t) _xdr_nis_name);
+  return res;
 }
 
 static bool_t
 xdr_link_obj (XDR *xdrs, link_obj *objp)
 {
-  if (!xdr_zotypes (xdrs, &objp->li_rtype))
-    return FALSE;
-  if (!xdr_array (xdrs, (char **) &objp->li_attrs.li_attrs_val,
-		  (u_int *) &objp->li_attrs.li_attrs_len, ~0,
-		  sizeof (nis_attr), (xdrproc_t) xdr_nis_attr))
-    return FALSE;
-  if (!_xdr_nis_name (xdrs, &objp->li_name))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_zotypes (xdrs, &objp->li_rtype);
+  if (__builtin_expect (res, TRUE))
+    {
+      res = xdr_array (xdrs, (char **) &objp->li_attrs.li_attrs_val,
+		       &objp->li_attrs.li_attrs_len, ~0,
+		       sizeof (nis_attr), (xdrproc_t) xdr_nis_attr);
+      if (__builtin_expect (res, TRUE))
+	res = xdr_nis_name (xdrs, &objp->li_name);
+    }
+  return res;
 }
 
 static bool_t
 xdr_table_col (XDR *xdrs, table_col *objp)
 {
-  if (!xdr_string (xdrs, &objp->tc_name, 64))
-    return FALSE;
-  if (!xdr_u_int (xdrs, &objp->tc_flags))
-    return FALSE;
-  if (!xdr_u_int (xdrs, &objp->tc_rights))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_string (xdrs, &objp->tc_name, 64);
+  if (__builtin_expect (res, TRUE))
+    {
+      res = xdr_u_int (xdrs, &objp->tc_flags);
+      if (__builtin_expect (res, TRUE))
+	res = xdr_u_int (xdrs, &objp->tc_rights);
+    }
+  return res;
 }
 
 static bool_t
 xdr_table_obj (XDR *xdrs, table_obj *objp)
 {
-  if (!xdr_string (xdrs, &objp->ta_type, 64))
-    return FALSE;
-  if (!xdr_int (xdrs, &objp->ta_maxcol))
-    return FALSE;
-  if (!xdr_u_char (xdrs, &objp->ta_sep))
-    return FALSE;
-  if (!xdr_array (xdrs, (char **) &objp->ta_cols.ta_cols_val,
-		  (u_int *) &objp->ta_cols.ta_cols_len, ~0,
-		  sizeof (table_col), (xdrproc_t) xdr_table_col))
-    return FALSE;
-  if (!xdr_string (xdrs, &objp->ta_path, ~0))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_string (xdrs, &objp->ta_type, 64);
+  if (__builtin_expect (res, TRUE))
+    {
+      res = xdr_int (xdrs, &objp->ta_maxcol);
+      if (__builtin_expect (res, TRUE))
+	{
+	  res = xdr_u_char (xdrs, &objp->ta_sep);
+	  if (__builtin_expect (res, TRUE))
+	    {
+	      res = xdr_array (xdrs, (char **) &objp->ta_cols.ta_cols_val,
+			       &objp->ta_cols.ta_cols_len, ~0,
+			       sizeof (table_col), (xdrproc_t) xdr_table_col);
+	      if (__builtin_expect (res, TRUE))
+		res = xdr_string (xdrs, &objp->ta_path, ~0);
+	    }
+	}
+    }
+  return res;
 }
 
 static bool_t
 xdr_objdata (XDR *xdrs, objdata *objp)
 {
-  if (!xdr_zotypes (xdrs, &objp->zo_type))
-    return FALSE;
+  bool_t res = xdr_zotypes (xdrs, &objp->zo_type);
+  if (!__builtin_expect (res, TRUE))
+    return res;
   switch (objp->zo_type)
     {
     case NIS_DIRECTORY_OBJ:
-      if (!_xdr_directory_obj (xdrs, &objp->objdata_u.di_data))
-	return FALSE;
-      break;
+      return _xdr_directory_obj (xdrs, &objp->objdata_u.di_data);
     case NIS_GROUP_OBJ:
-      if (!xdr_group_obj (xdrs, &objp->objdata_u.gr_data))
-	return FALSE;
-      break;
+      return xdr_group_obj (xdrs, &objp->objdata_u.gr_data);
     case NIS_TABLE_OBJ:
-      if (!xdr_table_obj (xdrs, &objp->objdata_u.ta_data))
-	return FALSE;
-      break;
+      return xdr_table_obj (xdrs, &objp->objdata_u.ta_data);
     case NIS_ENTRY_OBJ:
-      if (!xdr_entry_obj (xdrs, &objp->objdata_u.en_data))
-	return FALSE;
-      break;
+      return xdr_entry_obj (xdrs, &objp->objdata_u.en_data);
     case NIS_LINK_OBJ:
-      if (!xdr_link_obj (xdrs, &objp->objdata_u.li_data))
-	return FALSE;
-      break;
+      return xdr_link_obj (xdrs, &objp->objdata_u.li_data);
     case NIS_PRIVATE_OBJ:
-      if (!xdr_bytes (xdrs, (char **) &objp->objdata_u.po_data.po_data_val,
-		      (u_int *) & objp->objdata_u.po_data.po_data_len, ~0))
-	return FALSE;
-      break;
+      return xdr_bytes (xdrs, &objp->objdata_u.po_data.po_data_val,
+			&objp->objdata_u.po_data.po_data_len, ~0);
     case NIS_NO_OBJ:
-      break;
     case NIS_BOGUS_OBJ:
-      break;
     default:
-      break;
+      return TRUE;
     }
-  return TRUE;
 }
 
 static bool_t
 xdr_nis_oid (XDR *xdrs, nis_oid *objp)
 {
-  if (!xdr_uint32_t (xdrs, &objp->ctime))
-    return FALSE;
-  if (!xdr_uint32_t (xdrs, &objp->mtime))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_uint32_t (xdrs, &objp->ctime);
+  if  (__builtin_expect (res, TRUE))
+    res = xdr_uint32_t (xdrs, &objp->mtime);
+  return res;
 }
 
 bool_t
 _xdr_nis_object (XDR *xdrs, nis_object *objp)
 {
-  if (!xdr_nis_oid (xdrs, &objp->zo_oid))
-    return FALSE;
-  if (!_xdr_nis_name (xdrs, &objp->zo_name))
-    return FALSE;
-  if (!_xdr_nis_name (xdrs, &objp->zo_owner))
-    return FALSE;
-  if (!_xdr_nis_name (xdrs, &objp->zo_group))
-    return FALSE;
-  if (!_xdr_nis_name (xdrs, &objp->zo_domain))
-    return FALSE;
-  if (!xdr_u_int (xdrs, &objp->zo_access))
-    return FALSE;
-  if (!xdr_uint32_t (xdrs, &objp->zo_ttl))
-    return FALSE;
-  if (!xdr_objdata (xdrs, &objp->zo_data))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_nis_oid (xdrs, &objp->zo_oid);
+  if (__builtin_expect (res, TRUE))
+    {
+      res = xdr_nis_name (xdrs, &objp->zo_name);
+      if (__builtin_expect (res, TRUE))
+	{
+	  res = xdr_nis_name (xdrs, &objp->zo_owner);
+	  if (__builtin_expect (res, TRUE))
+	    {
+	      res = xdr_nis_name (xdrs, &objp->zo_group);
+	      if (__builtin_expect (res, TRUE))
+		{
+		  res = xdr_nis_name (xdrs, &objp->zo_domain);
+		  if (__builtin_expect (res, TRUE))
+		    {
+		      res = xdr_u_int (xdrs, &objp->zo_access);
+		      if (__builtin_expect (res, TRUE))
+			{
+			  res = xdr_uint32_t (xdrs, &objp->zo_ttl);
+			  if (__builtin_expect (res, TRUE))
+			    res = xdr_objdata (xdrs, &objp->zo_data);
+			}
+		    }
+		}
+	    }
+	}
+    }
+  return res;
+}
+
+static __always_inline bool_t
+xdr_nis_error (XDR *xdrs, nis_error *objp)
+{
+  return xdr_enum (xdrs, (enum_t *) objp);
 }
 
 bool_t
 _xdr_nis_error (XDR *xdrs, nis_error *objp)
 {
-  if (!xdr_enum (xdrs, (enum_t *) objp))
-    return FALSE;
-  return TRUE;
+  return xdr_nis_error (xdrs, objp);
 }
 
 bool_t
 _xdr_nis_result (XDR *xdrs, nis_result *objp)
 {
-  if (!_xdr_nis_error (xdrs, &objp->status))
-    return FALSE;
-  if (!xdr_array (xdrs, (char **) &objp->objects.objects_val,
-		  (u_int *) &objp->objects.objects_len, ~0,
-		  sizeof (nis_object), (xdrproc_t) _xdr_nis_object))
-    return FALSE;
-  if (!xdr_netobj (xdrs, &objp->cookie))
-    return FALSE;
-  if (!xdr_uint32_t (xdrs, &objp->zticks))
-    return FALSE;
-  if (!xdr_uint32_t (xdrs, &objp->dticks))
-    return FALSE;
-  if (!xdr_uint32_t (xdrs, &objp->aticks))
-    return FALSE;
-  if (!xdr_uint32_t (xdrs, &objp->cticks))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_nis_error (xdrs, &objp->status);
+  if (__builtin_expect (res, TRUE))
+    {
+      res = xdr_array (xdrs, (char **) &objp->objects.objects_val,
+		       &objp->objects.objects_len, ~0,
+		       sizeof (nis_object), (xdrproc_t) _xdr_nis_object);
+      if (__builtin_expect (res, TRUE))
+	{
+	  res = xdr_netobj (xdrs, &objp->cookie);
+	  if (__builtin_expect (res, TRUE))
+	    {
+	      res = xdr_uint32_t (xdrs, &objp->zticks);
+	      if (__builtin_expect (res, TRUE))
+		{
+		  res = xdr_uint32_t (xdrs, &objp->dticks);
+		  if (__builtin_expect (res, TRUE))
+		    {
+		      res = xdr_uint32_t (xdrs, &objp->aticks);
+		      if (__builtin_expect (res, TRUE))
+			res = xdr_uint32_t (xdrs, &objp->cticks);
+		    }
+		}
+	    }
+	}
+    }
+  return res;
 }
+libnsl_hidden_def (_xdr_nis_result)
 
 bool_t
 _xdr_ns_request (XDR *xdrs, ns_request *objp)
 {
-  if (!_xdr_nis_name (xdrs, &objp->ns_name))
-    return FALSE;
-  if (!xdr_array (xdrs, (char **) &objp->ns_object.ns_object_val,
-		  (u_int *) &objp->ns_object.ns_object_len, 1,
-		  sizeof (nis_object), (xdrproc_t) _xdr_nis_object))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_nis_name (xdrs, &objp->ns_name);
+  if (__builtin_expect (res, TRUE))
+    res = xdr_array (xdrs, (char **) &objp->ns_object.ns_object_val,
+		     &objp->ns_object.ns_object_len, 1,
+		     sizeof (nis_object), (xdrproc_t) _xdr_nis_object);
+  return res;
 }
 
 bool_t
 _xdr_ib_request (XDR *xdrs, ib_request *objp)
 {
-  if (!_xdr_nis_name (xdrs, &objp->ibr_name))
-    return FALSE;
-  if (!xdr_array (xdrs, (char **) &objp->ibr_srch.ibr_srch_val,
-		  (u_int *) &objp->ibr_srch.ibr_srch_len, ~0,
-		  sizeof (nis_attr), (xdrproc_t) xdr_nis_attr))
-    return FALSE;
-  if (!xdr_u_int (xdrs, &objp->ibr_flags))
-    return FALSE;
-  if (!xdr_array (xdrs, (char **) &objp->ibr_obj.ibr_obj_val,
-		  (u_int *) &objp->ibr_obj.ibr_obj_len, 1,
-		  sizeof (nis_object), (xdrproc_t) _xdr_nis_object))
-    return FALSE;
-  if (!xdr_array (xdrs, (char **) &objp->ibr_cbhost.ibr_cbhost_val,
-		  (u_int *) &objp->ibr_cbhost.ibr_cbhost_len, 1,
-		  sizeof (nis_server), (xdrproc_t) _xdr_nis_server))
-    return FALSE;
-  if (!xdr_u_int (xdrs, &objp->ibr_bufsize))
-    return FALSE;
-  if (!xdr_netobj (xdrs, &objp->ibr_cookie))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_nis_name (xdrs, &objp->ibr_name);
+  if (__builtin_expect (res, TRUE))
+    {
+      res = xdr_array (xdrs, (char **) &objp->ibr_srch.ibr_srch_val,
+		       &objp->ibr_srch.ibr_srch_len, ~0,
+		       sizeof (nis_attr), (xdrproc_t) xdr_nis_attr);
+      if (__builtin_expect (res, TRUE))
+	{
+	  res = xdr_u_int (xdrs, &objp->ibr_flags);
+	  if (__builtin_expect (res, TRUE))
+	    {
+	      res = xdr_array (xdrs, (char **) &objp->ibr_obj.ibr_obj_val,
+			       &objp->ibr_obj.ibr_obj_len, 1,
+			       sizeof (nis_object),
+			       (xdrproc_t) _xdr_nis_object);
+	      if (__builtin_expect (res, TRUE))
+		{
+		  res = xdr_array (xdrs,
+				   (char **) &objp->ibr_cbhost.ibr_cbhost_val,
+				   &objp->ibr_cbhost.ibr_cbhost_len, 1,
+				   sizeof (nis_server),
+				   (xdrproc_t) _xdr_nis_server);
+		  if (__builtin_expect (res, TRUE))
+		    {
+		      res = xdr_u_int (xdrs, &objp->ibr_bufsize);
+		      if (__builtin_expect (res, TRUE))
+			res =  xdr_netobj (xdrs, &objp->ibr_cookie);
+		    }
+		}
+	    }
+	}
+    }
+  return res;
 }
+libnsl_hidden_def (_xdr_ib_request)
 
 bool_t
 _xdr_ping_args (XDR *xdrs, ping_args *objp)
 {
-  if (!_xdr_nis_name (xdrs, &objp->dir))
-    return FALSE;
-  if (!xdr_uint32_t (xdrs, &objp->stamp))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_nis_name (xdrs, &objp->dir);
+  if (__builtin_expect (res, TRUE))
+    res = xdr_uint32_t (xdrs, &objp->stamp);
+  return res;
 }
 
 bool_t
 _xdr_cp_result (XDR *xdrs, cp_result *objp)
 {
-  if (!_xdr_nis_error (xdrs, &objp->cp_status))
-    return FALSE;
-  if (!xdr_uint32_t (xdrs, &objp->cp_zticks))
-    return FALSE;
-  if (!xdr_uint32_t (xdrs, &objp->cp_dticks))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_nis_error (xdrs, &objp->cp_status);
+  if (__builtin_expect (res, TRUE))
+    {
+      res = xdr_uint32_t (xdrs, &objp->cp_zticks);
+      if (__builtin_expect (res, TRUE))
+	res = xdr_uint32_t (xdrs, &objp->cp_dticks);
+    }
+  return res;
 }
 
 bool_t
 _xdr_nis_tag (XDR *xdrs, nis_tag *objp)
 {
-  if (!xdr_u_int (xdrs, &objp->tag_type))
-    return FALSE;
-  if (!xdr_string (xdrs, &objp->tag_val, ~0))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_u_int (xdrs, &objp->tag_type);
+  if (__builtin_expect (res, TRUE))
+    res = xdr_string (xdrs, &objp->tag_val, ~0);
+  return res;
 }
 
 bool_t
 _xdr_nis_taglist (XDR *xdrs, nis_taglist *objp)
 {
-  if (!xdr_array (xdrs, (char **) &objp->tags.tags_val,
-		  (u_int *) &objp->tags.tags_len, ~0, sizeof (nis_tag),
-		  (xdrproc_t) _xdr_nis_tag))
-    return FALSE;
-  return TRUE;
+  return xdr_array (xdrs, (char **) &objp->tags.tags_val,
+		    &objp->tags.tags_len, ~0, sizeof (nis_tag),
+		    (xdrproc_t) _xdr_nis_tag);
 }
 
 bool_t
 _xdr_fd_args (XDR *xdrs, fd_args *objp)
 {
-  if (!_xdr_nis_name (xdrs, &objp->dir_name))
-    return FALSE;
-  if (!_xdr_nis_name (xdrs, &objp->requester))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_nis_name (xdrs, &objp->dir_name);
+  if (__builtin_expect (res, TRUE))
+    res = xdr_nis_name (xdrs, &objp->requester);
+  return res;
 }
 
 bool_t
 _xdr_fd_result (XDR *xdrs, fd_result *objp)
 {
-  if (!_xdr_nis_error (xdrs, &objp->status))
-    return FALSE;
-  if (!_xdr_nis_name (xdrs, &objp->source))
-    return FALSE;
-  if (!xdr_bytes (xdrs, (char **) &objp->dir_data.dir_data_val,
-		  (u_int *) &objp->dir_data.dir_data_len, ~0))
-    return FALSE;
-  if (!xdr_bytes (xdrs, (char **) &objp->signature.signature_val,
-		  (u_int *) &objp->signature.signature_len, ~0))
-    return FALSE;
-  return TRUE;
+  bool_t res = xdr_nis_error (xdrs, &objp->status);
+  if (__builtin_expect (res, TRUE))
+    {
+      res = xdr_nis_name (xdrs, &objp->source);
+      if (__builtin_expect (res, TRUE))
+	{
+	  res = xdr_bytes (xdrs, (char **) &objp->dir_data.dir_data_val,
+			   &objp->dir_data.dir_data_len, ~0);
+	  if (__builtin_expect (res, TRUE))
+	    res = xdr_bytes (xdrs, (char **) &objp->signature.signature_val,
+			     &objp->signature.signature_len, ~0);
+	}
+    }
+  return res;
 }
 
 /* The following functions have prototypes in nis_callback.h.  So
@@ -412,18 +444,16 @@ _xdr_fd_result (XDR *xdrs, fd_result *objp)
 bool_t
 xdr_obj_p (XDR *xdrs, obj_p *objp)
 {
-  if (!xdr_pointer (xdrs, (char **)objp, sizeof (nis_object),
-		    (xdrproc_t)_xdr_nis_object))
-    return FALSE;
-  return TRUE;
+  return xdr_pointer (xdrs, (char **)objp, sizeof (nis_object),
+		      (xdrproc_t)_xdr_nis_object);
 }
+libnsl_hidden_def (xdr_obj_p)
 
 bool_t
 xdr_cback_data (XDR *xdrs, cback_data *objp)
 {
-  if (!xdr_array (xdrs, (char **)&objp->entries.entries_val,
-		  (u_int *) &objp->entries.entries_len, ~0,
-		  sizeof (obj_p), (xdrproc_t) xdr_obj_p))
-    return FALSE;
-  return TRUE;
+  return xdr_array (xdrs, (char **)&objp->entries.entries_val,
+		    &objp->entries.entries_len, ~0,
+		    sizeof (obj_p), (xdrproc_t) xdr_obj_p);
 }
+libnsl_hidden_def (xdr_cback_data)
diff --git a/nis/nis_xdr.h b/nis/nis_xdr.h
index 2f1a179e0a..a59362c78f 100644
--- a/nis/nis_xdr.h
+++ b/nis/nis_xdr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998, 1999 Free Software Foundation, Inc.
+/* Copyright (c) 1998, 1999, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
 
@@ -22,24 +22,23 @@
 
 #include <features.h>
 
-__BEGIN_DECLS
+extern  bool_t _xdr_nis_attr (XDR *, nis_attr*) attribute_hidden;
+extern  bool_t _xdr_nis_name (XDR *, nis_name*) attribute_hidden;
+extern  bool_t _xdr_nis_server (XDR *, nis_server*) attribute_hidden;
+extern  bool_t _xdr_directory_obj (XDR *, directory_obj*) attribute_hidden;
+extern  bool_t _xdr_nis_object (XDR *, nis_object*) attribute_hidden;
+extern  bool_t _xdr_nis_error (XDR *, nis_error*) attribute_hidden;
+extern  bool_t _xdr_ns_request (XDR *, ns_request*) attribute_hidden;
+extern  bool_t _xdr_ping_args (XDR *, ping_args*) attribute_hidden;
+extern  bool_t _xdr_cp_result (XDR *, cp_result*) attribute_hidden;
+extern  bool_t _xdr_nis_tag (XDR *, nis_tag*) attribute_hidden;
+extern  bool_t _xdr_nis_taglist (XDR *, nis_taglist*) attribute_hidden;
+extern  bool_t _xdr_fd_args (XDR *, fd_args*) attribute_hidden;
+extern  bool_t _xdr_fd_result (XDR *, fd_result*) attribute_hidden;
 
-extern  bool_t _xdr_nis_attr (XDR *, nis_attr*);
-extern  bool_t _xdr_nis_name (XDR *, nis_name*);
-extern  bool_t _xdr_nis_server (XDR *, nis_server*);
-extern  bool_t _xdr_directory_obj (XDR *, directory_obj*);
-extern  bool_t _xdr_nis_object (XDR *, nis_object*);
-extern  bool_t _xdr_nis_error (XDR *, nis_error*);
-extern  bool_t _xdr_nis_result (XDR *, nis_result*);
-extern  bool_t _xdr_ns_request (XDR *, ns_request*);
 extern  bool_t _xdr_ib_request (XDR *, ib_request*);
-extern  bool_t _xdr_ping_args (XDR *, ping_args*);
-extern  bool_t _xdr_cp_result (XDR *, cp_result*);
-extern  bool_t _xdr_nis_tag (XDR *, nis_tag*);
-extern  bool_t _xdr_nis_taglist (XDR *, nis_taglist*);
-extern  bool_t _xdr_fd_args (XDR *, fd_args*);
-extern  bool_t _xdr_fd_result (XDR *, fd_result*);
-
-__END_DECLS
+libnsl_hidden_proto (_xdr_ib_request)
+extern  bool_t _xdr_nis_result (XDR *, nis_result*);
+libnsl_hidden_proto (_xdr_nis_result)
 
 #endif
diff --git a/nis/nisplus-parser.h b/nis/nisplus-parser.h
index f4b8d49596..4dc8db8c9f 100644
--- a/nis/nisplus-parser.h
+++ b/nis/nisplus-parser.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -24,15 +24,13 @@
 #include <grp.h>
 #include <shadow.h>
 
-extern int _nss_nisplus_parse_pwent (nis_result *, struct passwd *,
-				     char *, size_t, int *);
-extern int _nss_nisplus_parse_grent (nis_result *, u_long, struct group *,
-				     char *, size_t, int *);
-extern int _nss_nisplus_parse_spent (nis_result *, struct spwd *,
-				     char *, size_t, int *);
+extern int _nss_nisplus_parse_pwent (nis_result *result, struct passwd *pw,
+				     char *buffer, size_t buflen, int *errnop);
 
-libnss_nisplus_hidden_proto (_nss_nisplus_parse_pwent)
-libnss_nisplus_hidden_proto (_nss_nisplus_parse_grent)
-libnss_nisplus_hidden_proto (_nss_nisplus_parse_spent)
+extern int _nss_nisplus_parse_grent (nis_result *result, struct group *gr,
+				     char *buffer, size_t buflen, int *errnop);
+
+extern int _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp,
+				     char *buffer, size_t buflen, int *errnop);
 
 #endif
diff --git a/nis/nss b/nis/nss
index 4f65f81120..b7007a6bd4 100644
--- a/nis/nss
+++ b/nis/nss
@@ -1,7 +1,7 @@
 # /etc/default/nss
 # This file can theoretically contain a bunch of customization variables
-# for Name Service Switch in the GNU C library.  For now there are only two
-# variables:
+# for Name Service Switch in the GNU C library.  For now there are only
+# three variables:
 #
 # NETID_AUTHORITATIVE
 #   If set to TRUE, the initgroups() function will accept the information
@@ -18,3 +18,11 @@
 #   primary service names and service aliases.  The system administrator
 #   has to make sure it is correctly generated.
 #SERVICES_AUTHORITATIVE=TRUE
+#
+# SETENT_BATCH_READ
+#  If set to TRUE, various setXXent() functions will read the entire
+#  database at once and then hand out the requests one by one from
+#  memory with every getXXent() call.  Otherwise each getXXent() call
+#  might result into a network communication with the server to get
+#  the next entry.
+SETENT_BATCH_READ=TRUE
diff --git a/nis/nss-default.c b/nis/nss-default.c
new file mode 100644
index 0000000000..046ddfee8d
--- /dev/null
+++ b/nis/nss-default.c
@@ -0,0 +1,127 @@
+/* Copyright (C) 1996, 2001, 2004, 2006, 2007 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 Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <string.h>
+#include <bits/libc-lock.h>
+
+#include <libnsl.h>
+
+
+/* Path of the file.  */
+static const char default_nss[] = "/etc/default/nss";
+
+/* Flags once read from the file.  */
+static int default_nss_flags;
+
+/* Code to make sure we call 'init' once.  */
+__libc_once_define (static, once);
+
+/* Table of the recognized variables.  */
+static const struct
+{
+  char name[23];
+  unsigned int len;
+  int flag;
+} vars[] =
+  {
+#define STRNLEN(s) s, sizeof (s) - 1
+    { STRNLEN ("NETID_AUTHORITATIVE"), NSS_FLAG_NETID_AUTHORITATIVE },
+    { STRNLEN ("SERVICES_AUTHORITATIVE"), NSS_FLAG_SERVICES_AUTHORITATIVE },
+    { STRNLEN ("SETENT_BATCH_READ"), NSS_FLAG_SETENT_BATCH_READ }
+  };
+#define nvars (sizeof (vars) / sizeof (vars[0]))
+
+
+static void
+init (void)
+{
+  int saved_errno = errno;
+  FILE *fp = fopen (default_nss, "rc");
+  if (fp != NULL)
+    {
+      char *line = NULL;
+      size_t linelen = 0;
+
+      __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+      while (!feof_unlocked (fp))
+	{
+	  ssize_t n = getline (&line, &linelen, fp);
+	  if (n <= 0)
+	    break;
+
+	  /* Recognize only
+
+	       <THE-VARIABLE> = TRUE
+
+	     with arbitrary white spaces.  */
+	  char *cp = line;
+	  while (isspace (*cp))
+	    ++cp;
+
+	  /* Recognize comment lines.  */
+	  if (*cp == '#')
+	    continue;
+
+	  int idx;
+	  for (idx = 0; idx < nvars; ++idx)
+	    if (strncmp (cp, vars[idx].name, vars[idx].len) == 0)
+	      break;
+	  if (idx == nvars)
+	    continue;
+
+	  cp += vars[idx].len;
+	  while (isspace (*cp))
+	    ++cp;
+	  if (*cp++ != '=')
+	    continue;
+	  while (isspace (*cp))
+	    ++cp;
+
+	  if (strncmp (cp, "TRUE", 4) != 0)
+	    continue;
+	  cp += 4;
+
+	  while (isspace (*cp))
+	    ++cp;
+
+	  if (*cp == '\0')
+	    default_nss_flags |= vars[idx].flag;
+	}
+
+      free (line);
+
+      fclose (fp);
+    }
+  __set_errno (saved_errno);
+}
+
+
+int
+_nsl_default_nss (void)
+{
+  /* If we have not yet read the file yet do it now.  */
+  __libc_once (once, init);
+
+  return default_nss_flags;
+}
diff --git a/nis/nss-nis.c b/nis/nss-nis.c
index 40370bae3b..cff1e765bb 100644
--- a/nis/nss-nis.c
+++ b/nis/nss-nis.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 2001, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 2001, 2004, 2006 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
@@ -16,13 +16,6 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#include <ctype.h>
-#include <stdio.h>
-#include <stdio_ext.h>
-#include <stdlib.h>
-#include <string.h>
-#include <rpcsvc/ypclnt.h>
-
 #include "nss-nis.h"
 #include "nsswitch.h"
 
@@ -50,81 +43,3 @@ const enum nss_status __yperr2nss_tab[] =
 };
 const unsigned int __yperr2nss_count = (sizeof (__yperr2nss_tab)
 				        / sizeof (__yperr2nss_tab[0]));
-
-int _nis_default_nss_flags;
-
-static const char default_nss[] = "/etc/default/nss";
-
-int
-_nis_check_default_nss (void)
-{
-  FILE *fp = fopen (default_nss, "rc");
-  int flags = NSS_FLAG_SET;
-  if (fp != NULL)
-    {
-      char *line = NULL;
-      size_t linelen = 0;
-
-      __fsetlocking (fp, FSETLOCKING_BYCALLER);
-
-      while (!feof_unlocked (fp))
-	{
-	  ssize_t n = getline (&line, &linelen, fp);
-	  if (n <= 0)
-	    break;
-
-	  /* There currently are only two variables we expect, so
-	     simplify the parsing.  Recognize only
-
-	       NETID_AUTHORITATIVE = TRUE
-	       SERVICES_AUTHORITATIVE = TRUE
-
-	     with arbitrary white spaces.  */
-	  char *cp = line;
-	  while (isspace (*cp))
-	    ++cp;
-
-	  /* Recognize comment lines.  */
-	  if (*cp == '#')
-	    continue;
-
-	  static const char netid_authoritative[] = "NETID_AUTHORITATIVE";
-	  static const char services_authoritative[]
-	    = "SERVICES_AUTHORITATIVE";
-	  size_t flag_len;
-	  if (strncmp (cp, netid_authoritative,
-		       flag_len = sizeof (netid_authoritative) - 1) != 0
-	      && strncmp (cp, services_authoritative,
-			  flag_len = sizeof (services_authoritative) - 1)
-		 != 0)
-	    continue;
-
-	  cp += flag_len;
-	  while (isspace (*cp))
-	    ++cp;
-	  if (*cp++ != '=')
-	    continue;
-	  while (isspace (*cp))
-	    ++cp;
-
-	  if (strncmp (cp, "TRUE", 4) != 0)
-	    continue;
-	  cp += 4;
-
-	  while (isspace (*cp))
-	    ++cp;
-
-	  if (*cp == '\0')
-	    flags |= flag_len == sizeof (netid_authoritative) - 1
-		     ? NSS_FLAG_NETID_AUTHORITATIVE
-		     : NSS_FLAG_SERVICES_AUTHORITATIVE;
-	}
-
-      free (line);
-
-      fclose (fp);
-    }
-
-  _nis_default_nss_flags = flags;
-  return flags;
-}
diff --git a/nis/nss-nis.h b/nis/nss-nis.h
index 659b3a14aa..a02583d14c 100644
--- a/nis/nss-nis.h
+++ b/nis/nss-nis.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 2004, 2006 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
@@ -25,8 +25,8 @@
 
 
 /* Convert YP error number to NSS error number.  */
-extern const enum nss_status __yperr2nss_tab[];
-extern const unsigned int __yperr2nss_count;
+extern const enum nss_status __yperr2nss_tab[] attribute_hidden;
+extern const unsigned int __yperr2nss_count attribute_hidden;
 
 static inline enum nss_status
 yperr2nss (int errval)
@@ -36,16 +36,24 @@ yperr2nss (int errval)
   return __yperr2nss_tab[(unsigned int) errval];
 }
 
-#define NSS_FLAG_SET			1
-#define NSS_FLAG_NETID_AUTHORITATIVE	2
-#define NSS_FLAG_SERVICES_AUTHORITATIVE	4
-extern int _nis_default_nss_flags attribute_hidden;
-extern int _nis_check_default_nss (void) attribute_hidden;
 
-extern inline __attribute__((always_inline)) int
-_nis_default_nss (void)
+struct response_t
 {
-  return _nis_default_nss_flags ?: _nis_check_default_nss ();
-}
+  struct response_t *next;
+  size_t size;
+  char mem[0];
+};
+
+typedef struct intern_t
+{
+  struct response_t *start;
+  struct response_t *next;
+  size_t offset;
+} intern_t;
+
+
+extern int _nis_saveit (int instatus, char *inkey, int inkeylen, char *inval,
+			int invallen, char *indata) attribute_hidden;
+
 
 #endif /* nis/nss-nis.h */
diff --git a/nis/nss-nisplus.h b/nis/nss-nisplus.h
index 7235c355b0..ad7f444440 100644
--- a/nis/nss-nisplus.h
+++ b/nis/nss-nisplus.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1997.
 
@@ -26,8 +26,8 @@
 
 
 /* Convert NIS+ error number to NSS error number.  */
-extern const enum nss_status __niserr2nss_tab[];
-extern const unsigned int __niserr2nss_count;
+extern const enum nss_status __niserr2nss_tab[] attribute_hidden;
+extern const unsigned int __niserr2nss_count attribute_hidden;
 
 static inline enum nss_status
 niserr2nss (int errval)
diff --git a/nis/nss_compat/compat-grp.c b/nis/nss_compat/compat-grp.c
index 08bf5d2f80..236c84a20f 100644
--- a/nis/nss_compat/compat-grp.c
+++ b/nis/nss_compat/compat-grp.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-1999,2001,2002,2003,2004 Free Software Foundation, Inc.
+/* Copyright (C) 1996-1999,2001-2005,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
 
@@ -59,12 +59,13 @@ struct blacklist_t
 struct ent_t
 {
   bool_t files;
+  enum nss_status setent_status;
   FILE *stream;
   struct blacklist_t blacklist;
 };
 typedef struct ent_t ent_t;
 
-static ent_t ext_ent = {TRUE, NULL, {NULL, 0, 0}};
+static ent_t ext_ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }};
 
 /* Protect global state against multiple changers.  */
 __libc_lock_define_initialized (static, lock)
@@ -89,7 +90,7 @@ init_nss_interface (void)
 }
 
 static enum nss_status
-internal_setgrent (ent_t *ent, int stayopen)
+internal_setgrent (ent_t *ent, int stayopen, int needent)
 {
   enum nss_status status = NSS_STATUS_SUCCESS;
 
@@ -137,8 +138,8 @@ internal_setgrent (ent_t *ent, int stayopen)
   else
     rewind (ent->stream);
 
-  if (status == NSS_STATUS_SUCCESS && nss_setgrent)
-    return nss_setgrent (stayopen);
+  if (needent && status == NSS_STATUS_SUCCESS && nss_setgrent)
+    ent->setent_status = nss_setgrent (stayopen);
 
   return status;
 }
@@ -154,7 +155,7 @@ _nss_compat_setgrent (int stayopen)
   if (ni == NULL)
     init_nss_interface ();
 
-  result = internal_setgrent (&ext_ent, stayopen);
+  result = internal_setgrent (&ext_ent, stayopen, 1);
 
   __libc_lock_unlock (lock);
 
@@ -208,6 +209,10 @@ getgrent_next_nss (struct group *result, ent_t *ent, char *buffer,
   if (!nss_getgrent_r)
     return NSS_STATUS_UNAVAIL;
 
+  /* If the setgrent call failed, say so.  */
+  if (ent->setent_status != NSS_STATUS_SUCCESS)
+    return ent->setent_status;
+
   do
     {
       enum nss_status status;
@@ -229,9 +234,10 @@ getgrnam_plusgroup (const char *name, struct group *result, ent_t *ent,
   if (!nss_getgrnam_r)
     return NSS_STATUS_UNAVAIL;
 
-  if (nss_getgrnam_r (name, result, buffer, buflen, errnop) !=
-      NSS_STATUS_SUCCESS)
-    return NSS_STATUS_NOTFOUND;
+  enum nss_status status = nss_getgrnam_r (name, result, buffer, buflen,
+					   errnop);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
 
   if (in_blacklist (result->gr_name, strlen (result->gr_name), ent))
     return NSS_STATUS_NOTFOUND;
@@ -358,7 +364,7 @@ _nss_compat_getgrent_r (struct group *grp, char *buffer, size_t buflen,
     init_nss_interface ();
 
   if (ext_ent.stream == NULL)
-    result = internal_setgrent (&ext_ent, 1);
+    result = internal_setgrent (&ext_ent, 1, 1);
 
   if (result == NSS_STATUS_SUCCESS)
     {
@@ -480,7 +486,7 @@ enum nss_status
 _nss_compat_getgrnam_r (const char *name, struct group *grp,
 			char *buffer, size_t buflen, int *errnop)
 {
-  ent_t ent = {TRUE, NULL, {NULL, 0, 0}};
+  ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }};
   enum nss_status result;
 
   if (name[0] == '-' || name[0] == '+')
@@ -493,7 +499,7 @@ _nss_compat_getgrnam_r (const char *name, struct group *grp,
 
   __libc_lock_unlock (lock);
 
-  result = internal_setgrent (&ent, 0);
+  result = internal_setgrent (&ent, 0, 0);
 
   if (result == NSS_STATUS_SUCCESS)
     result = internal_getgrnam_r (name, grp, &ent, buffer, buflen, errnop);
@@ -551,7 +557,7 @@ internal_getgrgid_r (gid_t gid, struct group *result, ent_t *ent,
 	     !(parse_res = _nss_files_parse_grent (p, result, data, buflen,
 						   errnop)));
 
-      if (parse_res == -1)
+      if (__builtin_expect (parse_res == -1, 0))
 	/* The parser ran out of space.  */
 	goto erange_reset;
 
@@ -574,13 +580,17 @@ internal_getgrgid_r (gid_t gid, struct group *result, ent_t *ent,
       /* +group */
       if (result->gr_name[0] == '+' && result->gr_name[1] != '\0')
 	{
+	  /* Yes, no +1, see the memcpy call below.  */
+	  size_t len = strlen (result->gr_name);
+	  char buf[len];
 	  enum nss_status status;
 
 	  /* Store the group in the blacklist for the "+" at the end of
 	     /etc/group */
-	  blacklist_store_name (&result->gr_name[1], ent);
+	  memcpy (buf, &result->gr_name[1], len);
 	  status = getgrnam_plusgroup (&result->gr_name[1], result, ent,
 				       buffer, buflen, errnop);
+	  blacklist_store_name (buf, ent);
 	  if (status == NSS_STATUS_SUCCESS && result->gr_gid == gid)
 	    break;
 	  else
@@ -589,9 +599,11 @@ internal_getgrgid_r (gid_t gid, struct group *result, ent_t *ent,
       /* +:... */
       if (result->gr_name[0] == '+' && result->gr_name[1] == '\0')
 	{
-	  enum nss_status status;
+	  if (!nss_getgrgid_r)
+	    return NSS_STATUS_UNAVAIL;
 
-	  status = nss_getgrgid_r (gid, result, buffer, buflen, errnop);
+	  enum nss_status status = nss_getgrgid_r (gid, result, buffer, buflen,
+						   errnop);
 	  if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
 	    return NSS_STATUS_NOTFOUND;
 	  else
@@ -606,7 +618,7 @@ enum nss_status
 _nss_compat_getgrgid_r (gid_t gid, struct group *grp,
 			char *buffer, size_t buflen, int *errnop)
 {
-  ent_t ent = {TRUE, NULL, {NULL, 0, 0}};
+  ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }};
   enum nss_status result;
 
   __libc_lock_lock (lock);
@@ -616,7 +628,7 @@ _nss_compat_getgrgid_r (gid_t gid, struct group *grp,
 
   __libc_lock_unlock (lock);
 
-  result = internal_setgrent (&ent, 0);
+  result = internal_setgrent (&ent, 0, 0);
 
   if (result == NSS_STATUS_SUCCESS)
     result = internal_getgrgid_r (gid, grp, &ent, buffer, buflen, errnop);
diff --git a/nis/nss_compat/compat-initgroups.c b/nis/nss_compat/compat-initgroups.c
index 9574ea7c0b..70403a0785 100644
--- a/nis/nss_compat/compat-initgroups.c
+++ b/nis/nss_compat/compat-initgroups.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998-2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1998-2003, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
 
@@ -36,7 +36,6 @@ static service_user *ni;
 static enum nss_status (*nss_initgroups_dyn) (const char *, gid_t,
 					      long int *, long int *,
 					      gid_t **, long int, int *);
-static enum nss_status (*nss_setgrent) (int stayopen);
 static enum nss_status (*nss_getgrnam_r) (const char *name,
 					  struct group * grp, char *buffer,
 					  size_t buflen, int *errnop);
@@ -45,7 +44,6 @@ static enum nss_status (*nss_getgrgid_r) (gid_t gid, struct group * grp,
 					  int *errnop);
 static enum nss_status (*nss_getgrent_r) (struct group * grp, char *buffer,
 					  size_t buflen, int *errnop);
-static enum nss_status (*nss_endgrent) (void);
 
 /* Protect global state against multiple changers.  */
 __libc_lock_define_initialized (static, lock)
@@ -92,11 +90,9 @@ init_nss_interface (void)
       && __nss_database_lookup ("group_compat", NULL, "nis", &ni) >= 0)
     {
       nss_initgroups_dyn = __nss_lookup_function (ni, "initgroups_dyn");
-      nss_setgrent = __nss_lookup_function (ni, "setgrent");
       nss_getgrnam_r = __nss_lookup_function (ni, "getgrnam_r");
       nss_getgrgid_r = __nss_lookup_function (ni, "getgrgid_r");
       nss_getgrent_r = __nss_lookup_function (ni, "getgrent_r");
-      nss_endgrent = __nss_lookup_function (ni, "endgrent");
     }
 
   __libc_lock_unlock (lock);
diff --git a/nis/nss_compat/compat-pwd.c b/nis/nss_compat/compat-pwd.c
index 89a6a7013e..ac132046da 100644
--- a/nis/nss_compat/compat-pwd.c
+++ b/nis/nss_compat/compat-pwd.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-1999,2001,2002,2003,2004 Free Software Foundation, Inc.
+/* Copyright (C) 1996-1999,2001-2005,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
 
@@ -62,9 +62,10 @@ struct blacklist_t
 
 struct ent_t
 {
-  bool_t netgroup;
-  bool_t first;
-  bool_t files;
+  bool netgroup;
+  bool first;
+  bool files;
+  enum nss_status setent_status;
   FILE *stream;
   struct blacklist_t blacklist;
   struct passwd pwd;
@@ -72,8 +73,9 @@ struct ent_t
 };
 typedef struct ent_t ent_t;
 
-static ent_t ext_ent = {0, 0, TRUE, NULL, {NULL, 0, 0},
-                        {NULL, NULL, 0, 0, NULL, NULL, NULL}};
+static ent_t ext_ent = { false, false, true, NSS_STATUS_SUCCESS, NULL,
+			 { NULL, 0, 0 },
+			 { NULL, NULL, 0, 0, NULL, NULL, NULL }};
 
 /* Protect global state against multiple changers.  */
 __libc_lock_define_initialized (static, lock)
@@ -202,12 +204,13 @@ copy_pwd_changes (struct passwd *dest, struct passwd *src,
 }
 
 static enum nss_status
-internal_setpwent (ent_t *ent, int stayopen)
+internal_setpwent (ent_t *ent, int stayopen, int needent)
 {
   enum nss_status status = NSS_STATUS_SUCCESS;
 
-  ent->first = ent->netgroup = FALSE;
-  ent->files = TRUE;
+  ent->first = ent->netgroup = false;
+  ent->files = true;
+  ent->setent_status = NSS_STATUS_SUCCESS;
 
   /* If something was left over free it.  */
   if (ent->netgroup)
@@ -257,8 +260,8 @@ internal_setpwent (ent_t *ent, int stayopen)
 
   give_pwd_free (&ent->pwd);
 
-  if (status == NSS_STATUS_SUCCESS && nss_setpwent)
-    return nss_setpwent (stayopen);
+  if (needent && status == NSS_STATUS_SUCCESS && nss_setpwent)
+    ent->setent_status = nss_setpwent (stayopen);
 
   return status;
 }
@@ -274,7 +277,7 @@ _nss_compat_setpwent (int stayopen)
   if (ni == NULL)
     init_nss_interface ();
 
-  result = internal_setpwent (&ext_ent, stayopen);
+  result = internal_setpwent (&ext_ent, stayopen, 1);
 
   __libc_lock_unlock (lock);
 
@@ -297,7 +300,7 @@ internal_endpwent (ent_t *ent)
   if (ent->netgroup)
     __internal_endnetgrent (&ent->netgrdata);
 
-  ent->first = ent->netgroup = FALSE;
+  ent->first = ent->netgroup = false;
 
   if (ent->blacklist.data != NULL)
     {
@@ -344,17 +347,17 @@ getpwent_next_nss_netgr (const char *name, struct passwd *result, ent_t *ent,
 
   if (yp_get_default_domain (&curdomain) != YPERR_SUCCESS)
     {
-      ent->netgroup = FALSE;
-      ent->first = FALSE;
+      ent->netgroup = false;
+      ent->first = false;
       give_pwd_free (&ent->pwd);
       return NSS_STATUS_UNAVAIL;
     }
 
-  if (ent->first == TRUE)
+  if (ent->first == true)
     {
       memset (&ent->netgrdata, 0, sizeof (struct __netgrent));
       __internal_setnetgrent (group, &ent->netgrdata);
-      ent->first = FALSE;
+      ent->first = false;
     }
 
   while (1)
@@ -423,6 +426,10 @@ getpwent_next_nss (struct passwd *result, ent_t *ent, char *buffer,
   if (!nss_getpwent_r)
     return NSS_STATUS_UNAVAIL;
 
+  /* If the setpwent call failed, say so.  */
+  if (ent->setent_status != NSS_STATUS_SUCCESS)
+    return ent->setent_status;
+
   p2len = pwd_need_buflen (&ent->pwd);
   if (p2len > buflen)
     {
@@ -433,7 +440,7 @@ getpwent_next_nss (struct passwd *result, ent_t *ent, char *buffer,
   buflen -= p2len;
 
   if (ent->first)
-    ent->first = FALSE;
+    ent->first = false;
 
   do
     {
@@ -453,29 +460,27 @@ static enum nss_status
 getpwnam_plususer (const char *name, struct passwd *result, ent_t *ent,
 		   char *buffer, size_t buflen, int *errnop)
 {
-  struct passwd pwd;
-  char *p;
-  size_t plen;
-
   if (!nss_getpwnam_r)
     return NSS_STATUS_UNAVAIL;
 
+  struct passwd pwd;
   memset (&pwd, '\0', sizeof (struct passwd));
 
   copy_pwd_changes (&pwd, result, NULL, 0);
 
-  plen = pwd_need_buflen (&pwd);
+  size_t plen = pwd_need_buflen (&pwd);
   if (plen > buflen)
     {
       *errnop = ERANGE;
       return NSS_STATUS_TRYAGAIN;
     }
-  p = buffer + (buflen - plen);
+  char *p = buffer + (buflen - plen);
   buflen -= plen;
 
-  if (nss_getpwnam_r (name, result, buffer, buflen, errnop) !=
-      NSS_STATUS_SUCCESS)
-    return NSS_STATUS_NOTFOUND;
+  enum nss_status status = nss_getpwnam_r (name, result, buffer, buflen,
+					   errnop);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
 
   if (in_blacklist (result->pw_name, strlen (result->pw_name), ent))
     return NSS_STATUS_NOTFOUND;
@@ -568,8 +573,8 @@ getpwent_next_file (struct passwd *result, ent_t *ent,
 	{
 	  enum nss_status status;
 
-	  ent->netgroup = TRUE;
-	  ent->first = TRUE;
+	  ent->netgroup = true;
+	  ent->first = true;
 	  copy_pwd_changes (&ent->pwd, result, NULL, 0);
 
 	  status = getpwent_next_nss_netgr (NULL, result, ent,
@@ -624,8 +629,8 @@ getpwent_next_file (struct passwd *result, ent_t *ent,
       /* +:... */
       if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
 	{
-	  ent->files = FALSE;
-	  ent->first = TRUE;
+	  ent->files = false;
+	  ent->first = true;
 	  copy_pwd_changes (&ent->pwd, result, NULL, 0);
 
 	  return getpwent_next_nss (result, ent, buffer, buflen, errnop);
@@ -673,7 +678,7 @@ _nss_compat_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen,
     init_nss_interface ();
 
   if (ext_ent.stream == NULL)
-    result = internal_setpwent (&ext_ent, 1);
+    result = internal_setpwent (&ext_ent, 1, 1);
 
   if (result == NSS_STATUS_SUCCESS)
     result = internal_getpwent_r (pwd, &ext_ent, buffer, buflen, errnop);
@@ -825,8 +830,8 @@ _nss_compat_getpwnam_r (const char *name, struct passwd *pwd,
 			char *buffer, size_t buflen, int *errnop)
 {
   enum nss_status result;
-  ent_t ent = {0, 0, TRUE, NULL, {NULL, 0, 0},
-               {NULL, NULL, 0, 0, NULL, NULL, NULL}};
+  ent_t ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 },
+		{ NULL, NULL, 0, 0, NULL, NULL, NULL }};
 
   if (name[0] == '-' || name[0] == '+')
     return NSS_STATUS_NOTFOUND;
@@ -838,7 +843,7 @@ _nss_compat_getpwnam_r (const char *name, struct passwd *pwd,
 
   __libc_lock_unlock (lock);
 
-  result = internal_setpwent (&ent, 0);
+  result = internal_setpwent (&ent, 0, 0);
 
   if (result == NSS_STATUS_SUCCESS)
     result = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop);
@@ -1067,8 +1072,8 @@ _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd,
 			char *buffer, size_t buflen, int *errnop)
 {
   enum nss_status result;
-  ent_t ent = {0, 0, TRUE, NULL, {NULL, 0, 0},
-               {NULL, NULL, 0, 0, NULL, NULL, NULL}};
+  ent_t ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 },
+		{ NULL, NULL, 0, 0, NULL, NULL, NULL }};
 
   __libc_lock_lock (lock);
 
@@ -1077,7 +1082,7 @@ _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd,
 
   __libc_lock_unlock (lock);
 
-  result = internal_setpwent (&ent, 0);
+  result = internal_setpwent (&ent, 0, 0);
 
   if (result == NSS_STATUS_SUCCESS)
     result = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop);
@@ -1134,7 +1139,7 @@ blacklist_store_name (const char *name, ent_t *ent)
   return;
 }
 
-/* returns TRUE if ent->blacklist contains name, else FALSE */
+/* Returns TRUE if ent->blacklist contains name, else FALSE.  */
 static bool_t
 in_blacklist (const char *name, int namelen, ent_t *ent)
 {
diff --git a/nis/nss_compat/compat-spwd.c b/nis/nss_compat/compat-spwd.c
index 4ca6368139..d1de3f75b0 100644
--- a/nis/nss_compat/compat-spwd.c
+++ b/nis/nss_compat/compat-spwd.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-1999,2001,2002,2003,2004 Free Software Foundation, Inc.
+/* Copyright (C) 1996-1999,2001-2005,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
 
@@ -59,9 +59,10 @@ struct blacklist_t
 
 struct ent_t
 {
-  bool_t netgroup;
-  bool_t files;
-  bool_t first;
+  bool netgroup;
+  bool files;
+  bool first;
+  enum nss_status setent_status;
   FILE *stream;
   struct blacklist_t blacklist;
   struct spwd pwd;
@@ -69,8 +70,9 @@ struct ent_t
 };
 typedef struct ent_t ent_t;
 
-static ent_t ext_ent = {0, TRUE, 0, NULL, {NULL, 0, 0},
-			{NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
+static ent_t ext_ent = { false, true, false, NSS_STATUS_SUCCESS, NULL,
+			 { NULL, 0, 0},
+			 { NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
 
 /* Protect global state against multiple changers.  */
 __libc_lock_define_initialized (static, lock)
@@ -161,7 +163,7 @@ internal_setspent (ent_t *ent, int stayopen)
   enum nss_status status = NSS_STATUS_SUCCESS;
 
   ent->first = ent->netgroup = 0;
-  ent->files = TRUE;
+  ent->files = true;
 
   /* If something was left over free it.  */
   if (ent->netgroup)
@@ -212,7 +214,7 @@ internal_setspent (ent_t *ent, int stayopen)
   give_spwd_free (&ent->pwd);
 
   if (status == NSS_STATUS_SUCCESS && nss_setspent)
-    return nss_setspent (stayopen);
+    ent->setent_status = nss_setspent (stayopen);
 
   return status;
 }
@@ -251,8 +253,8 @@ internal_endspent (ent_t *ent)
   if (ent->netgroup)
     __internal_endnetgrent (&ent->netgrdata);
 
-  ent->first = ent->netgroup = FALSE;
-  ent->files = TRUE;
+  ent->first = ent->netgroup = false;
+  ent->files = true;
 
   if (ent->blacklist.data != NULL)
     {
@@ -294,19 +296,23 @@ getspent_next_nss_netgr (const char *name, struct spwd *result, ent_t *ent,
   if (!nss_getspnam_r)
     return NSS_STATUS_UNAVAIL;
 
+  /* If the setpwent call failed, say so.  */
+  if (ent->setent_status != NSS_STATUS_SUCCESS)
+    return ent->setent_status;
+
   if (yp_get_default_domain (&curdomain) != YPERR_SUCCESS)
     {
-      ent->netgroup = FALSE;
-      ent->first = FALSE;
+      ent->netgroup = false;
+      ent->first = false;
       give_spwd_free (&ent->pwd);
       return NSS_STATUS_UNAVAIL;
     }
 
-  if (ent->first == TRUE)
+  if (ent->first == true)
     {
       memset (&ent->netgrdata, 0, sizeof (struct __netgrent));
       __internal_setnetgrent (group, &ent->netgrdata);
-      ent->first = FALSE;
+      ent->first = false;
     }
 
   while (1)
@@ -321,7 +327,7 @@ getspent_next_nss_netgr (const char *name, struct spwd *result, ent_t *ent,
       if (status != 1)
 	{
 	  __internal_endnetgrent (&ent->netgrdata);
-	  ent->netgroup = FALSE;
+	  ent->netgroup = false;
 	  give_spwd_free (&ent->pwd);
 	  return NSS_STATUS_RETURN;
 	}
@@ -396,18 +402,16 @@ getspent_next_nss (struct spwd *result, ent_t *ent,
   return NSS_STATUS_SUCCESS;
 }
 
+
 /* This function handle the +user entrys in /etc/shadow */
 static enum nss_status
 getspnam_plususer (const char *name, struct spwd *result, ent_t *ent,
 		   char *buffer, size_t buflen, int *errnop)
 {
-  struct spwd pwd;
-  char *p;
-  size_t plen;
-
   if (!nss_getspnam_r)
     return NSS_STATUS_UNAVAIL;
 
+  struct spwd pwd;
   memset (&pwd, '\0', sizeof (struct spwd));
   pwd.sp_warn = -1;
   pwd.sp_inact = -1;
@@ -416,18 +420,19 @@ getspnam_plususer (const char *name, struct spwd *result, ent_t *ent,
 
   copy_spwd_changes (&pwd, result, NULL, 0);
 
-  plen = spwd_need_buflen (&pwd);
+  size_t plen = spwd_need_buflen (&pwd);
   if (plen > buflen)
     {
       *errnop = ERANGE;
       return NSS_STATUS_TRYAGAIN;
     }
-  p = buffer + (buflen - plen);
+  char *p = buffer + (buflen - plen);
   buflen -= plen;
 
-  if (nss_getspnam_r (name, result, buffer, buflen, errnop) !=
-      NSS_STATUS_SUCCESS)
-    return NSS_STATUS_NOTFOUND;
+  enum nss_status status = nss_getspnam_r (name, result, buffer, buflen,
+					   errnop);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
 
   if (in_blacklist (result->sp_namp, strlen (result->sp_namp), ent))
     return NSS_STATUS_NOTFOUND;
@@ -438,6 +443,7 @@ getspnam_plususer (const char *name, struct spwd *result, ent_t *ent,
   return NSS_STATUS_SUCCESS;
 }
 
+
 static enum nss_status
 getspent_next_file (struct spwd *result, ent_t *ent,
 		    char *buffer, size_t buflen, int *errnop)
@@ -518,8 +524,8 @@ getspent_next_file (struct spwd *result, ent_t *ent,
 	{
 	  int status;
 
-	  ent->netgroup = TRUE;
-	  ent->first = TRUE;
+	  ent->netgroup = true;
+	  ent->first = true;
 	  copy_spwd_changes (&ent->pwd, result, NULL, 0);
 
 	  status = getspent_next_nss_netgr (NULL, result, ent,
@@ -575,8 +581,8 @@ getspent_next_file (struct spwd *result, ent_t *ent,
       /* +:... */
       if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0')
 	{
-	  ent->files = FALSE;
-	  ent->first = TRUE;
+	  ent->files = false;
+	  ent->first = true;
 	  copy_spwd_changes (&ent->pwd, result, NULL, 0);
 
 	  return getspent_next_nss (result, ent, buffer, buflen, errnop);
@@ -611,6 +617,7 @@ internal_getspent_r (struct spwd *pw, ent_t *ent,
     return getspent_next_nss (pw, ent, buffer, buflen, errnop);
 }
 
+
 enum nss_status
 _nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen,
 			int *errnop)
@@ -634,6 +641,7 @@ _nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen,
   return result;
 }
 
+
 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
 static enum nss_status
 internal_getspnam_r (const char *name, struct spwd *result, ent_t *ent,
@@ -776,13 +784,14 @@ internal_getspnam_r (const char *name, struct spwd *result, ent_t *ent,
   return NSS_STATUS_SUCCESS;
 }
 
+
 enum nss_status
 _nss_compat_getspnam_r (const char *name, struct spwd *pwd,
 			char *buffer, size_t buflen, int *errnop)
 {
   enum nss_status result;
-  ent_t ent = {0, TRUE, 0, NULL, {NULL, 0, 0},
-	       {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
+  ent_t ent = { false, true, false, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0},
+		{ NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
 
   if (name[0] == '-' || name[0] == '+')
     return NSS_STATUS_NOTFOUND;
@@ -804,6 +813,7 @@ _nss_compat_getspnam_r (const char *name, struct spwd *pwd,
   return result;
 }
 
+
 /* Support routines for remembering -@netgroup and -user entries.
    The names are stored in a single string with `|' as separator. */
 static void
@@ -850,6 +860,7 @@ blacklist_store_name (const char *name, ent_t *ent)
   return;
 }
 
+
 /* Returns TRUE if ent->blacklist contains name, else FALSE.  */
 static bool_t
 in_blacklist (const char *name, int namelen, ent_t *ent)
@@ -858,7 +869,7 @@ in_blacklist (const char *name, int namelen, ent_t *ent)
   char *cp;
 
   if (ent->blacklist.data == NULL)
-    return FALSE;
+    return false;
 
   buf[0] = '|';
   cp = stpcpy (&buf[1], name);
diff --git a/nis/nss_nis/nis-alias.c b/nis/nss_nis/nis-alias.c
index 3b0887be04..9286e36ba6 100644
--- a/nis/nss_nis/nis-alias.c
+++ b/nis/nss_nis/nis-alias.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2002, 2003, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
 
@@ -125,52 +125,53 @@ internal_nis_getaliasent_r (struct aliasent *alias, char *buffer,
 			    size_t buflen, int *errnop)
 {
   char *domain;
-  char *result;
-  int len;
-  char *outkey;
-  int keylen;
-  char *p;
-  int parse_res;
 
-  if (yp_get_default_domain (&domain))
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
   alias->alias_local = 0;
 
   /* Get the next entry until we found a correct one. */
+  int parse_res;
   do
     {
-      enum nss_status retval;
+      char *result;
+      int len;
+      char *outkey;
+      int keylen;
+      int yperr;
 
       if (new_start)
-        retval = yperr2nss (yp_first (domain, "mail.aliases",
-				      &outkey, &keylen, &result, &len));
+        yperr = yp_first (domain, "mail.aliases", &outkey, &keylen, &result,
+			  &len);
       else
-        retval = yperr2nss ( yp_next (domain, "mail.aliases", oldkey,
-				      oldkeylen, &outkey, &keylen,
-				      &result, &len));
-      if (retval != NSS_STATUS_SUCCESS)
+        yperr = yp_next (domain, "mail.aliases", oldkey, oldkeylen, &outkey,
+			 &keylen, &result, &len);
+
+      if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
 	{
+	  enum nss_status retval = yperr2nss (yperr);
+
 	  if (retval == NSS_STATUS_TRYAGAIN)
             *errnop = errno;
           return retval;
         }
 
-      if ((size_t) (len + 1) > buflen)
+      if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
         {
 	  free (result);
           *errnop = ERANGE;
           return NSS_STATUS_TRYAGAIN;
         }
-      p = strncpy (buffer, result, len);
+      char *p = strncpy (buffer, result, len);
       buffer[len] = '\0';
       while (isspace (*p))
         ++p;
       free (result);
 
-      parse_res = _nss_nis_parse_aliasent (outkey, p, alias, buffer, buflen,
-					   errnop);
-      if (parse_res == -1)
+      parse_res = _nss_nis_parse_aliasent (outkey, p, alias, buffer,
+					   buflen, errnop);
+      if (__builtin_expect (parse_res == -1, 0))
 	{
 	  free (outkey);
 	  *errnop = ERANGE;
@@ -206,56 +207,55 @@ enum nss_status
 _nss_nis_getaliasbyname_r (const char *name, struct aliasent *alias,
 			   char *buffer, size_t buflen, int *errnop)
 {
-  enum nss_status retval;
-  int parse_res;
-  char *domain;
-  char *result;
-  int len;
-  char *p;
-  size_t namlen = strlen (name);
-  char name2[namlen + 1];
-  size_t i;
-
   if (name == NULL)
     {
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
 
-  if (yp_get_default_domain (&domain))
+  size_t namlen = strlen (name);
+  char name2[namlen + 1];
+
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
   /* Convert name to lowercase.  */
+  size_t i;
   for (i = 0; i < namlen; ++i)
     name2[i] = _tolower (name[i]);
   name2[i] = '\0';
 
-  retval = yperr2nss (yp_match (domain, "mail.aliases", name2, namlen,
-				&result, &len));
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "mail.aliases", name2, namlen, &result, &len);
 
-  if (retval != NSS_STATUS_SUCCESS)
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
 	*errnop = errno;
       return retval;
     }
 
-  if ((size_t) (len + 1) > buflen)
+  if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
     {
       free (result);
       *errnop = ERANGE;
       return NSS_STATUS_TRYAGAIN;
     }
 
-  p = strncpy (buffer, result, len);
+  char *p = strncpy (buffer, result, len);
   buffer[len] = '\0';
   while (isspace (*p))
     ++p;
   free (result);
 
   alias->alias_local = 0;
-  parse_res = _nss_nis_parse_aliasent (name, p, alias, buffer, buflen, errnop);
-  if (parse_res < 1)
+  int parse_res = _nss_nis_parse_aliasent (name, p, alias, buffer, buflen,
+					   errnop);
+  if (__builtin_expect (parse_res < 1, 0))
     {
       if (parse_res == -1)
 	return NSS_STATUS_TRYAGAIN;
diff --git a/nis/nss_nis/nis-ethers.c b/nis/nss_nis/nis-ethers.c
index def4c22510..a3064282ab 100644
--- a/nis/nss_nis/nis-ethers.c
+++ b/nis/nss_nis/nis-ethers.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2003, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
 
@@ -182,45 +182,46 @@ enum nss_status
 _nss_nis_gethostton_r (const char *name, struct etherent *eth,
 		       char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  enum nss_status retval;
-  char *domain, *result, *p;
-  int len, parse_res;
-
   if (name == NULL)
     {
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
 
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
-  retval = yperr2nss (yp_match (domain, "ethers.byname", name,
-				strlen (name), &result, &len));
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "ethers.byname", name, strlen (name), &result,
+			&len);
 
-  if (retval != NSS_STATUS_SUCCESS)
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
         *errnop = errno;
       return retval;
     }
 
-  if ((size_t) (len + 1) > buflen)
+  if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
     {
       free (result);
       *errnop = ERANGE;
       return NSS_STATUS_TRYAGAIN;
     }
 
-  p = strncpy (buffer, result, len);
+  char *p = strncpy (buffer, result, len);
   buffer[len] = '\0';
   while (isspace (*p))
     ++p;
   free (result);
 
-  parse_res = _nss_files_parse_etherent (p, eth, data, buflen, errnop);
-  if (parse_res < 1)
+  int parse_res = _nss_files_parse_etherent (p, eth, (void *) buffer, buflen,
+					     errnop);
+  if (__builtin_expect (parse_res < 1, 0))
     {
       if (parse_res == -1)
 	return NSS_STATUS_TRYAGAIN;
@@ -234,54 +235,54 @@ enum nss_status
 _nss_nis_getntohost_r (const struct ether_addr *addr, struct etherent *eth,
 		       char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  enum nss_status retval;
-  char *domain, *result, *p;
-  int len, nlen, parse_res;
-  char buf[33];
-
   if (addr == NULL)
     {
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
 
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
-  nlen = sprintf (buf, "%x:%x:%x:%x:%x:%x",
-		  (int) addr->ether_addr_octet[0],
-		  (int) addr->ether_addr_octet[1],
-		  (int) addr->ether_addr_octet[2],
-		  (int) addr->ether_addr_octet[3],
-		  (int) addr->ether_addr_octet[4],
-		  (int) addr->ether_addr_octet[5]);
-
-  retval = yperr2nss (yp_match (domain, "ethers.byaddr", buf,
-				nlen, &result, &len));
-
-  if (retval != NSS_STATUS_SUCCESS)
+  char buf[33];
+  int nlen = snprintf (buf, sizeof (buf), "%x:%x:%x:%x:%x:%x",
+		      (int) addr->ether_addr_octet[0],
+		      (int) addr->ether_addr_octet[1],
+		      (int) addr->ether_addr_octet[2],
+		      (int) addr->ether_addr_octet[3],
+		      (int) addr->ether_addr_octet[4],
+		      (int) addr->ether_addr_octet[5]);
+
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "ethers.byaddr", buf, nlen, &result, &len);
+
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
         *errnop = errno;
       return retval;
     }
 
-  if ((size_t) (len + 1) > buflen)
+  if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
     {
       free (result);
       *errnop = ERANGE;
       return NSS_STATUS_TRYAGAIN;
     }
 
-  p = strncpy (buffer, result, len);
+  char *p = strncpy (buffer, result, len);
   buffer[len] = '\0';
   while (isspace (*p))
     ++p;
   free (result);
 
-  parse_res = _nss_files_parse_etherent (p, eth, data, buflen, errnop);
-  if (parse_res < 1)
+  int parse_res = _nss_files_parse_etherent (p, eth, (void *) buffer, buflen,
+					     errnop);
+  if (__builtin_expect (parse_res < 1, 0))
     {
       if (parse_res == -1)
 	return NSS_STATUS_TRYAGAIN;
diff --git a/nis/nss_nis/nis-grp.c b/nis/nss_nis/nis-grp.c
index 8be7332515..6e36cf828f 100644
--- a/nis/nss_nis/nis-grp.c
+++ b/nis/nss_nis/nis-grp.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-1999, 2001-2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1996-1999, 2001-2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
 
@@ -17,20 +17,17 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#include <nss.h>
-/* The following is an ugly trick to avoid a prototype declaration for
-   _nss_nis_endgrent.  */
-#define _nss_nis_endgrent _nss_nis_endgrent_XXX
-#include <grp.h>
-#undef _nss_nis_endgrent
 #include <ctype.h>
 #include <errno.h>
+#include <grp.h>
+#include <nss.h>
 #include <string.h>
 #include <bits/libc-lock.h>
 #include <rpcsvc/yp.h>
 #include <rpcsvc/ypclnt.h>
 
 #include "nss-nis.h"
+#include <libnsl.h>
 
 /* Get the declaration of the parser function.  */
 #define ENTNAME grent
@@ -44,12 +41,12 @@ __libc_lock_define_initialized (static, lock)
 static bool_t new_start = 1;
 static char *oldkey;
 static int oldkeylen;
+static intern_t intern;
 
-enum nss_status
-_nss_nis_setgrent (int stayopen)
-{
-  __libc_lock_lock (lock);
 
+static void
+internal_nis_endgrent (void)
+{
   new_start = 1;
   if (oldkey != NULL)
     {
@@ -58,72 +55,186 @@ _nss_nis_setgrent (int stayopen)
       oldkeylen = 0;
     }
 
+  struct response_t *curr = intern.next;
+
+  while (curr != NULL)
+    {
+      struct response_t *last = curr;
+      curr = curr->next;
+      free (last);
+    }
+
+  intern.next = intern.start = NULL;
+}
+
+
+enum nss_status
+_nss_nis_endgrent (void)
+{
+  __libc_lock_lock (lock);
+
+  internal_nis_endgrent ();
+
   __libc_lock_unlock (lock);
 
   return NSS_STATUS_SUCCESS;
 }
-/* Make _nss_nis_endgrent an alias of _nss_nis_setgrent.  We do this
-   even though the prototypes don't match.  The argument of setgrent
-   is not used so this makes no difference.  */
-strong_alias (_nss_nis_setgrent, _nss_nis_endgrent)
+
+
+enum nss_status
+internal_nis_setgrent (void)
+{
+  /* We have to read all the data now.  */
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
+    return NSS_STATUS_UNAVAIL;
+
+  struct ypall_callback ypcb;
+
+  ypcb.foreach = _nis_saveit;
+  ypcb.data = (char *) &intern;
+  enum nss_status status = yperr2nss (yp_all (domain, "group.byname", &ypcb));
+
+
+  /* Mark the last buffer as full.  */
+  if (intern.next != NULL)
+    intern.next->size = intern.offset;
+
+  intern.next = intern.start;
+  intern.offset = 0;
+
+  return status;
+}
+
+
+enum nss_status
+_nss_nis_setgrent (int stayopen)
+{
+  enum nss_status result = NSS_STATUS_SUCCESS;
+
+  __libc_lock_lock (lock);
+
+  internal_nis_endgrent ();
+
+  if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ)
+    result = internal_nis_setgrent ();
+
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
 
 static enum nss_status
 internal_nis_getgrent_r (struct group *grp, char *buffer, size_t buflen,
 			 int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  char *domain, *result, *outkey;
-  int len, keylen, parse_res;
+  /* If we read the entire database at setpwent time we just iterate
+     over the data we have in memory.  */
+  bool batch_read = intern.start != NULL;
 
-  if (yp_get_default_domain (&domain))
+  char *domain = NULL;
+  if (!batch_read && __builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
   /* Get the next entry until we found a correct one. */
+  int parse_res;
   do
     {
-      enum nss_status retval;
-      char *p;
+      char *result;
+      char *outkey;
+      int len;
+      int keylen;
 
-      if (new_start)
-        retval = yperr2nss (yp_first (domain, "group.byname",
-                                      &outkey, &keylen, &result, &len));
-      else
-        retval = yperr2nss ( yp_next (domain, "group.byname",
-                                      oldkey, oldkeylen,
-                                      &outkey, &keylen, &result, &len));
+      if (batch_read)
+	{
+	  struct response_t *bucket;
 
-      if (retval != NSS_STATUS_SUCCESS)
-        {
-          if (retval == NSS_STATUS_TRYAGAIN)
-            *errnop = errno;
-          return retval;
-        }
+	handle_batch_read:
+	  bucket = intern.next;
+
+	  if (__builtin_expect (intern.offset >= bucket->size, 0))
+	    {
+	      if (bucket->next == NULL)
+		return NSS_STATUS_NOTFOUND;
+
+	      /* We look at all the content in the current bucket.  Go on
+		 to the next.  */
+	      bucket = intern.next = bucket->next;
+	      intern.offset = 0;
+	    }
 
-      if ((size_t) (len + 1) > buflen)
+	  for (result = &bucket->mem[intern.offset]; isspace (*result);
+	       ++result)
+	    ++intern.offset;
+
+	  len = strlen (result);
+	}
+      else
+	{
+	  int yperr;
+
+	  if (new_start)
+	    {
+	      /* Maybe we should read the database in one piece.  */
+	      if ((_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ)
+		  && internal_nis_setgrent () == NSS_STATUS_SUCCESS
+		  && intern.start != NULL)
+		{
+		  batch_read = true;
+		  goto handle_batch_read;
+		}
+
+	      yperr = yp_first (domain, "group.byname", &outkey, &keylen,
+				&result, &len);
+	    }
+	  else
+	    yperr = yp_next (domain, "group.byname", oldkey, oldkeylen,
+			     &outkey, &keylen, &result, &len);
+
+	  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+	    {
+	      enum nss_status retval = yperr2nss (yperr);
+
+	      if (retval == NSS_STATUS_TRYAGAIN)
+		*errnop = errno;
+	      return retval;
+	    }
+	}
+
+      if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
         {
           free (result);
           *errnop = ERANGE;
           return NSS_STATUS_TRYAGAIN;
         }
 
-      p = strncpy (buffer, result, len);
+      char *p = strncpy (buffer, result, len);
       buffer[len] = '\0';
       while (isspace (*p))
         ++p;
-      free (result);
+      if (!batch_read)
+	free (result);
 
-      parse_res = _nss_files_parse_grent (p, grp, data, buflen, errnop);
-      if (parse_res == -1)
+      parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen,
+					  errnop);
+      if (__builtin_expect (parse_res == -1, 0))
 	{
-	  free (outkey);
+	  if (!batch_read)
+	    free (outkey);
 	  *errnop = ERANGE;
 	  return NSS_STATUS_TRYAGAIN;
 	}
 
-      free (oldkey);
-      oldkey = outkey;
-      oldkeylen = keylen;
-      new_start = 0;
+      if (batch_read)
+	intern.offset += len + 1;
+      else
+	{
+	  free (oldkey);
+	  oldkey = outkey;
+	  oldkeylen = keylen;
+	  new_start = 0;
+	}
     }
   while (parse_res < 1);
 
@@ -149,45 +260,46 @@ enum nss_status
 _nss_nis_getgrnam_r (const char *name, struct group *grp,
 		     char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  enum nss_status retval;
-  char *domain, *result, *p;
-  int len, parse_res;
-
   if (name == NULL)
     {
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
 
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
-  retval = yperr2nss (yp_match (domain, "group.byname", name,
-				strlen (name), &result, &len));
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "group.byname", name, strlen (name), &result,
+			&len);
 
-  if (retval != NSS_STATUS_SUCCESS)
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
         *errnop = errno;
       return retval;
     }
 
-  if ((size_t) (len + 1) > buflen)
+  if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
     {
       free (result);
       *errnop = ERANGE;
       return NSS_STATUS_TRYAGAIN;
     }
 
-  p = strncpy (buffer, result, len);
+  char *p = strncpy (buffer, result, len);
   buffer[len] = '\0';
   while (isspace (*p))
     ++p;
   free (result);
 
-  parse_res = _nss_files_parse_grent (p, grp, data, buflen, errnop);
-  if (parse_res < 1)
+  int parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen,
+					  errnop);
+  if (__builtin_expect  (parse_res < 1, 0))
     {
       if (parse_res == -1)
 	return NSS_STATUS_TRYAGAIN;
@@ -201,42 +313,42 @@ enum nss_status
 _nss_nis_getgrgid_r (gid_t gid, struct group *grp,
 		     char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  enum nss_status retval;
-  char *domain, *result, *p;
-  int len, nlen, parse_res;
-  char buf[32];
-
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
-  nlen = sprintf (buf, "%lu", (unsigned long int) gid);
+  char buf[32];
+  int nlen = sprintf (buf, "%lu", (unsigned long int) gid);
 
-  retval = yperr2nss (yp_match (domain, "group.bygid", buf,
-				nlen, &result, &len));
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "group.bygid", buf, nlen, &result, &len);
 
-  if (retval != NSS_STATUS_SUCCESS)
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
         *errnop = errno;
       return retval;
     }
 
-  if ((size_t) (len + 1) > buflen)
+  if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
     {
       free (result);
       *errnop = ERANGE;
       return NSS_STATUS_TRYAGAIN;
     }
 
-  p = strncpy (buffer, result, len);
+  char *p = strncpy (buffer, result, len);
   buffer[len] = '\0';
   while (isspace (*p))
     ++p;
   free (result);
 
-  parse_res = _nss_files_parse_grent (p, grp, data, buflen, errnop);
-  if (parse_res < 1)
+  int parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen,
+					  errnop);
+  if (__builtin_expect (parse_res < 1, 0))
     {
       if (parse_res == -1)
 	return NSS_STATUS_TRYAGAIN;
diff --git a/nis/nss_nis/nis-hosts.c b/nis/nss_nis/nis-hosts.c
index 58a9064f14..bde0a3291f 100644
--- a/nis/nss_nis/nis-hosts.c
+++ b/nis/nss_nis/nis-hosts.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2000, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2000, 2002, 2003, 2006, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
 
@@ -131,39 +131,42 @@ internal_nis_gethostent_r (struct hostent *host, char *buffer,
 			   int af, int flags)
 {
   char *domain;
-  char *result;
-  int len, parse_res;
-  char *outkey;
-  int keylen;
-  struct parser_data *data = (void *) buffer;
-  size_t linebuflen = buffer + buflen - data->linebuffer;
-
-  if (yp_get_default_domain (&domain))
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
-  if (buflen < sizeof *data + 1)
+  uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data);
+  buffer += pad;
+
+  struct parser_data *data = (void *) buffer;
+  if (__builtin_expect (buflen < sizeof *data + 1 + pad, 0))
     {
       *errnop = ERANGE;
       *h_errnop = NETDB_INTERNAL;
       return NSS_STATUS_TRYAGAIN;
     }
+  buflen -= pad;
 
   /* Get the next entry until we found a correct one. */
+  const size_t linebuflen = buffer + buflen - data->linebuffer;
+  int parse_res;
   do
     {
-      enum nss_status retval;
-      char *p;
-
+      char *result;
+      int len;
+      char *outkey;
+      int keylen;
+      int yperr;
       if (new_start)
-        retval = yperr2nss (yp_first (domain, "hosts.byname",
-                                      &outkey, &keylen, &result, &len));
+        yperr = yp_first (domain, "hosts.byname", &outkey, &keylen, &result,
+			  &len);
       else
-        retval = yperr2nss ( yp_next (domain, "hosts.byname",
-                                      oldkey, oldkeylen,
-                                      &outkey, &keylen, &result, &len));
+        yperr = yp_next (domain, "hosts.byname", oldkey, oldkeylen, &outkey,
+			 &keylen, &result, &len);
 
-      if (retval != NSS_STATUS_SUCCESS)
+      if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
         {
+	  enum nss_status retval = yperr2nss (yperr);
+
 	  switch (retval)
 	    {
 	    case NSS_STATUS_TRYAGAIN:
@@ -180,7 +183,7 @@ internal_nis_gethostent_r (struct hostent *host, char *buffer,
 	  return retval;
 	}
 
-      if ((size_t) (len + 1) > linebuflen)
+      if (__builtin_expect ((size_t) (len + 1) > linebuflen, 0))
         {
           free (result);
 	  *h_errnop = NETDB_INTERNAL;
@@ -188,14 +191,14 @@ internal_nis_gethostent_r (struct hostent *host, char *buffer,
           return NSS_STATUS_TRYAGAIN;
         }
 
-      p = strncpy (data->linebuffer, result, len);
+      char *p = strncpy (data->linebuffer, result, len);
       data->linebuffer[len] = '\0';
       while (isspace (*p))
 	++p;
       free (result);
 
       parse_res = parse_line (p, host, data, buflen, errnop, af, flags);
-      if (parse_res == -1)
+      if (__builtin_expect (parse_res == -1, 0))
 	{
 	  free (outkey);
 	  *h_errnop = NETDB_INTERNAL;
@@ -235,11 +238,10 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
 			   char *buffer, size_t buflen, int *errnop,
 			   int *h_errnop, int flags)
 {
-  enum nss_status retval;
-  char *domain, *result, *p;
-  int len, parse_res;
+  uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data);
+  buffer += pad;
+
   struct parser_data *data = (void *) buffer;
-  size_t linebuflen = buffer + buflen - data->linebuffer;
 
   if (name == NULL)
     {
@@ -247,33 +249,35 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
       return NSS_STATUS_UNAVAIL;
     }
 
+  char *domain;
   if (yp_get_default_domain (&domain))
     return NSS_STATUS_UNAVAIL;
 
-  if (buflen < sizeof *data + 1)
+  if (buflen < sizeof *data + 1 + pad)
     {
       *h_errnop = NETDB_INTERNAL;
       *errnop = ERANGE;
       return NSS_STATUS_TRYAGAIN;
     }
-  else
-    {
-      /* Convert name to lowercase.  */
-      size_t namlen = strlen (name);
-      char name2[namlen + 1];
-      size_t i;
+  buflen -= pad;
 
-      for (i = 0; i < namlen; ++i)
-	name2[i] = tolower (name[i]);
-      name2[i] = '\0';
+  /* Convert name to lowercase.  */
+  size_t namlen = strlen (name);
+  char name2[namlen + 1];
+  size_t i;
 
-      retval = yperr2nss (yp_match (domain, "hosts.byname", name2,
-				    namlen, &result, &len));
+  for (i = 0; i < namlen; ++i)
+    name2[i] = tolower (name[i]);
+  name2[i] = '\0';
 
-    }
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "hosts.byname", name2, namlen, &result, &len);
 
-  if (retval != NSS_STATUS_SUCCESS)
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
 	{
 	  *h_errnop = TRY_AGAIN;
@@ -284,7 +288,8 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
       return retval;
     }
 
-  if ((size_t) (len + 1) > linebuflen)
+  const size_t linebuflen = buffer + buflen - data->linebuffer;
+  if (__builtin_expect ((size_t) (len + 1) > linebuflen, 0))
     {
       free (result);
       *h_errnop = NETDB_INTERNAL;
@@ -292,15 +297,15 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
       return NSS_STATUS_TRYAGAIN;
     }
 
-  p = strncpy (data->linebuffer, result, len);
+  char *p = strncpy (data->linebuffer, result, len);
   data->linebuffer[len] = '\0';
   while (isspace (*p))
     ++p;
   free (result);
 
-  parse_res = parse_line (p, host, data, buflen, errnop, af, flags);
+  int parse_res = parse_line (p, host, data, buflen, errnop, af, flags);
 
-  if (parse_res < 1 || host->h_addrtype != af)
+  if (__builtin_expect (parse_res < 1 || host->h_addrtype != af, 0))
     {
       if (parse_res == -1)
 	{
@@ -351,42 +356,46 @@ _nss_nis_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af,
 			  struct hostent *host, char *buffer, size_t buflen,
 			  int *errnop, int *h_errnop)
 {
-  enum nss_status retval;
-  char *domain, *result, *p;
-  int len, parse_res;
-  char *buf;
-  struct parser_data *data = (void *) buffer;
-  size_t linebuflen = buffer + buflen - data->linebuffer;
-
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
-  if (buflen < sizeof *data + 1)
+  uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data);
+  buffer += pad;
+
+  struct parser_data *data = (void *) buffer;
+  if (__builtin_expect (buflen < sizeof *data + 1 + pad, 0))
     {
       *errnop = ERANGE;
       *h_errnop = NETDB_INTERNAL;
       return NSS_STATUS_TRYAGAIN;
     }
+  buflen -= pad;
 
-  buf = inet_ntoa (*(const struct in_addr *) addr);
+  char *buf = inet_ntoa (*(const struct in_addr *) addr);
 
-  retval = yperr2nss (yp_match (domain, "hosts.byaddr", buf,
-                                strlen (buf), &result, &len));
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "hosts.byaddr", buf, strlen (buf), &result,
+			&len);
 
-  if (retval != NSS_STATUS_SUCCESS)
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
 	{
 	  *h_errnop = TRY_AGAIN;
 	  *errnop = errno;
 	}
-      if (retval == NSS_STATUS_NOTFOUND)
+      else if (retval == NSS_STATUS_NOTFOUND)
 	*h_errnop = HOST_NOT_FOUND;
 
       return retval;
     }
 
-  if ((size_t) (len + 1) > linebuflen)
+  const size_t linebuflen = buffer + buflen - data->linebuffer;
+  if (__builtin_expect ((size_t) (len + 1) > linebuflen, 0))
     {
       free (result);
       *errnop = ERANGE;
@@ -394,15 +403,16 @@ _nss_nis_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af,
       return NSS_STATUS_TRYAGAIN;
     }
 
-  p = strncpy (data->linebuffer, result, len);
+  char *p = strncpy (data->linebuffer, result, len);
   data->linebuffer[len] = '\0';
   while (isspace (*p))
     ++p;
   free (result);
 
-  parse_res = parse_line (p, host, data, buflen, errnop, af,
-			  ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0));
-  if (parse_res < 1)
+  int parse_res = parse_line (p, host, data, buflen, errnop, af,
+			      ((_res.options & RES_USE_INET6)
+			       ? AI_V4MAPPED : 0));
+  if (__builtin_expect (parse_res < 1, 0))
     {
       if (parse_res == -1)
 	{
diff --git a/nis/nss_nis/nis-initgroups.c b/nis/nss_nis/nis-initgroups.c
index 33a9662b4c..a5a3ba6144 100644
--- a/nis/nss_nis/nis-initgroups.c
+++ b/nis/nss_nis/nis-initgroups.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998-2000, 2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1998-2000,2002,2003,2004,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
 
@@ -30,6 +30,7 @@
 #include <sys/param.h>
 
 #include "nss-nis.h"
+#include <libnsl.h>
 
 /* Get the declaration of the parser function.  */
 #define ENTNAME grent
@@ -37,47 +38,6 @@
 #define EXTERN_PARSER
 #include <nss/nss_files/files-parse.c>
 
-struct response_t
-{
-  struct response_t *next;
-  char val[0];
-};
-
-struct intern_t
-{
-  struct response_t *start;
-  struct response_t *next;
-};
-typedef struct intern_t intern_t;
-
-static int
-saveit (int instatus, char *inkey, int inkeylen, char *inval,
-        int invallen, char *indata)
-{
-  intern_t *intern = (intern_t *) indata;
-
-  if (instatus != YP_TRUE)
-    return 1;
-
-  if (inkey && inkeylen > 0 && inval && invallen > 0)
-    {
-      struct response_t *newp = malloc (sizeof (struct response_t)
-					+ invallen + 1);
-      if (newp == NULL)
-	return 1; /* We have no error code for out of memory */
-
-      if (intern->start == NULL)
-	intern->start = newp;
-      else
-	intern->next->next = newp;
-      intern->next = newp;
-
-      newp->next = NULL;
-      *((char *) mempcpy (newp->val, inval, invallen)) = '\0';
-    }
-
-  return 0;
-}
 
 static enum nss_status
 internal_setgrent (char *domainname, intern_t *intern)
@@ -85,41 +45,72 @@ internal_setgrent (char *domainname, intern_t *intern)
   struct ypall_callback ypcb;
   enum nss_status status;
 
-  intern->start = NULL;
-
-  ypcb.foreach = saveit;
+  ypcb.foreach = _nis_saveit;
   ypcb.data = (char *) intern;
   status = yperr2nss (yp_all (domainname, "group.byname", &ypcb));
+
+  /* Mark the last buffer as full.  */
+  if (intern->next != NULL)
+    intern->next->size = intern->offset;
+
   intern->next = intern->start;
+  intern->offset = 0;
 
   return status;
 }
 
+
 static enum nss_status
 internal_getgrent_r (struct group *grp, char *buffer, size_t buflen,
 		     int *errnop, intern_t *intern)
 {
-  struct parser_data *data = (void *) buffer;
-  int parse_res;
-  char *p;
-
   if (intern->start == NULL)
     return NSS_STATUS_NOTFOUND;
 
   /* Get the next entry until we found a correct one. */
+  int parse_res;
   do
     {
-      if (intern->next == NULL)
-	return NSS_STATUS_NOTFOUND;
+      struct response_t *bucket = intern->next;
+
+      if (__builtin_expect (intern->offset >= bucket->size, 0))
+	{
+	  if (bucket->next == NULL)
+	    return NSS_STATUS_NOTFOUND;
+
+	  /* We look at all the content in the current bucket.  Go on
+	     to the next.  */
+	  bucket = intern->next = bucket->next;
+	  intern->offset = 0;
+	}
+
+      char *p;
+      for (p = &bucket->mem[intern->offset]; isspace (*p); ++p)
+        ++intern->offset;
 
-      p = strncpy (buffer, intern->next->val, buflen);
-      while (isspace (*p))
-        ++p;
+      size_t len = strlen (p) + 1;
+      if (__builtin_expect (len > buflen, 0))
+	{
+	  *errnop = ERANGE;
+	  return NSS_STATUS_TRYAGAIN;
+	}
 
-      parse_res = _nss_files_parse_grent (p, grp, data, buflen, errnop);
-      if (parse_res == -1)
+      /* We unfortunately have to copy the data in the user-provided
+	 buffer because that buffer might be around for a very long
+	 time and the servent structure must remain valid.  If we would
+	 rely on the BUCKET memory the next 'setservent' or 'endservent'
+	 call would destroy it.
+
+	 The important thing is that it is a single NUL-terminated
+	 string.  This is what the parsing routine expects.  */
+      p = memcpy (buffer, &bucket->mem[intern->offset], len);
+
+      parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen,
+					  errnop);
+      if (__builtin_expect (parse_res == -1, 0))
         return NSS_STATUS_TRYAGAIN;
-      intern->next = intern->next->next;
+
+      intern->offset += len;
     }
   while (!parse_res);
 
@@ -166,13 +157,12 @@ initgroups_netid (uid_t uid, gid_t group, long int *start, long int *size,
   ssize_t keylen = snprintf (key, sizeof (key), "unix.%lu@%s",
 			     (unsigned long int) uid, domainname);
 
-  enum nss_status retval;
   char *result;
   int reslen;
-  retval = yperr2nss (yp_match (domainname, "netid.byname", key, keylen,
-				&result, &reslen));
-  if (retval != NSS_STATUS_SUCCESS)
-    return retval;
+  int yperr = yp_match (domainname, "netid.byname", key, keylen, &result,
+			&reslen);
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+    return yperr2nss (yperr);
 
   /* Parse the result: following the colon is a comma separated list of
      group IDs.  */
@@ -207,7 +197,6 @@ initgroups_netid (uid_t uid, gid_t group, long int *start, long int *size,
       if (*start == *size)
 	{
 	  /* Need a bigger buffer.  */
-	  gid_t *newgroups;
 	  long int newsize;
 
 	  if (limit > 0 && *size == limit)
@@ -219,7 +208,7 @@ initgroups_netid (uid_t uid, gid_t group, long int *start, long int *size,
 	  else
 	    newsize = MIN (limit, 2 * *size);
 
-	  newgroups = realloc (groups, newsize * sizeof (*groups));
+	  gid_t *newgroups = realloc (groups, newsize * sizeof (*groups));
 	  if (newgroups == NULL)
 	    goto errout;
 	  *groupsp = groups = newgroups;
@@ -247,7 +236,7 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start,
     return NSS_STATUS_UNAVAIL;
 
   /* Check whether we are supposed to use the netid.byname map.  */
-  if (_nis_default_nss () & NSS_FLAG_NETID_AUTHORITATIVE)
+  if (_nsl_default_nss () & NSS_FLAG_NETID_AUTHORITATIVE)
     {
       /* We need the user ID.  */
       uid_t uid;
@@ -262,7 +251,7 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start,
   size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
   char *tmpbuf;
   enum nss_status status;
-  intern_t intern = { NULL, NULL };
+  intern_t intern = { NULL, NULL, 0 };
   gid_t *groups = *groupsp;
 
   status = internal_setgrent (domainname, &intern);
diff --git a/nis/nss_nis/nis-netgrp.c b/nis/nss_nis/nis-netgrp.c
index d339dd5097..5a88b72d9c 100644
--- a/nis/nss_nis/nis-netgrp.c
+++ b/nis/nss_nis/nis-netgrp.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996,1997,1999,2000,2002,2003,2004
+/* Copyright (C) 1996,1997,1999,2000,2002,2003,2004,2005,2006
    Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
@@ -41,41 +41,37 @@ _nss_netgroup_parseline (char **cursor, struct __netgrent *netgrp,
 static void
 internal_nis_endnetgrent (struct __netgrent *netgrp)
 {
-  if (netgrp->data != NULL)
-    {
-      free (netgrp->data);
-      netgrp->data = NULL;
-      netgrp->data_size = 0;
-      netgrp->cursor = NULL;
-    }
+  free (netgrp->data);
+  netgrp->data = NULL;
+  netgrp->data_size = 0;
+  netgrp->cursor = NULL;
 }
 
+
 enum nss_status
 _nss_nis_setnetgrent (const char *group, struct __netgrent *netgrp)
 {
-  char *domain;
   int len;
   enum nss_status status;
 
   status = NSS_STATUS_SUCCESS;
 
-  if (group == NULL || group[0] == '\0')
+  if (__builtin_expect (group == NULL || group[0] == '\0', 0))
     return NSS_STATUS_UNAVAIL;
 
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
-  internal_nis_endnetgrent (netgrp);
-
   status = yperr2nss (yp_match (domain, "netgroup", group, strlen (group),
 				&netgrp->data, &len));
-  if (status == NSS_STATUS_SUCCESS)
+  if (__builtin_expect (status == NSS_STATUS_SUCCESS, 1))
     {
       /* Our implementation of yp_match already allocates a buffer
 	 which is one byte larger than the value in LEN specifies
 	 and the last byte is filled with NUL.  So we can simply
 	 use that buffer.  */
-      assert (len > 0);
+      assert (len >= 0);
       assert (malloc_usable_size (netgrp->data) >= len + 1);
       assert (netgrp->data[len] == '\0');
 
@@ -95,13 +91,11 @@ _nss_nis_endnetgrent (struct __netgrent *netgrp)
   return NSS_STATUS_SUCCESS;
 }
 
+
 enum nss_status
 _nss_nis_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen,
 			int *errnop)
 {
-  if (result->cursor == NULL)
-    return NSS_STATUS_NOTFOUND;
-
   return _nss_netgroup_parseline (&result->cursor, result, buffer, buflen,
 				  errnop);
 }
diff --git a/nis/nss_nis/nis-network.c b/nis/nss_nis/nis-network.c
index ed8439c814..9b02302e0b 100644
--- a/nis/nss_nis/nis-network.c
+++ b/nis/nss_nis/nis-network.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2003, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
 
@@ -73,28 +73,32 @@ internal_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen,
 			  int *errnop, int *herrnop)
 {
   struct parser_data *data = (void *) buffer;
-  char *domain, *result, *outkey;
-  int len, keylen, parse_res;
 
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
   /* Get the next entry until we found a correct one. */
+  int parse_res;
   do
     {
-      enum nss_status retval;
-      char *p;
+      char *result;
+      char *outkey;
+      int len;
+      int keylen;
+      int yperr;
 
       if (new_start)
-        retval = yperr2nss (yp_first (domain, "networks.byname",
-                                      &outkey, &keylen, &result, &len));
+        yperr = yp_first (domain, "networks.byname", &outkey, &keylen, &result,
+			  &len);
       else
-        retval = yperr2nss ( yp_next (domain, "networks.byname",
-                                      oldkey, oldkeylen,
-                                      &outkey, &keylen, &result, &len));
+        yperr = yp_next (domain, "networks.byname", oldkey, oldkeylen, &outkey,
+			 &keylen, &result, &len);
 
-      if (retval != NSS_STATUS_SUCCESS)
+      if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
         {
+	  enum nss_status retval = yperr2nss (yperr);
+
           if (retval == NSS_STATUS_TRYAGAIN)
 	    {
 	      *herrnop = NETDB_INTERNAL;
@@ -103,7 +107,7 @@ internal_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen,
           return retval;
         }
 
-      if ((size_t) (len + 1) > buflen)
+      if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
         {
           free (result);
 	  *errnop = ERANGE;
@@ -111,14 +115,14 @@ internal_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen,
           return NSS_STATUS_TRYAGAIN;
         }
 
-      p = strncpy (buffer, result, len);
+      char *p = strncpy (buffer, result, len);
       buffer[len] = '\0';
       while (isspace (*p))
         ++p;
       free (result);
 
       parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop);
-      if (parse_res == -1)
+      if (__builtin_expect (parse_res == -1, 0))
 	{
 	  free (outkey);
 	  *herrnop = NETDB_INTERNAL;
@@ -155,11 +159,6 @@ enum nss_status
 _nss_nis_getnetbyname_r (const char *name, struct netent *net, char *buffer,
 			 size_t buflen, int *errnop, int *herrnop)
 {
-  enum nss_status retval;
-  struct parser_data *data = (void *) buffer;
-  char *domain, *result, *p;
-  int len, parse_res;
-
   if (name == NULL)
     {
       *errnop = EINVAL;
@@ -167,33 +166,36 @@ _nss_nis_getnetbyname_r (const char *name, struct netent *net, char *buffer,
       return NSS_STATUS_UNAVAIL;
     }
 
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
+  struct parser_data *data = (void *) buffer;
   if (buflen < sizeof *data + 1)
     {
       *herrnop = NETDB_INTERNAL;
       *errnop = ERANGE;
       return NSS_STATUS_TRYAGAIN;
     }
-  else
-    {
-      /* Convert name to lowercase.  */
-      size_t namlen = strlen (name);
-      char name2[namlen + 1];
-      size_t i;
 
-      for (i = 0; i < namlen; ++i)
-	name2[i] = _tolower (name[i]);
-      name2[i] = '\0';
+  /* Convert name to lowercase.  */
+  size_t namlen = strlen (name);
+  char name2[namlen + 1];
+  size_t i;
 
-      retval = yperr2nss (yp_match (domain, "networks.byname", name2,
-				    namlen, &result, &len));
-    }
+  for (i = 0; i < namlen; ++i)
+    name2[i] = _tolower (name[i]);
+  name2[i] = '\0';
 
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "networks.byname", name2, namlen, &result,
+			&len);
 
-  if (retval != NSS_STATUS_SUCCESS)
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
 	{
 	  *errnop = errno;
@@ -202,7 +204,7 @@ _nss_nis_getnetbyname_r (const char *name, struct netent *net, char *buffer,
       return retval;
     }
 
-  if ((size_t) (len + 1) > buflen)
+  if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
     {
       free (result);
       *errnop = ERANGE;
@@ -210,15 +212,15 @@ _nss_nis_getnetbyname_r (const char *name, struct netent *net, char *buffer,
       return NSS_STATUS_TRYAGAIN;
     }
 
-  p = strncpy (buffer, result, len);
+  char *p = strncpy (buffer, result, len);
   buffer[len] = '\0';
   while (isspace (*p))
     ++p;
   free (result);
 
-  parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop);
+  int parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop);
 
-  if (parse_res < 1)
+  if (__builtin_expect (parse_res < 1, 0))
     {
       *herrnop = NETDB_INTERNAL;
       if (parse_res == -1)
@@ -235,32 +237,26 @@ _nss_nis_getnetbyaddr_r (uint32_t addr, int type, struct netent *net,
 			 char *buffer, size_t buflen, int *errnop,
 			 int *herrnop)
 {
-  struct parser_data *data = (void *) buffer;
   char *domain;
-  char *result;
-  int len;
-  char buf[256];
-  int blen;
-  struct in_addr in;
-  char *p;
-
-  if (yp_get_default_domain (&domain))
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
-  in = inet_makeaddr (addr, 0);
-  strcpy (buf, inet_ntoa (in));
-  blen = strlen (buf);
+  struct in_addr in = inet_makeaddr (addr, 0);
+  char *buf = inet_ntoa (in);
+  size_t blen = strlen (buf);
 
   while (1)
     {
-      enum nss_status retval;
-      int parse_res;
+      char *result;
+      int len;
 
-      retval = yperr2nss (yp_match (domain, "networks.byaddr", buf,
-				    strlen (buf), &result, &len));
+      int yperr = yp_match (domain, "networks.byaddr", buf, blen, &result,
+			    &len);
 
-	if (retval != NSS_STATUS_SUCCESS)
+      if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
 	  {
+	    enum nss_status retval = yperr2nss (yperr);
+
 	    if (retval == NSS_STATUS_NOTFOUND)
 	      {
 		if (buf[blen - 2] == '.' && buf[blen - 1] == '0')
@@ -282,7 +278,7 @@ _nss_nis_getnetbyaddr_r (uint32_t addr, int type, struct netent *net,
 	      }
 	  }
 
-      if ((size_t) (len + 1) > buflen)
+      if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
 	{
 	  free (result);
 	  *errnop = ERANGE;
@@ -290,15 +286,16 @@ _nss_nis_getnetbyaddr_r (uint32_t addr, int type, struct netent *net,
 	  return NSS_STATUS_TRYAGAIN;
 	}
 
-        p = strncpy (buffer, result, len);
+        char *p = strncpy (buffer, result, len);
 	buffer[len] = '\0';
 	while (isspace (*p))
 	  ++p;
 	free (result);
 
-	parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop);
+	int parse_res = _nss_files_parse_netent (p, net, (void *) buffer,
+						 buflen, errnop);
 
-	if (parse_res < 1)
+	if (__builtin_expect (parse_res < 1, 0))
 	  {
 	    *herrnop = NETDB_INTERNAL;
 	    if (parse_res == -1)
diff --git a/nis/nss_nis/nis-proto.c b/nis/nss_nis/nis-proto.c
index f1069283ab..1480a928b5 100644
--- a/nis/nss_nis/nis-proto.c
+++ b/nis/nss_nis/nis-proto.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-1998, 2000-2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1996-1998, 2000-2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
 
@@ -179,45 +179,46 @@ enum nss_status
 _nss_nis_getprotobyname_r (const char *name, struct protoent *proto,
 			   char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  enum nss_status retval;
-  char *domain, *result, *p;
-  int len, parse_res;
-
   if (name == NULL)
     {
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
 
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
-  retval = yperr2nss (yp_match (domain, "protocols.byname", name,
-                                strlen (name), &result, &len));
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "protocols.byname", name, strlen (name),
+			&result, &len);
 
-  if (retval != NSS_STATUS_SUCCESS)
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
 	*errnop = errno;
       return retval;
     }
 
-  if ((size_t) (len + 1) > buflen)
+  if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
     {
       free (result);
       *errnop = ERANGE;
       return NSS_STATUS_TRYAGAIN;
     }
 
-  p = strncpy (buffer, result, len);
+  char *p = strncpy (buffer, result, len);
   buffer[len] = '\0';
   while (isspace (*p))
     ++p;
   free (result);
 
-  parse_res = _nss_files_parse_protoent (p, proto, data, buflen, errnop);
-  if (parse_res < 1)
+  int parse_res = _nss_files_parse_protoent (p, proto, (void *) buffer, buflen,
+					     errnop);
+  if (__builtin_expect (parse_res < 1, 0))
     {
       if (parse_res == -1)
 	return NSS_STATUS_TRYAGAIN;
@@ -231,42 +232,43 @@ enum nss_status
 _nss_nis_getprotobynumber_r (int number, struct protoent *proto,
 			     char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  enum nss_status retval;
-  char *domain, *result, *p;
-  int len, nlen, parse_res;
-  char buf[32];
-
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
-  nlen = sprintf (buf, "%d", number);
+  char buf[32];
+  int nlen = snprintf (buf, sizeof (buf), "%d", number);
 
-  retval = yperr2nss (yp_match (domain, "protocols.bynumber", buf,
-                                nlen, &result, &len));
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "protocols.bynumber", buf, nlen, &result,
+			&len);
 
-  if (retval != NSS_STATUS_SUCCESS)
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
 	*errnop = errno;
       return retval;
     }
 
-  if ((size_t) (len + 1) > buflen)
+  if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
     {
       free (result);
       *errnop = ERANGE;
       return NSS_STATUS_TRYAGAIN;
     }
 
-  p = strncpy (buffer, result, len);
+  char *p = strncpy (buffer, result, len);
   buffer[len] = '\0';
   while (isspace (*p))
     ++p;
   free (result);
 
-  parse_res = _nss_files_parse_protoent (p, proto, data, buflen, errnop);
-  if (parse_res < 1)
+  int parse_res = _nss_files_parse_protoent (p, proto, (void *) buffer, buflen,
+					     errnop);
+  if (__builtin_expect (parse_res < 1, 0))
     {
       if (parse_res == -1)
 	return NSS_STATUS_TRYAGAIN;
diff --git a/nis/nss_nis/nis-publickey.c b/nis/nss_nis/nis-publickey.c
index 6e92112d11..f58eb154ad 100644
--- a/nis/nss_nis/nis-publickey.c
+++ b/nis/nss_nis/nis-publickey.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996,1997,1998,1999,2001,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1996-1999,2001,2002,2005,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
 
@@ -36,10 +36,6 @@ extern int xdecrypt (char *, char *);
 enum nss_status
 _nss_nis_getpublickey (const char *netname, char *pkey, int *errnop)
 {
-  enum nss_status retval;
-  char *domain, *result;
-  int len;
-
   pkey[0] = 0;
 
   if (netname == NULL)
@@ -48,19 +44,23 @@ _nss_nis_getpublickey (const char *netname, char *pkey, int *errnop)
       return NSS_STATUS_UNAVAIL;
     }
 
-  domain = strchr (netname, '@');
-  if (!domain)
+  char *domain = strchr (netname, '@');
+  if (domain == NULL)
     {
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
   ++domain;
 
-  retval = yperr2nss (yp_match (domain, "publickey.byname", netname,
-				strlen (netname), &result, &len));
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "publickey.byname", netname, strlen (netname),
+			&result, &len);
 
-  if (retval != NSS_STATUS_SUCCESS)
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
 	*errnop = errno;
       return retval;
@@ -73,6 +73,7 @@ _nss_nis_getpublickey (const char *netname, char *pkey, int *errnop)
 	*p = 0;
       strncpy (pkey, result, HEXKEYBYTES + 1);
       pkey[HEXKEYBYTES] = '\0';
+      free (result);
     }
   return NSS_STATUS_SUCCESS;
 }
@@ -81,11 +82,6 @@ enum nss_status
 _nss_nis_getsecretkey (const char *netname, char *skey, char *passwd,
 		       int *errnop)
 {
-  enum nss_status retval;
-  char buf[2 * (HEXKEYBYTES + 1)];
-  char *domain, *result;
-  int len;
-
   skey[0] = 0;
 
   if (netname == NULL || passwd == NULL)
@@ -94,19 +90,23 @@ _nss_nis_getsecretkey (const char *netname, char *skey, char *passwd,
       return NSS_STATUS_UNAVAIL;
     }
 
-  domain = strchr (netname, '@');
-  if (!domain)
+  char *domain = strchr (netname, '@');
+  if (domain == NULL)
     {
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
   ++domain;
 
-  retval = yperr2nss (yp_match (domain, "publickey.byname", netname,
-				strlen (netname), &result, &len));
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "publickey.byname", netname, strlen (netname),
+			&result, &len);
 
-  if (retval != NSS_STATUS_SUCCESS)
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
 	*errnop = errno;
       return retval;
@@ -115,20 +115,22 @@ _nss_nis_getsecretkey (const char *netname, char *skey, char *passwd,
   if (result != NULL)
     {
       char *p = strchr (result, ':');
-      if (p == NULL)
-	return NSS_STATUS_SUCCESS;
-
-      ++p;
-      strncpy (buf, p, 2 * (HEXKEYBYTES + 1));
-      buf[2 * (HEXKEYBYTES + 1)] = '\0';
-      if (!xdecrypt (buf, passwd))
-	return NSS_STATUS_SUCCESS;
-
-      if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0)
-	return NSS_STATUS_SUCCESS;
-
-      buf[HEXKEYBYTES] = '\0';
-      strcpy (skey, buf);
+      if (p != NULL)
+	{
+	  char buf[2 * (HEXKEYBYTES + 1)];
+
+	  ++p;
+	  strncpy (buf, p, 2 * (HEXKEYBYTES + 1));
+	  buf[2 * HEXKEYBYTES + 1] = '\0';
+	  if (xdecrypt (buf, passwd)
+	      && memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) == 0)
+	    {
+	      buf[HEXKEYBYTES] = '\0';
+	      strcpy (skey, buf);
+	    }
+	}
+
+      free (result);
     }
   return NSS_STATUS_SUCCESS;
 }
@@ -194,13 +196,8 @@ enum nss_status
 _nss_nis_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
 		       gid_t *gidp, int *gidlenp, gid_t *gidlist, int *errnop)
 {
-  char *domain;
-  int yperr;
-  char *lookup;
-  int len;
-
-  domain = strchr (netname, '@');
-  if (!domain)
+  char *domain = strchr (netname, '@');
+  if (domain == NULL)
     {
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
@@ -208,9 +205,10 @@ _nss_nis_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
 
   /* Point past the '@' character */
   ++domain;
-  lookup = NULL;
-  yperr = yp_match (domain, "netid.byname", netname, strlen (netname),
-		    &lookup, &len);
+  char *lookup = NULL;
+  int len;
+  int yperr = yp_match (domain, "netid.byname", netname, strlen (netname),
+			&lookup, &len);
   switch (yperr)
     {
     case YPERR_SUCCESS:
@@ -223,17 +221,15 @@ _nss_nis_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
       return NSS_STATUS_UNAVAIL;
     }
 
-  if (lookup)
-    {
-      enum nss_status err;
-
-      lookup[len] = '\0';
-      err = parse_netid_str (lookup, uidp, gidp, gidlenp, gidlist);
-      free (lookup);
-      return err;
-    }
-  else
+  if (lookup == NULL)
     return NSS_STATUS_NOTFOUND;
 
-  return NSS_STATUS_SUCCESS;
+
+  lookup[len] = '\0';
+
+  enum nss_status err = parse_netid_str (lookup, uidp, gidp, gidlenp, gidlist);
+
+  free (lookup);
+
+  return err;
 }
diff --git a/nis/nss_nis/nis-pwd.c b/nis/nss_nis/nis-pwd.c
index 0f56ced014..1b5206ad6d 100644
--- a/nis/nss_nis/nis-pwd.c
+++ b/nis/nss_nis/nis-pwd.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-1998, 2001, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1996-1998,2001,2002,2003,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
 
@@ -17,20 +17,18 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#include <nss.h>
-/* The following is an ugly trick to avoid a prototype declaration for
-   _nss_nis_endpwent.  */
-#define _nss_nis_endpwent _nss_nis_endpwent_XXX
-#include <pwd.h>
-#undef _nss_nis_endpwent
+#include <assert.h>
 #include <ctype.h>
 #include <errno.h>
+#include <nss.h>
+#include <pwd.h>
 #include <string.h>
 #include <bits/libc-lock.h>
 #include <rpcsvc/yp.h>
 #include <rpcsvc/ypclnt.h>
 
 #include "nss-nis.h"
+#include <libnsl.h>
 
 /* Get the declaration of the parser function.  */
 #define ENTNAME pwent
@@ -44,12 +42,72 @@ __libc_lock_define_initialized (static, lock)
 static bool_t new_start = 1;
 static char *oldkey;
 static int oldkeylen;
+static intern_t intern;
 
-enum nss_status
-_nss_nis_setpwent (int stayopen)
+
+int
+_nis_saveit (int instatus, char *inkey, int inkeylen, char *inval,
+	     int invallen, char *indata)
 {
-  __libc_lock_lock (lock);
+  intern_t *intern = (intern_t *) indata;
+
+  if (instatus != YP_TRUE)
+    return 1;
+
+  if (inkey && inkeylen > 0 && inval && invallen > 0)
+    {
+      struct response_t *bucket = intern->next;
 
+      if (__builtin_expect (bucket == NULL, 0))
+	{
+#define MINSIZE 4096 - 4 * sizeof (void *)
+	  const size_t minsize = MAX (MINSIZE, 2 * (invallen + 1));
+	  bucket = malloc (sizeof (struct response_t) + minsize);
+	  if (bucket == NULL)
+	    /* We have no error code for out of memory.  */
+	    return 1;
+
+	  bucket->next = NULL;
+	  bucket->size = minsize;
+	  intern->start = intern->next = bucket;
+	  intern->offset = 0;
+	}
+      else if (__builtin_expect (invallen + 1 > bucket->size - intern->offset,
+				 0))
+	{
+	  /* We need a new (larger) buffer.  */
+	  const size_t newsize = 2 * MAX (bucket->size, invallen + 1);
+	  struct response_t *newp = malloc (sizeof (struct response_t)
+					    + newsize);
+	  if (newp == NULL)
+	    /* We have no error code for out of memory.  */
+	    return 1;
+
+	  /* Mark the old bucket as full.  */
+	  bucket->size = intern->offset;
+
+	  newp->next = NULL;
+	  newp->size = newsize;
+	  bucket = intern->next = bucket->next = newp;
+	  intern->offset = 0;
+	}
+
+      char *p = mempcpy (&bucket->mem[intern->offset], inval, invallen);
+      if (__builtin_expect (p[-1] != '\0', 0))
+	{
+	  *p = '\0';
+	  ++invallen;
+	}
+      intern->offset += invallen;
+    }
+
+  return 0;
+}
+
+
+static void
+internal_nis_endpwent (void)
+{
   new_start = 1;
   if (oldkey != NULL)
     {
@@ -58,52 +116,159 @@ _nss_nis_setpwent (int stayopen)
       oldkeylen = 0;
     }
 
+  struct response_t *curr = intern.next;
+
+  while (curr != NULL)
+    {
+      struct response_t *last = curr;
+      curr = curr->next;
+      free (last);
+    }
+
+  intern.next = intern.start = NULL;
+}
+
+
+enum nss_status
+_nss_nis_endpwent (void)
+{
+  __libc_lock_lock (lock);
+
+  internal_nis_endpwent ();
+
   __libc_lock_unlock (lock);
 
   return NSS_STATUS_SUCCESS;
 }
-/* Make _nss_nis_endpwent an alias of _nss_nis_setpwent.  We do this
-   even though the prototypes don't match.  The argument of setpwent
-   is not used so this makes no difference.  */
-strong_alias (_nss_nis_setpwent, _nss_nis_endpwent)
+
+
+enum nss_status
+internal_nis_setpwent (void)
+{
+  /* We have to read all the data now.  */
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
+    return NSS_STATUS_UNAVAIL;
+
+  struct ypall_callback ypcb;
+
+  ypcb.foreach = _nis_saveit;
+  ypcb.data = (char *) &intern;
+  enum nss_status status = yperr2nss (yp_all (domain, "passwd.byname", &ypcb));
+
+
+  /* Mark the last buffer as full.  */
+  if (intern.next != NULL)
+    intern.next->size = intern.offset;
+
+  intern.next = intern.start;
+  intern.offset = 0;
+
+  return status;
+}
+
+
+enum nss_status
+_nss_nis_setpwent (int stayopen)
+{
+  enum nss_status result = NSS_STATUS_SUCCESS;
+
+  __libc_lock_lock (lock);
+
+  internal_nis_endpwent ();
+
+  if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ)
+    result = internal_nis_setpwent ();
+
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
 
 static enum nss_status
 internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen,
 			 int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  char *domain;
-  int parse_res;
+  /* If we read the entire database at setpwent time we just iterate
+     over the data we have in memory.  */
+  bool batch_read = intern.start != NULL;
 
-  if (yp_get_default_domain (&domain))
+  char *domain = NULL;
+  if (!batch_read && __builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
   /* Get the next entry until we found a correct one. */
+  int parse_res;
   do
     {
-      enum nss_status retval;
-      char *result, *outkey, *result2, *p;
-      int len, keylen, len2;
-      size_t namelen;
+      char *result;
+      char *outkey;
+      int len;
+      int keylen;
+
+      if (batch_read)
+	{
+	  struct response_t *bucket;
+
+	handle_batch_read:
+	  bucket = intern.next;
 
-      if (new_start)
-        retval = yperr2nss (yp_first (domain, "passwd.byname",
-                                      &outkey, &keylen, &result, &len));
+	  if (__builtin_expect (intern.offset >= bucket->size, 0))
+	    {
+	      if (bucket->next == NULL)
+		return NSS_STATUS_NOTFOUND;
+
+	      /* We look at all the content in the current bucket.  Go on
+		 to the next.  */
+	      bucket = intern.next = bucket->next;
+	      intern.offset = 0;
+	    }
+
+	  for (result = &bucket->mem[intern.offset]; isspace (*result);
+	       ++result)
+	    ++intern.offset;
+
+	  len = strlen (result);
+	}
       else
-        retval = yperr2nss ( yp_next (domain, "passwd.byname",
-                                      oldkey, oldkeylen,
-                                      &outkey, &keylen, &result, &len));
+	{
+	  int yperr;
 
-      if (retval != NSS_STATUS_SUCCESS)
-        {
-          if (retval == NSS_STATUS_TRYAGAIN)
-            *errnop = errno;
-          return retval;
-        }
+	  if (new_start)
+	    {
+	      /* Maybe we should read the database in one piece.  */
+	      if ((_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ)
+		  && internal_nis_setpwent () == NSS_STATUS_SUCCESS
+		  && intern.start != NULL)
+		{
+		  batch_read = true;
+		  goto handle_batch_read;
+		}
+
+	      yperr = yp_first (domain, "passwd.byname", &outkey, &keylen,
+				&result, &len);
+	    }
+	  else
+	    yperr = yp_next (domain, "passwd.byname", oldkey, oldkeylen,
+			     &outkey, &keylen, &result, &len);
+
+	  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+	    {
+	      enum nss_status retval = yperr2nss (yperr);
+
+	      if (retval == NSS_STATUS_TRYAGAIN)
+		*errnop = errno;
+	      return retval;
+	    }
+	}
 
       /* Check for adjunct style secret passwords.  They can be
 	 recognized by a password starting with "##".  */
-      p = strchr (result, ':');
+      char *p = strchr (result, ':');
+      size_t namelen;
+      char *result2;
+      int len2;
       if (p != NULL	/* This better should be true in all cases.  */
 	  && p[1] == '#' && p[2] == '#'
 	  && (namelen = p - result,
@@ -128,7 +293,8 @@ internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen,
 	    }
 
 	  restlen = len - (p - result);
-	  if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
+	  if (__builtin_expect ((size_t) (namelen + (endp - encrypted)
+					  + restlen + 2) > buflen, 0))
 	    {
 	      free (result2);
 	      free (result);
@@ -136,10 +302,10 @@ internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen,
 	      return NSS_STATUS_TRYAGAIN;
 	    }
 
-	  __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, result, namelen),
-					   ":", 1),
-				encrypted, endp - encrypted),
-		     p, restlen + 1);
+	  mempcpy (mempcpy (mempcpy (mempcpy (buffer, result, namelen),
+				     ":", 1),
+			    encrypted, endp - encrypted),
+		   p, restlen + 1);
 	  p = buffer;
 
 	  free (result2);
@@ -147,33 +313,41 @@ internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen,
       else
 	{
 	non_adjunct:
-	  if ((size_t) (len + 1) > buflen)
+	  if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
 	    {
 	      free (result);
 	      *errnop = ERANGE;
 	      return NSS_STATUS_TRYAGAIN;
 	    }
 
-	  p = strncpy (buffer, result, len);
-	  buffer[len] = '\0';
+	  p = buffer;
+	  *((char *) mempcpy (buffer, result, len)) = '\0';
 	}
 
       while (isspace (*p))
         ++p;
-      free (result);
+      if (!batch_read)
+	free (result);
 
-      parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop);
-      if (parse_res == -1)
+      parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen,
+					  errnop);
+      if (__builtin_expect (parse_res == -1, 0))
 	{
-	  free (outkey);
+	  if (!batch_read)
+	    free (outkey);
 	  *errnop = ERANGE;
 	  return NSS_STATUS_TRYAGAIN;
 	}
 
-      free (oldkey);
-      oldkey = outkey;
-      oldkeylen = keylen;
-      new_start = 0;
+      if (batch_read)
+	intern.offset += len + 1;
+      else
+	{
+	  free (oldkey);
+	  oldkey = outkey;
+	  oldkeylen = keylen;
+	  new_start = 0;
+	}
     }
   while (parse_res < 1);
 
@@ -199,28 +373,26 @@ enum nss_status
 _nss_nis_getpwnam_r (const char *name, struct passwd *pwd,
 		     char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  enum nss_status retval;
-  char *domain, *result, *result2, *p;
-  int len, len2, parse_res;
-  size_t namelen;
-
   if (name == NULL)
     {
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
 
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
-  namelen = strlen (name);
+  size_t namelen = strlen (name);
 
-  retval = yperr2nss (yp_match (domain, "passwd.byname", name,
-				namelen, &result, &len));
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "passwd.byname", name, namelen, &result, &len);
 
-  if (retval != NSS_STATUS_SUCCESS)
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
 	*errnop = errno;
       return retval;
@@ -228,7 +400,9 @@ _nss_nis_getpwnam_r (const char *name, struct passwd *pwd,
 
   /* Check for adjunct style secret passwords.  They can be recognized
      by a password starting with "##".  */
-  p = strchr (result, ':');
+  char *result2;
+  int len2;
+  char *p = strchr (result, ':');
   if (p != NULL	/* This better should be true in all cases.  */
       && p[1] == '#' && p[2] == '#'
       && yp_match (domain, "passwd.adjunct.byname", name, namelen,
@@ -238,7 +412,6 @@ _nss_nis_getpwnam_r (const char *name, struct passwd *pwd,
 	 therein into original result.  */
       char *encrypted = strchr (result2, ':');
       char *endp;
-      size_t restlen;
 
       if (encrypted == NULL
 	  || (endp = strchr (++encrypted, ':')) == NULL
@@ -251,8 +424,9 @@ _nss_nis_getpwnam_r (const char *name, struct passwd *pwd,
 	  goto non_adjunct;
 	}
 
-      restlen = len - (p - result);
-      if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
+      size_t restlen = len - (p - result);
+      if (__builtin_expect ((size_t) (namelen + (endp - encrypted)
+				      + restlen + 2) > buflen, 0))
 	{
 	  free (result2);
 	  free (result);
@@ -271,7 +445,7 @@ _nss_nis_getpwnam_r (const char *name, struct passwd *pwd,
   else
     {
     non_adjunct:
-      if ((size_t) (len + 1) > buflen)
+      if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
 	{
 	  free (result);
 	  *errnop = ERANGE;
@@ -286,8 +460,9 @@ _nss_nis_getpwnam_r (const char *name, struct passwd *pwd,
     ++p;
   free (result);
 
-  parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop);
-  if (parse_res < 1)
+  int parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen,
+					  errnop);
+  if (__builtin_expect (parse_res < 1, 0))
     {
       if (parse_res == -1)
         return NSS_STATUS_TRYAGAIN;
@@ -302,23 +477,21 @@ enum nss_status
 _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd,
 		     char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  enum nss_status retval;
-  char *domain, *result, *p, *result2;
-  int len, nlen, parse_res, len2;
-  char buf[32];
-  size_t namelen;
-
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
-  nlen = sprintf (buf, "%lu", (unsigned long int) uid);
+  char buf[32];
+  int nlen = snprintf (buf, sizeof (buf), "%lu", (unsigned long int) uid);
 
-  retval = yperr2nss (yp_match (domain, "passwd.byuid", buf,
-				nlen, &result, &len));
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "passwd.byuid", buf, nlen, &result, &len);
 
-  if (retval != NSS_STATUS_SUCCESS)
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
 	*errnop = errno;
       return retval;
@@ -326,7 +499,10 @@ _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd,
 
   /* Check for adjunct style secret passwords.  They can be recognized
      by a password starting with "##".  */
-  p = strchr (result, ':');
+  char *result2;
+  int len2;
+  size_t namelen;
+  char *p = strchr (result, ':');
   if (p != NULL	/* This better should be true in all cases.  */
       && p[1] == '#' && p[2] == '#'
       && (namelen = p - result,
@@ -351,7 +527,8 @@ _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd,
 	}
 
       restlen = len - (p - result);
-      if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
+      if (__builtin_expect ((size_t) (namelen + (endp - encrypted)
+				      + restlen + 2) > buflen, 0))
 	{
 	  free (result2);
 	  free (result);
@@ -370,7 +547,7 @@ _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd,
   else
     {
     non_adjunct:
-      if ((size_t) (len + 1) > buflen)
+      if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
 	{
 	  free (result);
 	  *errnop = ERANGE;
@@ -385,8 +562,9 @@ _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd,
     ++p;
   free (result);
 
-  parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop);
-  if (parse_res < 1)
+  int parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen,
+					  errnop);
+  if (__builtin_expect (parse_res < 1, 0))
     {
       if (parse_res == -1)
         return NSS_STATUS_TRYAGAIN;
diff --git a/nis/nss_nis/nis-rpc.c b/nis/nss_nis/nis-rpc.c
index d1ab94371a..2fdb16ddde 100644
--- a/nis/nss_nis/nis-rpc.c
+++ b/nis/nss_nis/nis-rpc.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1996-1998,2000,2002,2003,2004 Free Software Foundation, Inc.
+/* Copyright (C) 1996-1998,2000,2002,2003,2004,2006
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
 
@@ -35,59 +36,22 @@
 
 __libc_lock_define_initialized (static, lock)
 
-struct response_t
-{
-  struct response_t *next;
-  char val[0];
-};
-
-struct intern_t
-{
-  struct response_t *start;
-  struct response_t *next;
-};
-typedef struct intern_t intern_t;
-
-static intern_t intern = {NULL, NULL};
-
-static int
-saveit (int instatus, char *inkey, int inkeylen, char *inval,
-        int invallen, char *indata)
-{
-  intern_t *intern = (intern_t *)indata;
-
-  if (instatus != YP_TRUE)
-    return 1;
-
-  if (inkey && inkeylen > 0 && inval && invallen > 0)
-    {
-      struct response_t *newp = malloc (sizeof (struct response_t)
-					+ invallen + 1);
-      if (newp == NULL)
-	return 1; /* We have no error code for out of memory */
-
-      if (intern->start == NULL)
-	intern->start = newp;
-      else
-	intern->next->next = newp;
-      intern->next = newp;
+static intern_t intern;
 
-      newp->next = NULL;
-      *((char *) mempcpy (newp->val, inval, invallen)) = '\0';
-    }
-
-  return 0;
-}
 
 static void
 internal_nis_endrpcent (intern_t *intern)
 {
-  while (intern->start != NULL)
+  struct response_t *curr = intern->next;
+
+  while (curr != NULL)
     {
-      intern->next = intern->start;
-      intern->start = intern->start->next;
-      free (intern->next);
+      struct response_t *last = curr;
+      curr = curr->next;
+      free (last);
     }
+
+  intern->next = intern->start = NULL;
 }
 
 static enum nss_status
@@ -102,10 +66,16 @@ internal_nis_setrpcent (intern_t *intern)
 
   internal_nis_endrpcent (intern);
 
-  ypcb.foreach = saveit;
-  ypcb.data = (char *)intern;
-  status = yperr2nss (yp_all(domainname, "rpc.bynumber", &ypcb));
+  ypcb.foreach = _nis_saveit;
+  ypcb.data = (char *) intern;
+  status = yperr2nss (yp_all (domainname, "rpc.bynumber", &ypcb));
+
+  /* Mark the last buffer as full.  */
+  if (intern->next != NULL)
+    intern->next->size = intern->offset;
+
   intern->next = intern->start;
+  intern->offset = 0;
 
   return status;
 }
@@ -138,29 +108,60 @@ _nss_nis_endrpcent (void)
 
 static enum nss_status
 internal_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen,
-			  int *errnop, intern_t *data)
+			  int *errnop, intern_t *intern)
 {
   struct parser_data *pdata = (void *) buffer;
   int parse_res;
   char *p;
 
-  if (data->start == NULL)
-    internal_nis_setrpcent (data);
+  if (intern->start == NULL)
+    internal_nis_setrpcent (intern);
+
+  if (intern->next == NULL)
+    /* Not one entry in the map.  */
+    return NSS_STATUS_NOTFOUND;
 
   /* Get the next entry until we found a correct one. */
   do
     {
-      if (data->next == NULL)
-	return NSS_STATUS_NOTFOUND;
+      struct response_t *bucket = intern->next;
 
-      p = strncpy (buffer, data->next->val, buflen);
-      while (isspace (*p))
-        ++p;
+      if (__builtin_expect (intern->offset >= bucket->size, 0))
+	{
+	  if (bucket->next == NULL)
+	    return NSS_STATUS_NOTFOUND;
+
+	  /* We look at all the content in the current bucket.  Go on
+	     to the next.  */
+	  bucket = intern->next = bucket->next;
+	  intern->offset = 0;
+	}
+
+      for (p = &bucket->mem[intern->offset]; isspace (*p); ++p)
+        ++intern->offset;
+
+      size_t len = strlen (p) + 1;
+      if (__builtin_expect (len > buflen, 0))
+	{
+	  *errnop = ERANGE;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      /* We unfortunately have to copy the data in the user-provided
+	 buffer because that buffer might be around for a very long
+	 time and the servent structure must remain valid.  If we would
+	 rely on the BUCKET memory the next 'setservent' or 'endservent'
+	 call would destroy it.
+
+	 The important thing is that it is a single NUL-terminated
+	 string.  This is what the parsing routine expects.  */
+      p = memcpy (buffer, &bucket->mem[intern->offset], len);
 
       parse_res = _nss_files_parse_rpcent (p, rpc, pdata, buflen, errnop);
-      if (parse_res == -1)
+      if (__builtin_expect (parse_res == -1, 0))
 	return NSS_STATUS_TRYAGAIN;
-      data->next = data->next->next;
+
+      intern->offset += len;
     }
   while (!parse_res);
 
@@ -186,21 +187,18 @@ enum nss_status
 _nss_nis_getrpcbyname_r (const char *name, struct rpcent *rpc,
 			 char *buffer, size_t buflen, int *errnop)
 {
-  intern_t data = {NULL, NULL};
-  enum nss_status status;
-  int found;
-
   if (name == NULL)
     {
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
 
-  status = internal_nis_setrpcent (&data);
-  if (status != NSS_STATUS_SUCCESS)
+  intern_t data = { NULL, NULL, 0 };
+  enum nss_status status = internal_nis_setrpcent (&data);
+  if (__builtin_expect (status != NSS_STATUS_SUCCESS, 0))
     return status;
 
-  found = 0;
+  int found = 0;
   while (!found &&
          ((status = internal_nis_getrpcent_r (rpc, buffer, buflen, errnop,
 					      &data)) == NSS_STATUS_SUCCESS))
@@ -226,53 +224,52 @@ _nss_nis_getrpcbyname_r (const char *name, struct rpcent *rpc,
 
   internal_nis_endrpcent (&data);
 
-  if (!found && status == NSS_STATUS_SUCCESS)
+  if (__builtin_expect (!found && status == NSS_STATUS_SUCCESS, 0))
     return NSS_STATUS_NOTFOUND;
-  else
-    return status;
+
+  return status;
 }
 
 enum nss_status
 _nss_nis_getrpcbynumber_r (int number, struct rpcent *rpc,
 			   char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  enum nss_status retval;
-  char *domain, *result, *p;
-  int len, nlen, parse_res;
-  char buf[32];
-
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
-  nlen = sprintf (buf, "%d", number);
+  char buf[32];
+  int nlen = snprintf (buf, sizeof (buf), "%d", number);
 
-  retval = yperr2nss (yp_match (domain, "rpc.bynumber", buf,
-				 nlen, &result, &len));
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "rpc.bynumber", buf, nlen, &result, &len);
 
-  if (retval != NSS_STATUS_SUCCESS)
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
 	*errnop = errno;
       return retval;
     }
 
-  if ((size_t) (len + 1) > buflen)
+  if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
     {
       free (result);
       *errnop = ERANGE;
       return NSS_STATUS_TRYAGAIN;
     }
 
-  p = strncpy (buffer, result, len);
+  char *p = strncpy (buffer, result, len);
   buffer[len] = '\0';
   while (isspace (*p))
     ++p;
   free (result);
 
-  parse_res = _nss_files_parse_rpcent (p, rpc, data, buflen, errnop);
-
-  if (parse_res < 1)
+  int parse_res = _nss_files_parse_rpcent (p, rpc, (void  *) buffer, buflen,
+					   errnop);
+  if (__builtin_expect (parse_res < 1, 0))
     {
       if (parse_res == -1)
 	return NSS_STATUS_TRYAGAIN;
diff --git a/nis/nss_nis/nis-service.c b/nis/nss_nis/nis-service.c
index 1e879d04e3..59a598f296 100644
--- a/nis/nss_nis/nis-service.c
+++ b/nis/nss_nis/nis-service.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
 
@@ -27,6 +27,7 @@
 #include <rpcsvc/ypclnt.h>
 
 #include "nss-nis.h"
+#include <libnsl.h>
 
 
 /* Get the declaration of the parser function.  */
@@ -36,20 +37,7 @@
 
 __libc_lock_define_initialized (static, lock)
 
-struct response_t
-{
-  struct response_t *next;
-  char val[0];
-};
-
-struct intern_t
-{
-  struct response_t *start;
-  struct response_t *next;
-};
-typedef struct intern_t intern_t;
-
-static intern_t intern = { NULL, NULL };
+static intern_t intern;
 
 struct search_t
 {
@@ -64,63 +52,31 @@ struct search_t
 };
 
 static int
-saveit (int instatus, char *inkey, int inkeylen, char *inval,
-        int invallen, char *indata)
-{
-  intern_t *intern = (intern_t *) indata;
-
-  if (instatus != YP_TRUE)
-    return 1;
-
-  if (inkey && inkeylen > 0 && inval && invallen > 0)
-    {
-      struct response_t *newp = malloc (sizeof (struct response_t)
-					+ invallen + 1);
-      if (newp == NULL)
-	return 1; /* We have no error code for out of memory */
-
-      if (intern->start == NULL)
-	intern->start = newp;
-      else
-	intern->next->next = newp;
-      intern->next = newp;
-
-      newp->next = NULL;
-      *((char *) mempcpy (newp->val, inval, invallen)) = '\0';
-    }
-
-  return 0;
-}
-
-static int
 dosearch (int instatus, char *inkey, int inkeylen, char *inval,
 	  int invallen, char *indata)
 {
   struct search_t *req = (struct search_t *) indata;
 
-  if (instatus != YP_TRUE)
+  if (__builtin_expect (instatus != YP_TRUE, 0))
     return 1;
 
   if (inkey && inkeylen > 0 && inval && invallen > 0)
     {
-      struct parser_data *pdata = (void *) req->buffer;
-      int parse_res;
-      char *p;
-
-      if ((size_t) (invallen + 1) > req->buflen)
+      if (__builtin_expect ((size_t) (invallen + 1) > req->buflen, 0))
 	{
 	  *req->errnop = ERANGE;
 	  req->status = NSS_STATUS_TRYAGAIN;
 	  return 1;
 	}
 
-      p = strncpy (req->buffer, inval, invallen);
+      char *p = strncpy (req->buffer, inval, invallen);
       req->buffer[invallen] = '\0';
       while (isspace (*p))
         ++p;
 
-      parse_res = _nss_files_parse_servent (p, req->serv, pdata, req->buflen,
-					    req->errnop);
+      int parse_res = _nss_files_parse_servent (p, req->serv,
+						(void *) req->buffer,
+						req->buflen, req->errnop);
       if (parse_res == -1)
 	{
 	  req->status = NSS_STATUS_TRYAGAIN;
@@ -154,35 +110,35 @@ dosearch (int instatus, char *inkey, int inkeylen, char *inval,
   return 0;
 }
 
-static enum nss_status
-internal_nis_endservent (intern_t * intern)
+static void
+internal_nis_endservent (void)
 {
-  while (intern->start != NULL)
+  struct response_t *curr = intern.next;
+
+  while (curr != NULL)
     {
-      intern->next = intern->start;
-      intern->start = intern->start->next;
-      free (intern->next);
+      struct response_t *last = curr;
+      curr = curr->next;
+      free (last);
     }
 
-  return NSS_STATUS_SUCCESS;
+  intern.next = intern.start = NULL;
 }
 
 enum nss_status
 _nss_nis_endservent (void)
 {
-  enum nss_status status;
-
   __libc_lock_lock (lock);
 
-  status = internal_nis_endservent (&intern);
+  internal_nis_endservent ();
 
   __libc_lock_unlock (lock);
 
-  return status;
+  return NSS_STATUS_SUCCESS;
 }
 
 static enum nss_status
-internal_nis_setservent (intern_t *intern)
+internal_nis_setservent (void)
 {
   char *domainname;
   struct ypall_callback ypcb;
@@ -191,12 +147,18 @@ internal_nis_setservent (intern_t *intern)
   if (yp_get_default_domain (&domainname))
     return NSS_STATUS_UNAVAIL;
 
-  (void) internal_nis_endservent (intern);
+  internal_nis_endservent ();
 
-  ypcb.foreach = saveit;
-  ypcb.data = (char *) intern;
+  ypcb.foreach = _nis_saveit;
+  ypcb.data = (char *) &intern;
   status = yperr2nss (yp_all (domainname, "services.byname", &ypcb));
-  intern->next = intern->start;
+
+  /* Mark the last buffer as full.  */
+  if (intern.next != NULL)
+    intern.next->size = intern.offset;
+
+  intern.next = intern.start;
+  intern.offset = 0;
 
   return status;
 }
@@ -208,7 +170,7 @@ _nss_nis_setservent (int stayopen)
 
   __libc_lock_lock (lock);
 
-  status = internal_nis_setservent (&intern);
+  status = internal_nis_setservent ();
 
   __libc_lock_unlock (lock);
 
@@ -217,29 +179,60 @@ _nss_nis_setservent (int stayopen)
 
 static enum nss_status
 internal_nis_getservent_r (struct servent *serv, char *buffer,
-			   size_t buflen, int *errnop, intern_t *data)
+			   size_t buflen, int *errnop)
 {
   struct parser_data *pdata = (void *) buffer;
   int parse_res;
   char *p;
 
-  if (data->start == NULL)
-    internal_nis_setservent (data);
+  if (intern.start == NULL)
+    internal_nis_setservent ();
 
-  /* Get the next entry until we found a correct one. */
+  if (intern.next == NULL)
+    /* Not one entry in the map.  */
+    return NSS_STATUS_NOTFOUND;
+
+  /* Get the next entry until we found a correct one.  */
   do
     {
-      if (data->next == NULL)
-	return NSS_STATUS_NOTFOUND;
+      struct response_t *bucket = intern.next;
 
-      p = strncpy (buffer, data->next->val, buflen);
-      while (isspace (*p))
-        ++p;
+      if (__builtin_expect (intern.offset >= bucket->size, 0))
+	{
+	  if (bucket->next == NULL)
+	    return NSS_STATUS_NOTFOUND;
+
+	  /* We look at all the content in the current bucket.  Go on
+	     to the next.  */
+	  bucket = intern.next = bucket->next;
+	  intern.offset = 0;
+	}
+
+      for (p = &bucket->mem[intern.offset]; isspace (*p); ++p)
+        ++intern.offset;
+
+      size_t len = strlen (p) + 1;
+      if (__builtin_expect (len > buflen, 0))
+	{
+	  *errnop = ERANGE;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      /* We unfortunately have to copy the data in the user-provided
+	 buffer because that buffer might be around for a very long
+	 time and the servent structure must remain valid.  If we would
+	 rely on the BUCKET memory the next 'setservent' or 'endservent'
+	 call would destroy it.
+
+	 The important thing is that it is a single NUL-terminated
+	 string.  This is what the parsing routine expects.  */
+      p = memcpy (buffer, &bucket->mem[intern.offset], len);
 
       parse_res = _nss_files_parse_servent (p, serv, pdata, buflen, errnop);
-      if (parse_res == -1)
+      if (__builtin_expect (parse_res == -1, 0))
         return NSS_STATUS_TRYAGAIN;
-      data->next = data->next->next;
+
+      intern.offset += len;
     }
   while (!parse_res);
 
@@ -254,7 +247,7 @@ _nss_nis_getservent_r (struct servent *serv, char *buffer, size_t buflen,
 
   __libc_lock_lock (lock);
 
-  status = internal_nis_getservent_r (serv, buffer, buflen, errnop, &intern);
+  status = internal_nis_getservent_r (serv, buffer, buflen, errnop);
 
   __libc_lock_unlock (lock);
 
@@ -266,60 +259,55 @@ _nss_nis_getservbyname_r (const char *name, const char *protocol,
 			  struct servent *serv, char *buffer, size_t buflen,
 			  int *errnop)
 {
-  enum nss_status status;
-  char *domain;
-
   if (name == NULL)
     {
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
 
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
   /* If the protocol is given, we could try if our NIS server knows
      about services.byservicename map. If yes, we only need one query.  */
-  char key[strlen (name) + (protocol ? strlen (protocol) : 0) + 2];
-  char *cp, *result;
-  size_t keylen, len;
-  int int_len;
+  size_t keylen = strlen (name) + (protocol ? 1 + strlen (protocol) : 0);
+  char key[keylen + 1];
 
   /* key is: "name/proto" */
-  cp = stpcpy (key, name);
-  if (protocol)
+  char *cp = stpcpy (key, name);
+  if (protocol != NULL)
     {
       *cp++ = '/';
       strcpy (cp, protocol);
     }
-  keylen = strlen (key);
-  status = yperr2nss (yp_match (domain, "services.byservicename", key,
-				keylen, &result, &int_len));
-  len = int_len;
+
+  char *result;
+  int int_len;
+  int status = yp_match (domain, "services.byservicename", key,
+			 keylen, &result, &int_len);
+  size_t len = int_len;
 
   /* If we found the key, it's ok and parse the result. If not,
      fall through and parse the complete table. */
-  if (status == NSS_STATUS_SUCCESS)
+  if (__builtin_expect (status == YPERR_SUCCESS, 1))
     {
-      struct parser_data *pdata = (void *) buffer;
-      int parse_res;
-      char *p;
-
-      if ((size_t) (len + 1) > buflen)
+      if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
 	{
 	  free (result);
 	  *errnop = ERANGE;
 	  return NSS_STATUS_TRYAGAIN;
 	}
 
-      p = strncpy (buffer, result, len);
+      char *p = strncpy (buffer, result, len);
       buffer[len] = '\0';
       while (isspace (*p))
 	++p;
       free (result);
-      parse_res = _nss_files_parse_servent (p, serv, pdata,
-					    buflen, errnop);
-      if (parse_res < 0)
+
+      int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer,
+						buflen, errnop);
+      if (__builtin_expect (parse_res < 0, 0))
 	{
 	  if (parse_res == -1)
 	    return NSS_STATUS_TRYAGAIN;
@@ -331,8 +319,8 @@ _nss_nis_getservbyname_r (const char *name, const char *protocol,
     }
 
   /* Check if it is safe to rely on services.byservicename.  */
-  if (_nis_default_nss () & NSS_FLAG_SERVICES_AUTHORITATIVE)
-    return status;
+  if (_nsl_default_nss () & NSS_FLAG_SERVICES_AUTHORITATIVE)
+    return yperr2nss (status);
 
   struct ypall_callback ypcb;
   struct search_t req;
@@ -347,10 +335,10 @@ _nss_nis_getservbyname_r (const char *name, const char *protocol,
   req.buflen = buflen;
   req.errnop = errnop;
   req.status = NSS_STATUS_NOTFOUND;
-  status = yperr2nss (yp_all (domain, "services.byname", &ypcb));
+  status = yp_all (domain, "services.byname", &ypcb);
 
-  if (status != NSS_STATUS_SUCCESS)
-    return status;
+  if (__builtin_expect (status != YPERR_SUCCESS, 0))
+    return yperr2nss (status);
 
   return req.status;
 }
@@ -360,10 +348,8 @@ _nss_nis_getservbyport_r (int port, const char *protocol,
 			  struct servent *serv, char *buffer,
 			  size_t buflen, int *errnop)
 {
-  enum nss_status status;
   char *domain;
-
-  if (yp_get_default_domain (&domain))
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
   /* If the protocol is given, we only need one query.
@@ -372,48 +358,44 @@ _nss_nis_getservbyport_r (int port, const char *protocol,
   const char *proto = protocol != NULL ? protocol : "tcp";
   do
     {
+      /* key is: "port/proto" */
       char key[sizeof (int) * 3 + strlen (proto) + 2];
+      size_t keylen = snprintf (key, sizeof (key), "%d/%s", ntohs (port),
+				proto);
+
       char *result;
-      size_t keylen, len;
       int int_len;
-
-      /* key is: "port/proto" */
-      keylen = snprintf (key, sizeof (key), "%d/%s", ntohs (port), proto);
-      status = yperr2nss (yp_match (domain, "services.byname", key,
-				    keylen, &result, &int_len));
-      len = int_len;
+      int status = yp_match (domain, "services.byname", key, keylen, &result,
+			     &int_len);
+      size_t len = int_len;
 
       /* If we found the key, it's ok and parse the result. If not,
 	 fall through and parse the complete table. */
-      if (status == NSS_STATUS_SUCCESS)
+      if (__builtin_expect (status == YPERR_SUCCESS, 1))
 	{
-	  struct parser_data *pdata = (void *) buffer;
-	  int parse_res;
-	  char *p;
-
-	  if ((size_t) (len + 1) > buflen)
+	  if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
 	    {
 	      free (result);
 	      *errnop = ERANGE;
 	      return NSS_STATUS_TRYAGAIN;
 	    }
 
-	  p = strncpy (buffer, result, len);
+	  char  *p = strncpy (buffer, result, len);
 	  buffer[len] = '\0';
 	  while (isspace (*p))
 	    ++p;
 	  free (result);
-	  parse_res = _nss_files_parse_servent (p, serv, pdata,
-						buflen, errnop);
-	  if (parse_res < 0)
+	  int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer,
+						    buflen, errnop);
+	  if (__builtin_expect (parse_res < 0, 0))
 	    {
 	      if (parse_res == -1)
 		return NSS_STATUS_TRYAGAIN;
 	      else
 		return NSS_STATUS_NOTFOUND;
 	    }
-	  else
-	    return NSS_STATUS_SUCCESS;
+
+	  return NSS_STATUS_SUCCESS;
 	}
     }
   while (protocol == NULL && (proto[0] == 't' ? (proto = "udp") : NULL));
@@ -434,10 +416,10 @@ _nss_nis_getservbyport_r (int port, const char *protocol,
   req.buflen = buflen;
   req.errnop = errnop;
   req.status = NSS_STATUS_NOTFOUND;
-  status = yperr2nss (yp_all (domain, "services.byname", &ypcb));
+  int status = yp_all (domain, "services.byname", &ypcb);
 
-  if (status != NSS_STATUS_SUCCESS)
-    return status;
+  if (__builtin_expect (status != YPERR_SUCCESS, 0))
+    return yperr2nss (status);
 
   return req.status;
 }
diff --git a/nis/nss_nis/nis-spwd.c b/nis/nss_nis/nis-spwd.c
index 99a9ed5f48..0fc4e17c42 100644
--- a/nis/nss_nis/nis-spwd.c
+++ b/nis/nss_nis/nis-spwd.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-1998, 2001, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1996-1998,2001,2002,2003,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
 
@@ -68,49 +68,52 @@ static enum nss_status
 internal_nis_getspent_r (struct spwd *sp, char *buffer, size_t buflen,
 			 int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  char *domain, *result, *outkey;
-  int len, keylen, parse_res;
-
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
   /* Get the next entry until we found a correct one. */
+  int parse_res;
   do
     {
-      enum nss_status retval;
-      char *p;
+      char *result;
+      char *outkey;
+      int len;
+      int keylen;
+      int yperr;
 
       if (new_start)
-        retval = yperr2nss (yp_first (domain, "shadow.byname",
-                                      &outkey, &keylen, &result, &len));
+        yperr = yp_first (domain, "shadow.byname", &outkey, &keylen, &result,
+			  &len);
       else
-        retval = yperr2nss ( yp_next (domain, "shadow.byname",
-                                      oldkey, oldkeylen,
-                                      &outkey, &keylen, &result, &len));
+        yperr = yp_next (domain, "shadow.byname", oldkey, oldkeylen, &outkey,
+			 &keylen, &result, &len);
 
-      if (retval != NSS_STATUS_SUCCESS)
+      if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
         {
+	  enum nss_status retval = yperr2nss (yperr);
+
 	  if (retval == NSS_STATUS_TRYAGAIN)
 	    *errnop = errno;
           return retval;
         }
 
-      if ((size_t) (len + 1) > buflen)
+      if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
         {
           free (result);
 	  *errnop = ERANGE;
           return NSS_STATUS_TRYAGAIN;
         }
 
-      p = strncpy (buffer, result, len);
+      char *p = strncpy (buffer, result, len);
       buffer[len] = '\0';
       while (isspace (*p))
         ++p;
       free (result);
 
-      parse_res = _nss_files_parse_spent (p, sp, data, buflen, errnop);
-      if (parse_res == -1)
+      parse_res = _nss_files_parse_spent (p, sp, (void *) buffer, buflen,
+					  errnop);
+      if (__builtin_expect  (parse_res == -1, 0))
 	{
 	  free (outkey);
 	  *errnop = ERANGE;
@@ -146,45 +149,46 @@ enum nss_status
 _nss_nis_getspnam_r (const char *name, struct spwd *sp,
 		     char *buffer, size_t buflen, int *errnop)
 {
-  struct parser_data *data = (void *) buffer;
-  enum nss_status retval;
-  char *domain, *result, *p;
-  int len, parse_res;
-
   if (name == NULL)
     {
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
 
-  if (yp_get_default_domain (&domain))
+  char *domain;
+  if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
-  retval = yperr2nss (yp_match (domain, "shadow.byname", name,
-				strlen (name), &result, &len));
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "shadow.byname", name, strlen (name), &result,
+			&len);
 
-  if (retval != NSS_STATUS_SUCCESS)
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
+      enum nss_status retval = yperr2nss (yperr);
+
       if (retval == NSS_STATUS_TRYAGAIN)
 	*errnop = errno;
       return retval;
     }
 
-  if ((size_t) (len + 1) > buflen)
+  if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
     {
       free (result);
       *errnop = ERANGE;
       return NSS_STATUS_TRYAGAIN;
     }
 
-  p = strncpy (buffer, result, len);
+  char *p = strncpy (buffer, result, len);
   buffer[len] = '\0';
   while (isspace (*p))
     ++p;
   free (result);
 
-  parse_res = _nss_files_parse_spent (p, sp, data, buflen, errnop);
-  if (parse_res < 1)
+  int parse_res = _nss_files_parse_spent (p, sp, (void *) buffer, buflen,
+					  errnop);
+  if (__builtin_expect (parse_res < 1, 0))
     {
       if (parse_res == -1)
 	return NSS_STATUS_TRYAGAIN;
diff --git a/nis/nss_nisplus/nisplus-alias.c b/nis/nss_nisplus/nisplus-alias.c
index 152e5fc3fc..57858721a1 100644
--- a/nis/nss_nisplus/nisplus-alias.c
+++ b/nis/nss_nisplus/nisplus-alias.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1997, 1998, 2001, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 2001, 2002, 2003, 2005, 2006
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -17,6 +18,7 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <atomic.h>
 #include <nss.h>
 #include <errno.h>
 #include <ctype.h>
@@ -32,32 +34,39 @@ __libc_lock_define_initialized (static, lock)
 static nis_result *result;
 static u_long next_entry;
 static nis_name tablename_val;
-static u_long tablename_len;
+static size_t tablename_len;
 
-#define NISENTRYVAL(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+#define NISENTRYVAL(idx, col, res) \
+        (NIS_RES_OBJECT (res)[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)
+#define NISENTRYLEN(idx, col, res) \
+        (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
 
 static enum nss_status
 _nss_create_tablename (int *errnop)
 {
   if (tablename_val == NULL)
     {
-      char buf [40 + strlen (nis_local_directory ())];
-      char *p;
+      const char *local_dir = nis_local_directory ();
+      size_t local_dir_len = strlen (local_dir);
+      static const char prefix[] = "mail_aliases.org_dir.";
 
-      p = __stpcpy (buf, "mail_aliases.org_dir.");
-      p = __stpcpy (p, nis_local_directory ());
-      tablename_val = __strdup (buf);
-      if (tablename_val == NULL)
+      char *p = malloc (sizeof (prefix) + local_dir_len);
+      if (p == NULL)
 	{
 	  *errnop = errno;
 	  return NSS_STATUS_TRYAGAIN;
 	}
-      tablename_len = strlen (tablename_val);
+
+      memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
+
+      tablename_len = sizeof (prefix) - 1 + local_dir_len;
+
+      atomic_write_barrier ();
+
+      tablename_val = p;
     }
+
   return NSS_STATUS_SUCCESS;
 }
 
@@ -70,86 +79,87 @@ _nss_nisplus_parse_aliasent (nis_result *result, unsigned long entry,
     return 0;
 
   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
-      || __type_of (&result->objects.objects_val[entry]) != NIS_ENTRY_OBJ
-      || strcmp (result->objects.objects_val[entry].EN_data.en_type,
+      || __type_of (&NIS_RES_OBJECT (result)[entry]) != NIS_ENTRY_OBJ
+      || strcmp (NIS_RES_OBJECT (result)[entry].EN_data.en_type,
 		 "mail_aliases") != 0
-      || result->objects.objects_val[entry].EN_data.en_cols.en_cols_len < 2)
+      || NIS_RES_OBJECT (result)[entry].EN_data.en_cols.en_cols_len < 2)
     return 0;
-  else
+
+  if (NISENTRYLEN (entry, 1, result) >= buflen)
     {
-      char *first_unused = buffer + NISENTRYLEN (0, 1, result) + 1;
-      size_t room_left =
-	buflen - (buflen % __alignof__ (char *)) -
-	NISENTRYLEN (0, 1, result) - 2;
-      char *line;
-      char *cp;
-
-      if (NISENTRYLEN (entry, 1, result) >= buflen)
-	{
-	  /* The line is too long for our buffer.  */
-	no_more_room:
-	  *errnop = ERANGE;
-	  return -1;
-	}
-      else
-	{
-	  cp = __stpncpy (buffer, NISENTRYVAL (entry, 1, result),
-			 NISENTRYLEN (entry, 1, result));
-	  *cp = '\0';
-	}
+      /* The line is too long for our buffer.  */
+    no_more_room:
+      *errnop = ERANGE;
+      return -1;
+    }
+
+  char *cp = __stpncpy (buffer, NISENTRYVAL (entry, 1, result),
+			NISENTRYLEN (entry, 1, result));
+  *cp = '\0';
+
+  char *first_unused = cp + 1;
+  size_t room_left = buflen - (first_unused - buffer);
 
-      if (NISENTRYLEN(entry, 0, result) >= room_left)
+  alias->alias_local = 0;
+  alias->alias_members_len = 0;
+
+  if (NISENTRYLEN (entry, 0, result) >= room_left)
+    goto no_more_room;
+
+  cp = __stpncpy (first_unused, NISENTRYVAL (entry, 0, result),
+		  NISENTRYLEN (entry, 0, result));
+  *cp = '\0';
+  alias->alias_name = first_unused;
+
+  /* Terminate the line for any case.  */
+  cp = strpbrk (alias->alias_name, "#\n");
+  if (cp != NULL)
+    *cp = '\0';
+
+  size_t len = strlen (alias->alias_name) + 1;
+  first_unused += len;
+  room_left -= len;
+
+  /* Adjust the pointer so it is aligned for
+     storing pointers.  */
+  size_t adjust = ((__alignof__ (char *)
+		    - (first_unused - (char *) 0) % __alignof__ (char *))
+		   % __alignof__ (char *));
+  if (room_left < adjust)
+    goto no_more_room;
+  first_unused += adjust;
+  room_left -= adjust;
+
+  alias->alias_members = (char **) first_unused;
+
+  char *line = buffer;
+  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 *);
+      alias->alias_members[alias->alias_members_len] = line;
+
+      while (*line != '\0' && *line != ',')
+	++line;
 
-      alias->alias_local = 0;
-      alias->alias_members_len = 0;
-      *first_unused = '\0';
-      ++first_unused;
-      cp = __stpncpy (first_unused, NISENTRYVAL (entry, 0, result),
-		      NISENTRYLEN (entry, 0, result));
-      *cp = '\0';
-      alias->alias_name = first_unused;
-
-      /* Terminate the line for any case.  */
-      cp = strpbrk (alias->alias_name, "#\n");
-      if (cp != NULL)
-	*cp = '\0';
-
-      first_unused += strlen (alias->alias_name) +1;
-      /* Adjust the pointer so it is aligned for
-	 storing pointers.  */
-      first_unused += __alignof__ (char *) - 1;
-      first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
-      alias->alias_members = (char **) first_unused;
-
-      line = buffer;
-
-      while (*line != '\0')
+      if (line != alias->alias_members[alias->alias_members_len])
 	{
-	  /* Skip leading blanks.  */
-	  while (isspace (*line))
-	    ++line;
-
-	  if (*line == '\0')
-	    break;
-
-	  if (room_left < sizeof (char *))
-	    goto no_more_room;
-	  room_left -= sizeof (char *);
-	  alias->alias_members[alias->alias_members_len] = line;
-
-	  while (*line != '\0' && *line != ',')
-	    ++line;
-
-	  if (line != alias->alias_members[alias->alias_members_len])
-	    {
-	      *line++ = '\0';
-	      alias->alias_members_len++;
-	    }
+	  *line++ = '\0';
+	  ++alias->alias_members_len;
 	}
-
-      return alias->alias_members_len == 0 ? 0 : 1;
+      else if (*line == ',')
+	++line;
     }
+
+  return alias->alias_members_len == 0 ? 0 : 1;
 }
 
 static enum nss_status
@@ -158,9 +168,11 @@ internal_setaliasent (void)
   enum nss_status status;
   int err;
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result !=  NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
 
   if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS)
     return NSS_STATUS_UNAVAIL;
@@ -203,9 +215,11 @@ _nss_nisplus_endaliasent (void)
 {
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result != NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
   next_entry = 0;
 
   __libc_lock_unlock (lock);
@@ -240,7 +254,8 @@ internal_nisplus_getaliasent_r (struct aliasent *alias,
 	return NSS_STATUS_TRYAGAIN;
 
       ++next_entry;
-    } while (!parse_res);
+    }
+  while (!parse_res);
 
   return NSS_STATUS_SUCCESS;
 }
@@ -268,7 +283,12 @@ _nss_nisplus_getaliasbyname_r (const char *name, struct aliasent *alias,
 
   if (tablename_val == NULL)
     {
+      __libc_lock_lock (lock);
+
       enum nss_status status = _nss_create_tablename (errnop);
+
+      __libc_lock_unlock (lock);
+
       if (status != NSS_STATUS_SUCCESS)
 	return status;
     }
@@ -278,35 +298,42 @@ _nss_nisplus_getaliasbyname_r (const char *name, struct aliasent *alias,
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
-  else
+
+  char buf[strlen (name) + 9 + tablename_len];
+  int olderr = errno;
+
+  snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
+
+  nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+
+  if (result == NULL)
     {
-      nis_result *result;
-      char buf[strlen (name) + 30 + tablename_len];
-      int olderr = errno;
+      *errnop = ENOMEM;
+      return NSS_STATUS_TRYAGAIN;
+    }
 
-      sprintf (buf, "[name=%s],%s", name, tablename_val);
+  if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
+    {
+      enum nss_status status = niserr2nss (result->status);
+      nis_freeresult (result);
+      return status;
+    }
 
-      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+  parse_res = _nss_nisplus_parse_aliasent (result, 0, alias,
+					   buffer, buflen, errnop);
 
-      if (result == NULL)
-	{
-	  *errnop = ENOMEM;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-	return niserr2nss (result->status);
+  /* We do not need the lookup result anymore.  */
+  nis_freeresult (result);
 
-      parse_res = _nss_nisplus_parse_aliasent (result, 0, alias,
-					       buffer, buflen, errnop);
-      if (parse_res < 1)
-	{
-	  __set_errno (olderr);
+  if (__builtin_expect (parse_res < 1, 0))
+    {
+      __set_errno (olderr);
 
-	  if (parse_res == -1)
-	    return NSS_STATUS_TRYAGAIN;
-	  else
-	    return NSS_STATUS_NOTFOUND;
-	}
-      return NSS_STATUS_SUCCESS;
+      if (parse_res == -1)
+	return NSS_STATUS_TRYAGAIN;
+      else
+	return NSS_STATUS_NOTFOUND;
     }
+
+  return NSS_STATUS_SUCCESS;
 }
diff --git a/nis/nss_nisplus/nisplus-ethers.c b/nis/nss_nisplus/nisplus-ethers.c
index 028309c841..298869f931 100644
--- a/nis/nss_nisplus/nisplus-ethers.c
+++ b/nis/nss_nisplus/nisplus-ethers.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1997,1998,2000,2001,2002,2003 Free Software Foundation, Inc.
+/* Copyright (C) 1997,1998,2000-2003,2005,2006,2007
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
 
@@ -17,15 +18,17 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#include <nss.h>
-#include <errno.h>
+#include <atomic.h>
 #include <ctype.h>
-#include <string.h>
-#include <bits/libc-lock.h>
+#include <errno.h>
+#include <inttypes.h>
 #include <netdb.h>
+#include <nss.h>
+#include <string.h>
 #include <netinet/ether.h>
-#include <rpcsvc/nis.h>
 #include <netinet/if_ether.h>
+#include <rpcsvc/nis.h>
+#include <bits/libc-lock.h>
 
 #include "nss-nisplus.h"
 
@@ -36,11 +39,11 @@ static nis_name tablename_val;
 static u_long tablename_len;
 
 
-#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 NISENTRYVAL(idx, col, res) \
+        (NIS_RES_OBJECT (res)[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)
+#define NISENTRYLEN(idx, col, res) \
+        (NIS_RES_OBJECT (res)[idx].zo_data.objdata_u.en_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
 
 static int
 _nss_nisplus_parse_etherent (nis_result *result, struct etherent *ether,
@@ -53,7 +56,7 @@ _nss_nisplus_parse_etherent (nis_result *result, struct etherent *ether,
     return 0;
 
   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
-      || result->objects.objects_len != 1
+      || NIS_RES_NUMOBJ (result) != 1
       || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
       || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type,
 		 "ethers_tbl") != 0
@@ -61,16 +64,25 @@ _nss_nisplus_parse_etherent (nis_result *result, struct etherent *ether,
     return 0;
 
   /* Generate the ether entry format and use the normal parser */
-  if (NISENTRYLEN (0, 0, result) +1 > room_left)
+  if (NISENTRYLEN (0, 0, result) + 1 > room_left)
     {
       *errnop = ERANGE;
       return -1;
     }
-  strncpy (p, NISENTRYVAL (0, 0, result), NISENTRYLEN (0, 0, result));
-  room_left -= (NISENTRYLEN (0, 0, result) +1);
+  char *cp = __stpncpy (p, NISENTRYVAL (0, 0, result),
+			NISENTRYLEN (0, 0, result));
+  *cp = '\0';
+  room_left -= NISENTRYLEN (0, 0, result) + 1;
   ether->e_name = p;
 
-  ether->e_addr = *ether_aton (NISENTRYVAL (0, 1, result));
+  struct ether_addr *ea = ether_aton (NISENTRYVAL (0, 1, result));
+  if (ea == NULL)
+    {
+      *errnop = EINVAL;
+      return -2;
+    }
+
+  ether->e_addr = *ea;
 
   return 1;
 }
@@ -80,18 +92,24 @@ _nss_create_tablename (int *errnop)
 {
   if (tablename_val == NULL)
     {
-      char buf [40 + strlen (nis_local_directory ())];
-      char *p;
+      const char *local_dir = nis_local_directory ();
+      size_t local_dir_len = strlen (local_dir);
+      static const char prefix[] = "ethers.org_dir.";
 
-      p = __stpcpy (buf, "ethers.org_dir.");
-      p = __stpcpy (p, nis_local_directory ());
-      tablename_val = __strdup (buf);
-      if (tablename_val == NULL)
+      char *p = malloc (sizeof (prefix) + local_dir_len);
+      if (p == NULL)
 	{
 	  *errnop = errno;
 	  return NSS_STATUS_TRYAGAIN;
 	}
-      tablename_len = strlen (tablename_val);
+
+      memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
+
+      tablename_len = sizeof (prefix) - 1 + local_dir_len;
+
+      atomic_write_barrier ();
+
+      tablename_val = p;
     }
   return NSS_STATUS_SUCCESS;
 }
@@ -107,9 +125,11 @@ _nss_nisplus_setetherent (int stayopen)
 
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result != NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
 
   if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS)
     status = NSS_STATUS_UNAVAIL;
@@ -124,9 +144,11 @@ _nss_nisplus_endetherent (void)
 {
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result != NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
 
   __libc_lock_unlock (lock);
 
@@ -137,8 +159,6 @@ static enum nss_status
 internal_nisplus_getetherent_r (struct etherent *ether, char *buffer,
 				size_t buflen, int *errnop)
 {
-  int parse_res;
-
   if (tablename_val == NULL)
     {
       enum nss_status status = _nss_create_tablename (errnop);
@@ -148,6 +168,7 @@ internal_nisplus_getetherent_r (struct etherent *ether, char *buffer,
     }
 
   /* Get the next entry until we found a correct one. */
+  int parse_res;
   do
     {
       nis_result *saved_result;
@@ -156,16 +177,23 @@ internal_nisplus_getetherent_r (struct etherent *ether, char *buffer,
 	{
 	  saved_result = NULL;
 	  result = nis_first_entry (tablename_val);
+	  if (result == NULL)
+	    {
+	      *errnop = errno;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    return niserr2nss (result->status);
 	}
       else
 	{
-	  nis_result *res2;
-
-	  res2 = nis_next_entry(tablename_val, &result->cookie);
 	  saved_result = result;
-	  result = res2;
+	  result = nis_next_entry (tablename_val, &result->cookie);
+	  if (result == NULL)
+	    {
+	      *errnop = errno;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    {
 	      nis_freeresult (saved_result);
@@ -178,17 +206,15 @@ internal_nisplus_getetherent_r (struct etherent *ether, char *buffer,
       if (parse_res == -1)
 	{
 	  nis_freeresult (result);
-	  *errnop = ERANGE;
 	  result = saved_result;
 	  return NSS_STATUS_TRYAGAIN;
 	}
-      else
-	{
-	  if (saved_result != NULL)
-	    nis_freeresult (saved_result);
-	}
 
-    } while (!parse_res);
+      if (saved_result != NULL)
+	nis_freeresult (saved_result);
+
+    }
+  while (!parse_res);
 
   return NSS_STATUS_SUCCESS;
 }
@@ -212,8 +238,6 @@ enum nss_status
 _nss_nisplus_gethostton_r (const char *name, struct etherent *eth,
 			   char *buffer, size_t buflen, int *errnop)
 {
-  int parse_res;
-
   if (tablename_val == NULL)
     {
       enum nss_status status = _nss_create_tablename (errnop);
@@ -227,56 +251,59 @@ _nss_nisplus_gethostton_r (const char *name, struct etherent *eth,
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
-  else
-    {
-      nis_result *result;
-      char buf[strlen (name) + 40 + tablename_len];
-      int olderr = errno;
 
-      sprintf (buf, "[name=%s],%s", name, tablename_val);
+  char buf[strlen (name) + 9 + tablename_len];
+  int olderr = errno;
 
-      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+  snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
 
-      if (result == NULL)
-	{
-	  *errnop = ENOMEM;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-	{
-	  enum nss_status status = niserr2nss (result->status);
-	  nis_freeresult (result);
-	  return status;
-	}
+  nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
+				 NULL, NULL);
 
-      parse_res = _nss_nisplus_parse_etherent (result, eth, buffer,
+  if (result == NULL)
+    {
+      *errnop = ENOMEM;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
+    {
+      enum nss_status status = niserr2nss (result->status);
+      nis_freeresult (result);
+      return status;
+    }
+
+  int parse_res = _nss_nisplus_parse_etherent (result, eth, buffer,
 					       buflen, errnop);
-      if (parse_res < 1)
-	{
-	  __set_errno (olderr);
 
-	  if (parse_res == -1)
-	    {
-	      nis_freeresult (result);
-	      *errnop = ERANGE;
-	      return NSS_STATUS_TRYAGAIN;
-	    }
-	  else
-	   return NSS_STATUS_NOTFOUND;
-	}
-      return NSS_STATUS_SUCCESS;
+  /* We do not need the lookup result anymore.  */
+  nis_freeresult (result);
+
+  if (__builtin_expect (parse_res < 1, 0))
+    {
+      __set_errno (olderr);
+
+      if (parse_res == -1)
+	return NSS_STATUS_TRYAGAIN;
+
+      return NSS_STATUS_NOTFOUND;
     }
+
+  return NSS_STATUS_SUCCESS;
 }
 
 enum nss_status
-_nss_nisplus_getntohost_r (const struct ether_addr *addr,
-			   struct etherent *eth,
+_nss_nisplus_getntohost_r (const struct ether_addr *addr, struct etherent *eth,
 			   char *buffer, size_t buflen, int *errnop)
 {
   if (tablename_val == NULL)
     {
+      __libc_lock_lock (lock);
+
       enum nss_status status = _nss_create_tablename (errnop);
 
+      __libc_lock_unlock (lock);
+
       if (status != NSS_STATUS_SUCCESS)
 	return status;
     }
@@ -286,44 +313,46 @@ _nss_nisplus_getntohost_r (const struct ether_addr *addr,
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
-  else
-    {
-      int parse_res;
-      nis_result *result;
-      char buf[255 + tablename_len];
 
-      sprintf (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]);
+  char buf[26 + tablename_len];
 
-      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+  snprintf (buf, sizeof (buf),
+	    "[addr=%" PRIx8 ":%" PRIx8 ":%" PRIx8 ":%" PRIx8 ":%" PRIx8
+	    ":%" PRIx8 "],%s",
+	    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],
+	    tablename_val);
 
-      if (result == NULL)
-	{
-	  *errnop = ENOMEM;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-	{
-	  enum nss_status status = niserr2nss (result->status);
-	  nis_freeresult (result);
-	  return status;
-	}
+  nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
+				 NULL, NULL);
+
+  if (result == NULL)
+    {
+      *errnop = ENOMEM;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
+    {
+      enum nss_status status = niserr2nss (result->status);
+      nis_freeresult (result);
+      return status;
+    }
 
-      parse_res = _nss_nisplus_parse_etherent (result, eth, buffer,
+  int parse_res = _nss_nisplus_parse_etherent (result, eth, buffer,
 					       buflen, errnop);
-      if (parse_res < 1)
-	{
-	  if (parse_res == -1)
-	    {
-	      nis_freeresult (result);
-	      *errnop = ERANGE;
-	      return NSS_STATUS_TRYAGAIN;
-	    }
-	  else
-	    return NSS_STATUS_NOTFOUND;
-	}
-      return NSS_STATUS_SUCCESS;
+
+  /* We do not need the lookup result anymore.  */
+  nis_freeresult (result);
+
+  if (__builtin_expect (parse_res < 1, 0))
+    {
+      if (parse_res == -1)
+	return NSS_STATUS_TRYAGAIN;
+
+      return NSS_STATUS_NOTFOUND;
     }
+
+  return NSS_STATUS_SUCCESS;
 }
diff --git a/nis/nss_nisplus/nisplus-grp.c b/nis/nss_nisplus/nisplus-grp.c
index daca94fc87..7cc762fea9 100644
--- a/nis/nss_nisplus/nisplus-grp.c
+++ b/nis/nss_nisplus/nisplus-grp.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1997, 2001, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 2001, 2002, 2003, 2005, 2006
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -17,6 +18,7 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <atomic.h>
 #include <nss.h>
 #include <grp.h>
 #include <ctype.h>
@@ -27,68 +29,110 @@
 
 #include "nss-nisplus.h"
 #include "nisplus-parser.h"
+#include <libnsl.h>
+#include <nis_intern.h>
+#include <nis_xdr.h>
+
 
 __libc_lock_define_initialized (static, lock);
 
-static nis_result *result;
-static unsigned long next_entry;
-static nis_name tablename_val;
-static u_long tablename_len;
+/* Connection information.  */
+static ib_request *ibreq;
+static directory_obj *dir;
+static dir_binding bptr;
+static char *tablepath;
+static char *tableptr;
+/* Cursor.  */
+static netobj cursor;
 
-static enum nss_status
-_nss_create_tablename (int *errnop)
+
+nis_name grp_tablename_val attribute_hidden;
+size_t grp_tablename_len attribute_hidden;
+
+enum nss_status
+_nss_grp_create_tablename (int *errnop)
 {
-  if (tablename_val == NULL)
+  if (grp_tablename_val == NULL)
     {
-      char buf [40 + strlen (nis_local_directory ())];
-      char *p;
+      const char *local_dir = nis_local_directory ();
+      size_t local_dir_len = strlen (local_dir);
+      static const char prefix[] = "group.org_dir.";
 
-      p = __stpcpy (buf, "group.org_dir.");
-      p = __stpcpy (p, nis_local_directory ());
-      tablename_val = __strdup (buf);
-      if (tablename_val == NULL)
+      char *p = malloc (sizeof (prefix) + local_dir_len);
+      if (p == NULL)
 	{
 	  *errnop = errno;
 	  return NSS_STATUS_TRYAGAIN;
 	}
-      tablename_len = strlen (tablename_val);
+
+      memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
+
+      grp_tablename_len = sizeof (prefix) - 1 + local_dir_len;
+
+      atomic_write_barrier ();
+
+      if (atomic_compare_and_exchange_bool_acq (&grp_tablename_val, p, NULL))
+	{
+	  /* Another thread already installed the value.  */
+	  free (p);
+	  grp_tablename_len = strlen (grp_tablename_val);
+	}
     }
+
   return NSS_STATUS_SUCCESS;
 }
 
-static enum nss_status
-internal_setgrent (void)
+
+static void
+internal_endgrent (void)
 {
-  enum nss_status status;
-  int err;
+  __nisbind_destroy (&bptr);
+  memset (&bptr, '\0', sizeof (bptr));
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
-  next_entry = 0;
+  nis_free_directory (dir);
+  dir = NULL;
 
-  if (tablename_val == NULL)
-    if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS)
-      return NSS_STATUS_UNAVAIL;
+  nis_free_request (ibreq);
+  ibreq = NULL;
 
-  result = nis_list (tablename_val, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
-  if (result == NULL)
-    {
-      status = NSS_STATUS_TRYAGAIN;
-      __set_errno (ENOMEM);
-    }
-  else
+  xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor);
+  memset (&cursor, '\0', sizeof (cursor));
+
+  free (tablepath);
+  tableptr = tablepath = NULL;
+}
+
+
+static enum nss_status
+internal_setgrent (int *errnop)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  if (grp_tablename_val == NULL)
+    status = _nss_grp_create_tablename (errnop);
+
+  if (status == NSS_STATUS_SUCCESS)
     {
-      status = niserr2nss (result->status);
-      if (status != NSS_STATUS_SUCCESS)
+      ibreq = __create_ib_request (grp_tablename_val, 0);
+      if (ibreq == NULL)
 	{
-	  nis_freeresult (result);
-	  result = NULL;
+	  *errnop = errno;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      nis_error retcode = __prepare_niscall (grp_tablename_val, &dir, &bptr, 0);
+      if (retcode != NIS_SUCCESS)
+	{
+	  nis_free_request (ibreq);
+	  ibreq = NULL;
+	  status = niserr2nss (retcode);
 	}
     }
+
   return status;
 }
 
+
 enum nss_status
 _nss_nisplus_setgrent (int stayopen)
 {
@@ -96,58 +140,133 @@ _nss_nisplus_setgrent (int stayopen)
 
   __libc_lock_lock (lock);
 
-  status = internal_setgrent ();
+  internal_endgrent ();
+
+  // XXX We need to be able to set errno.  Pass in new parameter.
+  int err;
+  status = internal_setgrent (&err);
 
   __libc_lock_unlock (lock);
 
   return status;
 }
 
+
 enum nss_status
 _nss_nisplus_endgrent (void)
 {
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  internal_endgrent ();
 
   __libc_lock_unlock (lock);
 
   return NSS_STATUS_SUCCESS;
 }
 
+
 static enum nss_status
 internal_nisplus_getgrent_r (struct group *gr, char *buffer, size_t buflen,
 			     int *errnop)
 {
-  int parse_res;
-
-  if (result == NULL)
-    {
-      enum nss_status status;
-
-      status = internal_setgrent ();
-      if (result == NULL || status != NSS_STATUS_SUCCESS)
-	return status;
-    }
+  int parse_res = -1;
+  enum nss_status retval = NSS_STATUS_SUCCESS;
 
   /* Get the next entry until we found a correct one. */
   do
     {
-      if (next_entry >= result->objects.objects_len)
-	return NSS_STATUS_NOTFOUND;
+      nis_error status;
+      nis_result result;
+      memset (&result, '\0', sizeof (result));
+
+      if (cursor.n_bytes == NULL)
+	{
+	  if (ibreq == NULL)
+	    {
+	      retval = internal_setgrent (errnop);
+	      if (retval != NSS_STATUS_SUCCESS)
+		return retval;
+	    }
+
+	  status = __do_niscall3 (&bptr, NIS_IBFIRST,
+				  (xdrproc_t) _xdr_ib_request,
+				  (caddr_t) ibreq,
+				  (xdrproc_t) _xdr_nis_result,
+				  (caddr_t) &result,
+				  0, NULL);
+	}
+      else
+	{
+	  ibreq->ibr_cookie.n_bytes = cursor.n_bytes;
+	  ibreq->ibr_cookie.n_len = cursor.n_len;
+
+	  status = __do_niscall3 (&bptr, NIS_IBNEXT,
+				  (xdrproc_t) _xdr_ib_request,
+				  (caddr_t) ibreq,
+				  (xdrproc_t) _xdr_nis_result,
+				  (caddr_t) &result,
+				  0, NULL);
+
+	  ibreq->ibr_cookie.n_bytes = NULL;
+	  ibreq->ibr_cookie.n_len = 0;
+	}
+
+      if (status != NIS_SUCCESS)
+	return niserr2nss (status);
 
-      parse_res = _nss_nisplus_parse_grent (result, next_entry, gr,
+      if (NIS_RES_STATUS (&result) == NIS_NOTFOUND)
+	{
+	  /* No more entries on this server.  This means we have to go
+	     to the next server on the path.  */
+	  status = __follow_path (&tablepath, &tableptr, ibreq, &bptr);
+	  if (status != NIS_SUCCESS)
+	    return niserr2nss (status);
+
+	  directory_obj *newdir = NULL;
+	  dir_binding newbptr;
+	  status = __prepare_niscall (ibreq->ibr_name, &newdir, &newbptr, 0);
+	  if (status != NIS_SUCCESS)
+	    return niserr2nss (status);
+
+	  nis_free_directory (dir);
+	  dir = newdir;
+	  __nisbind_destroy (&bptr);
+	  bptr = newbptr;
+
+	  xdr_free ((xdrproc_t) xdr_netobj, (char *) &result.cookie);
+	  result.cookie.n_bytes = NULL;
+	  result.cookie.n_len = 0;
+	  parse_res = 0;
+	  goto next;
+	}
+      else if (NIS_RES_STATUS (&result) != NIS_SUCCESS)
+	return niserr2nss (NIS_RES_STATUS (&result));
+
+      parse_res = _nss_nisplus_parse_grent (&result, gr,
 					    buffer, buflen, errnop);
-      if (parse_res == -1)
-	return NSS_STATUS_TRYAGAIN;
+      if (__builtin_expect (parse_res == -1, 0))
+	{
+	  *errnop = ERANGE;
+	  retval = NSS_STATUS_TRYAGAIN;
+	  goto freeres;
+	}
 
-      ++next_entry;
+    next:
+      /* Free the old cursor.  */
+      xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor);
+      /* Remember the new one.  */
+      cursor.n_bytes = result.cookie.n_bytes;
+      cursor.n_len = result.cookie.n_len;
+      /* Free the result structure.  NB: we do not remove the cookie.  */
+      result.cookie.n_bytes = NULL;
+      result.cookie.n_len = 0;
+    freeres:
+      xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &result);
+      memset (&result, '\0', sizeof (result));
     }
   while (!parse_res);
 
-  return NSS_STATUS_SUCCESS;
+  return retval;
 }
 
 enum nss_status
@@ -171,9 +290,9 @@ _nss_nisplus_getgrnam_r (const char *name, struct group *gr,
 {
   int parse_res;
 
-  if (tablename_val == NULL)
+  if (grp_tablename_val == NULL)
     {
-      enum nss_status status = _nss_create_tablename (errnop);
+      enum nss_status status = _nss_grp_create_tablename (errnop);
 
       if (status != NSS_STATUS_SUCCESS)
 	return status;
@@ -184,102 +303,101 @@ _nss_nisplus_getgrnam_r (const char *name, struct group *gr,
       *errnop = EINVAL;
       return NSS_STATUS_NOTFOUND;
     }
-  else
+
+  nis_result *result;
+  char buf[strlen (name) + 9 + grp_tablename_len];
+  int olderr = errno;
+
+  snprintf (buf, sizeof (buf), "[name=%s],%s", name, grp_tablename_val);
+
+  result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+
+  if (result == NULL)
     {
-      nis_result *result;
-      char buf[strlen (name) + 24 + tablename_len];
-      int olderr = errno;
+      *errnop = ENOMEM;
+      return NSS_STATUS_TRYAGAIN;
+    }
 
-      sprintf (buf, "[name=%s],%s", name, tablename_val);
+  if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
+    {
+      enum nss_status status = niserr2nss (result->status);
 
-      result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+      nis_freeresult (result);
+      return status;
+    }
 
-      if (result == NULL)
+  parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen, errnop);
+  nis_freeresult (result);
+  if (__builtin_expect (parse_res < 1, 0))
+    {
+      if (parse_res == -1)
 	{
-	  *errnop = ENOMEM;
+	  *errnop = ERANGE;
 	  return NSS_STATUS_TRYAGAIN;
 	}
-      if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+      else
 	{
-	  enum nss_status status = niserr2nss (result->status);
-
-	  nis_freeresult (result);
-	  return status;
-	}
-
-      parse_res = _nss_nisplus_parse_grent (result, 0, gr, buffer, buflen,
-					    errnop);
-      nis_freeresult (result);
-      if (parse_res < 1)
-	{
-	  if (parse_res == -1)
-	    {
-	      *errnop = ERANGE;
-	      return NSS_STATUS_TRYAGAIN;
-	    }
-	  else
-	    {
-	      __set_errno (olderr);
-	      return NSS_STATUS_NOTFOUND;
-	    }
+	  __set_errno (olderr);
+	  return NSS_STATUS_NOTFOUND;
 	}
-      return NSS_STATUS_SUCCESS;
     }
+
+  return NSS_STATUS_SUCCESS;
 }
 
 enum nss_status
 _nss_nisplus_getgrgid_r (const gid_t gid, struct group *gr,
 			 char *buffer, size_t buflen, int *errnop)
 {
-  if (tablename_val == NULL)
+  if (grp_tablename_val == NULL)
     {
-      enum nss_status status = _nss_create_tablename (errnop);
+      enum nss_status status = _nss_grp_create_tablename (errnop);
 
       if (status != NSS_STATUS_SUCCESS)
 	return status;
     }
 
-  {
-    int parse_res;
-    nis_result *result;
-    char buf[36 + tablename_len];
-    int olderr = errno;
+  int parse_res;
+  nis_result *result;
+  char buf[8 + 3 * sizeof (unsigned long int) + grp_tablename_len];
+  int olderr = errno;
+
+  snprintf (buf, sizeof (buf), "[gid=%lu],%s",
+	    (unsigned long int) gid, grp_tablename_val);
 
-    sprintf (buf, "[gid=%lu],%s", (unsigned long int) gid, tablename_val);
+  result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
-    result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+  if (result == NULL)
+    {
+      *errnop = ENOMEM;
+      return NSS_STATUS_TRYAGAIN;
+    }
 
-    if (result == NULL)
-      {
-	*errnop = ENOMEM;
-	return NSS_STATUS_TRYAGAIN;
-      }
-    if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-      {
-	enum nss_status status = niserr2nss (result->status);
+  if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
+    {
+      enum nss_status status = niserr2nss (result->status);
 
-	__set_errno (olderr);
+      __set_errno (olderr);
 
-	nis_freeresult (result);
-	return status;
-      }
-
-    parse_res = _nss_nisplus_parse_grent (result, 0, gr, buffer, buflen,
-					  errnop);
-
-    nis_freeresult (result);
-    if (parse_res < 1)
-      {
-	__set_errno (olderr);
-
-	if (parse_res == -1)
-	  {
-	    *errnop = ERANGE;
-	    return NSS_STATUS_TRYAGAIN;
-	  }
-	else
-	  return NSS_STATUS_NOTFOUND;
-      }
-    return NSS_STATUS_SUCCESS;
-  }
+      nis_freeresult (result);
+      return status;
+    }
+
+  parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen, errnop);
+
+  nis_freeresult (result);
+  if (__builtin_expect (parse_res < 1, 0))
+    {
+      __set_errno (olderr);
+
+      if (parse_res == -1)
+	{
+	  *errnop = ERANGE;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      else
+	return NSS_STATUS_NOTFOUND;
+    }
+
+  return NSS_STATUS_SUCCESS;
 }
diff --git a/nis/nss_nisplus/nisplus-hosts.c b/nis/nss_nisplus/nisplus-hosts.c
index 540469894e..f5f0ac96da 100644
--- a/nis/nss_nisplus/nisplus-hosts.c
+++ b/nis/nss_nisplus/nisplus-hosts.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997-2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1997-2002, 2003, 2005, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
 
@@ -17,15 +17,16 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#include <nss.h>
-#include <netdb.h>
-#include <errno.h>
+#include <atomic.h>
 #include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <nss.h>
 #include <string.h>
-#include <netinet/in.h>
 #include <arpa/inet.h>
-#include <bits/libc-lock.h>
+#include <netinet/in.h>
 #include <rpcsvc/nis.h>
+#include <bits/libc-lock.h>
 
 #include "nss-nisplus.h"
 
@@ -35,15 +36,16 @@ static nis_result *result;
 static nis_name tablename_val;
 static u_long tablename_len;
 
-#define NISENTRYVAL(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+#define NISENTRYVAL(idx, col, res) \
+        (NIS_RES_OBJECT (res)[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)
+#define NISENTRYLEN(idx, col, res) \
+        (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
 
 /* Get implementation for some internal functions. */
 #include <resolv/mapv4v6addr.h>
 
+
 static int
 _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host,
 			    char *buffer, size_t buflen, int *errnop,
@@ -52,27 +54,26 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host,
   unsigned int i;
   char *first_unused = buffer;
   size_t room_left = buflen;
-  char *data, *p, *line;
 
   if (result == NULL)
     return 0;
 
   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
-      __type_of (result->objects.objects_val) != NIS_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)
+      __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ ||
+      strcmp(NIS_RES_OBJECT (result)[0].EN_data.en_type, "hosts_tbl") != 0 ||
+      NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4)
     return 0;
 
-  if (room_left < NISENTRYLEN (0, 2, result) + 1)
+  char *data = first_unused;
+
+  if (room_left < (af == AF_INET6 || (flags & AI_V4MAPPED) != 0
+		   ? IN6ADDRSZ : INADDRSZ))
     {
     no_more_room:
       *errnop = ERANGE;
       return -1;
     }
 
-  data = first_unused;
-
   /* Parse address.  */
   if (af == AF_INET && inet_pton (af, NISENTRYVAL (0, 2, result), data) > 0)
     {
@@ -98,51 +99,53 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host,
     /* Illegal address: ignore line.  */
     return 0;
 
-  first_unused+=host->h_length;
-  room_left-=host->h_length;
+  first_unused += host->h_length;
+  room_left -= host->h_length;
 
   if (NISENTRYLEN (0, 0, result) + 1 > room_left)
     goto no_more_room;
 
-  p = __stpncpy (first_unused, NISENTRYVAL (0, 0, result),
-		 NISENTRYLEN (0, 0, result));
-  *p = '\0';
-  room_left -= (NISENTRYLEN (0, 0, result) + 1);
   host->h_name = first_unused;
-  first_unused += NISENTRYLEN (0, 0, result) +1;
-  p = first_unused;
-
-  line = p;
-  for (i = 0; i < result->objects.objects_len; ++i)
+  first_unused = __stpncpy (first_unused, NISENTRYVAL (0, 0, result),
+			    NISENTRYLEN (0, 0, result));
+  *first_unused++ = '\0';
+  room_left -= NISENTRYLEN (0, 0, result) + 1;
+
+  /* XXX Rewrite at some point to allocate the array first and then
+     copy the strings.  It wasteful to first concatenate the strings
+     to just split them again later.  */
+  char *line = first_unused;
+  for (i = 0; i < NIS_RES_NUMOBJ (result); ++i)
     {
       if (strcmp (NISENTRYVAL (i, 1, result), host->h_name) != 0)
 	{
 	  if (NISENTRYLEN (i, 1, result) + 2 > room_left)
 	    goto no_more_room;
 
-	  *p++ = ' ';
-	  p = __stpncpy (p, NISENTRYVAL (i, 1, result),
-			 NISENTRYLEN (i, 1, result));
-	  *p = '\0';
-	  room_left -= (NISENTRYLEN (i, 1, result) + 1);
+	  *first_unused++ = ' ';
+	  first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result),
+				    NISENTRYLEN (i, 1, result));
+	  *first_unused = '\0';
+	  room_left -= NISENTRYLEN (i, 1, result) + 1;
 	}
     }
-  *p++ = '\0';
-  first_unused = p;
+  *first_unused++ = '\0';
 
   /* Adjust the pointer so it is aligned for
      storing pointers.  */
-  first_unused += __alignof__ (char *) - 1;
-  first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
-  host->h_addr_list = (char **) first_unused;
-  if (room_left < 2 * sizeof (char *))
+  size_t adjust = ((__alignof__ (char *)
+		    - (first_unused - (char *) 0) % __alignof__ (char *))
+		   % __alignof__ (char *));
+  if (room_left < adjust + 3 * sizeof (char *))
     goto no_more_room;
+  first_unused += adjust;
+  room_left -= adjust;
+  host->h_addr_list = (char **) first_unused;
 
-  room_left -= (2 * sizeof (char *));
+  room_left -= 3 * sizeof (char *);
   host->h_addr_list[0] = data;
   host->h_addr_list[1] = NULL;
   host->h_aliases = &host->h_addr_list[2];
-  host->h_aliases[0] = NULL;
 
   i = 0;
   while (*line != '\0')
@@ -158,41 +161,46 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host,
 	goto no_more_room;
 
       room_left -= sizeof (char *);
-      host->h_aliases[i] = line;
+      host->h_aliases[i++] = line;
 
       while (*line != '\0' && *line != ' ')
 	++line;
 
       if (*line == ' ')
-	{
-	  *line = '\0';
-	  ++line;
-	  ++i;
-	}
-      else
-	host->h_aliases[i+1] = NULL;
+	*line++ = '\0';
     }
+
+  host->h_aliases[i] = NULL;
+
   return 1;
 }
 
+
 static enum nss_status
 _nss_create_tablename (int *errnop)
 {
   if (tablename_val == NULL)
     {
-      char buf [40 + strlen (nis_local_directory ())];
-      char *p;
+      const char *local_dir = nis_local_directory ();
+      size_t local_dir_len = strlen (local_dir);
+      static const char prefix[] = "hosts.org_dir.";
 
-      p = __stpcpy (buf, "hosts.org_dir.");
-      p = __stpcpy (p, nis_local_directory ());
-      tablename_val = __strdup (buf);
-      if (tablename_val == NULL)
+      char *p = malloc (sizeof (prefix) + local_dir_len);
+      if (p == NULL)
 	{
 	  *errnop = errno;
 	  return NSS_STATUS_TRYAGAIN;
 	}
-      tablename_len = strlen (tablename_val);
+
+      memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
+
+      tablename_len = sizeof (prefix) - 1 + local_dir_len;
+
+      atomic_write_barrier ();
+
+      tablename_val = p;
     }
+
   return NSS_STATUS_SUCCESS;
 }
 
@@ -204,9 +212,11 @@ _nss_nisplus_sethostent (int stayopen)
 
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result != NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
 
   if (tablename_val == NULL)
     status = _nss_create_tablename (&err);
@@ -221,9 +231,11 @@ _nss_nisplus_endhostent (void)
 {
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result != NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
 
   __libc_lock_unlock (lock);
 
@@ -253,6 +265,11 @@ internal_nisplus_gethostent_r (struct hostent *host, char *buffer,
 	    }
 
 	  result = nis_first_entry (tablename_val);
+	  if (result == NULL)
+	    {
+	      *errnop = errno;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
             {
               enum nss_status retval = niserr2nss (result->status);
@@ -267,11 +284,13 @@ internal_nisplus_gethostent_r (struct hostent *host, char *buffer,
 	}
       else
 	{
-	  nis_result *res2;
-
 	  saved_res = result;
-	  res2 = nis_next_entry(tablename_val, &result->cookie);
-	  result = res2;
+	  result = nis_next_entry (tablename_val, &result->cookie);
+	  if (result == NULL)
+	    {
+	      *errnop = errno;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
             {
               enum nss_status retval= niserr2nss (result->status);
@@ -335,8 +354,12 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
 
   if (tablename_val == NULL)
     {
+      __libc_lock_lock (lock);
+
       enum nss_status status = _nss_create_tablename (errnop);
 
+      __libc_lock_unlock (lock);
+
       if (status != NSS_STATUS_SUCCESS)
 	{
 	  *herrnop = NETDB_INTERNAL;
@@ -350,75 +373,81 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
       *herrnop = NETDB_INTERNAL;
       return NSS_STATUS_NOTFOUND;
     }
-  else
-    {
-      nis_result *result;
-      char buf[strlen (name) + 255 + tablename_len];
-      int olderr = errno;
-
-      /* Search at first in the alias list, and use the correct name
-	 for the next search */
-      sprintf (buf, "[name=%s],%s", name, tablename_val);
-      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
-      if (result != 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)
-	      || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
-	      || strcmp (result->objects.objects_val->EN_data.en_type,
-			 "hosts_tbl") != 0
-	      || 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],%s", NISENTRYVAL(0, 0, result),
-		     tablename_val);
+  nis_result *result;
+  char buf[strlen (name) + 10 + tablename_len];
+  int olderr = errno;
 
-	  nis_freeresult (result);
-	  result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
-	}
+  /* Search at first in the alias list, and use the correct name
+     for the next search.  */
+  snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
+  result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
-      if (result == NULL)
+  if (result != NULL)
+    {
+      char *bufptr = buf;
+
+      /* If we did 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)
+	  || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
+	  || strcmp (result->objects.objects_val->EN_data.en_type,
+		     "hosts_tbl") != 0
+	  || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
+	snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
+      else
 	{
-	  *errnop = ENOMEM;
-	  return NSS_STATUS_TRYAGAIN;
+	  /* We need to allocate a new buffer since there is no
+	     guarantee the returned name has a length limit.  */
+	  const char *entryval = NISENTRYVAL(0, 0, result);
+	  size_t buflen = strlen (entryval) + 10 + tablename_len;
+	  bufptr = alloca (buflen);
+	  snprintf (bufptr, buflen, "[cname=%s],%s",
+		    entryval, tablename_val);
 	}
-      retval = niserr2nss (result->status);
-      if (retval != NSS_STATUS_SUCCESS)
-        {
-          if (retval == NSS_STATUS_TRYAGAIN)
-            {
-	      *errnop = errno;
-              *herrnop = NETDB_INTERNAL;
-            }
-	  else
-	    __set_errno (olderr);
-	  nis_freeresult (result);
-          return retval;
-        }
-
-      parse_res = _nss_nisplus_parse_hostent (result, af, host, buffer,
-					      buflen, errnop, flags);
 
       nis_freeresult (result);
+      result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+    }
 
-      if (parse_res > 0)
-	return NSS_STATUS_SUCCESS;
+  if (result == NULL)
+    {
+      *errnop = ENOMEM;
+      return NSS_STATUS_TRYAGAIN;
+    }
 
-      *herrnop = NETDB_INTERNAL;
-      if (parse_res == -1)
+  retval = niserr2nss (result->status);
+  if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0))
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
 	{
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
+	  *errnop = errno;
+	  *herrnop = NETDB_INTERNAL;
 	}
       else
-	{
-	  __set_errno (olderr);
-	  return NSS_STATUS_NOTFOUND;
-	}
+	__set_errno (olderr);
+      nis_freeresult (result);
+      return retval;
+    }
+
+  parse_res = _nss_nisplus_parse_hostent (result, af, host, buffer,
+					  buflen, errnop, flags);
+
+  nis_freeresult (result);
+
+  if (parse_res > 0)
+    return NSS_STATUS_SUCCESS;
+
+  *herrnop = NETDB_INTERNAL;
+  if (parse_res == -1)
+    {
+      *errnop = ERANGE;
+      return NSS_STATUS_TRYAGAIN;
     }
+
+  __set_errno (olderr);
+  return NSS_STATUS_NOTFOUND;
 }
 
 enum nss_status
@@ -431,17 +460,6 @@ _nss_nisplus_gethostbyname2_r (const char *name, int af, struct hostent *host,
 			 ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0));
 }
 
-#if 0
-enum nss_status
-_nss_nisplus_getipnodebyname_r (const char *name, int af, int flags,
-				struct hostent *result, char *buffer,
-				size_t buflen, int *errnop, int *herrnop)
-{
-  return internal_gethostbyname2_r (name, af, result, buffer, buflen,
-				    errnop, herrnop, flags);
-}
-#endif
-
 enum nss_status
 _nss_nisplus_gethostbyname_r (const char *name, struct hostent *host,
 			      char *buffer, size_t buflen, int *errnop,
@@ -469,62 +487,63 @@ _nss_nisplus_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af,
 {
   if (tablename_val == NULL)
     {
+      __libc_lock_lock (lock);
+
       enum nss_status status = _nss_create_tablename (errnop);
 
+      __libc_lock_unlock (lock);
+
       if (status != NSS_STATUS_SUCCESS)
 	return status;
     }
 
   if (addr == NULL)
     return NSS_STATUS_NOTFOUND;
-  else
-    {
-      nis_result *result;
-      char buf[255 + tablename_len];
-      int retval, parse_res;
-      int olderr = errno;
-
-      sprintf (buf, "[addr=%s],%s",
-	       inet_ntoa (*(const struct in_addr *) addr), tablename_val);
-      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
-      if (result == NULL)
-	{
-	  __set_errno (ENOMEM);
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      retval = niserr2nss (result->status);
-      if (retval != NSS_STATUS_SUCCESS)
-        {
-          if (retval == NSS_STATUS_TRYAGAIN)
-            {
-	      *errnop = errno;
-              *herrnop = NETDB_INTERNAL;
-            }
-	  else
-	    __set_errno (olderr);
-	  nis_freeresult (result);
-          return retval;
-        }
+  char buf[24 + tablename_len];
+  int retval, parse_res;
+  int olderr = errno;
 
-      parse_res = _nss_nisplus_parse_hostent (result, af, host,
-					      buffer, buflen, errnop,
-		     ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0));
-      nis_freeresult (result);
+  snprintf (buf, sizeof (buf), "[addr=%s],%s",
+	   inet_ntoa (*(const struct in_addr *) addr), tablename_val);
+  nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
-      if (parse_res > 0)
-	return NSS_STATUS_SUCCESS;
+  if (result == NULL)
+    {
+      __set_errno (ENOMEM);
+      return NSS_STATUS_TRYAGAIN;
+    }
 
-      *herrnop = NETDB_INTERNAL;
-      if (parse_res == -1)
+  retval = niserr2nss (result->status);
+  if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0))
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
 	{
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
+	  *errnop = errno;
+	  *herrnop = NETDB_INTERNAL;
 	}
       else
-	{
-	  __set_errno (olderr);
-	  return NSS_STATUS_NOTFOUND;
-	}
+	__set_errno (olderr);
+      nis_freeresult (result);
+      return retval;
     }
+
+  parse_res = _nss_nisplus_parse_hostent (result, af, host,
+					  buffer, buflen, errnop,
+					  ((_res.options & RES_USE_INET6)
+					   ? AI_V4MAPPED : 0));
+  nis_freeresult (result);
+
+  if (parse_res > 0)
+    return NSS_STATUS_SUCCESS;
+
+  *herrnop = NETDB_INTERNAL;
+  if (parse_res == -1)
+    {
+      *errnop = ERANGE;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  __set_errno (olderr);
+  return NSS_STATUS_NOTFOUND;
 }
diff --git a/nis/nss_nisplus/nisplus-initgroups.c b/nis/nss_nisplus/nisplus-initgroups.c
new file mode 100644
index 0000000000..6588ec2533
--- /dev/null
+++ b/nis/nss_nisplus/nisplus-initgroups.c
@@ -0,0 +1,150 @@
+/* Copyright (C) 1997, 2001, 2002, 2003, 2005, 2006
+   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 Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <atomic.h>
+#include <nss.h>
+#include <grp.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <bits/libc-lock.h>
+#include <rpcsvc/nis.h>
+
+#include "nss-nisplus.h"
+#include "nisplus-parser.h"
+#include <libnsl.h>
+#include <nis_intern.h>
+#include <nis_xdr.h>
+
+#define NISOBJVAL(col, obj) \
+  ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
+
+#define NISOBJLEN(col, obj) \
+  ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
+
+extern nis_name grp_tablename_val attribute_hidden;
+extern size_t grp_tablename_len attribute_hidden;
+extern enum nss_status _nss_grp_create_tablename (int *errnop);
+
+
+enum nss_status
+_nss_nisplus_initgroups_dyn (const char *user, gid_t group, long int *start,
+			     long int *size, gid_t **groupsp, long int limit,
+			     int *errnop)
+{
+  if (grp_tablename_val == NULL)
+    {
+      enum nss_status status = _nss_grp_create_tablename (errnop);
+
+      if (status != NSS_STATUS_SUCCESS)
+	return status;
+    }
+
+  nis_result *result;
+  char buf[strlen (user) + 12 + grp_tablename_len];
+
+  snprintf (buf, sizeof (buf), "[members=%s],%s", user, grp_tablename_val);
+
+  result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | ALL_RESULTS, NULL, NULL);
+
+  if (result == NULL)
+    {
+      *errnop = ENOMEM;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
+    {
+      enum nss_status status = niserr2nss (result->status);
+
+      nis_freeresult (result);
+      return status;
+    }
+
+  if (NIS_RES_NUMOBJ (result) == 0)
+    {
+    errout:
+      nis_freeresult (result);
+      return NSS_STATUS_NOTFOUND;
+    }
+
+  gid_t *groups = *groupsp;
+  nis_object *obj = NIS_RES_OBJECT (result);
+  for (unsigned int cnt = 0; cnt < NIS_RES_NUMOBJ (result); ++cnt, ++obj)
+    {
+      if (__type_of (obj) != NIS_ENTRY_OBJ
+	  || strcmp (obj->EN_data.en_type, "group_tbl") != 0
+	  || obj->EN_data.en_cols.en_cols_len < 4)
+	continue;
+
+      char *numstr = NISOBJVAL (2, obj);
+      size_t len = NISOBJLEN (2, obj);
+      if (len == 0 || numstr[0] == '\0')
+	continue;
+
+      gid_t gid;
+      char *endp;
+      if (__builtin_expect (numstr[len - 1] != '\0', 0))
+	{
+	  char numstrbuf[len + 1];
+	  memcpy (numstrbuf, numstr, len);
+	  numstrbuf[len] = '\0';
+	  gid = strtoul (numstrbuf, &endp, 10);
+	  if (*endp)
+	    continue;
+	}
+      else
+	{
+	  gid = strtoul (numstr, &endp, 10);
+	  if (*endp)
+	    continue;
+	}
+
+      if (gid == group)
+	continue;
+
+      /* Insert this group.  */
+      if (*start == *size)
+	{
+	  /* Need a bigger buffer.  */
+	  long int newsize;
+
+	  if (limit > 0 && *size == limit)
+	    /* We reached the maximum.  */
+	    break;
+
+	  if (limit <= 0)
+	    newsize = 2 * *size;
+	  else
+	    newsize = MIN (limit, 2 * *size);
+
+	  gid_t *newgroups = realloc (groups, newsize * sizeof (*groups));
+	  if (newgroups == NULL)
+	    goto errout;
+	  *groupsp = groups = newgroups;
+	  *size = newsize;
+	}
+
+      groups[*start] = gid;
+      *start += 1;
+    }
+
+  nis_freeresult (result);
+  return NSS_STATUS_SUCCESS;
+}
diff --git a/nis/nss_nisplus/nisplus-netgrp.c b/nis/nss_nisplus/nisplus-netgrp.c
index 607bc2c1ca..24303b1474 100644
--- a/nis/nss_nisplus/nisplus-netgrp.c
+++ b/nis/nss_nisplus/nisplus-netgrp.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -27,11 +27,11 @@
 
 #include "nss-nisplus.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 NISENTRYVAL(idx, col, res) \
+        (NIS_RES_OBJECT (res)[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)
+#define NISENTRYLEN(idx, col, res) \
+        (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
 
 enum nss_status
 _nss_nisplus_getnetgrent_r (struct __netgrent *result, char *buffer,
@@ -141,29 +141,23 @@ _nss_nisplus_getnetgrent_r (struct __netgrent *result, char *buffer,
 static void
 internal_endnetgrent (struct __netgrent *netgrp)
 {
-  if (netgrp->data != NULL)
-    {
-      nis_freeresult ((nis_result *) netgrp->data);
-      netgrp->data = NULL;
-      netgrp->data_size = 0;
-      netgrp->position = 0;
-    }
+  nis_freeresult ((nis_result *) netgrp->data);
+  netgrp->data = NULL;
+  netgrp->data_size = 0;
+  netgrp->position = 0;
 }
 
 enum nss_status
 _nss_nisplus_setnetgrent (const char *group, struct __netgrent *netgrp)
 {
-  enum nss_status status;
-  char buf[strlen (group) + 30];
+  char buf[strlen (group) + 25];
 
   if (group == NULL || group[0] == '\0')
     return NSS_STATUS_UNAVAIL;
 
-  status = NSS_STATUS_SUCCESS;
-
-  internal_endnetgrent (netgrp);
+  enum nss_status status = NSS_STATUS_SUCCESS;
 
-  sprintf (buf, "[name=%s],netgroup.org_dir", group);
+  snprintf (buf, sizeof (buf), "[name=%s],netgroup.org_dir", group);
 
   netgrp->data = (char *) nis_list (buf, EXPAND_NAME, NULL, NULL);
 
diff --git a/nis/nss_nisplus/nisplus-network.c b/nis/nss_nisplus/nisplus-network.c
index 422b02b82a..1cf652f071 100644
--- a/nis/nss_nisplus/nisplus-network.c
+++ b/nis/nss_nisplus/nisplus-network.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1997,1998,2000,2001,2002,2003 Free Software Foundation, Inc.
+/* Copyright (C) 1997,1998,2000-2003,2005,2006,2007
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -17,15 +18,16 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#include <nss.h>
-#include <netdb.h>
-#include <errno.h>
+#include <atomic.h>
 #include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <nss.h>
 #include <stdint.h>
 #include <string.h>
 #include <arpa/inet.h>
-#include <bits/libc-lock.h>
 #include <rpcsvc/nis.h>
+#include <bits/libc-lock.h>
 
 #include "nss-nisplus.h"
 
@@ -35,33 +37,31 @@ static nis_result *result;
 static nis_name tablename_val;
 static u_long tablename_len;
 
-#define NISENTRYVAL(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+#define NISENTRYVAL(idx, col, res) \
+        (NIS_RES_OBJECT (res)[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)
+#define NISENTRYLEN(idx, col, res) \
+        (NIS_RES_OBJECT (res)[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, int *errnop)
+			   char *buffer, size_t buflen, int *errnop)
 {
   char *first_unused = buffer;
   size_t room_left = buflen;
-  unsigned int i;
-  char *p, *line;
 
   if (result == NULL)
     return 0;
 
   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
-      || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
-      || strcmp (result->objects.objects_val[0].EN_data.en_type,
+      || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
+      || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type,
 		 "networks_tbl") != 0
-      || result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 3)
+      || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 3)
     return 0;
 
-  if (NISENTRYLEN(0, 0, result) >= room_left)
+  if (NISENTRYLEN (0, 0, result) >= room_left)
     {
       /* The line is too long for our buffer.  */
     no_more_room:
@@ -69,50 +69,56 @@ _nss_nisplus_parse_netent (nis_result *result, struct netent *network,
       return -1;
     }
 
-  strncpy (first_unused, NISENTRYVAL(0, 0, result),
+  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;
+  size_t len = strlen (first_unused) + 1;
+  room_left -= len;
+  first_unused += len;
+
   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)
+  /* XXX Rewrite at some point to allocate the array first and then
+     copy the strings.  It wasteful to first concatenate the strings
+     to just split them again later.  */
+  char *line = first_unused;
+  for (unsigned int i = 0; i < NIS_RES_NUMOBJ (result); ++i)
     {
       if (strcmp (NISENTRYVAL (i, 1, result), network->n_name) != 0)
         {
           if (NISENTRYLEN (i, 1, result) + 2 > room_left)
 	    goto no_more_room;
 
-	  *p++ = ' ';
-          p = __stpncpy (p, NISENTRYVAL (i, 1, result),
-			 NISENTRYLEN (i, 1, result));
-          *p = '\0';
+	  *first_unused++ = ' ';
+          first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result),
+				    NISENTRYLEN (i, 1, result));
           room_left -= (NISENTRYLEN (i, 1, result) + 1);
         }
     }
-  *p++ = '\0';
-  first_unused = p;
+  *first_unused++ = '\0';
 
   /* 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 *))
+  size_t adjust = ((__alignof__ (char *)
+		    - (first_unused - (char *) 0) % __alignof__ (char *))
+		   % __alignof__ (char *));
+  if (room_left < adjust + sizeof (char *))
     goto no_more_room;
-  room_left -= (2 * sizeof (char *));
-  network->n_aliases[0] = NULL;
+  first_unused += adjust;
+  room_left -= adjust;
+  network->n_aliases = (char **) first_unused;
+
+  /* For the terminating NULL pointer.  */
+  room_left -= sizeof (char *);
 
-  i = 0;
+  unsigned int i = 0;
   while (*line != '\0')
     {
       /* Skip leading blanks.  */
       while (isspace (*line))
-        line++;
+        ++line;
 
       if (*line == '\0')
         break;
@@ -121,42 +127,45 @@ _nss_nisplus_parse_netent (nis_result *result, struct netent *network,
 	goto no_more_room;
 
       room_left -= sizeof (char *);
-      network->n_aliases[i] = line;
+      network->n_aliases[i++] = line;
 
       while (*line != '\0' && *line != ' ')
         ++line;
 
       if (*line == ' ')
-	{
-	  *line = '\0';
-	  ++line;
-          ++i;
-        }
-      else
-        network->n_aliases[i+1] = NULL;
+	*line++ = '\0';
     }
+  network->n_aliases[i] = NULL;
 
   return 1;
 }
 
+
 static enum nss_status
 _nss_create_tablename (int *errnop)
 {
   if (tablename_val == NULL)
     {
-      char buf [40 + strlen (nis_local_directory ())];
-      char *p;
+      const char *local_dir = nis_local_directory ();
+      size_t local_dir_len = strlen (local_dir);
+      static const char prefix[] = "networks.org_dir.";
 
-      p = __stpcpy (buf, "networks.org_dir.");
-      p = __stpcpy (p, nis_local_directory ());
-      tablename_val = __strdup (buf);
-      if (tablename_val == NULL)
+      char *p = malloc (sizeof (prefix) + local_dir_len);
+      if (p == NULL)
 	{
 	  *errnop = errno;
 	  return NSS_STATUS_TRYAGAIN;
 	}
-      tablename_len = strlen (tablename_val);
+
+      memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
+
+      tablename_len = sizeof (prefix) - 1 + local_dir_len;
+
+      atomic_write_barrier ();
+
+      tablename_val = p;
     }
+
   return NSS_STATUS_SUCCESS;
 }
 
@@ -164,16 +173,20 @@ enum nss_status
 _nss_nisplus_setnetent (int stayopen)
 {
   enum nss_status status = NSS_STATUS_SUCCESS;
-  int err;
 
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result != NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
 
   if (tablename_val == NULL)
-    status = _nss_create_tablename (&err);
+    {
+      int err;
+      status = _nss_create_tablename (&err);
+    }
 
   __libc_lock_unlock (lock);
 
@@ -185,9 +198,11 @@ _nss_nisplus_endnetent (void)
 {
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result != NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
 
   __libc_lock_unlock (lock);
 
@@ -218,11 +233,14 @@ internal_nisplus_getnetent_r (struct netent *network, char *buffer,
 	    }
 
 	  result = nis_first_entry (tablename_val);
+	  if (result == NULL)
+	    {
+	      *errnop = errno;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    {
-	      int retval;
-
-	      retval = niserr2nss (result->status);
+	      int retval = niserr2nss (result->status);
 	      nis_freeresult (result);
 	      result = NULL;
 	      if (retval == NSS_STATUS_TRYAGAIN)
@@ -237,16 +255,16 @@ internal_nisplus_getnetent_r (struct netent *network, char *buffer,
 	}
       else
 	{
-	  nis_result *res;
-
-	  res = nis_next_entry (tablename_val, &result->cookie);
 	  saved_res = result;
-	  result = res;
+	  result = nis_next_entry (tablename_val, &result->cookie);
+	  if (result == NULL)
+	    {
+	      *errnop = errno;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    {
-	      int retval;
-
-	      retval = niserr2nss (result->status);
+	      int retval = niserr2nss (result->status);
 	      nis_freeresult (result);
 	      result = saved_res;
 	      if (retval == NSS_STATUS_TRYAGAIN)
@@ -266,7 +284,8 @@ internal_nisplus_getnetent_r (struct netent *network, char *buffer,
           return NSS_STATUS_TRYAGAIN;
         }
 
-    } while (!parse_res);
+    }
+  while (!parse_res);
 
   return NSS_STATUS_SUCCESS;
 }
@@ -296,8 +315,12 @@ _nss_nisplus_getnetbyname_r (const char *name, struct netent *network,
 
   if (tablename_val == NULL)
     {
+      __libc_lock_lock (lock);
+
       enum nss_status status = _nss_create_tablename (errnop);
 
+      __libc_lock_unlock (lock);
+
       if (status != NSS_STATUS_SUCCESS)
 	return status;
     }
@@ -308,76 +331,83 @@ _nss_nisplus_getnetbyname_r (const char *name, struct netent *network,
       *herrnop = NETDB_INTERNAL;
       return NSS_STATUS_UNAVAIL;
     }
-  else
-    {
-      nis_result *result;
-      char buf[strlen (name) + 255 + tablename_len];
-      int olderr = errno;
 
-      /* Search at first in the alias list, and use the correct name
-	 for the next search */
-      sprintf (buf, "[name=%s],%s", name, tablename_val);
-      result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+  nis_result *result;
+  char buf[strlen (name) + 10 + tablename_len];
+  int olderr = errno;
 
-      if (result != 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)
-	      || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
-	      || strcmp (result->objects.objects_val[0].EN_data.en_type,
-			 "networks_tbl") != 0
-	      || (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],%s", NISENTRYVAL (0, 0, result),
-		     tablename_val);
-
-	  nis_freeresult (result);
-	  result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
-	}
+  /* Search at first in the alias list, and use the correct name
+     for the next search */
+  snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
+  result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM, NULL, NULL);
 
-      if (result == NULL)
-	{
-	  __set_errno (ENOMEM);
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      retval = niserr2nss (result->status);
-      if (retval != NSS_STATUS_SUCCESS)
+  if (result != NULL)
+    {
+      char *bufptr = buf;
+
+      /* 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)
+	  || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
+	  || strcmp (result->objects.objects_val[0].EN_data.en_type,
+		     "networks_tbl") != 0
+	  || (result->objects.objects_val[0].EN_data.en_cols.en_cols_len
+	      < 3))
+	snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
+      else
 	{
-	  if (retval == NSS_STATUS_TRYAGAIN)
-	    {
-	      *errnop = errno;
-	      *herrnop = NETDB_INTERNAL;
-	    }
-	  else
-	    __set_errno (olderr);
-	  nis_freeresult (result);
-	  return retval;
+	  /* We need to allocate a new buffer since there is no
+	     guarantee the returned name has a length limit.  */
+	  const char *entryval = NISENTRYVAL (0, 0, result);
+	  size_t buflen = strlen (entryval) + 10 + tablename_len;
+	  bufptr = alloca (buflen);
+	  snprintf (bufptr, buflen, "[cname=%s],%s",
+		    entryval, tablename_val);
 	}
 
-      parse_res = _nss_nisplus_parse_netent (result, network, buffer, buflen,
-					     errnop);
-
       nis_freeresult (result);
+      result = nis_list (bufptr, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM,
+			 NULL, NULL);
+    }
 
-      if (parse_res > 0)
-	return NSS_STATUS_SUCCESS;
+  if (result == NULL)
+    {
+      __set_errno (ENOMEM);
+      return NSS_STATUS_TRYAGAIN;
+    }
 
-      *herrnop = NETDB_INTERNAL;
-      if (parse_res == -1)
+  retval = niserr2nss (result->status);
+  if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0))
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
 	{
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
+	  *errnop = errno;
+	  *herrnop = NETDB_INTERNAL;
 	}
       else
-	{
-	  __set_errno (olderr);
-	  return NSS_STATUS_NOTFOUND;
-	}
+	__set_errno (olderr);
+      nis_freeresult (result);
+      return retval;
     }
+
+  parse_res = _nss_nisplus_parse_netent (result, network, buffer, buflen,
+					 errnop);
+
+  nis_freeresult (result);
+
+  if (parse_res > 0)
+    return NSS_STATUS_SUCCESS;
+
+  *herrnop = NETDB_INTERNAL;
+  if (parse_res == -1)
+    {
+      *errnop = ERANGE;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  __set_errno (olderr);
+  return NSS_STATUS_NOTFOUND;
 }
 
 /* XXX type is ignored, SUN's NIS+ table doesn't support it */
@@ -388,48 +418,48 @@ _nss_nisplus_getnetbyaddr_r (uint32_t addr, const int type,
 {
   if (tablename_val == NULL)
     {
+      __libc_lock_lock (lock);
+
       enum nss_status status = _nss_create_tablename (errnop);
 
+      __libc_lock_unlock (lock);
+
       if (status != NSS_STATUS_SUCCESS)
 	return status;
     }
 
   {
-    int parse_res, retval;
-    nis_result *result;
-    char buf[1024 + tablename_len];
-    struct in_addr in;
-    char buf2[256];
-    int b2len;
+    char buf[27 + tablename_len];
+    char buf2[18];
     int olderr = errno;
 
-    in = inet_makeaddr (addr, 0);
+    struct in_addr in = inet_makeaddr (addr, 0);
     strcpy (buf2, inet_ntoa (in));
-    b2len = strlen (buf2);
+    size_t b2len = strlen (buf2);
 
     while (1)
       {
-	sprintf (buf, "[addr=%s],%s", buf2, tablename_val);
-	result = nis_list (buf, EXPAND_NAME, NULL, NULL);
+	snprintf (buf, sizeof (buf), "[addr=%s],%s", buf2, tablename_val);
+	nis_result *result = nis_list (buf, EXPAND_NAME | USE_DGRAM,
+				       NULL, NULL);
 
 	if (result == NULL)
 	  {
 	    __set_errno (ENOMEM);
 	    return NSS_STATUS_TRYAGAIN;
 	  }
-	retval = niserr2nss (result->status);
-	if (retval != NSS_STATUS_SUCCESS)
+	enum nss_status retval = niserr2nss (result->status);
+	if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0))
 	  {
-	    if (buf2[b2len -2] == '.' && buf2[b2len -1] == '0')
+	    if (b2len > 2 && buf2[b2len - 2] == '.' && buf2[b2len - 1] == '0')
 	      {
 		/* Try again, but with trailing dot(s)
 		   removed (one by one) */
 		buf2[b2len - 2] = '\0';
 		b2len -= 2;
+		nis_freeresult (result);
 		continue;
 	      }
-	    else
-	      return NSS_STATUS_NOTFOUND;
 
 	    if (retval == NSS_STATUS_TRYAGAIN)
 	      {
@@ -442,8 +472,8 @@ _nss_nisplus_getnetbyaddr_r (uint32_t addr, const int type,
 	    return retval;
 	  }
 
-	parse_res = _nss_nisplus_parse_netent (result, network, buffer,
-					       buflen, errnop);
+	int parse_res = _nss_nisplus_parse_netent (result, network, buffer,
+						   buflen, errnop);
 
 	nis_freeresult (result);
 
diff --git a/nis/nss_nisplus/nisplus-parser.c b/nis/nss_nisplus/nisplus-parser.c
index b61733a628..1e1a343d52 100644
--- a/nis/nss_nisplus/nisplus-parser.c
+++ b/nis/nss_nisplus/nisplus-parser.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1999, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1999, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -25,33 +25,36 @@
 
 #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 NISENTRYVAL(idx, col, res) \
+        (NIS_RES_OBJECT (res)[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)
+#define NISENTRYLEN(idx, col, res) \
+        (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
+
+#define NISOBJVAL(col, obj) \
+  ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
+
+#define NISOBJLEN(col, obj) \
+  ((obj)->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, int *errnop)
 {
+  if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
+      || NIS_RES_NUMOBJ (result) != 1
+      || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
+      || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "passwd_tbl") != 0
+      || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 7)
+    return 0;
+
+  nis_object *obj = NIS_RES_OBJECT (result);
   char *first_unused = buffer;
   size_t room_left = buflen;
   size_t len;
 
-  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) != NIS_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)
+  if (NISOBJLEN (0, obj) >= room_left)
     {
       /* The line is too long for our buffer.  */
     no_more_room:
@@ -59,111 +62,109 @@ _nss_nisplus_parse_pwent (nis_result *result, struct passwd *pw,
       return -1;
     }
 
-  strncpy (first_unused, NISENTRYVAL (0, 0, result),
-	   NISENTRYLEN (0, 0, result));
-  first_unused[NISENTRYLEN (0, 0, result)] = '\0';
+  strncpy (first_unused, NISOBJVAL (0, obj), NISOBJLEN (0, obj));
+  first_unused[NISOBJLEN (0, obj)] = '\0';
   len = strlen (first_unused);
   if (len == 0) /* No name ? Should never happen, database is corrupt */
     return 0;
   pw->pw_name = first_unused;
-  room_left -= (len + 1);
-  first_unused += (len + 1);
+  room_left -= len + 1;
+  first_unused += len + 1;
 
-  if (NISENTRYLEN (0, 1, result) >= room_left)
+  if (NISOBJLEN (1, obj) >= room_left)
     goto no_more_room;
 
-  strncpy (first_unused, NISENTRYVAL (0, 1, result),
-	   NISENTRYLEN (0, 1, result));
-  first_unused[NISENTRYLEN (0, 1, result)] = '\0';
+  strncpy (first_unused, NISOBJVAL (1, obj), NISOBJLEN (1, obj));
+  first_unused[NISOBJLEN (1, obj)] = '\0';
   pw->pw_passwd = first_unused;
   len = strlen (first_unused);
-  room_left -= (len + 1);
-  first_unused += (len + 1);
+  room_left -= len + 1;
+  first_unused += len + 1;
 
-  if (NISENTRYLEN(0, 2, result) >= room_left)
-    goto no_more_room;
+  char *numstr = NISOBJVAL (2, obj);
+  len = NISOBJLEN (2, obj);
+  if (len == 0 && numstr[len - 1] != '\0')
+    {
+      if (len >= room_left)
+	goto no_more_room;
 
-  strncpy (first_unused, NISENTRYVAL (0, 2, result),
-	   NISENTRYLEN (0, 2, result));
-  first_unused[NISENTRYLEN (0, 2, result)] = '\0';
-  len = strlen (first_unused);
-  if (len == 0) /* If we don't have a uid, it's an invalid shadow entry */
+      strncpy (first_unused, numstr, len);
+      first_unused[len] = '\0';
+      numstr = first_unused;
+    }
+  if (numstr[0] == '\0')
+    /* If we don't have a uid, it's an invalid shadow entry.  */
     return 0;
-  pw->pw_uid = strtoul (first_unused, NULL, 10);
-  room_left -= (len + 1);
-  first_unused += (len + 1);
+  pw->pw_uid = strtoul (numstr, NULL, 10);
 
-  if (NISENTRYLEN (0, 3, result) >= room_left)
-    goto no_more_room;
+  numstr = NISOBJVAL (3, obj);
+  len = NISOBJLEN (3, obj);
+  if (len == 0 && numstr[len - 1] != '\0')
+    {
+      if (len >= room_left)
+	goto no_more_room;
 
-  strncpy (first_unused, NISENTRYVAL (0, 3, result),
-	   NISENTRYLEN (0, 3, result));
-  first_unused[NISENTRYLEN (0, 3, result)] = '\0';
-  len = strlen (first_unused);
-  if (len == 0) /* If we don't have a gid, it's an invalid shadow entry */
+      strncpy (first_unused, numstr, len);
+      first_unused[len] = '\0';
+      numstr = first_unused;
+    }
+  if (numstr[0] == '\0')
+    /* If we don't have a gid, it's an invalid shadow entry.  */
     return 0;
-  pw->pw_gid = strtoul (first_unused, NULL, 10);
-  room_left -= (len + 1);
-  first_unused += (len + 1);
+  pw->pw_gid = strtoul (numstr, NULL, 10);
 
-  if (NISENTRYLEN(0, 4, result) >= room_left)
+  if (NISOBJLEN(4, obj) >= room_left)
     goto no_more_room;
 
-  strncpy (first_unused, NISENTRYVAL (0, 4, result),
-	   NISENTRYLEN (0, 4, result));
-  first_unused[NISENTRYLEN (0, 4, result)] = '\0';
+  strncpy (first_unused, NISOBJVAL (4, obj), NISOBJLEN (4, obj));
+  first_unused[NISOBJLEN (4, obj)] = '\0';
   pw->pw_gecos = first_unused;
   len = strlen (first_unused);
-  room_left -= (len + 1);
-  first_unused += (len + 1);
+  room_left -= len + 1;
+  first_unused += len + 1;
 
-  if (NISENTRYLEN (0, 5, result) >= room_left)
+  if (NISOBJLEN (5, obj) >= room_left)
     goto no_more_room;
 
-  strncpy (first_unused, NISENTRYVAL (0, 5, result),
-	   NISENTRYLEN (0, 5, result));
-  first_unused[NISENTRYLEN (0, 5, result)] = '\0';
+  strncpy (first_unused, NISOBJVAL (5, obj), NISOBJLEN (5, obj));
+  first_unused[NISOBJLEN (5, obj)] = '\0';
   pw->pw_dir = first_unused;
   len = strlen (first_unused);
-  room_left -= (len + 1);
-  first_unused += (len + 1);
+  room_left -= len + 1;
+  first_unused += len + 1;
 
-  if (NISENTRYLEN (0, 6, result) >= room_left)
+  if (NISOBJLEN (6, obj) >= room_left)
     goto no_more_room;
 
-  strncpy (first_unused, NISENTRYVAL (0, 6, result),
-	   NISENTRYLEN (0, 6, result));
-  first_unused[NISENTRYLEN (0, 6, result)] = '\0';
+  strncpy (first_unused, NISOBJVAL (6, obj), NISOBJLEN (6, obj));
+  first_unused[NISOBJLEN (6, obj)] = '\0';
   pw->pw_shell = first_unused;
   len = strlen (first_unused);
-  room_left -= (len + 1);
-  first_unused += (len + 1);
+  room_left -= len + 1;
+  first_unused += len + 1;
 
   return 1;
 }
-libnss_nisplus_hidden_def (_nss_nisplus_parse_pwent)
+
 
 int
-_nss_nisplus_parse_grent (nis_result *result, u_long entry, struct group *gr,
+_nss_nisplus_parse_grent (nis_result *result, struct group *gr,
 			  char *buffer, size_t buflen, int *errnop)
 {
+  if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
+      || __type_of(NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
+      || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "group_tbl") != 0
+      || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4)
+    return 0;
+
+  nis_object *obj = NIS_RES_OBJECT (result);
   char *first_unused = buffer;
   size_t room_left = buflen;
   char *line;
   int count;
   size_t len;
 
-  if (result == NULL)
-    return 0;
-
-  if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
-      || __type_of(result->objects.objects_val) != NIS_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)
+  if (NISOBJLEN (0, obj) >= room_left)
     {
       /* The line is too long for our buffer.  */
     no_more_room:
@@ -171,54 +172,59 @@ _nss_nisplus_parse_grent (nis_result *result, u_long entry, struct group *gr,
       return -1;
     }
 
-  strncpy (first_unused, NISENTRYVAL (entry, 0, result),
-	   NISENTRYLEN (entry, 0, result));
-  first_unused[NISENTRYLEN (entry, 0, result)] = '\0';
+  strncpy (first_unused, NISOBJVAL (0, obj), NISOBJLEN (0, obj));
+  first_unused[NISOBJLEN (0, obj)] = '\0';
   len = strlen (first_unused);
   if (len == 0) /* group table is corrupt */
     return 0;
   gr->gr_name = first_unused;
-  room_left -= (len + 1);
-  first_unused += (len + 1);
+  room_left -= len + 1;
+  first_unused += len + 1;
 
-  if (NISENTRYLEN (entry, 1, result) >= room_left)
+  if (NISOBJLEN (1, obj) >= room_left)
     goto no_more_room;
 
-  strncpy (first_unused, NISENTRYVAL (entry, 1, result),
-	   NISENTRYLEN (entry, 1, result));
-  first_unused[NISENTRYLEN (entry, 1, result)] = '\0';
+  strncpy (first_unused, NISOBJVAL (1, obj), NISOBJLEN (1, obj));
+  first_unused[NISOBJLEN (1, obj)] = '\0';
   gr->gr_passwd = first_unused;
   len = strlen (first_unused);
-  room_left -= (len + 1);
-  first_unused += (len + 1);
+  room_left -= len + 1;
+  first_unused += len + 1;
 
-  if (NISENTRYLEN (entry, 2, result) >= room_left)
-    goto no_more_room;
+  char *numstr = NISOBJVAL (2, obj);
+  len = NISOBJLEN (2, obj);
+  if (len == 0 || numstr[len - 1] != '\0')
+    {
+      if (len >= room_left)
+	goto no_more_room;
 
-  strncpy (first_unused, NISENTRYVAL (entry, 2, result),
-	   NISENTRYLEN (entry, 2, result));
-  first_unused[NISENTRYLEN (entry, 2, result)] = '\0';
-  len = strlen (first_unused);
-  if (len == 0) /* We should always have an gid */
+      strncpy (first_unused, numstr, len);
+      first_unused[len] = '\0';
+      numstr = first_unused;
+    }
+  if (numstr[0] == '\0')
+    /* We should always have a gid.  */
     return 0;
-  gr->gr_gid = strtoul (first_unused, NULL, 10);
-  room_left -= (strlen (first_unused) + 1);
-  first_unused += strlen (first_unused) + 1;
+  gr->gr_gid = strtoul (numstr, NULL, 10);
 
-  if (NISENTRYLEN (entry, 3, result) >= room_left)
+  if (NISOBJLEN (3, obj) >= room_left)
     goto no_more_room;
 
-  strncpy (first_unused, NISENTRYVAL (entry, 3, result),
-	   NISENTRYLEN (entry, 3, result));
-  first_unused[NISENTRYLEN (entry, 3, result)] = '\0';
+  strncpy (first_unused, NISOBJVAL (3, obj), NISOBJLEN (3, obj));
+  first_unused[NISOBJLEN (3, obj)] = '\0';
   line = first_unused;
   len = strlen (line);
-  room_left -= (len + 1);
-  first_unused += (len + 1);
+  room_left -= len + 1;
+  first_unused += len + 1;
   /* Adjust the pointer so it is aligned for
      storing pointers.  */
-  first_unused += __alignof__ (char *) - 1;
-  first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
+  size_t adjust = ((__alignof__ (char *)
+		    - (first_unused - (char *) 0) % __alignof__ (char *))
+		   % __alignof__ (char *));
+  if (room_left < adjust)
+    goto no_more_room;
+  first_unused += adjust;
+  room_left -= adjust;
   gr->gr_mem = (char **) first_unused;
 
   count = 0;
@@ -243,12 +249,10 @@ _nss_nisplus_parse_grent (nis_result *result, u_long entry, struct group *gr,
 	{
 	  int is = isspace (*line);
 
-	  *line = '\0';
+	  *line++ = '\0';
 	  if (is)
 	    while (*line != '\0' && (*line == ',' || isspace (*line)))
 	      ++line;
-	  else
-	    ++line;
 	}
     }
   if (room_left < sizeof (char *))
@@ -258,7 +262,7 @@ _nss_nisplus_parse_grent (nis_result *result, u_long entry, struct group *gr,
 
   return 1;
 }
-libnss_nisplus_hidden_def (_nss_nisplus_parse_grent)
+
 
 int
 _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp,
@@ -272,11 +276,10 @@ _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp,
     return 0;
 
   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
-      || result->objects.objects_len != 1
-      || __type_of(result->objects.objects_val) != NIS_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)
+      || NIS_RES_NUMOBJ (result) != 1
+      || __type_of(NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
+      || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "passwd_tbl") != 0
+      || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 8)
     return 0;
 
   if (NISENTRYLEN (0, 0, result) >= room_left)
@@ -294,8 +297,8 @@ _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp,
   if (len == 0)
     return 0;
   sp->sp_namp = first_unused;
-  room_left -= (len + 1);
-  first_unused += (len + 1);
+  room_left -= len + 1;
+  first_unused += len + 1;
 
   if (NISENTRYLEN (0, 1, result) >= room_left)
     goto no_more_room;
@@ -305,8 +308,8 @@ _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp,
   first_unused[NISENTRYLEN (0, 1, result)] = '\0';
   sp->sp_pwdp = first_unused;
   len = strlen (first_unused);
-  room_left -= (len + 1);
-  first_unused += (len + 1);
+  room_left -= len + 1;
+  first_unused += len + 1;
 
   sp->sp_lstchg = sp->sp_min = sp->sp_max = sp->sp_warn = sp->sp_inact =
     sp->sp_expire = -1;
@@ -314,10 +317,8 @@ _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp,
 
   if (NISENTRYLEN (0, 7, result) > 0)
     {
-      char *line, *cp;
-
-      line = NISENTRYVAL (0, 7, result);
-      cp = strchr (line, ':');
+      char *line = NISENTRYVAL (0, 7, result);
+      char *cp = strchr (line, ':');
       if (cp == NULL)
 	return 1;
       *cp++ = '\0';
@@ -373,4 +374,3 @@ _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp,
 
   return 1;
 }
-libnss_nisplus_hidden_def (_nss_nisplus_parse_spent)
diff --git a/nis/nss_nisplus/nisplus-proto.c b/nis/nss_nisplus/nisplus-proto.c
index 83456cae64..42a2d088da 100644
--- a/nis/nss_nisplus/nisplus-proto.c
+++ b/nis/nss_nisplus/nisplus-proto.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1997, 1998, 2001, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 2001, 2002, 2003, 2005, 2006
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -17,13 +18,14 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#include <nss.h>
-#include <errno.h>
+#include <atomic.h>
 #include <ctype.h>
+#include <errno.h>
 #include <netdb.h>
+#include <nss.h>
 #include <string.h>
-#include <bits/libc-lock.h>
 #include <rpcsvc/nis.h>
+#include <bits/libc-lock.h>
 
 #include "nss-nisplus.h"
 
@@ -33,20 +35,20 @@ static nis_result *result;
 static nis_name tablename_val;
 static u_long tablename_len;
 
-#define NISENTRYVAL(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+#define NISENTRYVAL(idx, col, res) \
+        (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
+
+#define NISENTRYLEN(idx, col, res) \
+        (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
 
-#define NISENTRYLEN(idx,col,res) \
-        ((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,
+_nss_nisplus_parse_protoent (nis_result *result, struct protoent *proto,
 			     char *buffer, size_t buflen, int *errnop)
 {
   char *first_unused = buffer;
   size_t room_left = buflen;
   unsigned int i;
-  char *p, *line;
 
   if (result == NULL)
     return 0;
@@ -69,41 +71,44 @@ _nss_nisplus_parse_protoent (nis_result * result, struct protoent *proto,
            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;
+  size_t len = strlen (first_unused) + 1;
+  room_left -= len;
+  first_unused += len;
 
 
-  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)
+  /* XXX Rewrite at some point to allocate the array first and then
+     copy the strings.  It wasteful to first concatenate the strings
+     to just split them again later.  */
+  char *line = first_unused;
+  for (i = 0; i < NIS_RES_NUMOBJ (result); ++i)
     {
       if (strcmp (NISENTRYVAL (i, 1, result), proto->p_name) != 0)
         {
           if (NISENTRYLEN (i, 1, result) + 2 > room_left)
             goto no_more_room;
-	  *p++ = ' ';
-          p = __stpncpy (p, NISENTRYVAL (i, 1, result),
-			 NISENTRYLEN (i, 1, result));
-          *p = '\0';
-          room_left -= (NISENTRYLEN (i, 1, result) + 1);
+	  *first_unused++ = ' ';
+          first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result),
+				    NISENTRYLEN (i, 1, result));
+          room_left -= NISENTRYLEN (i, 1, result) + 1;
         }
     }
-  *p++ = '\0';
-  first_unused = p;
+  *first_unused++ = '\0';
 
   /* 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 *))
+  size_t adjust = ((__alignof__ (char *)
+		    - (first_unused - (char *) 0) % __alignof__ (char *))
+		   % __alignof__ (char *));
+  if (room_left < adjust + sizeof (char *))
     goto no_more_room;
+  first_unused += adjust;
+  room_left -= adjust;
+  proto->p_aliases = (char **) first_unused;
+
+  /* For the terminating NULL pointer.  */
   room_left -= sizeof (char *);
-  proto->p_aliases[0] = NULL;
 
   i = 0;
   while (*line != '\0')
@@ -118,20 +123,15 @@ _nss_nisplus_parse_protoent (nis_result * result, struct protoent *proto,
         goto no_more_room;
 
       room_left -= sizeof (char *);
-      proto->p_aliases[i] = line;
+      proto->p_aliases[i++] = line;
 
       while (*line != '\0' && *line != ' ')
         ++line;
 
       if (*line == ' ')
-        {
-          *line = '\0';
-          ++line;
-          ++i;
-        }
-      else
-        proto->p_aliases[i+1] = NULL;
+	*line++ = '\0';
     }
+  proto->p_aliases[i] = NULL;
 
   return 1;
 }
@@ -141,19 +141,26 @@ _nss_create_tablename (int *errnop)
 {
   if (tablename_val == NULL)
     {
-      char buf [40 + strlen (nis_local_directory ())];
-      char *p;
+      const char *local_dir = nis_local_directory ();
+      size_t local_dir_len = strlen (local_dir);
+      static const char prefix[] = "protocols.org_dir.";
 
-      p = __stpcpy (buf, "protocols.org_dir.");
-      p = __stpcpy (p, nis_local_directory ());
-      tablename_val = __strdup (buf);
-      if (tablename_val == NULL)
+      char *p = malloc (sizeof (prefix) + local_dir_len);
+      if (p == NULL)
 	{
 	  *errnop = errno;
 	  return NSS_STATUS_TRYAGAIN;
 	}
-      tablename_len = strlen (tablename_val);
+
+      memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
+
+      tablename_len = sizeof (prefix) - 1 + local_dir_len;
+
+      atomic_write_barrier ();
+
+      tablename_val = p;
     }
+
   return NSS_STATUS_SUCCESS;
 }
 
@@ -164,9 +171,11 @@ _nss_nisplus_setprotoent (int stayopen)
 
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result != NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
 
   if (tablename_val == NULL)
     {
@@ -184,9 +193,11 @@ _nss_nisplus_endprotoent (void)
 {
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result != NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
 
   __libc_lock_unlock (lock);
 
@@ -216,17 +227,23 @@ internal_nisplus_getprotoent_r (struct protoent *proto, char *buffer,
 	    }
 
 	  result = nis_first_entry (tablename_val);
+	  if (result == NULL)
+	    {
+	      *errnop = errno;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    return niserr2nss (result->status);
 	}
       else
 	{
-	  nis_result *res;
-
 	  saved_res = result;
-	  res = nis_next_entry (tablename_val, &result->cookie);
-	  result = res;
-
+	  result = nis_next_entry (tablename_val, &result->cookie);
+	  if (result == NULL)
+	    {
+	      *errnop = errno;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    {
 	      nis_freeresult (saved_res);
@@ -277,79 +294,91 @@ _nss_nisplus_getprotobyname_r (const char *name, struct protoent *proto,
 
   if (tablename_val == NULL)
     {
+      __libc_lock_lock (lock);
+
       enum nss_status status = _nss_create_tablename (errnop);
 
+      __libc_lock_unlock (lock);
+
       if (status != NSS_STATUS_SUCCESS)
 	return status;
     }
 
   if (name == NULL)
     return NSS_STATUS_NOTFOUND;
-  else
-    {
-      nis_result *result;
-      char buf[strlen (name) + 255 + tablename_len];
-      int olderr = errno;
 
-      /* Search at first in the alias list, and use the correct name
-         for the next search */
-      sprintf (buf, "[name=%s],%s", name, tablename_val);
-      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
-
-      if (result != 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)
-	      || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
-	      || strcmp (result->objects.objects_val->EN_data.en_type,
-			 "protocols_tbl") != 0
-	      || 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],%s", NISENTRYVAL (0, 0, result),
-		     tablename_val);
+  char buf[strlen (name) + 10 + tablename_len];
+  int olderr = errno;
 
-	  nis_freeresult (result);
-	  result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
-	}
+  /* Search at first in the alias list, and use the correct name
+     for the next search */
+  snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
+  nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
-      if (result == NULL)
+  if (result != NULL)
+    {
+      char *bufptr = buf;
+
+      /* If we did 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)
+	  || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
+	  || strcmp (result->objects.objects_val->EN_data.en_type,
+			 "protocols_tbl") != 0
+	  || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
+	snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
+      else
 	{
-	  __set_errno (ENOMEM);
-	  return NSS_STATUS_TRYAGAIN;
+	  /* We need to allocate a new buffer since there is no
+	     guarantee the returned name has a length limit.  */
+	  const char *entryval = NISENTRYVAL (0, 0, result);
+	  size_t buflen = strlen (entryval) + 10 + tablename_len;
+	  bufptr = alloca (buflen);
+	  snprintf (bufptr, buflen, "[cname=%s],%s",
+		    entryval, tablename_val);
 	}
-      if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-	{
-	  enum nss_status status = niserr2nss (result->status);
 
-	  __set_errno (olderr);
+      nis_freeresult (result);
+      result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+    }
 
-	  nis_freeresult (result);
-	  return status;
-	}
+  if (result == NULL)
+    {
+      __set_errno (ENOMEM);
+      return NSS_STATUS_TRYAGAIN;
+    }
 
-      parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen,
-					       errnop);
+  if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
+    {
+      enum nss_status status = niserr2nss (result->status);
+
+      __set_errno (olderr);
 
       nis_freeresult (result);
+      return status;
+    }
 
-      if (parse_res < 1)
+  parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen,
+					   errnop);
+
+  nis_freeresult (result);
+
+  if (parse_res < 1)
+    {
+      if (parse_res == -1)
 	{
-	  if (parse_res == -1)
-	    {
-	      *errnop = ERANGE;
-	      return NSS_STATUS_TRYAGAIN;
-	    }
-	  else
-	    {
-	      __set_errno (olderr);
-	      return NSS_STATUS_NOTFOUND;
-	    }
+	  *errnop = ERANGE;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      else
+	{
+	  __set_errno (olderr);
+	  return NSS_STATUS_NOTFOUND;
 	}
-      return NSS_STATUS_SUCCESS;
     }
+
+  return NSS_STATUS_SUCCESS;
 }
 
 enum nss_status
@@ -358,55 +387,57 @@ _nss_nisplus_getprotobynumber_r (const int number, struct protoent *proto,
 {
   if (tablename_val == NULL)
     {
+      __libc_lock_lock (lock);
+
       enum nss_status status = _nss_create_tablename (errnop);
 
+      __libc_lock_unlock (lock);
+
       if (status != NSS_STATUS_SUCCESS)
 	return status;
     }
 
-  {
-    int parse_res;
-    nis_result *result;
-    char buf[46 + tablename_len];
-    int olderr = errno;
+  char buf[12 + 3 * sizeof (number) + tablename_len];
+  int olderr = errno;
 
-    sprintf (buf, "[number=%d],%s", number, tablename_val);
+  snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val);
 
-    result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+  nis_result *result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
 
-    if (result == NULL)
-      {
-	__set_errno (ENOMEM);
-	return NSS_STATUS_TRYAGAIN;
-      }
-    if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-      {
-	enum nss_status status = niserr2nss (result->status);
+  if (result == NULL)
+    {
+      __set_errno (ENOMEM);
+      return NSS_STATUS_TRYAGAIN;
+    }
 
-	__set_errno (olderr);
+  if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
+    {
+      enum nss_status status = niserr2nss (result->status);
 
-	nis_freeresult (result);
-	return status;
-      }
-
-    parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen,
-					     errnop);
-
-    nis_freeresult (result);
-
-    if (parse_res < 1)
-      {
-	if (parse_res == -1)
-	  {
-	    *errnop = ERANGE;
-	    return NSS_STATUS_TRYAGAIN;
-	  }
-	else
-	  {
-	    __set_errno (olderr);
-	    return NSS_STATUS_NOTFOUND;
-	  }
-      }
-    return NSS_STATUS_SUCCESS;
-  }
+      __set_errno (olderr);
+
+      nis_freeresult (result);
+      return status;
+    }
+
+  int parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen,
+					       errnop);
+
+  nis_freeresult (result);
+
+  if (parse_res < 1)
+    {
+      if (parse_res == -1)
+	{
+	  *errnop = ERANGE;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      else
+	{
+	  __set_errno (olderr);
+	  return NSS_STATUS_NOTFOUND;
+	}
+    }
+
+  return NSS_STATUS_SUCCESS;
 }
diff --git a/nis/nss_nisplus/nisplus-publickey.c b/nis/nss_nisplus/nisplus-publickey.c
index 58ae7012af..f6b32f8827 100644
--- a/nis/nss_nisplus/nisplus-publickey.c
+++ b/nis/nss_nisplus/nisplus-publickey.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997, 1999, 2001, 2003 Free Software Foundation, Inc.
+/* Copyright (c) 1997,1999,2001,2003,2005,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
 
@@ -37,7 +37,7 @@ _nss_nisplus_getpublickey (const char *netname, char *pkey, int *errnop)
 {
   nis_result *res;
   enum nss_status retval;
-  char buf[NIS_MAXNAMELEN+2];
+  char buf[NIS_MAXNAMELEN + 2];
   size_t slen;
   char *domain, *cptr;
   int len;
@@ -91,20 +91,20 @@ _nss_nisplus_getpublickey (const char *netname, char *pkey, int *errnop)
       return retval;
     }
 
-  if (res->objects.objects_len > 1)
+  if (NIS_RES_NUMOBJ (res) > 1)
     {
       /*
        * More than one principal with same uid?
        * something wrong with cred table. Should be unique
        * Warn user and continue.
        */
-      printf (_("DES entry for netname %s not unique\n"), netname);
+      syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname);
       nis_freeresult (res);
       return NSS_STATUS_SUCCESS;
     }
 
-  len = ENTRY_LEN (res->objects.objects_val, 3);
-  memcpy (pkey, ENTRY_VAL (res->objects.objects_val,3), len);
+  len = ENTRY_LEN (NIS_RES_OBJECT (res), 3);
+  memcpy (pkey, ENTRY_VAL (NIS_RES_OBJECT (res),3), len);
   pkey[len] = 0;
   cptr = strchr (pkey, ':');
   if (cptr)
@@ -114,13 +114,14 @@ _nss_nisplus_getpublickey (const char *netname, char *pkey, int *errnop)
   return NSS_STATUS_SUCCESS;
 }
 
+
 enum nss_status
 _nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd,
 			   int *errnop)
 {
   nis_result *res;
   enum nss_status retval;
-  char buf[NIS_MAXNAMELEN+2];
+  char buf[NIS_MAXNAMELEN + 2];
   size_t slen;
   char *domain, *cptr;
   int len;
@@ -154,7 +155,7 @@ _nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd,
       buf[slen] = '\0';
     }
 
-  res = nis_list (buf, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
+  res = nis_list (buf, USE_DGRAM | NO_AUTHINFO | FOLLOW_LINKS | FOLLOW_PATH,
 		  NULL, NULL);
 
   if (res == NULL)
@@ -172,20 +173,20 @@ _nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd,
       return retval;
     }
 
-  if (res->objects.objects_len > 1)
+  if (NIS_RES_NUMOBJ (res) > 1)
     {
       /*
        * More than one principal with same uid?
        * something wrong with cred table. Should be unique
        * Warn user and continue.
        */
-      printf (_("DES entry for netname %s not unique\n"), netname);
+      syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname);
       nis_freeresult (res);
       return NSS_STATUS_SUCCESS;
     }
 
-  len = ENTRY_LEN (res->objects.objects_val, 4);
-  memcpy (buf, ENTRY_VAL (res->objects.objects_val,4), len);
+  len = ENTRY_LEN (NIS_RES_OBJECT (res), 4);
+  memcpy (buf, ENTRY_VAL (NIS_RES_OBJECT (res), 4), len);
   buf[len] = '\0';
   cptr = strchr (buf, ':');
   if (cptr)
@@ -204,6 +205,7 @@ _nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd,
   return NSS_STATUS_SUCCESS;
 }
 
+
 /* Parse information from the passed string.
    The format of the string passed is gid,grp,grp, ...  */
 static enum nss_status
@@ -224,8 +226,12 @@ parse_grp_str (const char *s, gid_t *gidp, int *gidlenp, gid_t *gidlist,
   gidlen = 0;
 
   /* After strtoul() ep should point to the marker ',', which means
-     here starts a new value. */
-  while (ep != NULL && *ep == ',')
+     here starts a new value.
+
+     The Sun man pages show that GIDLIST should contain at least NGRPS
+     elements.  Limiting the number written by this value is the best
+     we can do.  */
+  while (ep != NULL && *ep == ',' && gidlen < NGRPS)
     {
       ep++;
       s = ep;
@@ -242,9 +248,9 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
 {
   char *domain;
   nis_result *res;
-  char sname[NIS_MAXNAMELEN+2]; /*  search criteria + table name */
+  char sname[NIS_MAXNAMELEN + 2]; /*  search criteria + table name */
   size_t slen;
-  char principal[NIS_MAXNAMELEN+1];
+  char principal[NIS_MAXNAMELEN + 1];
   int len;
 
   /* 1.  Get home domain of user. */
@@ -255,10 +261,6 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
   ++domain;  /* skip '@' */
 
   /* 2.  Get user's nisplus principal name.  */
-  if ((strlen (netname) + strlen (domain)+45) >
-      (size_t) NIS_MAXNAMELEN)
-    return NSS_STATUS_UNAVAIL;
-
   slen = snprintf (sname, NIS_MAXNAMELEN,
 		   "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
 		   netname, domain);
@@ -309,7 +311,7 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
       return NSS_STATUS_UNAVAIL;
     }
 
-  if (res->objects.objects_len > 1)
+  if (NIS_RES_NUMOBJ (res) > 1)
     /*
      * A netname belonging to more than one principal?
      * Something wrong with cred table. should be unique.
@@ -319,8 +321,8 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
 	    _("netname2user: DES entry for %s in directory %s not unique"),
 	    netname, domain);
 
-  len = ENTRY_LEN (res->objects.objects_val, 0);
-  strncpy (principal, ENTRY_VAL (res->objects.objects_val, 0), len);
+  len = ENTRY_LEN (NIS_RES_OBJECT (res), 0);
+  strncpy (principal, ENTRY_VAL (NIS_RES_OBJECT (res), 0), len);
   principal[len] = '\0';
   nis_freeresult (res);
 
@@ -332,15 +334,16 @@ _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) > (size_t) NIS_MAXNAMELEN)
+  if (strlen (principal) + strlen (domain) + 45 > (size_t) NIS_MAXNAMELEN)
     {
       syslog (LOG_ERR, _("netname2user: principal name `%s' too long"),
 	      principal);
       return NSS_STATUS_UNAVAIL;
     }
 
-  slen = sprintf (sname, "[cname=%s,auth_type=LOCAL],cred.org_dir.%s",
-		  principal, domain);
+  slen = snprintf (sname, sizeof  (sname),
+		   "[cname=%s,auth_type=LOCAL],cred.org_dir.%s",
+		   principal, domain);
 
   if (sname[slen - 1] != '.')
     {
@@ -382,7 +385,7 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
       return NSS_STATUS_UNAVAIL;
     }
 
-  if (res->objects.objects_len > 1)
+  if (NIS_RES_NUMOBJ (res) > 1)
     /*
      * A principal can have more than one LOCAL entry?
      * Something wrong with cred table.
@@ -392,15 +395,16 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
 	    _("netname2user: LOCAL entry for %s in directory %s not unique"),
 	    netname, domain);
   /* Fetch the uid */
-  *uidp = strtoul (ENTRY_VAL (res->objects.objects_val, 2), NULL, 10);
+  *uidp = strtoul (ENTRY_VAL (NIS_RES_OBJECT (res), 2), NULL, 10);
 
   if (*uidp == 0)
     {
       syslog (LOG_ERR, _("netname2user: should not have uid 0"));
+      nis_freeresult (res);
       return NSS_STATUS_NOTFOUND;
     }
 
-  parse_grp_str (ENTRY_VAL (res->objects.objects_val, 3),
+  parse_grp_str (ENTRY_VAL (NIS_RES_OBJECT (res), 3),
 		 gidp, gidlenp, gidlist, errnop);
 
   nis_freeresult (res);
diff --git a/nis/nss_nisplus/nisplus-pwd.c b/nis/nss_nisplus/nisplus-pwd.c
index 8f3bc997b3..cd33aebbcc 100644
--- a/nis/nss_nisplus/nisplus-pwd.c
+++ b/nis/nss_nisplus/nisplus-pwd.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1997, 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1999, 2001, 2002, 2003, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -17,6 +18,7 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <atomic.h>
 #include <nss.h>
 #include <errno.h>
 #include <pwd.h>
@@ -26,126 +28,246 @@
 
 #include "nss-nisplus.h"
 #include "nisplus-parser.h"
+#include <libnsl.h>
+#include <nis_intern.h>
+#include <nis_xdr.h>
+
 
 __libc_lock_define_initialized (static, lock)
 
-static nis_result *result;
-static nis_name tablename_val;
-static u_long tablename_len;
+/* Connection information.  */
+static ib_request *ibreq;
+static directory_obj *dir;
+static dir_binding bptr;
+static char *tablepath;
+static char *tableptr;
+/* Cursor.  */
+static netobj cursor;
 
-static enum nss_status
-_nss_create_tablename (int *errnop)
+
+nis_name pwd_tablename_val attribute_hidden;
+size_t pwd_tablename_len attribute_hidden;
+
+enum nss_status
+_nss_pwd_create_tablename (int *errnop)
 {
-  if (tablename_val == NULL)
+  if (pwd_tablename_val == NULL)
     {
-      char buf [40 + strlen (nis_local_directory ())];
-      char *p;
+      const char *local_dir = nis_local_directory ();
+      size_t local_dir_len = strlen (local_dir);
+      static const char prefix[] = "passwd.org_dir.";
 
-      p = __stpcpy (buf, "passwd.org_dir.");
-      p = __stpcpy (p, nis_local_directory ());
-      tablename_val = __strdup (buf);
-      if (tablename_val == NULL)
+      char *p = malloc (sizeof (prefix) + local_dir_len);
+      if (p == NULL)
 	{
 	  *errnop = errno;
 	  return NSS_STATUS_TRYAGAIN;
 	}
-      tablename_len = strlen (tablename_val);
+
+      memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
+
+      pwd_tablename_len = sizeof (prefix) - 1 + local_dir_len;
+
+      atomic_write_barrier ();
+
+      if (atomic_compare_and_exchange_bool_acq (&pwd_tablename_val, p, NULL))
+	{
+	  /* Another thread already installed the value.  */
+	  free (p);
+	  pwd_tablename_len = strlen (pwd_tablename_val);
+	}
     }
+
   return NSS_STATUS_SUCCESS;
 }
 
 
+static void
+internal_nisplus_endpwent (void)
+{
+  __nisbind_destroy (&bptr);
+  memset (&bptr, '\0', sizeof (bptr));
+
+  nis_free_directory (dir);
+  dir = NULL;
+
+  nis_free_request (ibreq);
+  ibreq = NULL;
+
+  xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor);
+  memset (&cursor, '\0', sizeof (cursor));
+
+  free (tablepath);
+  tableptr = tablepath = NULL;
+}
+
+
+static enum nss_status
+internal_nisplus_setpwent (int *errnop)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  if (pwd_tablename_val == NULL)
+    status = _nss_pwd_create_tablename (errnop);
+
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      ibreq = __create_ib_request (pwd_tablename_val, 0);
+      if (ibreq == NULL)
+	{
+	  *errnop = errno;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      nis_error retcode = __prepare_niscall (pwd_tablename_val, &dir,
+					     &bptr, 0);
+      if (retcode != NIS_SUCCESS)
+	{
+	  nis_free_request (ibreq);
+	  ibreq = NULL;
+	  status = niserr2nss (retcode);
+	}
+    }
+
+  return status;
+}
+
+
 enum nss_status
 _nss_nisplus_setpwent (int stayopen)
 {
-  enum nss_status status = NSS_STATUS_SUCCESS;
-  int err;
+  enum nss_status status;
 
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  internal_nisplus_endpwent ();
 
-  if (tablename_val == NULL)
-    status = _nss_create_tablename (&err);
+  // XXX We need to be able to set errno.  Pass in new parameter.
+  int err;
+  status = internal_nisplus_setpwent (&err);
 
   __libc_lock_unlock (lock);
 
   return status;
 }
 
+
 enum nss_status
 _nss_nisplus_endpwent (void)
 {
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  internal_nisplus_endpwent ();
 
   __libc_lock_unlock (lock);
 
   return NSS_STATUS_SUCCESS;
 }
 
+
 static enum nss_status
 internal_nisplus_getpwent_r (struct passwd *pw, char *buffer, size_t buflen,
 			     int *errnop)
 {
-  int parse_res;
+  int parse_res = -1;
+  enum nss_status retval = NSS_STATUS_SUCCESS;
 
   /* Get the next entry until we found a correct one. */
   do
     {
-      nis_result *saved_res;
+      nis_error status;
+      nis_result result;
+      memset (&result, '\0', sizeof (result));
 
-      if (result == NULL)
+      if (cursor.n_bytes == NULL)
 	{
-	  saved_res = NULL;
-          if (tablename_val == NULL)
+	  if (ibreq == NULL)
 	    {
-	      enum nss_status status = _nss_create_tablename (errnop);
-
-	      if (status != NSS_STATUS_SUCCESS)
-		return status;
+	      retval = internal_nisplus_setpwent (errnop);
+	      if (retval != NSS_STATUS_SUCCESS)
+		return retval;
 	    }
 
-	  result = nis_first_entry (tablename_val);
-	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-	    return niserr2nss (result->status);
+	  status = __do_niscall3 (&bptr, NIS_IBFIRST,
+				  (xdrproc_t) _xdr_ib_request,
+				  (caddr_t) ibreq,
+				  (xdrproc_t) _xdr_nis_result,
+				  (caddr_t) &result,
+				  0, NULL);
 	}
       else
 	{
-	  nis_result *res;
+	  ibreq->ibr_cookie.n_bytes = cursor.n_bytes;
+	  ibreq->ibr_cookie.n_len = cursor.n_len;
+
+	  status = __do_niscall3 (&bptr, NIS_IBNEXT,
+				  (xdrproc_t) _xdr_ib_request,
+				  (caddr_t) ibreq,
+				  (xdrproc_t) _xdr_nis_result,
+				  (caddr_t) &result,
+				  0, NULL);
+
+	  ibreq->ibr_cookie.n_bytes = NULL;
+	  ibreq->ibr_cookie.n_len = 0;
+	}
 
-	  saved_res = result;
-	  res = nis_next_entry (tablename_val, &result->cookie);
-	  result = res;
-	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-	    {
-	      nis_freeresult (saved_res);
-	      return niserr2nss (result->status);
-	    }
+      if (status != NIS_SUCCESS)
+	return niserr2nss (status);
+
+      if (NIS_RES_STATUS (&result) == NIS_NOTFOUND)
+	{
+	  /* No more entries on this server.  This means we have to go
+	     to the next server on the path.  */
+	  status = __follow_path (&tablepath, &tableptr, ibreq, &bptr);
+	  if (status != NIS_SUCCESS)
+	    return niserr2nss (status);
+
+	  directory_obj *newdir = NULL;
+	  dir_binding newbptr;
+	  status = __prepare_niscall (ibreq->ibr_name, &newdir, &newbptr, 0);
+	  if (status != NIS_SUCCESS)
+	    return niserr2nss (status);
+
+	  nis_free_directory (dir);
+	  dir = newdir;
+	  __nisbind_destroy (&bptr);
+	  bptr = newbptr;
+
+	  xdr_free ((xdrproc_t) xdr_netobj, (char *) &result.cookie);
+	  result.cookie.n_bytes = NULL;
+	  result.cookie.n_len = 0;
+	  parse_res = 0;
+	  goto next;
 	}
+      else if (NIS_RES_STATUS (&result) != NIS_SUCCESS)
+	return niserr2nss (NIS_RES_STATUS (&result));
 
-      parse_res = _nss_nisplus_parse_pwent (result, pw, buffer,
+      parse_res = _nss_nisplus_parse_pwent (&result, pw, buffer,
 					    buflen, errnop);
-      if (parse_res == -1)
+
+      if (__builtin_expect (parse_res == -1, 0))
 	{
-	  nis_freeresult (result);
-	  result = saved_res;
 	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
+	  retval = NSS_STATUS_TRYAGAIN;
+	  goto freeres;
 	}
-      else
-	{
-	  if (saved_res)
-	    nis_freeresult (saved_res);
-	}
-    } while (!parse_res);
 
-  return NSS_STATUS_SUCCESS;
+    next:
+      /* Free the old cursor.  */
+      xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor);
+      /* Remember the new one.  */
+      cursor.n_bytes = result.cookie.n_bytes;
+      cursor.n_len = result.cookie.n_len;
+      /* Free the result structure.  NB: we do not remove the cookie.  */
+      result.cookie.n_bytes = NULL;
+      result.cookie.n_len = 0;
+    freeres:
+      xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &result);
+      memset (&result, '\0', sizeof (result));
+    }
+  while (!parse_res);
+
+  return retval;
 }
 
 enum nss_status
@@ -169,9 +291,9 @@ _nss_nisplus_getpwnam_r (const char *name, struct passwd *pw,
 {
   int parse_res;
 
-  if (tablename_val == NULL)
+  if (pwd_tablename_val == NULL)
     {
-      enum nss_status status = _nss_create_tablename (errnop);
+      enum nss_status status = _nss_pwd_create_tablename (errnop);
 
       if (status != NSS_STATUS_SUCCESS)
 	return status;
@@ -182,107 +304,107 @@ _nss_nisplus_getpwnam_r (const char *name, struct passwd *pw,
       *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
-  else
-    {
-      nis_result *result;
-      char buf[strlen (name) + 24 + tablename_len];
-      int olderr = errno;
 
-      sprintf (buf, "[name=%s],%s", name, tablename_val);
+  nis_result *result;
+  char buf[strlen (name) + 9 + pwd_tablename_len];
+  int olderr = errno;
 
-      result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+  snprintf (buf, sizeof (buf), "[name=%s],%s", name, pwd_tablename_val);
 
-      if (result == NULL)
-	{
-	  *errnop = ENOMEM;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-	{
-	  enum nss_status status =  niserr2nss (result->status);
+  result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL);
 
-	  __set_errno (olderr);
+  if (result == NULL)
+    {
+      *errnop = ENOMEM;
+      return NSS_STATUS_TRYAGAIN;
+    }
 
-	  nis_freeresult (result);
-	  return status;
-	}
+  if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
+    {
+      enum nss_status status =  niserr2nss (result->status);
 
-      parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen,
-					    errnop);
+      __set_errno (olderr);
 
       nis_freeresult (result);
+      return status;
+    }
+
+  parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop);
 
-      if (parse_res < 1)
+  nis_freeresult (result);
+
+  if (__builtin_expect (parse_res < 1, 0))
+    {
+      if (parse_res == -1)
 	{
-	  if (parse_res == -1)
-	    {
-	      *errnop = ERANGE;
-	      return NSS_STATUS_TRYAGAIN;
-	    }
-	  else
-	    {
-	      __set_errno (olderr);
-	      return NSS_STATUS_NOTFOUND;
-	    }
+	  *errnop = ERANGE;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      else
+	{
+	  __set_errno (olderr);
+	  return NSS_STATUS_NOTFOUND;
 	}
-      return NSS_STATUS_SUCCESS;
     }
+
+  return NSS_STATUS_SUCCESS;
 }
 
 enum nss_status
 _nss_nisplus_getpwuid_r (const uid_t uid, struct passwd *pw,
 			 char *buffer, size_t buflen, int *errnop)
 {
-  if (tablename_val == NULL)
+  if (pwd_tablename_val == NULL)
     {
-      enum nss_status status = _nss_create_tablename (errnop);
+      enum nss_status status = _nss_pwd_create_tablename (errnop);
 
       if (status != NSS_STATUS_SUCCESS)
 	return status;
     }
 
-  {
-    int parse_res;
-    nis_result *result;
-    char buf[100 + tablename_len];
-    int olderr = errno;
+  int parse_res;
+  nis_result *result;
+  char buf[8 + 3 * sizeof (unsigned long int) + pwd_tablename_len];
+  int olderr = errno;
+
+  snprintf (buf, sizeof (buf), "[uid=%lu],%s",
+	    (unsigned long int) uid, pwd_tablename_val);
+
+  result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL);
+
+  if (result == NULL)
+    {
+      *errnop = ENOMEM;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
+    {
+      enum nss_status status = niserr2nss (result->status);
 
-    sprintf (buf, "[uid=%lu],%s", (unsigned long int) uid, tablename_val);
+      __set_errno (olderr);
 
-    result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+      nis_freeresult (result);
+      return status;
+    }
 
-    if (result == NULL)
-      {
-	*errnop = ENOMEM;
-	return NSS_STATUS_TRYAGAIN;
-      }
-    if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-      {
-	enum nss_status status = niserr2nss (result->status);
+  parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop);
 
-	__set_errno (olderr);
+  nis_freeresult (result);
 
-	nis_freeresult (result);
-	return status;
-      }
-
-    parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop);
-
-    nis_freeresult (result);
-
-    if (parse_res < 1)
-      {
-	if (parse_res == -1)
-	  {
-	    *errnop = ERANGE;
-	    return NSS_STATUS_TRYAGAIN;
-	  }
-	else
-	  {
-	    __set_errno (olderr);
-	    return NSS_STATUS_NOTFOUND;
-	  }
-      }
-    return NSS_STATUS_SUCCESS;
-  }
+  if (__builtin_expect (parse_res < 1, 0))
+    {
+      if (parse_res == -1)
+	{
+	  *errnop = ERANGE;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      else
+	{
+	  __set_errno (olderr);
+	  return NSS_STATUS_NOTFOUND;
+	}
+    }
+
+  return NSS_STATUS_SUCCESS;
 }
diff --git a/nis/nss_nisplus/nisplus-rpc.c b/nis/nss_nisplus/nisplus-rpc.c
index 31d48d17a3..711c6bc273 100644
--- a/nis/nss_nisplus/nisplus-rpc.c
+++ b/nis/nss_nisplus/nisplus-rpc.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1997, 1998, 2001, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 2001, 2002, 2003, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -17,13 +18,14 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#include <nss.h>
-#include <errno.h>
+#include <atomic.h>
 #include <ctype.h>
+#include <errno.h>
+#include <nss.h>
 #include <string.h>
-#include <bits/libc-lock.h>
 #include <rpc/netdb.h>
 #include <rpcsvc/nis.h>
+#include <bits/libc-lock.h>
 
 #include "nss-nisplus.h"
 
@@ -33,11 +35,12 @@ static nis_result *result;
 static nis_name tablename_val;
 static u_long tablename_len;
 
-#define NISENTRYVAL(idx,col,res) \
-        ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+#define NISENTRYVAL(idx, col, res) \
+        (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
+
+#define NISENTRYLEN(idx, col, res) \
+        (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
 
-#define NISENTRYLEN(idx,col,res) \
-        ((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,
@@ -46,17 +49,16 @@ _nss_nisplus_parse_rpcent (nis_result *result, struct rpcent *rpc,
   char *first_unused = buffer;
   size_t room_left = buflen;
   unsigned int i;
-  char *p, *line;
+  char *line;
 
 
   if (result == NULL)
     return 0;
 
   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
-      || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
-      || strcmp (result->objects.objects_val[0].EN_data.en_type,
-		 "rpc_tbl") != 0
-      || result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 3)
+      || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
+      || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "rpc_tbl") != 0
+      || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 3)
     return 0;
 
   if (NISENTRYLEN (0, 0, result) >= room_left)
@@ -69,37 +71,43 @@ _nss_nisplus_parse_rpcent (nis_result *result, struct rpcent *rpc,
            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;
+  size_t len = strlen (first_unused) + 1;
+  room_left -= len;
+  first_unused += len;
+
   rpc->r_number = atoi (NISENTRYVAL (0, 2, result));
-  p = first_unused;
 
-  line = p;
-  for (i = 0; i < result->objects.objects_len; ++i)
+  /* XXX Rewrite at some point to allocate the array first and then
+     copy the strings.  It wasteful to first concatenate the strings
+     to just split them again later.  */
+  line = first_unused;
+  for (i = 0; i < NIS_RES_NUMOBJ (result); ++i)
     {
       if (strcmp (NISENTRYVAL (i, 1, result), rpc->r_name) != 0)
         {
           if (NISENTRYLEN (i, 1, result) + 2 > room_left)
 	    goto no_more_room;
-	  *p++ = ' ';
-          p = __stpncpy (p, NISENTRYVAL (i, 1, result),
-			 NISENTRYLEN (i, 1, result));
-          *p = '\0';
-          room_left -= (NISENTRYLEN (i, 1, result) + 1);
+	  *first_unused++ = ' ';
+          first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result),
+				    NISENTRYLEN (i, 1, result));
+          room_left -= NISENTRYLEN (i, 1, result) + 1;
         }
     }
-  ++p;
-  first_unused = p;
+  *first_unused++ = '\0';
 
   /* 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 *))
+  size_t adjust = ((__alignof__ (char *)
+		    - (first_unused - (char *) 0) % __alignof__ (char *))
+		   % __alignof__ (char *));
+  if (room_left < adjust + sizeof (char *))
     goto no_more_room;
+  first_unused += adjust;
+  room_left -= adjust;
+  rpc->r_aliases = (char **) first_unused;
+
+  /* For the terminating NULL pointer.  */
   room_left -= sizeof (char *);
-  rpc->r_aliases[0] = NULL;
 
   i = 0;
   while (*line != '\0')
@@ -115,42 +123,45 @@ _nss_nisplus_parse_rpcent (nis_result *result, struct rpcent *rpc,
 	goto no_more_room;
 
       room_left -= sizeof (char *);
-      rpc->r_aliases[i] = line;
+      rpc->r_aliases[i++] = line;
 
       while (*line != '\0' && *line != ' ')
         ++line;
 
       if (*line == ' ')
-        {
-	  *line = '\0';
-	  ++line;
-          ++i;
-        }
-      else
-        rpc->r_aliases[i+1] = NULL;
+	*line++ = '\0';
     }
+  rpc->r_aliases[i] = NULL;
 
   return 1;
 }
 
+
 static enum nss_status
 _nss_create_tablename (int *errnop)
 {
   if (tablename_val == NULL)
     {
-      char buf [40 + strlen (nis_local_directory ())];
-      char *p;
+      const char *local_dir = nis_local_directory ();
+      size_t local_dir_len = strlen (local_dir);
+      static const char prefix[] = "rpc.org_dir.";
 
-      p = __stpcpy (buf, "rpc.org_dir.");
-      p = __stpcpy (p, nis_local_directory ());
-      tablename_val = __strdup (buf);
-      if (tablename_val == NULL)
+      char *p = malloc (sizeof (prefix) + local_dir_len);
+      if (p == NULL)
 	{
 	  *errnop = errno;
 	  return NSS_STATUS_TRYAGAIN;
 	}
-      tablename_len = strlen (tablename_val);
+
+      memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
+
+      tablename_len = sizeof (prefix) - 1 + local_dir_len;
+
+      atomic_write_barrier ();
+
+      tablename_val = p;
     }
+
   return NSS_STATUS_SUCCESS;
 }
 
@@ -159,16 +170,20 @@ enum nss_status
 _nss_nisplus_setrpcent (int stayopen)
 {
   enum nss_status status = NSS_STATUS_SUCCESS;
-  int err;
 
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result != NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
 
   if (tablename_val == NULL)
-    status = _nss_create_tablename (&err);
+    {
+      int err;
+      status = _nss_create_tablename (&err);
+    }
 
   __libc_lock_unlock (lock);
 
@@ -180,9 +195,11 @@ _nss_nisplus_endrpcent (void)
 {
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result != NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
 
   __libc_lock_unlock (lock);
 
@@ -212,16 +229,23 @@ internal_nisplus_getrpcent_r (struct rpcent *rpc, char *buffer,
 	    }
 
 	  result = nis_first_entry (tablename_val);
+	  if (result == NULL)
+	    {
+	      *errnop = errno;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    return niserr2nss (result->status);
 	}
       else
 	{
-	  nis_result *res;
-
 	  saved_res = result;
-	  res = nis_next_entry (tablename_val, &result->cookie);
-	  result = res;
+	  result = nis_next_entry (tablename_val, &result->cookie);
+	  if (result == NULL)
+	    {
+	      *errnop = errno;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    {
 	      nis_freeresult (saved_res);
@@ -243,7 +267,8 @@ internal_nisplus_getrpcent_r (struct rpcent *rpc, char *buffer,
 	  if (saved_res)
 	    nis_freeresult (saved_res);
 	}
-    } while (!parse_res);
+    }
+  while (!parse_res);
 
   return NSS_STATUS_SUCCESS;
 }
@@ -271,77 +296,91 @@ _nss_nisplus_getrpcbyname_r (const char *name, struct rpcent *rpc,
 
   if (tablename_val == NULL)
     {
+      __libc_lock_lock (lock);
+
       enum nss_status status = _nss_create_tablename (errnop);
 
+      __libc_lock_unlock (lock);
+
       if (status != NSS_STATUS_SUCCESS)
 	return status;
     }
 
   if (name == NULL)
     return NSS_STATUS_NOTFOUND;
-  else
-    {
-      nis_result *result;
-      char buf[strlen (name) + 255 + tablename_len];
-      int olderr = errno;
 
-      /* Search at first in the alias list, and use the correct name
-         for the next search */
-      sprintf (buf, "[name=%s],%s", name, tablename_val);
-      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+  char buf[strlen (name) + 10 + tablename_len];
+  int olderr = errno;
 
-      if (result != 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)
-	      || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
-	      || strcmp (result->objects.objects_val->EN_data.en_type,
-			 "rpc_tbl") != 0
-	      || 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],%s", NISENTRYVAL (0, 0, result),
-		     tablename_val);
-
-	  nis_freeresult (result);
-	  result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS , NULL, NULL);
-	}
+  /* Search at first in the alias list, and use the correct name
+     for the next search */
+  snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
+  nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
+				 NULL, NULL);
 
-      if (result == NULL)
+  if (result != NULL)
+    {
+      char *bufptr = buf;
+
+      /* If we did 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)
+	  || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
+	  || strcmp (result->objects.objects_val->EN_data.en_type,
+		     "rpc_tbl") != 0
+	  || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
+	snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
+      else
 	{
-	  *errnop = ENOMEM;
-	  return NSS_STATUS_TRYAGAIN;
+	  /* We need to allocate a new buffer since there is no
+	     guarantee the returned name has a length limit.  */
+	  const char *entryval = NISENTRYVAL (0, 0, result);
+	  size_t buflen = strlen (entryval) + 10 + tablename_len;
+	  bufptr = alloca (buflen);
+	  snprintf (bufptr, buflen, "[cname=%s],%s",
+		    entryval, tablename_val);
 	}
-      if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-	{
-	  enum nss_status status = niserr2nss (result->status);
 
-	  __set_errno (olderr);
+      nis_freeresult (result);
+      result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
+			 NULL, NULL);
+    }
 
-	  nis_freeresult (result);
-	  return status;
-	}
+  if (result == NULL)
+    {
+      *errnop = ENOMEM;
+      return NSS_STATUS_TRYAGAIN;
+    }
 
-      parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
-					     errnop);
+  if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
+    {
+      enum nss_status status = niserr2nss (result->status);
+
+      __set_errno (olderr);
 
       nis_freeresult (result);
+      return status;
+    }
 
-      if (parse_res < 1)
-	{
-	  if (parse_res == -1)
-	    {
-	      *errnop = ERANGE;
-	      return NSS_STATUS_TRYAGAIN;
-	    }
+  parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
+					     errnop);
 
-	  __set_errno (olderr);
-	  return NSS_STATUS_NOTFOUND;
+  nis_freeresult (result);
+
+  if (parse_res < 1)
+    {
+      if (parse_res == -1)
+	{
+	  *errnop = ERANGE;
+	  return NSS_STATUS_TRYAGAIN;
 	}
-      return NSS_STATUS_SUCCESS;
+
+      __set_errno (olderr);
+      return NSS_STATUS_NOTFOUND;
     }
+
+  return NSS_STATUS_SUCCESS;
 }
 
 enum nss_status
@@ -350,55 +389,58 @@ _nss_nisplus_getrpcbynumber_r (const int number, struct rpcent *rpc,
 {
   if (tablename_val == NULL)
     {
+      __libc_lock_lock (lock);
+
       enum nss_status status = _nss_create_tablename (errnop);
 
+      __libc_lock_unlock (lock);
+
       if (status != NSS_STATUS_SUCCESS)
 	return status;
     }
 
-  {
-    int parse_res;
-    nis_result *result;
-    char buf[100 + tablename_len];
-    int olderr = errno;
+  char buf[12 + 3 * sizeof (number) + tablename_len];
+  int olderr = errno;
 
-    sprintf (buf, "[number=%d],%s", number, tablename_val);
+  snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val);
 
-    result = nis_list(buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+  nis_result *result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM,
+				 NULL, NULL);
 
-    if (result == NULL)
-      {
-	*errnop = ENOMEM;
-	return NSS_STATUS_TRYAGAIN;
-      }
-    if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-      {
-	enum nss_status status = niserr2nss (result->status);
+  if (result == NULL)
+    {
+      *errnop = ENOMEM;
+      return NSS_STATUS_TRYAGAIN;
+    }
 
-	__set_errno (olderr);
+  if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS,  0))
+    {
+      enum nss_status status = niserr2nss (result->status);
 
-	nis_freeresult (result);
-	return status;
-      }
-
-    parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
-					   errnop);
-
-    nis_freeresult (result);
-
-    if (parse_res < 1)
-      {
-	if (parse_res == -1)
-	  {
-	    *errnop = ERANGE;
-	    return NSS_STATUS_TRYAGAIN;
-	  }
-	else
-	  {
-	    __set_errno (olderr);
-	    return NSS_STATUS_NOTFOUND;
-	  }
-      }
-    return NSS_STATUS_SUCCESS;
-  }
+      __set_errno (olderr);
+
+      nis_freeresult (result);
+      return status;
+    }
+
+  int parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
+					     errnop);
+
+  nis_freeresult (result);
+
+  if (parse_res < 1)
+    {
+      if (parse_res == -1)
+	{
+	  *errnop = ERANGE;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      else
+	{
+	  __set_errno (olderr);
+	  return NSS_STATUS_NOTFOUND;
+	}
+    }
+
+  return NSS_STATUS_SUCCESS;
 }
diff --git a/nis/nss_nisplus/nisplus-service.c b/nis/nss_nisplus/nisplus-service.c
index fbb6987e9e..607ce80b01 100644
--- a/nis/nss_nisplus/nisplus-service.c
+++ b/nis/nss_nisplus/nisplus-service.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1997,1998,1999,2001,2002,2003 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 1999, 2001, 2002, 2003, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
 
@@ -17,13 +18,14 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#include <nss.h>
-#include <errno.h>
+#include <atomic.h>
 #include <ctype.h>
+#include <errno.h>
 #include <netdb.h>
+#include <nss.h>
 #include <string.h>
-#include <bits/libc-lock.h>
 #include <rpcsvc/nis.h>
+#include <bits/libc-lock.h>
 
 #include "nss-nisplus.h"
 
@@ -33,11 +35,12 @@ static nis_result *result;
 static nis_name tablename_val;
 static u_long tablename_len;
 
-#define NISENTRYVAL(idx,col,res) \
-  ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+#define NISENTRYVAL(idx, col, res) \
+  (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
+
+#define NISENTRYLEN(idx, col, res) \
+    (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
 
-#define NISENTRYLEN(idx,col,res) \
-    ((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,
@@ -45,17 +48,14 @@ _nss_nisplus_parse_servent (nis_result *result, struct servent *serv,
 {
   char *first_unused = buffer;
   size_t room_left = buflen;
-  unsigned int i;
-  char *p, *line;
 
   if (result == NULL)
     return 0;
 
   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
-      || __type_of (result->objects.objects_val) != NIS_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)
+      || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
+      || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "services_tbl") != 0
+      || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 4)
     return 0;
 
   if (NISENTRYLEN (0, 0, result) >= room_left)
@@ -68,8 +68,9 @@ _nss_nisplus_parse_servent (nis_result *result, struct servent *serv,
            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;
+  size_t len = strlen (first_unused) + 1;
+  room_left -= len;
+  first_unused += len;
 
   if (NISENTRYLEN (0, 2, result) >= room_left)
     goto no_more_room;
@@ -77,40 +78,45 @@ _nss_nisplus_parse_servent (nis_result *result, struct servent *serv,
            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;
+  len = strlen (first_unused) + 1;
+  room_left -= len;
+  first_unused += len;
 
   serv->s_port = htons (atoi (NISENTRYVAL (0, 3, result)));
-  p = first_unused;
 
-  line = p;
-  for (i = 0; i < result->objects.objects_len; ++i)
+  /* XXX Rewrite at some point to allocate the array first and then
+     copy the strings.  It wasteful to first concatenate the strings
+     to just split them again later.  */
+  char *line = first_unused;
+  for (unsigned int i = 0; i < NIS_RES_NUMOBJ (result); ++i)
     {
       if (strcmp (NISENTRYVAL (i, 1, result), serv->s_name) != 0)
         {
           if (NISENTRYLEN (i, 1, result) + 2 > room_left)
             goto no_more_room;
-	  *p++ = ' ';
-          p = __stpncpy (p, NISENTRYVAL (i, 1, result),
-			 NISENTRYLEN (i, 1, result));
-          *p = '\0';
-          room_left -= (NISENTRYLEN (i, 1, result) + 1);
+	  *first_unused++ = ' ';
+          first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result),
+				    NISENTRYLEN (i, 1, result));
+          room_left -= NISENTRYLEN (i, 1, result) + 1;
         }
     }
-  *p++ = '\0';
-  first_unused = p;
+  *first_unused++ = '\0';
 
   /* 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 *))
+  size_t adjust = ((__alignof__ (char *)
+		    - (first_unused - (char *) 0) % __alignof__ (char *))
+		   % __alignof__ (char *));
+  if (room_left < adjust + sizeof (char *))
     goto no_more_room;
+  first_unused += adjust;
+  room_left -= adjust;
+  serv->s_aliases = (char **) first_unused;
+
+  /* For the terminating NULL pointer.  */
   room_left -= (sizeof (char *));
-  serv->s_aliases[0] = NULL;
 
-  i = 0;
+  unsigned int i = 0;
   while (*line != '\0')
     {
       /* Skip leading blanks.  */
@@ -124,42 +130,45 @@ _nss_nisplus_parse_servent (nis_result *result, struct servent *serv,
         goto no_more_room;
 
       room_left -= sizeof (char *);
-      serv->s_aliases[i] = line;
+      serv->s_aliases[i++] = line;
 
       while (*line != '\0' && *line != ' ')
         ++line;
 
       if (*line == ' ')
-        {
-	  *line = '\0';
-	  ++line;
-          ++i;
-	}
-      else
-        serv->s_aliases[i+1] = NULL;
+	*line++ = '\0';
     }
+  serv->s_aliases[i] = NULL;
 
   return 1;
 }
 
+
 static enum nss_status
 _nss_create_tablename (int *errnop)
 {
   if (tablename_val == NULL)
     {
-      char buf [40 + strlen (nis_local_directory ())];
-      char *p;
+      const char *local_dir = nis_local_directory ();
+      size_t local_dir_len = strlen (local_dir);
+      static const char prefix[] = "services.org_dir.";
 
-      p = __stpcpy (buf, "services.org_dir.");
-      p = __stpcpy (p, nis_local_directory ());
-      tablename_val = __strdup (buf);
-      if (tablename_val == NULL)
+      char *p = malloc (sizeof (prefix) + local_dir_len);
+      if (p == NULL)
 	{
 	  *errnop = errno;
 	  return NSS_STATUS_TRYAGAIN;
 	}
-      tablename_len = strlen (tablename_val);
+
+      memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
+
+      tablename_len = sizeof (prefix) - 1 + local_dir_len;
+
+      atomic_write_barrier ();
+
+      tablename_val = p;
     }
+
   return NSS_STATUS_SUCCESS;
 }
 
@@ -172,9 +181,11 @@ _nss_nisplus_setservent (int stayopen)
 
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result != NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
 
   if (tablename_val == NULL)
     status = _nss_create_tablename (&err);
@@ -189,9 +200,11 @@ _nss_nisplus_endservent (void)
 {
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result != NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
 
   __libc_lock_unlock (lock);
 
@@ -221,16 +234,23 @@ internal_nisplus_getservent_r (struct servent *serv, char *buffer,
 	    }
 
 	  result = nis_first_entry (tablename_val);
+	  if (result == NULL)
+	    {
+	      *errnop = errno;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    return niserr2nss (result->status);
 	}
       else
 	{
-	  nis_result *res;
-
 	  saved_res = result;
-	  res = nis_next_entry (tablename_val, &result->cookie);
-	  result = res;
+	  result = nis_next_entry (tablename_val, &result->cookie);
+	  if (result == NULL)
+	    {
+	      *errnop = errno;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    {
 	      nis_freeresult (saved_res);
@@ -240,7 +260,7 @@ internal_nisplus_getservent_r (struct servent *serv, char *buffer,
 
       parse_res = _nss_nisplus_parse_servent (result, serv, buffer,
 					      buflen, errnop);
-      if (parse_res == -1)
+      if (__builtin_expect (parse_res == -1, 0))
 	{
 	  nis_freeresult (result);
 	  result = saved_res;
@@ -262,11 +282,9 @@ enum nss_status
 _nss_nisplus_getservent_r (struct servent *result, char *buffer,
 			   size_t buflen, int *errnop)
 {
-  int status;
-
   __libc_lock_lock (lock);
 
-  status = internal_nisplus_getservent_r (result, buffer, buflen, errnop);
+  int status = internal_nisplus_getservent_r (result, buffer, buflen, errnop);
 
   __libc_lock_unlock (lock);
 
@@ -278,12 +296,14 @@ _nss_nisplus_getservbyname_r (const char *name, const char *protocol,
 			      struct servent *serv,
 			      char *buffer, size_t buflen, int *errnop)
 {
-  int parse_res;
-
   if (tablename_val == NULL)
     {
+      __libc_lock_lock (lock);
+
       enum nss_status status = _nss_create_tablename (errnop);
 
+      __libc_lock_unlock (lock);
+
       if (status != NSS_STATUS_SUCCESS)
 	return status;
     }
@@ -293,72 +313,84 @@ _nss_nisplus_getservbyname_r (const char *name, const char *protocol,
       *errnop = EINVAL;
       return NSS_STATUS_NOTFOUND;
     }
-  else
-    {
-      nis_result *result;
-      char buf[strlen (name) + 255 + tablename_len];
-      int olderr = errno;
 
-      /* Search at first in the alias list, and use the correct name
-         for the next search */
-      sprintf (buf, "[name=%s,proto=%s],%s", name, protocol,
-	       tablename_val);
-      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+  size_t protocol_len = strlen (protocol);
+  char buf[strlen (name) + protocol_len + 17 + tablename_len];
+  int olderr = errno;
 
-      if (result != 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)
-	      || __type_of (result->objects.objects_val) != NIS_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)
-	    sprintf (buf, "[cname=%s,proto=%s],%s", name, protocol,
-		     tablename_val);
-	  else
-	    sprintf (buf, "[cname=%s,proto=%s],%s",
-		     NISENTRYVAL (0, 0, result), protocol, tablename_val);
-
-	  nis_freeresult (result);
-	  result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
-	}
+  /* Search at first in the alias list, and use the correct name
+     for the next search */
+  snprintf (buf, sizeof (buf), "[name=%s,proto=%s],%s", name, protocol,
+	    tablename_val);
+  nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
+				 NULL, NULL);
 
-      if (result == NULL)
+  if (result != NULL)
+    {
+      char *bufptr = buf;
+
+      /* If we did 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)
+	  || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
+	  || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type,
+		     "services_tbl") != 0
+	  || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 4)
+	snprintf (buf, sizeof (buf), "[cname=%s,proto=%s],%s", name, protocol,
+		  tablename_val);
+      else
 	{
-	  *errnop = ENOMEM;
-	  return NSS_STATUS_TRYAGAIN;
+	  /* We need to allocate a new buffer since there is no
+	     guarantee the returned name has a length limit.  */
+	  const char *entryval = NISENTRYVAL(0, 0, result);
+	  size_t buflen = (strlen (entryval) + protocol_len + 17
+			   + tablename_len);
+	  bufptr = alloca (buflen);
+	  snprintf (bufptr, buflen, "[cname=%s,proto=%s],%s",
+		    entryval, protocol, tablename_val);
 	}
-      if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-	{
-	  enum nss_status status = niserr2nss (result->status);
 
-	  __set_errno (olderr);
+      nis_freeresult (result);
+      result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
+			 NULL, NULL);
+    }
 
-	  nis_freeresult (result);
-	  return status;
-	}
+  if (result == NULL)
+    {
+      *errnop = ENOMEM;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
+    {
+      enum nss_status status = niserr2nss (result->status);
+
+      __set_errno (olderr);
 
-      parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen,
-					      errnop);
       nis_freeresult (result);
+      return status;
+    }
 
-      if (parse_res < 1)
+  int parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen,
+					      errnop);
+  nis_freeresult (result);
+
+  if (__builtin_expect (parse_res < 1, 0))
+    {
+      if (parse_res == -1)
 	{
-	  if (parse_res == -1)
-	    {
-	      *errnop = ERANGE;
-	      return NSS_STATUS_TRYAGAIN;
-	    }
-	  else
-	    {
-	      __set_errno (olderr);
-	      return NSS_STATUS_NOTFOUND;
-	    }
+	  *errnop = ERANGE;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      else
+	{
+	  __set_errno (olderr);
+	  return NSS_STATUS_NOTFOUND;
 	}
-      return NSS_STATUS_SUCCESS;
     }
+
+  return NSS_STATUS_SUCCESS;
 }
 
 enum nss_status
@@ -368,8 +400,12 @@ _nss_nisplus_getservbyport_r (const int number, const char *protocol,
 {
   if (tablename_val == NULL)
     {
+      __libc_lock_lock (lock);
+
       enum nss_status status = _nss_create_tablename (errnop);
 
+      __libc_lock_unlock (lock);
+
       if (status != NSS_STATUS_SUCCESS)
 	return status;
     }
@@ -379,50 +415,49 @@ _nss_nisplus_getservbyport_r (const int number, const char *protocol,
       *errnop = EINVAL;
       return NSS_STATUS_NOTFOUND;
     }
-  else
-    {
-      int parse_res;
-      nis_result *result;
-      char buf[60 + strlen (protocol) + tablename_len];
-      int olderr = errno;
 
-      sprintf (buf, "[port=%d,proto=%s],%s",
-	       number, protocol, tablename_val);
+  char buf[17 + 3 * sizeof (int) + strlen (protocol) + tablename_len];
+  int olderr = errno;
 
-      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+  snprintf (buf, sizeof (buf), "[port=%d,proto=%s],%s",
+	    number, protocol, tablename_val);
 
-      if (result == NULL)
-	{
-	  *errnop = ENOMEM;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-	{
-	  enum nss_status status = niserr2nss (result->status);
+  nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
+				 NULL, NULL);
 
-	  __set_errno (olderr);
+  if (result == NULL)
+    {
+      *errnop = ENOMEM;
+      return NSS_STATUS_TRYAGAIN;
+    }
 
-	  nis_freeresult (result);
-	  return status;
-	}
+  if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
+    {
+      enum nss_status status = niserr2nss (result->status);
+
+      __set_errno (olderr);
 
-      parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen,
-					      errnop);
       nis_freeresult (result);
+      return status;
+    }
 
-      if (parse_res < 1)
+  int parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen,
+					      errnop);
+  nis_freeresult (result);
+
+  if (__builtin_expect (parse_res < 1, 0))
+    {
+      if (parse_res == -1)
 	{
-	  if (parse_res == -1)
-	    {
-	      *errnop = ERANGE;
-	      return NSS_STATUS_TRYAGAIN;
-	    }
-	  else
-	    {
-	      __set_errno (olderr);
-	      return NSS_STATUS_NOTFOUND;
-	    }
+	  *errnop = ERANGE;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      else
+	{
+	  __set_errno (olderr);
+	  return NSS_STATUS_NOTFOUND;
 	}
-      return NSS_STATUS_SUCCESS;
     }
+
+  return NSS_STATUS_SUCCESS;
 }
diff --git a/nis/nss_nisplus/nisplus-spwd.c b/nis/nss_nisplus/nisplus-spwd.c
index c317469137..f256f3eb90 100644
--- a/nis/nss_nisplus/nisplus-spwd.c
+++ b/nis/nss_nisplus/nisplus-spwd.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1997, 2001, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 2001, 2002, 2003, 2005, 2007
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -30,29 +31,12 @@
 __libc_lock_define_initialized (static, lock)
 
 static nis_result *result;
-static nis_name tablename_val;
-static u_long tablename_len;
 
-static enum nss_status
-_nss_create_tablename (int *errnop)
-{
-  if (tablename_val == NULL)
-    {
-      char buf [40 + strlen (nis_local_directory ())];
-      char *p;
+/* Defined in nisplus-pwd.c.  */
+extern nis_name pwd_tablename_val attribute_hidden;
+extern size_t pwd_tablename_len attribute_hidden;
+extern enum nss_status _nss_pwd_create_tablename (int *errnop);
 
-      p = __stpcpy (buf, "passwd.org_dir.");
-      p = __stpcpy (p, nis_local_directory ());
-      tablename_val = __strdup (buf);
-      if (tablename_val == NULL)
-	{
-	  *errnop = errno;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      tablename_len = strlen (tablename_val);
-    }
-  return NSS_STATUS_SUCCESS;
-}
 
 enum nss_status
 _nss_nisplus_setspent (int stayopen)
@@ -62,12 +46,14 @@ _nss_nisplus_setspent (int stayopen)
 
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result != NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
 
-  if (tablename_val == NULL)
-    status = _nss_create_tablename (&err);
+  if (pwd_tablename_val == NULL)
+    status = _nss_pwd_create_tablename (&err);
 
   __libc_lock_unlock (lock);
 
@@ -79,9 +65,11 @@ _nss_nisplus_endspent (void)
 {
   __libc_lock_lock (lock);
 
-  if (result)
-    nis_freeresult (result);
-  result = NULL;
+  if (result != NULL)
+    {
+      nis_freeresult (result);
+      result = NULL;
+    }
 
   __libc_lock_unlock (lock);
 
@@ -103,25 +91,32 @@ internal_nisplus_getspent_r (struct spwd *sp, char *buffer, size_t buflen,
 	{
 	  saved_res = NULL;
 
-          if (tablename_val == NULL)
+          if (pwd_tablename_val == NULL)
 	    {
-	      enum nss_status status = _nss_create_tablename (errnop);
+	      enum nss_status status = _nss_pwd_create_tablename (errnop);
 
 	      if (status != NSS_STATUS_SUCCESS)
 		return status;
 	    }
 
-	  result = nis_first_entry (tablename_val);
+	  result = nis_first_entry (pwd_tablename_val);
+	  if (result == NULL)
+	    {
+	      *errnop = errno;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    return niserr2nss (result->status);
 	}
       else
 	{
-	  nis_result *res;
-
 	  saved_res = result;
-	  res = nis_next_entry (tablename_val, &result->cookie);
-	  result = res;
+	  result = nis_next_entry (pwd_tablename_val, &result->cookie);
+	  if (result == NULL)
+	    {
+	      *errnop = errno;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
 	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
 	    {
 	      nis_freeresult (saved_res);
@@ -131,19 +126,18 @@ internal_nisplus_getspent_r (struct spwd *sp, char *buffer, size_t buflen,
 
       parse_res = _nss_nisplus_parse_spent (result, sp, buffer,
 					    buflen, errnop);
-      if (parse_res == -1)
+      if (__builtin_expect (parse_res == -1, 0))
 	{
 	  nis_freeresult (result);
 	  result = saved_res;
 	  *errnop = ERANGE;
 	  return NSS_STATUS_TRYAGAIN;
 	}
-      else
-	{
-	  if (saved_res)
-	    nis_freeresult (saved_res);
-	}
-    } while (!parse_res);
+
+      if (saved_res != NULL)
+	nis_freeresult (saved_res);
+    }
+  while (!parse_res);
 
   return NSS_STATUS_SUCCESS;
 }
@@ -169,9 +163,9 @@ _nss_nisplus_getspnam_r (const char *name, struct spwd *sp,
 {
   int parse_res;
 
-  if (tablename_val == NULL)
+  if (pwd_tablename_val == NULL)
     {
-      enum nss_status status = _nss_create_tablename (errnop);
+      enum nss_status status = _nss_pwd_create_tablename (errnop);
 
       if (status != NSS_STATUS_SUCCESS)
 	return status;
@@ -182,48 +176,47 @@ _nss_nisplus_getspnam_r (const char *name, struct spwd *sp,
       *errnop = EINVAL;
       return NSS_STATUS_NOTFOUND;
     }
-  else
-    {
-      nis_result *result;
-      char buf[strlen (name) + 24 + tablename_len];
-      int olderr = errno;
 
-      sprintf (buf, "[name=%s],%s", name, tablename_val);
+  nis_result *result;
+  char buf[strlen (name) + 9 + pwd_tablename_len];
+  int olderr = errno;
 
-      result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+  snprintf (buf, sizeof (buf), "[name=%s],%s", name, pwd_tablename_val);
 
-      if (result == NULL)
-	{
-	  *errnop = ENOMEM;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-      if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
-	{
-	  enum nss_status status = niserr2nss (result->status);
+  result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL);
 
-	  __set_errno (olderr);
+  if (result == NULL)
+    {
+      *errnop = ENOMEM;
+      return NSS_STATUS_TRYAGAIN;
+    }
 
-	  nis_freeresult (result);
-	  return status;
-	}
+  if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
+    {
+      enum nss_status status = niserr2nss (result->status);
+
+      __set_errno (olderr);
 
-      parse_res = _nss_nisplus_parse_spent (result, sp, buffer, buflen,
-					    errnop);
       nis_freeresult (result);
+      return status;
+    }
+
+  parse_res = _nss_nisplus_parse_spent (result, sp, buffer, buflen, errnop);
+  nis_freeresult (result);
 
-      if (parse_res < 1)
+  if (__builtin_expect (parse_res < 1, 0))
+    {
+      if (parse_res == -1)
 	{
-	  if (parse_res == -1)
-	    {
-	      *errnop = ERANGE;
-	      return NSS_STATUS_TRYAGAIN;
-	    }
-	  else
-	    {
-	      __set_errno (olderr);
-	      return NSS_STATUS_NOTFOUND;
-	    }
+	  *errnop = ERANGE;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      else
+	{
+	  __set_errno (olderr);
+	  return NSS_STATUS_NOTFOUND;
 	}
-      return NSS_STATUS_SUCCESS;
     }
+
+  return NSS_STATUS_SUCCESS;
 }
diff --git a/nis/rpcsvc/nislib.h b/nis/rpcsvc/nislib.h
index a55de61830..c8927ece17 100644
--- a/nis/rpcsvc/nislib.h
+++ b/nis/rpcsvc/nislib.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 1999, 2006, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
 
@@ -272,11 +272,13 @@ struct dir_binding
 typedef struct dir_binding dir_binding;
 
 extern nis_error __nisbind_create (dir_binding *, const nis_server *,
-				   unsigned int, unsigned int) __THROW;
+				   unsigned int, unsigned int, unsigned int,
+				   unsigned int) __THROW;
 extern nis_error __nisbind_connect (dir_binding *) __THROW;
 extern nis_error __nisbind_next (dir_binding *) __THROW;
 extern void __nisbind_destroy (dir_binding *) __THROW;
-extern nis_error __nisfind_server (const_nis_name, directory_obj **) __THROW;
+extern nis_error __nisfind_server (const_nis_name, int, directory_obj **,
+				   dir_binding *, unsigned int) __THROW;
 
 #endif
 
diff --git a/nis/yp_xdr.c b/nis/yp_xdr.c
index 0ee80126e8..b87ee06151 100644
--- a/nis/yp_xdr.c
+++ b/nis/yp_xdr.c
@@ -103,6 +103,7 @@ xdr_ypreq_key (XDR *xdrs, ypreq_key *objp)
     return FALSE;
   return xdr_keydat (xdrs, &objp->key);
 }
+libnsl_hidden_def (xdr_ypreq_key)
 
 bool_t
 xdr_ypreq_nokey (XDR *xdrs, ypreq_nokey *objp)
@@ -111,6 +112,7 @@ xdr_ypreq_nokey (XDR *xdrs, ypreq_nokey *objp)
     return FALSE;
   return xdr_mapname (xdrs, &objp->map);
 }
+libnsl_hidden_def (xdr_ypreq_nokey)
 
 bool_t
 xdr_ypreq_xfr (XDR *xdrs, ypreq_xfr *objp)
@@ -131,6 +133,7 @@ xdr_ypresp_val (XDR *xdrs, ypresp_val *objp)
     return FALSE;
   return xdr_valdat (xdrs, &objp->val);
 }
+libnsl_hidden_def (xdr_ypresp_val)
 
 bool_t
 xdr_ypresp_key_val (XDR *xdrs, ypresp_key_val *objp)
@@ -150,6 +153,7 @@ xdr_ypresp_master (XDR *xdrs, ypresp_master *objp)
     return FALSE;
   return xdr_peername (xdrs, &objp->peer);
 }
+libnsl_hidden_def (xdr_ypresp_master)
 
 bool_t
 xdr_ypresp_order (XDR *xdrs, ypresp_order *objp)
@@ -158,6 +162,7 @@ xdr_ypresp_order (XDR *xdrs, ypresp_order *objp)
     return FALSE;
   return xdr_u_int (xdrs, &objp->ordernum);
 }
+libnsl_hidden_def (xdr_ypresp_order)
 
 bool_t
 xdr_ypresp_all (XDR *xdrs, ypresp_all *objp)
@@ -193,6 +198,7 @@ xdr_ypmaplist (XDR *xdrs, ypmaplist *objp)
   return xdr_pointer (xdrs, (char **) &objp->next, sizeof (ypmaplist),
 		      (xdrproc_t) xdr_ypmaplist);
 }
+libnsl_hidden_def (xdr_ypmaplist)
 
 bool_t
 xdr_ypresp_maplist (XDR *xdrs, ypresp_maplist *objp)
@@ -202,6 +208,7 @@ xdr_ypresp_maplist (XDR *xdrs, ypresp_maplist *objp)
   return xdr_pointer (xdrs, (char **) &objp->maps, sizeof (ypmaplist),
 		      (xdrproc_t) xdr_ypmaplist);
 }
+libnsl_hidden_def (xdr_ypresp_maplist)
 
 bool_t
 xdr_yppush_status (XDR *xdrs, yppush_status *objp)
@@ -248,6 +255,7 @@ xdr_ypbind_resp (XDR *xdrs, ypbind_resp *objp)
     }
   return FALSE;
 }
+libnsl_hidden_def (xdr_ypbind_resp)
 
 bool_t
 xdr_ypbind_setdom (XDR *xdrs, ypbind_setdom *objp)
diff --git a/nis/ypclnt.c b/nis/ypclnt.c
index 85292b62d9..ae04ee9212 100644
--- a/nis/ypclnt.c
+++ b/nis/ypclnt.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1996-2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
 
@@ -45,12 +46,12 @@ struct dom_binding
   };
 typedef struct dom_binding dom_binding;
 
-static struct timeval RPCTIMEOUT = {25, 0};
-static struct timeval UDPTIMEOUT = {5, 0};
+static const struct timeval RPCTIMEOUT = {25, 0};
+static const struct timeval UDPTIMEOUT = {5, 0};
 static int const MAXTRIES = 2;
-static char __ypdomainname[NIS_MAXNAMELEN + 1] = "\0";
+static char ypdomainname[NIS_MAXNAMELEN + 1];
 __libc_lock_define_initialized (static, ypbindlist_lock)
-static dom_binding *__ypbindlist = NULL;
+static dom_binding *ypbindlist = NULL;
 
 
 static void
@@ -110,8 +111,8 @@ yp_bind_ypbindprog (const char *domain, dom_binding *ysd)
   int clnt_sock;
   CLIENT *client;
 
-  memset (&clnt_saddr, '\0', sizeof clnt_saddr);
   clnt_saddr.sin_family = AF_INET;
+  clnt_saddr.sin_port = 0;
   clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
   clnt_sock = RPC_ANYSOCK;
   client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
@@ -141,7 +142,7 @@ yp_bind_ypbindprog (const char *domain, dom_binding *ysd)
 
   if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
     {
-      fprintf (stderr, _("YPBINDPROC_DOMAIN: %s\n"),
+      fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n",
 	       ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
       return YPERR_DOMAIN;
     }
@@ -224,7 +225,7 @@ yp_bind (const char *indomain)
 
   __libc_lock_lock (ypbindlist_lock);
 
-  status = __yp_bind (indomain, &__ypbindlist);
+  status = __yp_bind (indomain, &ypbindlist);
 
   __libc_lock_unlock (ypbindlist_lock);
 
@@ -238,7 +239,7 @@ yp_unbind_locked (const char *indomain)
   dom_binding *ydbptr, *ydbptr2;
 
   ydbptr2 = NULL;
-  ydbptr = __ypbindlist;
+  ydbptr = ypbindlist;
 
   while (ydbptr != NULL)
     {
@@ -248,7 +249,7 @@ yp_unbind_locked (const char *indomain)
 
 	  work = ydbptr;
 	  if (ydbptr2 == NULL)
-	    __ypbindlist = __ypbindlist->dom_pnext;
+	    ypbindlist = ypbindlist->dom_pnext;
 	  else
 	    ydbptr2 = ydbptr->dom_pnext;
 	  __yp_unbind (work);
@@ -305,7 +306,7 @@ do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
   status = YPERR_YPERR;
 
   __libc_lock_lock (ypbindlist_lock);
-  ydb = __ypbindlist;
+  ydb = ypbindlist;
   while (ydb != NULL)
     {
       if (strcmp (domain, ydb->dom_domain) == 0)
@@ -348,7 +349,7 @@ do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
   if (status != YPERR_SUCCESS)
     {
       ydb = calloc (1, sizeof (dom_binding));
-      if (yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
+      if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
 	{
 	  status = __ypclnt_call (domain, prog, xargs, req, xres,
 				  resp, &ydb, 1);
@@ -364,6 +365,21 @@ do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
   return status;
 }
 
+/* Like do_ypcall, but translate the status value if necessary.  */
+static int
+do_ypcall_tr (const char *domain, u_long prog, xdrproc_t xargs,
+	      caddr_t req, xdrproc_t xres, caddr_t resp)
+{
+  int status = do_ypcall (domain, prog, xargs, req, xres, resp);
+  if (status == YPERR_SUCCESS)
+    /* We cast to ypresp_val although the pointer could also be of
+       type ypresp_key_val or ypresp_master or ypresp_order or
+       ypresp_maplist.  But the stat element is in a common prefix so
+       this does not matter.  */
+    status = ypprot_err (((struct ypresp_val *) resp)->stat);
+  return status;
+}
+
 
 __libc_lock_define_initialized (static, domainname_lock)
 
@@ -375,21 +391,21 @@ yp_get_default_domain (char **outdomain)
 
   __libc_lock_lock (domainname_lock);
 
-  if (__ypdomainname[0] == '\0')
+  if (ypdomainname[0] == '\0')
     {
-      if (getdomainname (__ypdomainname, NIS_MAXNAMELEN))
+      if (getdomainname (ypdomainname, NIS_MAXNAMELEN))
 	result = YPERR_NODOM;
-      else if (strcmp (__ypdomainname, "(none)") == 0)
+      else if (strcmp (ypdomainname, "(none)") == 0)
 	{
 	  /* If domainname is not set, some systems will return "(none)" */
-	  __ypdomainname[0] = '\0';
+	  ypdomainname[0] = '\0';
 	  result = YPERR_NODOM;
 	}
       else
-	*outdomain = __ypdomainname;
+	*outdomain = ypdomainname;
     }
   else
-    *outdomain = __ypdomainname;
+    *outdomain = ypdomainname;
 
   __libc_lock_unlock (domainname_lock);
 
@@ -402,14 +418,14 @@ __yp_check (char **domain)
 {
   char *unused;
 
-  if (__ypdomainname[0] == '\0')
+  if (ypdomainname[0] == '\0')
     if (yp_get_default_domain (&unused))
       return 0;
 
   if (domain)
-    *domain = __ypdomainname;
+    *domain = ypdomainname;
 
-  if (yp_bind (__ypdomainname) == 0)
+  if (yp_bind (ypdomainname) == 0)
     return 1;
   return 0;
 }
@@ -436,25 +452,26 @@ yp_match (const char *indomain, const char *inmap, const char *inkey,
   *outvallen = 0;
   memset (&resp, '\0', sizeof (resp));
 
-  result = do_ypcall (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
-		      (caddr_t) & req, (xdrproc_t) xdr_ypresp_val,
-		      (caddr_t) & resp);
+  result = do_ypcall_tr (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
+			 (caddr_t) &req, (xdrproc_t) xdr_ypresp_val,
+			 (caddr_t) &resp);
 
   if (result != YPERR_SUCCESS)
     return result;
-  if (resp.stat != YP_TRUE)
-    return ypprot_err (resp.stat);
 
   *outvallen = resp.val.valdat_len;
   *outval = malloc (*outvallen + 1);
-  if (__builtin_expect (*outval == NULL, 0))
-    return YPERR_RESRC;
-  memcpy (*outval, resp.val.valdat_val, *outvallen);
-  (*outval)[*outvallen] = '\0';
+  int status = YPERR_RESRC;
+  if (__builtin_expect (*outval != NULL, 1))
+    {
+      memcpy (*outval, resp.val.valdat_val, *outvallen);
+      (*outval)[*outvallen] = '\0';
+      status = YPERR_SUCCESS;
+    }
 
   xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
 
-  return YPERR_SUCCESS;
+  return status;
 }
 
 int
@@ -477,30 +494,38 @@ yp_first (const char *indomain, const char *inmap, char **outkey,
   memset (&resp, '\0', sizeof (resp));
 
   result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
-		      (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
-		      (caddr_t) & resp);
+		      (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
+		      (caddr_t) &resp);
 
   if (result != RPC_SUCCESS)
     return YPERR_RPC;
   if (resp.stat != YP_TRUE)
     return ypprot_err (resp.stat);
 
-  *outkeylen = resp.key.keydat_len;
-  *outkey = malloc (*outkeylen + 1);
-  if (__builtin_expect (*outkey == NULL, 0))
-    return YPERR_RESRC;
-  memcpy (*outkey, resp.key.keydat_val, *outkeylen);
-  (*outkey)[*outkeylen] = '\0';
-  *outvallen = resp.val.valdat_len;
-  *outval = malloc (*outvallen + 1);
-  if (__builtin_expect (*outval == NULL, 0))
-    return YPERR_RESRC;
-  memcpy (*outval, resp.val.valdat_val, *outvallen);
-  (*outval)[*outvallen] = '\0';
+  int status;
+  if (__builtin_expect ((*outkey  = malloc (resp.key.keydat_len + 1)) != NULL
+			&& (*outval = malloc (resp.val.valdat_len
+					      + 1)) != NULL, 1))
+    {
+      *outkeylen = resp.key.keydat_len;
+      memcpy (*outkey, resp.key.keydat_val, *outkeylen);
+      (*outkey)[*outkeylen] = '\0';
+
+      *outvallen = resp.val.valdat_len;
+      memcpy (*outval, resp.val.valdat_val, *outvallen);
+      (*outval)[*outvallen] = '\0';
+
+      status = YPERR_SUCCESS;
+    }
+  else
+    {
+      free (*outkey);
+      status = YPERR_RESRC;
+    }
 
   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
 
-  return YPERR_SUCCESS;
+  return status;
 }
 
 int
@@ -526,31 +551,37 @@ yp_next (const char *indomain, const char *inmap, const char *inkey,
   *outkeylen = *outvallen = 0;
   memset (&resp, '\0', sizeof (resp));
 
-  result = do_ypcall (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
-		      (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
-		      (caddr_t) & resp);
+  result = do_ypcall_tr (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
+			 (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
+			 (caddr_t) &resp);
 
   if (result != YPERR_SUCCESS)
     return result;
-  if (resp.stat != YP_TRUE)
-    return ypprot_err (resp.stat);
 
-  *outkeylen = resp.key.keydat_len;
-  *outkey = malloc (*outkeylen + 1);
-  if (__builtin_expect (*outkey == NULL, 0))
-    return YPERR_RESRC;
-  memcpy (*outkey, resp.key.keydat_val, *outkeylen);
-  (*outkey)[*outkeylen] = '\0';
-  *outvallen = resp.val.valdat_len;
-  *outval = malloc (*outvallen + 1);
-  if (__builtin_expect (*outval == NULL, 0))
-    return YPERR_RESRC;
-  memcpy (*outval, resp.val.valdat_val, *outvallen);
-  (*outval)[*outvallen] = '\0';
+  int status;
+  if (__builtin_expect ((*outkey  = malloc (resp.key.keydat_len + 1)) != NULL
+			&& (*outval = malloc (resp.val.valdat_len
+					      + 1)) != NULL, 1))
+    {
+      *outkeylen = resp.key.keydat_len;
+      memcpy (*outkey, resp.key.keydat_val, *outkeylen);
+      (*outkey)[*outkeylen] = '\0';
+
+      *outvallen = resp.val.valdat_len;
+      memcpy (*outval, resp.val.valdat_val, *outvallen);
+      (*outval)[*outvallen] = '\0';
+
+      status = YPERR_SUCCESS;
+    }
+  else
+    {
+      free (*outkey);
+      status = YPERR_RESRC;
+    }
 
   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
 
-  return YPERR_SUCCESS;
+  return status;
 }
 
 int
@@ -569,13 +600,12 @@ yp_master (const char *indomain, const char *inmap, char **outname)
 
   memset (&resp, '\0', sizeof (ypresp_master));
 
-  result = do_ypcall (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
-	  (caddr_t) & req, (xdrproc_t) xdr_ypresp_master, (caddr_t) & resp);
+  result = do_ypcall_tr (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
+			 (caddr_t) &req, (xdrproc_t) xdr_ypresp_master,
+			 (caddr_t) &resp);
 
   if (result != YPERR_SUCCESS)
     return result;
-  if (resp.stat != YP_TRUE)
-    return ypprot_err (resp.stat);
 
   *outname = strdup (resp.peer);
   xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
@@ -592,7 +622,7 @@ yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
   enum clnt_stat result;
 
   if (indomain == NULL || indomain[0] == '\0' ||
-      inmap == NULL || inmap == '\0')
+      inmap == NULL || inmap[0] == '\0')
     return YPERR_BADARGS;
 
   req.domain = (char *) indomain;
@@ -600,18 +630,17 @@ yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
 
   memset (&resp, '\0', sizeof (resp));
 
-  result = do_ypcall (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
-	   (caddr_t) & req, (xdrproc_t) xdr_ypresp_order, (caddr_t) & resp);
+  result = do_ypcall_tr (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
+			 (caddr_t) &req, (xdrproc_t) xdr_ypresp_order,
+			 (caddr_t) &resp);
 
-  if (result != YPERR_SUCCESS)
+  if (result == YPERR_SUCCESS)
     return result;
-  if (resp.stat != YP_TRUE)
-    return ypprot_err (resp.stat);
 
   *outorder = resp.ordernum;
   xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
 
-  return YPERR_SUCCESS;
+  return result;
 }
 
 struct ypresp_all_data
@@ -657,10 +686,10 @@ __xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp)
 	       if we don't modify the length. So add an extra NUL
 	       character to avoid trouble with broken code. */
 	    objp->status = YP_TRUE;
-	    memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen);
-	    key[keylen] = '\0';
-	    memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen);
-	    val[vallen] = '\0';
+	    *((char *) __mempcpy (key, resp.ypresp_all_u.val.key.keydat_val,
+				  keylen)) = '\0';
+	    *((char *) __mempcpy (val, resp.ypresp_all_u.val.val.valdat_val,
+				  vallen)) = '\0';
 	    xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
 	    if ((*objp->foreach) (objp->status, key, keylen,
 				  val, vallen, objp->data))
@@ -671,7 +700,7 @@ __xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp)
 	  objp->status = resp.ypresp_all_u.val.stat;
 	  xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
 	  /* Sun says we don't need to make this call, but must return
-	     immediatly. Since Solaris makes this call, we will call
+	     immediately. Since Solaris makes this call, we will call
 	     the callback function, too. */
 	  (*objp->foreach) (objp->status, NULL, 0, NULL, 0, objp->data);
 	  return TRUE;
@@ -693,8 +722,8 @@ yp_all (const char *indomain, const char *inmap,
   int clnt_sock;
   int saved_errno = errno;
 
-  if (indomain == NULL || indomain[0] == '\0' ||
-      inmap == NULL || inmap == '\0')
+  if (indomain == NULL || indomain[0] == '\0'
+      || inmap == NULL || inmap[0] == '\0')
     return YPERR_BADARGS;
 
   try = 0;
@@ -732,9 +761,9 @@ yp_all (const char *indomain, const char *inmap,
 			  (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
 			  (caddr_t) &data, RPCTIMEOUT);
 
-      if (result != RPC_SUCCESS)
+      if (__builtin_expect (result != RPC_SUCCESS, 0))
 	{
-	  /* Print the error message only on the last try */
+	  /* Print the error message only on the last try.  */
 	  if (try == MAXTRIES - 1)
 	    clnt_perror (clnt, "yp_all: clnt_call");
 	  res = YPERR_RPC;
@@ -758,6 +787,7 @@ yp_all (const char *indomain, const char *inmap,
 }
 
 int
+
 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
 {
   struct ypresp_maplist resp;
@@ -768,67 +798,92 @@ yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
 
   memset (&resp, '\0', sizeof (resp));
 
-  result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
-    (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp);
-
-  if (result != YPERR_SUCCESS)
-    return result;
-  if (resp.stat != YP_TRUE)
-    return ypprot_err (resp.stat);
+  result = do_ypcall_tr (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
+			 (caddr_t) &indomain, (xdrproc_t) xdr_ypresp_maplist,
+			 (caddr_t) &resp);
 
-  *outmaplist = resp.maps;
-  /* We give the list not free, this will be done by ypserv
-     xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
+  if (__builtin_expect (result == YPERR_SUCCESS, 1))
+    {
+      *outmaplist = resp.maps;
+      /* We don't free the list, this will be done by ypserv
+	 xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
+    }
 
-  return YPERR_SUCCESS;
+  return result;
 }
 
 const char *
 yperr_string (const int error)
 {
+  const char *str;
   switch (error)
     {
     case YPERR_SUCCESS:
-      return _("Success");
+      str = N_("Success");
+      break;
     case YPERR_BADARGS:
-      return _("Request arguments bad");
+      str = N_("Request arguments bad");
+      break;
     case YPERR_RPC:
-      return _("RPC failure on NIS operation");
+      str = N_("RPC failure on NIS operation");
+      break;
     case YPERR_DOMAIN:
-      return _("Can't bind to server which serves this domain");
+      str = N_("Can't bind to server which serves this domain");
+      break;
     case YPERR_MAP:
-      return _("No such map in server's domain");
+      str = N_("No such map in server's domain");
+      break;
     case YPERR_KEY:
-      return _("No such key in map");
+      str = N_("No such key in map");
+      break;
     case YPERR_YPERR:
-      return _("Internal NIS error");
+      str = N_("Internal NIS error");
+      break;
     case YPERR_RESRC:
-      return _("Local resource allocation failure");
+      str = N_("Local resource allocation failure");
+      break;
     case YPERR_NOMORE:
-      return _("No more records in map database");
+      str = N_("No more records in map database");
+      break;
     case YPERR_PMAP:
-      return _("Can't communicate with portmapper");
+      str = N_("Can't communicate with portmapper");
+      break;
     case YPERR_YPBIND:
-      return _("Can't communicate with ypbind");
+      str = N_("Can't communicate with ypbind");
+      break;
     case YPERR_YPSERV:
-      return _("Can't communicate with ypserv");
+      str = N_("Can't communicate with ypserv");
+      break;
     case YPERR_NODOM:
-      return _("Local domain name not set");
+      str = N_("Local domain name not set");
+      break;
     case YPERR_BADDB:
-      return _("NIS map database is bad");
+      str = N_("NIS map database is bad");
+      break;
     case YPERR_VERS:
-      return _("NIS client/server version mismatch - can't supply service");
+      str = N_("NIS client/server version mismatch - can't supply service");
+      break;
     case YPERR_ACCESS:
-      return _("Permission denied");
+      str = N_("Permission denied");
+      break;
     case YPERR_BUSY:
-      return _("Database is busy");
+      str = N_("Database is busy");
+      break;
+    default:
+      str = N_("Unknown NIS error code");
+      break;
     }
-  return _("Unknown NIS error code");
+  return _(str);
 }
 
 static const int8_t yp_2_yperr[] =
   {
 #define YP2YPERR(yp, yperr)  [YP_##yp - YP_VERS] = YPERR_##yperr
+    YP2YPERR (TRUE, SUCCESS),
+    YP2YPERR (NOMORE, NOMORE),
+    YP2YPERR (FALSE, YPERR),
+    YP2YPERR (NOMAP, MAP),
+    YP2YPERR (NODOM, DOMAIN),
     YP2YPERR (NOKEY, KEY),
     YP2YPERR (BADOP, YPERR),
     YP2YPERR (BADDB, BADDB),
@@ -839,7 +894,7 @@ static const int8_t yp_2_yperr[] =
 int
 ypprot_err (const int code)
 {
-  if (code < YP_VERS || code > YP_NOKEY)
+  if (code < YP_VERS || code > YP_NOMORE)
     return YPERR_YPERR;
   return yp_2_yperr[code - YP_VERS];
 }
@@ -848,19 +903,26 @@ libnsl_hidden_def (ypprot_err)
 const char *
 ypbinderr_string (const int error)
 {
+  const char *str;
   switch (error)
     {
     case 0:
-      return _("Success");
+      str = N_("Success");
+      break;
     case YPBIND_ERR_ERR:
-      return _("Internal ypbind error");
+      str = N_("Internal ypbind error");
+      break;
     case YPBIND_ERR_NOSERV:
-      return _("Domain not bound");
+      str = N_("Domain not bound");
+      break;
     case YPBIND_ERR_RESC:
-      return _("System resource allocation failure");
+      str = N_("System resource allocation failure");
+      break;
     default:
-      return _("Unknown ypbind error");
+      str = N_("Unknown ypbind error");
+      break;
     }
+  return _(str);
 }
 libnsl_hidden_def (ypbinderr_string)
 
@@ -893,16 +955,22 @@ yp_update (char *domain, char *map, unsigned ypop,
   args.update_args.datum.yp_buf_len = datalen;
   args.update_args.datum.yp_buf_val = data;
 
-  if ((r = yp_master (domain, map, &master)) != 0)
+  if ((r = yp_master (domain, map, &master)) != YPERR_SUCCESS)
     return r;
 
   if (!host2netname (servername, master, domain))
     {
       fputs (_("yp_update: cannot convert host to netname\n"), stderr);
+      free (master);
       return YPERR_YPERR;
     }
 
-  if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
+  clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp");
+
+  /* We do not need the string anymore.  */
+  free (master);
+
+  if (clnt == NULL)
     {
       clnt_pcreateerror ("yp_update: clnt_create");
       return YPERR_RPC;
@@ -942,6 +1010,7 @@ again:
     {
       if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
 	{
+	  auth_destroy (clnt->cl_auth);
 	  clnt->cl_auth = authunix_create_default ();
 	  goto again;
 	}
diff --git a/nis/ypupdate_xdr.c b/nis/ypupdate_xdr.c
index 4789e47c3e..0f5469fa23 100644
--- a/nis/ypupdate_xdr.c
+++ b/nis/ypupdate_xdr.c
@@ -50,6 +50,7 @@ xdr_ypupdate_args (XDR *xdrs, ypupdate_args *objp)
     return FALSE;
   return xdr_yp_buf (xdrs, &objp->datum);
 }
+libnsl_hidden_def (xdr_ypupdate_args)
 
 bool_t
 xdr_ypdelete_args (XDR *xdrs, ypdelete_args *objp)
@@ -58,3 +59,4 @@ xdr_ypdelete_args (XDR *xdrs, ypdelete_args *objp)
     return FALSE;
   return xdr_yp_buf (xdrs, &objp->key);
 }
+libnsl_hidden_def (xdr_ypdelete_args)