about summary refs log tree commit diff
path: root/nis/nis_call.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1997-07-11 01:19:07 +0000
committerUlrich Drepper <drepper@redhat.com>1997-07-11 01:19:07 +0000
commit2d7da676f38bc00f40d2b604036c0295c156529e (patch)
treeb07f60862c86c9a3cd03ec0e4bfbe600b99c0f55 /nis/nis_call.c
parent9c2322bc08c01e34c7488ef12c1d1bf26097190b (diff)
downloadglibc-2d7da676f38bc00f40d2b604036c0295c156529e.tar.gz
glibc-2d7da676f38bc00f40d2b604036c0295c156529e.tar.xz
glibc-2d7da676f38bc00f40d2b604036c0295c156529e.zip
1997-07-11 03:00  Ulrich Drepper  <drepper@cygnus.com>

	* inet/inet_ntoa.c: Prevent looking for thread data key if we found
	one.

	* signal/sigandset.c: Include stddef.h to get NULL defined.
	* signal/sigisempty.c: Likewise.
	* signal/sigorset.c: Likewise.
	* sysdeps/stub/if_index.h: Likewise.
	* wcsmbs/wcstod_l.c: Include locale.h to get __locale_t defined.
	* wcsmbs/wcstof_l.c: Likewise.
	* wcsmbs/wcstol_l.c: Likewise.
	* wcsmbs/wcstold_l.c: Likewise.
	* wcsmbs/wcstoll_l.c: Likewise.
	* wcsmbs/wcstoul_l.c: Likewise.
	* wcsmbs/wcstoull_l.c: Likewise.
	Reported by Marcus G. Daniels <marcus@cathcart.sysc.pdx.edu>.

	* stdio-common/snprintf.c: Use ISO C function definition form.

	* sysdeps/stub/libc-lock.h: Don't define __libc_key_create and
	__libc_setspecific as empty macros since they are used as
	function with return value.
	Reported by Andreas Jaeger.

1997-07-10  Marcus G. Daniels  <marcus@cathcart.sysc.pdx.edu>

	* sysdeps/mach/hurd/select.c (__select): Need bit count for
	MACH_MSG_TYPE_INTEGER_T.

1997-07-08 10:12  Fila Kolodny  <fila@ibi.com>

	* sysdeps/i370/Implies: New file for i370-ibm-mvs port.
	* sysdeps/mvs/Implies: Likewise.

1997-07-09 23:06  Thorsten Kukuk  <kukuk@vt.uni-paderborn.de>

	* nis/Makefile: Add new source files.

	* nis/nis_intern.h: Add new internal functions.
	* nis/rpcsvc/nislib.h: Likewise.

	* nis/lckcache.c: New.
	* nis/nis_cache.c: New, dummy functions in the moment.
	* nis/nis_util.c: New.
	* nis/nisplus-parser.h: New.
	* nis/nss_nisplus/nisplus-parser.c: New.
	* nis/rpcsvc/nis_cache.h: New.
	* nis/rpcsvc/nis_cache.x: New.

	* nis/nss_compat/compat-grp.c: Matches Solaris behaviour now.
	* nis/nss_compat/compat-pwd.c: Likewise.
	* nis/nss_compat/compat-spwd.c: Likewise.
	* nis/nss_nisplus/nisplus-alias.c: Likewise.
	* nis/nss_nisplus/nisplus-ethers.c: Likewise.
	* nis/nss_nisplus/nisplus-grp.c: Likewise.
	* nis/nss_nisplus/nisplus-hosts.c: Likewise.
	* nis/nss_nisplus/nisplus-netgrp.c: Likewise.
	* nis/nss_nisplus/nisplus-network.c: Likewise.
	* nis/nss_nisplus/nisplus-proto.c: Likewise.
	* nis/nss_nisplus/nisplus-publickey.c: Likewise.
	* nis/nss_nisplus/nisplus-pwd.c: Likewise.
	* nis/nss_nisplus/nisplus-rpc.c: Likewise.
	* nis/nss_nisplus/nisplus-service.c: Likewise.
	* nis/nss_nisplus/nisplus-spwd.c: Likewise.

	* nis/nss_nis/nis-publickey.c: Remove libc-lock.h include.

	* nis/nis_intern.c: Removed.

	* nis/nis_call.c: Complete rewrite.
	* nis/nis_lookup.c: Likewise.
	* nis/nis_table.c: Likewise.

	* nis/libnsl.map: Add missing symbols.

	* nis/nis_print.c: Fix nis_print_link.
	* nis/nis_subr.c: Fix nis_getnames.

1997-07-09 07:19  H.J. Lu  <hjl@gnu.ai.mit.edu>

	* posix/execvp.c (execvp): Handle ESTALE.

1997-07-10 13:54  Ulrich Drepper  <drepper@cygnus.com>

	* posix/regex.c: Make CHAR_SET_SIZE definition always available,
	even if SYNTAX_TABLE is defined.
	Patch by Akim Demaille <demaille@inf.enst.fr>.

1997-07-09 08:16  H.J. Lu  <hjl@gnu.ai.mit.edu>

	* libio/fileops.c (_IO_file_underflow): Adjust pointers
	before calling _IO_SYSREAD ().

1997-07-07 22:54  Zack Weinberg  <zack@rabi.phys.columbia.edu>

	* sysdeps/sparc/divrem.m4: Eliminate use of "DEFS.h"
	(sysdep.h does the same job).
	* sysdeps/sparc/alloca.S: Likewise.
	* sysdeps/sparc/dotmul.S: Likewise.
	* sysdeps/sparc/udiv_qrnnd.S: Likewise.

	* sysdeps/sparc/rem.S: Regenerated.
	* sysdeps/sparc/sdiv.S: Regenerated.
	* sysdeps/sparc/udiv.S: Regenerated.
	* sysdeps/sparc/urem.S: Regenerated.

	* sysdeps/sparc/DEFS.h: Removed.
	* sysdeps/sparc/elf/DEFS.h: Removed.
	* sysdeps/sparc/Dist: Don't distribute DEFS.h.

	* sysdeps/unix/sparc/sysdep.h: Use 4 byte alignment. Add .type
	directive #ifdef HAVE_ELF.  Minor format changes.

	* sysdeps/alpha/DEFS.h: Removed.
	* sysdeps/alpha/Dist: Don't distribute DEFS.h.

1997-07-07 19:03  H.J. Lu  <hjl@gnu.ai.mit.edu>

	* math/test-fenv.c (feenv_nomask_test): Move
	fesetenv (FE_NOMASK_ENV) after fork () to work with
	SMP.

	* sysdeps/i386/fpu_control.h (_FPU_IEEE): Fix comment.

1997-07-08  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* libc.map: Add _IO_peekc_locked.

1997-07-07 15:45  Fila Kolodny  <fila@ibi.com>

	* Makeconfig: Add dbobjdir to rpath-link analogous to nssobjdir.

1997-07-08  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sysdeps/m68k/fpu/feholdexcpt.c: Shift the exception mask in the
	right position.
	* sysdeps/m68k/fpu/fesetenv.c (fesetenv): Likewise.

1997-07-08 13:59  Ulrich Drepper  <drepper@cygnus.com>

	* time/strftime.c (spaces, zeroes): Handle broken SGI compiler.
	Patch by Richard Stallman <rms@gnu.ai.mit.edu>.
Diffstat (limited to 'nis/nis_call.c')
-rw-r--r--nis/nis_call.c546
1 files changed, 349 insertions, 197 deletions
diff --git a/nis/nis_call.c b/nis/nis_call.c
index 08a20acd73..f25b8017a5 100644
--- a/nis/nis_call.c
+++ b/nis/nis_call.c
@@ -17,6 +17,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <fcntl.h>
 #include <string.h>
 #include <rpc/rpc.h>
 #include <rpc/auth.h>
@@ -26,8 +27,30 @@
 #include <arpa/inet.h>
 #include "nis_intern.h"
 
-static struct timeval TIMEOUT = {25, 0};
-static int const MAXTRIES = 3;
+static struct timeval TIMEOUT = {10, 0};
+
+struct dir_binding
+{
+  CLIENT *clnt;                  /* RPC CLIENT handle */
+  nis_server *server_val;        /* List of servers */
+  u_int server_len;              /* # of servers */
+  u_int server_used;             /* Which server we are bind in the moment ? */
+  u_int trys;                    /* How many server have we tried ? */
+  bool_t master_only;            /* Is only binded to the master */
+  bool_t use_auth;               /* Do we use AUTH ? */
+  bool_t use_udp;                /* Do we use UDP ? */
+  time_t create;                 /* Binding creation time */
+  struct sockaddr_in addr;       /* Server's IP address */
+  int socket;                    /* Server's local socket */
+  unsigned short port;           /* Local port */
+};
+typedef struct dir_binding dir_binding;
+
+static inline u_int
+__nis_ping (const nis_server *serv, u_int serv_len)
+{
+  return 0;
+}
 
 static unsigned long
 inetstr2int (const char *str)
@@ -53,110 +76,217 @@ inetstr2int (const char *str)
   return inet_addr (buffer);
 }
 
-static CLIENT *
-__nis_dobind (const nis_server *server, u_long flags)
+static void
+__bind_destroy (dir_binding *bind)
 {
-  struct sockaddr_in clnt_saddr;
-  int clnt_sock;
-  size_t i;
-  CLIENT *client = NULL;
-
-  memset (&clnt_saddr, '\0', sizeof clnt_saddr);
-  clnt_saddr.sin_family = AF_INET;
-  for (i = 0; i < server->ep.ep_len; i++)
+  if (bind->clnt != NULL)
     {
-      if (strcmp (server->ep.ep_val[i].family, "loopback") == 0)
+      if (bind->use_auth)
+	auth_destroy (bind->clnt->cl_auth);
+      clnt_destroy (bind->clnt);
+    }
+  free (bind->server_val);
+  free (bind);
+}
+
+static nis_error
+__bind_next (dir_binding *bind)
+{
+  if (bind->trys >= bind->server_len)
+    return NIS_FAIL;
+  
+  bind->server_used++;
+  if (bind->server_used >= bind->server_len)
+    bind->server_used = 0;
+
+  if (bind->clnt != NULL)
+    {
+      if (bind->use_auth)
+	auth_destroy (bind->clnt->cl_auth);
+      clnt_destroy (bind->clnt);
+      bind->clnt = NULL;
+    }
+  
+  return NIS_SUCCESS;
+}
+
+static nis_error
+__bind_connect (dir_binding *dbp)
+{
+  struct sockaddr_in check;
+  nis_server *serv;
+  int checklen;
+  u_int i;
+
+  if (dbp == NULL)
+    return NIS_FAIL;
+
+  serv = &dbp->server_val[dbp->server_used];
+
+  memset (&dbp->addr, '\0', sizeof (dbp->addr));
+  dbp->addr.sin_family = AF_INET;
+  for (i = 0; i < serv->ep.ep_len; ++i)
+    {
+      if (strcmp (serv->ep.ep_val[i].family, "inet") == 0)
 	{
-	  if (server->ep.ep_val[i].uaddr[i] == '-')
-	    clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+	  if (dbp->use_udp)
+	    {
+	      if (strcmp (serv->ep.ep_val[i].proto, "udp") == 0)
+		dbp->addr.sin_addr.s_addr =
+		  inetstr2int (serv->ep.ep_val[i].uaddr);
+	      else
+		continue;
+	    }
 	  else
-	    if (strcmp (server->ep.ep_val[i].proto, "udp") == 0)
-	      {
-		if ((flags & USE_DGRAM) == USE_DGRAM)
-		  clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-		else
-		  continue;
-	      }
-	    else
-	      if (strcmp (server->ep.ep_val[i].proto, "tcp") == 0)
-		{
-		  if ((flags & USE_DGRAM) == USE_DGRAM)
-		    continue;
-		  else
-		    clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-		}
+	    if (strcmp (serv->ep.ep_val[i].proto, "tcp") == 0)
+	      dbp->addr.sin_addr.s_addr =
+		inetstr2int (serv->ep.ep_val[i].uaddr);
 	}
       else
-	if (strcmp (server->ep.ep_val[i].family, "inet") == 0)
-	  {
-	    if (server->ep.ep_val[i].uaddr[i] == '-')
-	      clnt_saddr.sin_addr.s_addr =
-		inetstr2int (server->ep.ep_val[i].uaddr);
-	    else
-	      if (strcmp (server->ep.ep_val[i].proto, "udp") == 0)
-		{
-		  if ((flags & USE_DGRAM) == USE_DGRAM)
-		    clnt_saddr.sin_addr.s_addr =
-		      inetstr2int (server->ep.ep_val[i].uaddr);
-		  else
-		    continue;
-		}
-	      else
-		if (strcmp (server->ep.ep_val[i].proto, "tcp") == 0)
-		  {
-		    if ((flags & USE_DGRAM) == USE_DGRAM)
-		      continue;
-		    else
-		      clnt_saddr.sin_addr.s_addr =
-			inetstr2int (server->ep.ep_val[i].uaddr);
-		  }
-	  }
-	else
-	  continue;
-
-      clnt_sock = RPC_ANYSOCK;
-      if ((flags & USE_DGRAM) == USE_DGRAM)
-	client = clntudp_create (&clnt_saddr, NIS_PROG, NIS_VERSION,
-				 TIMEOUT, &clnt_sock);
-      else
-	client = clnttcp_create (&clnt_saddr, NIS_PROG, NIS_VERSION,
-				 &clnt_sock, 0, 0);
-
-      if (client == NULL)
 	continue;
-      if (clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
-		     (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS)
+    }
+  if (dbp->addr.sin_addr.s_addr == 0)
+    return NIS_FAIL;
+
+  dbp->socket = RPC_ANYSOCK;
+  if (dbp->use_udp)
+    dbp->clnt = clntudp_create (&dbp->addr, NIS_PROG, NIS_VERSION,
+				 TIMEOUT, &dbp->socket);
+  else
+    dbp->clnt = clnttcp_create (&dbp->addr, NIS_PROG, NIS_VERSION,
+				 &dbp->socket, 0, 0);
+  
+  if (dbp->clnt == NULL)
+    return NIS_RPCERROR;
+  
+  clnt_control (dbp->clnt, CLSET_TIMEOUT, (caddr_t)&TIMEOUT);
+  /* If the program exists, close the socket */
+  if (fcntl (dbp->socket, F_SETFD, 1) == -1)
+    perror (_("fcntl: F_SETFD"));
+  
+  if (dbp->use_auth)
+    {
+#if defined(HAVE_SECURE_RPC)
+      if (serv->key_type == NIS_PK_DH)
 	{
-	  clnt_destroy (client);
-	  continue;
+	  char netname[MAXNETNAMELEN+1];
+	  char *p;
+	  
+	  p = stpcpy (netname, "unix.");
+	  strncpy (p, serv->name,MAXNETNAMELEN-5);
+	  netname[MAXNETNAMELEN] = '\0';
+	  p = strchr (netname, '.');
+	  *p = '@';
+	  dbp->clnt->cl_auth =
+	    authdes_pk_create (netname, &serv->pkey, 300, NULL, NULL);
+	  if (!dbp->clnt->cl_auth)
+	    dbp->clnt->cl_auth = authunix_create_default ();
 	}
+      else
+#endif
+	dbp->clnt->cl_auth = authunix_create_default ();
+      dbp->use_auth = TRUE;
+    }
+  
+  /* Get port for sanity checks later */
+  checklen = sizeof (struct sockaddr_in);
+  memset (&check, 0, checklen);
+  if (dbp->use_udp)
+    bind (dbp->socket, (struct sockaddr *)&check, checklen);
+  check.sin_family = AF_INET;
+  if (!getsockname (dbp->socket, (struct sockaddr *)&check, &checklen))
+    dbp->port = check.sin_port;
+
+  dbp->create = time (NULL);
+
+  return NIS_SUCCESS;
+}
 
-      if ((flags & NO_AUTHINFO) != NO_AUTHINFO)
+static dir_binding *
+__bind_create (const nis_server *serv_val, u_int serv_len, u_long flags)
+{
+  dir_binding *dbp;
+  u_int i;
+  
+  dbp = calloc (1, sizeof (dir_binding));
+  if (dbp == NULL)
+    return NULL;
+  
+  dbp->server_len = serv_len;
+  dbp->server_val = calloc (1, sizeof (nis_server) * serv_len);
+  if (dbp->server_val == NULL)
+    {
+      free (dbp);
+      return NULL;
+    }
+  
+  for (i = 0; i < serv_len; ++i)
+    {
+      if (serv_val[i].name != NULL)
+	dbp->server_val[i].name = strdup (serv_val[i].name);
+      
+      dbp->server_val[i].ep.ep_len = serv_val[i].ep.ep_len;
+      if (dbp->server_val[i].ep.ep_len > 0)
 	{
-#if defined(HAVE_SECURE_RPC)
-	  if (server->key_type == NIS_PK_DH && getenv ("NO_SECURE_RPC") == NULL)
+	  unsigned long j;
+	  
+	  dbp->server_val[i].ep.ep_val =
+	    malloc (serv_val[i].ep.ep_len * sizeof (endpoint));
+	  for (j = 0; j < dbp->server_val[i].ep.ep_len; ++j)
 	    {
-	      char netname[MAXNETNAMELEN+1];
-	      char *p;
-
-	      p = stpcpy (netname, "unix.");
-	      strncpy (p, server->name,MAXNETNAMELEN-5);
-	      netname[MAXNETNAMELEN] = '\0';
-	      p = strchr (netname, '.');
-	      *p = '@';
-	      client->cl_auth =
-		authdes_pk_create (netname, &server->pkey, 300, NULL, NULL);
-	      if (!client->cl_auth)
-		client->cl_auth = authunix_create_default ();
+	      if (serv_val[i].ep.ep_val[j].uaddr)
+		dbp->server_val[i].ep.ep_val[j].uaddr =
+		  strdup (serv_val[i].ep.ep_val[j].uaddr);
+	      else
+		dbp->server_val[i].ep.ep_val[j].uaddr = NULL;
+	      if (serv_val[i].ep.ep_val[j].family)
+		dbp->server_val[i].ep.ep_val[j].family =
+		  strdup (serv_val[i].ep.ep_val[j].family);
+	      else
+		dbp->server_val[i].ep.ep_val[j].family = NULL;
+	      if (serv_val[i].ep.ep_val[j].proto)
+		dbp->server_val[i].ep.ep_val[j].proto =
+		  strdup (serv_val[i].ep.ep_val[j].proto);
+	      else
+		dbp->server_val[i].ep.ep_val[j].proto = NULL;
 	    }
-	  else
-#endif
-	    client->cl_auth = authunix_create_default ();
 	}
-      return client;
+      else
+	dbp->server_val[i].ep.ep_val = NULL;
+      dbp->server_val[i].key_type = serv_val[i].key_type;
+      dbp->server_val[i].pkey.n_len = serv_val[i].pkey.n_len;
+      if (serv_val[i].pkey.n_len > 0)
+	{
+	  dbp->server_val[i].pkey.n_bytes =
+	    malloc (serv_val[i].pkey.n_len);
+	  if (dbp->server_val[i].pkey.n_bytes == NULL)
+	    return NULL;
+	  memcpy (dbp->server_val[i].pkey.n_bytes, serv_val[i].pkey.n_bytes,
+		  serv_val[i].pkey.n_len);
+	}
+      else
+	dbp->server_val[i].pkey.n_bytes = NULL;
     }
+  
+  dbp->server_used = __nis_ping (dbp->server_val, dbp->server_len);
+  if (flags & USE_DGRAM)
+    dbp->use_udp = TRUE;
+  else
+    dbp->use_udp = FALSE;
 
-  return NULL;
+  if (flags & NO_AUTHINFO)
+    dbp->use_auth = FALSE;
+  else
+    dbp->use_auth = TRUE;
+
+  if (flags & MASTER_ONLY)
+    dbp->master_only = TRUE;
+  else
+    dbp->master_only = FALSE;
+
+  dbp->trys = 1;
+
+  return dbp;
 }
 
 nis_error
@@ -164,89 +294,84 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
 	       xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp,
 	       u_long flags)
 {
-  CLIENT *clnt;
-  int try, result;
-
-  try = 0;
-  result = NIS_NAMEUNREACHABLE;
-
-  if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1)
-    server_len = 1; /* The first entry is the master */
-
-  while (try < MAXTRIES && result != RPC_SUCCESS)
+  enum clnt_stat result;
+  nis_error retcode;
+  dir_binding *dbp;
+
+  if (flags & MASTER_ONLY) 
+    server_len = 1;
+  
+  dbp = __bind_create (server, server_len, flags);
+  while (__bind_connect (dbp) != NIS_SUCCESS)
     {
-      unsigned int i;
-
-      if ((flags & HARD_LOOKUP) == 0)
-	++try;
-
-      for (i = 0; i < server_len; i++)
+      if (__bind_next (dbp) != NIS_SUCCESS)
 	{
-	  if ((clnt = __nis_dobind (&server[i], flags)) == NULL)
-	    continue;
-
-	  result = clnt_call (clnt, prog, xargs, req, xres, resp, TIMEOUT);
-
-	  if (result != RPC_SUCCESS)
-	    {
-	      clnt_perror (clnt, "do_niscall: clnt_call");
-	      clnt_destroy (clnt);
-	      result = NIS_RPCERROR;
-	    }
-	  else
-	    clnt_destroy (clnt);
+	  __bind_destroy (dbp);
+	  return NIS_NAMEUNREACHABLE;
 	}
     }
 
-  return result;
-}
-
-static directory_obj *
-dir_lookup (const_nis_name name, nis_server *serv, u_long flags)
-{
-  CLIENT *clnt;
-  int try, result;
-  nis_result *res;
-  struct ns_request req;
-  directory_obj *dir;
-
-  res = calloc (1, sizeof (nis_result));
-  req.ns_name = (char *)name;
-  req.ns_object.ns_object_len = 0;
-  req.ns_object.ns_object_val = NULL;
-  try = 0;
-  result = NIS_NAMEUNREACHABLE;
-
-  while (try < MAXTRIES && result != RPC_SUCCESS)
+  do
     {
-      if ((clnt = __nis_dobind (serv, flags)) == NULL)
-	continue;
-
-      result = clnt_call (clnt, NIS_LOOKUP, (xdrproc_t) xdr_ns_request,
-			  (caddr_t) &req, (xdrproc_t) xdr_nis_result,
-			  (caddr_t) res, TIMEOUT);
-
+    again:
+      result = clnt_call (dbp->clnt, prog, xargs, req, xres, resp, TIMEOUT);
+      
       if (result != RPC_SUCCESS)
 	{
-	  clnt_perror (clnt, "do_niscall: clnt_call");
-	  clnt_destroy (clnt);
-	  result = NIS_RPCERROR;
+	  clnt_perror (dbp->clnt, "__do_niscall2: clnt_call");
+	  __bind_destroy (dbp);
+	  retcode = NIS_RPCERROR;
 	}
       else
-	clnt_destroy (clnt);
+	{
+	  switch (prog)
+	    {
+	    case NIS_LOOKUP:
+	    case NIS_ADD:
+	    case NIS_MODIFY:
+	    case NIS_REMOVE:
+	    case NIS_IBLIST:
+	    case NIS_IBADD:
+	    case NIS_IBMODIFY:
+	    case NIS_IBREMOVE:
+	    case NIS_IBFIRST:
+	    case NIS_IBNEXT:
+	      if ((((nis_result *)xres)->status != NIS_SUCCESS) &&
+		  (((nis_result *)xres)->status != NIS_S_SUCCESS))
+		if (__bind_next (dbp) == NIS_SUCCESS)
+		  goto again;
+	    case NIS_FINDDIRECTORY:
+	      if (((fd_result *)xres)->status != NIS_SUCCESS)
+		if (__bind_next (dbp) == NIS_SUCCESS)
+		  goto again;
+	      break;
+#if 0
+	    case NIS_STATUS: /* nis_taglist */
+	    case NIS_SERVSTATE:
+	      break;
+	    case NIS_DUMPLOG: /* log_result */
+	    case NIS_DUMP:
+	      break;
+	    case NIS_CHECKPOINT: /* cp_result */
+	      break;
+#endif
+	    default:
+	      break;
+	    }
+	  __bind_destroy (dbp);
+	  retcode = NIS_SUCCESS;
+	}
     }
-  if (result != RPC_SUCCESS || res->status != NIS_SUCCESS)
-    return NULL;
-
-  dir = nis_clone_directory (&res->objects.objects_val->DI_data, NULL);
-  nis_freeresult (res);
-
-  return dir;
+  while ((flags & HARD_LOOKUP) && retcode == NIS_RPCERROR);
+  
+  return retcode; 
 }
 
 static directory_obj *
 rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
 {
+  fd_result *fd_res;
+  XDR xdrs;
   char domain [strlen (name) + 3];
 
   nis_domain_of_r (name, domain, sizeof (domain));
@@ -287,8 +412,20 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
 	/* The root server of our domain is a replica of the parent
 	   domain ! (Now I understand why a root server must be a
 	   replica of the parent domain) */
-	obj = dir_lookup (ndomain, dir->do_servers.do_servers_val,
-			  flags);
+	fd_res = __nis_finddirectory (dir, ndomain);
+	if (fd_res->status != NIS_SUCCESS)
+	  {
+	    nis_free_directory (dir);
+	    xdr_free((xdrproc_t)xdr_fd_result, (caddr_t)fd_res);
+	    return NULL;
+	  }
+	__cache_add (fd_res);
+	obj = calloc(1, sizeof(directory_obj));
+	xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val,
+		      fd_res->dir_data.dir_data_len, XDR_DECODE);
+	xdr_directory_obj(&xdrs, obj);
+	xdr_destroy(&xdrs);
+	xdr_free((xdrproc_t)xdr_fd_result, (caddr_t)fd_res);
 	if (obj != NULL)
 	  {
 	    /* We have found a NIS+ server serving ndomain, now
@@ -303,15 +440,14 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
 	    return NULL;
 	  }
       }
-      break;
+    break;
     case LOWER_NAME:
       {
 	directory_obj *obj;
 	char leaf [strlen (name) + 3];
 	char ndomain [strlen (name) + 3];
-	u_int i;
 	char *cp;
-
+	
 	do
 	  {
 	    if (strlen (domain) == 0)
@@ -327,21 +463,30 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
 	cp = strchr (leaf, '\0');
 	*cp++ = '.';
 	strcpy (cp, domain);
-
-	for (i = 0; i < dir->do_servers.do_servers_len; ++i)
+	
+	fd_res = __nis_finddirectory (dir, leaf);
+	if (fd_res->status != NIS_SUCCESS)
 	  {
-	    obj = dir_lookup (leaf, &dir->do_servers.do_servers_val[i],
-			      flags);
-	    if (obj != NULL)
-	      {
-		/* We have found a NIS+ server serving ndomain, now
-		   let us search for "name" */
-		nis_free_directory (dir);
-		return rec_dirsearch (name, obj, flags);
-	      }
+	    nis_free_directory (dir);
+	    xdr_free((xdrproc_t)xdr_fd_result, (caddr_t)fd_res);
+	    return NULL;
+	  }
+	__cache_add (fd_res);
+	obj = calloc(1, sizeof(directory_obj));
+	xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val,
+		      fd_res->dir_data.dir_data_len, XDR_DECODE);
+	xdr_directory_obj(&xdrs, obj);
+	xdr_destroy(&xdrs);
+	xdr_free((xdrproc_t)xdr_fd_result, (caddr_t)fd_res);
+	if (obj != NULL)
+	  {
+	    /* We have found a NIS+ server serving ndomain, now
+	       let us search for "name" */
+	    nis_free_directory (dir);
+	    return rec_dirsearch (name, obj, flags);
 	  }
       }
-      break;
+    break;
     case BAD_NAME:
       nis_free_directory (dir);
       return NULL;
@@ -354,37 +499,44 @@ nis_error
 __do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs,
 	      caddr_t req, xdrproc_t xres, caddr_t resp, u_long flags)
 {
-  nis_error result;
+  nis_error retcode;
   directory_obj *dir = NULL;
-  const nis_server *server;
+  nis_server *server;
   u_int server_len;
 
+  if (name == NULL)
+    return NIS_BADNAME;
 
-  dir = readColdStartFile ();
-  if (dir == NULL) /* No /var/nis/NIS_COLD_START -> no NIS+ installed */
-    return NIS_UNAVAIL;
-
-  if (name != NULL)
+  if ((flags & NO_CACHE) !=  NO_CACHE)
+    dir = __cache_search (name);
+  
+  if (dir == NULL)
     {
+      dir = readColdStartFile ();
+      if (dir == NULL) /* No /var/nis/NIS_COLD_START->no NIS+ installed */
+	return NIS_UNAVAIL;
+      
       dir = rec_dirsearch (name, dir, flags);
       if (dir == NULL)
-	{
-	  if (nis_dir_cmp (nis_local_directory(), name) == NOT_SEQUENTIAL)
-	    return NIS_NAMEUNREACHABLE;
-	  else
-	    return NIS_NOTFOUND;
-	}
+	return NIS_NOTFOUND;
     }
-  server = dir->do_servers.do_servers_val;
-  server_len = dir->do_servers.do_servers_len;
 
-  if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1)
-    server_len = 1; /* The first entry is the master */
-
-  result = __do_niscall2 (server, server_len, prog, xargs, req, xres,
-			  resp, flags);
-  if (dir != NULL)
-    nis_free_directory (dir);
+  if (flags & MASTER_ONLY) 
+    {
+      server = dir->do_servers.do_servers_val;
+      server_len = 1;
+    }
+  else
+    {
+      server = dir->do_servers.do_servers_val;
+      server_len = dir->do_servers.do_servers_len;
+    }
+  
+  
+  retcode = __do_niscall2 (server, server_len, prog, xargs, req, xres, resp,
+			   flags);
+  
+  nis_free_directory (dir);
 
-  return result;
+  return retcode;
 }