about summary refs log tree commit diff
path: root/nis
diff options
context:
space:
mode:
Diffstat (limited to 'nis')
-rw-r--r--nis/Banner2
-rw-r--r--nis/Makefile6
-rw-r--r--nis/Versions7
-rw-r--r--nis/nis_call.c216
-rw-r--r--nis/nis_checkpoint.c2
-rw-r--r--nis/nis_file.c32
-rw-r--r--nis/nis_findserv.c22
-rw-r--r--nis/nis_intern.h35
-rw-r--r--nis/nis_lookup.c166
-rw-r--r--nis/nis_mkdir.c2
-rw-r--r--nis/nis_ping.c2
-rw-r--r--nis/nis_rmdir.c2
-rw-r--r--nis/nis_server.c4
-rw-r--r--nis/nis_table.c399
-rw-r--r--nis/nis_util.c2
-rw-r--r--nis/rpcsvc/nislib.h31
16 files changed, 573 insertions, 357 deletions
diff --git a/nis/Banner b/nis/Banner
index 478c9b996e..1df3a1652b 100644
--- a/nis/Banner
+++ b/nis/Banner
@@ -1 +1 @@
-NIS(YP)/NIS+ NSS modules 0.17 by Thorsten Kukuk
+NIS(YP)/NIS+ NSS modules 0.18 by Thorsten Kukuk
diff --git a/nis/Makefile b/nis/Makefile
index c736b5a59a..78fdd072ec 100644
--- a/nis/Makefile
+++ b/nis/Makefile
@@ -23,7 +23,7 @@ subdir	:= nis
 
 headers			:= $(wildcard rpcsvc/*.[hx])
 distribute		:= nss-nis.h nss-nisplus.h nis_intern.h Banner \
-			nisplus-parser.h nis_cache2.h nis_xdr.h
+			nisplus-parser.h nis_xdr.h
 
 # These are the databases available for the nis (and perhaps later nisplus)
 # service.  This must be a superset of the services in nss.
@@ -44,8 +44,8 @@ vpath %.c $(subdir-dirs)
 
 libnsl-routines = yp_xdr ypclnt ypupdate_xdr \
                   nis_subr nis_local_names nis_free nis_file \
-                  nis_print nis_error nis_call nis_lookup nis_cache\
-                  nis_table nis_xdr nis_server nis_ping nis_cache2_xdr\
+                  nis_print nis_error nis_call nis_lookup\
+                  nis_table nis_xdr nis_server nis_ping \
 		  nis_checkpoint nis_mkdir nis_rmdir nis_getservlist\
 		  nis_verifygroup nis_ismember nis_addmember nis_util\
 		  nis_removemember nis_creategroup nis_destroygroup\
diff --git a/nis/Versions b/nis/Versions
index aa2df3a048..d26cba75b3 100644
--- a/nis/Versions
+++ b/nis/Versions
@@ -48,9 +48,10 @@ libnsl {
 
     # This functions are needed by the NIS+ tools and rpc.nisd,
     # they should never be used in a normal user program !
-    __do_niscall2;        __free_fdresult;     __nis_default_access;
-    __nis_default_group;  __nis_default_owner; __nis_default_ttl;
-    __nis_finddirectory;  __nis_hash;
+    __free_fdresult;      __nis_default_access; __nis_default_group;  
+    __nis_default_owner;  __nis_default_ttl;   __nis_finddirectory;  
+    __nis_hash;           __nisbind_connect;   __nisbind_create;
+    __nisbind_destroy;    __nisbind_next;
     readColdStartFile;    writeColdStartFile;
   }
 }
diff --git a/nis/nis_call.c b/nis/nis_call.c
index 94144d50ea..ce7607f4e1 100644
--- a/nis/nis_call.c
+++ b/nis/nis_call.c
@@ -60,8 +60,8 @@ inetstr2int (const char *str)
   return inet_addr (buffer);
 }
 
-static void
-__bind_destroy (dir_binding *bind)
+void
+__nisbind_destroy (dir_binding *bind)
 {
   if (bind->clnt != NULL)
     {
@@ -71,8 +71,8 @@ __bind_destroy (dir_binding *bind)
     }
 }
 
-static nis_error
-__bind_next (dir_binding *bind)
+nis_error
+__nisbind_next (dir_binding *bind)
 {
   u_int j;
 
@@ -91,8 +91,7 @@ __bind_next (dir_binding *bind)
        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 (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].proto,
-		  "-") == 0)
+      if (bind->server_val[bind->server_used].ep.ep_val[j].proto[0] == '-')
 	{
 	  bind->current_ep = j;
 	  return NIS_SUCCESS;
@@ -115,8 +114,8 @@ __bind_next (dir_binding *bind)
   return NIS_FAIL;
 }
 
-static nis_error
-__bind_connect (dir_binding *dbp)
+nis_error
+__nisbind_connect (dir_binding *dbp)
 {
   nis_server *serv;
 
@@ -157,7 +156,7 @@ __bind_connect (dir_binding *dbp)
 
   if (dbp->use_auth)
     {
-      if (serv->key_type == NIS_PK_DH && key_secretkey_is_set ())
+      if (serv->key_type == NIS_PK_DH)
 	{
 	  char netname[MAXNETNAMELEN+1];
 	  char *p;
@@ -180,9 +179,9 @@ __bind_connect (dir_binding *dbp)
   return NIS_SUCCESS;
 }
 
-static nis_error
-__bind_create (dir_binding *dbp, const nis_server *serv_val, u_int serv_len,
-	       u_long flags, cache2_info *cinfo)
+nis_error
+__nisbind_create (dir_binding *dbp, const nis_server *serv_val, u_int serv_len,
+		  u_long flags)
 {
   dbp->clnt = NULL;
 
@@ -208,54 +207,34 @@ __bind_create (dir_binding *dbp, const nis_server *serv_val, u_int serv_len,
   dbp->trys = 1;
 
   dbp->class = -1;
-  if (cinfo != NULL && cinfo->server_used >= 0)
-    {
-      dbp->server_used = cinfo->server_used;
-      dbp->current_ep = cinfo->current_ep;
-      dbp->class = cinfo->class;
-    }
-  else if (__nis_findfastest (dbp) < 1)
+  if (__nis_findfastest (dbp) < 1)
     {
-      __bind_destroy (dbp);
+      __nisbind_destroy (dbp);
       return NIS_NAMEUNREACHABLE;
     }
 
   return NIS_SUCCESS;
 }
 
+/* __nisbind_connect (dbp) must be run before calling this function !
+   So we could use the same binding twice */
 nis_error
-__do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
-	       xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp,
-	       u_long flags, nis_cb *cb, cache2_info *cinfo)
+__do_niscall3 (dir_binding *dbp, u_long prog, xdrproc_t xargs, caddr_t req,
+	       xdrproc_t xres, caddr_t resp, u_long flags, nis_cb *cb)
 {
   enum clnt_stat result;
   nis_error retcode;
-  dir_binding dbp;
 
-  if (flags & MASTER_ONLY)
-    server_len = 1;
-
-  if (__bind_create (&dbp, server, server_len, flags, cinfo) != NIS_SUCCESS)
+  if (dbp == NULL)
     return NIS_NAMEUNREACHABLE;
-  while (__bind_connect (&dbp) != NIS_SUCCESS)
-    {
-      if (__bind_next (&dbp) != NIS_SUCCESS)
-	{
-	  __bind_destroy (&dbp);
-	  return NIS_NAMEUNREACHABLE;
-	}
-    }
 
   do
     {
     again:
-      result = clnt_call (dbp.clnt, prog, xargs, req, xres, resp, RPCTIMEOUT);
+      result = clnt_call (dbp->clnt, prog, xargs, req, xres, resp, RPCTIMEOUT);
 
       if (result != RPC_SUCCESS)
-	{
-	  __bind_destroy (&dbp);
-	  retcode = NIS_RPCERROR;
-	}
+	retcode = NIS_RPCERROR;
       else
 	{
 	  switch (prog)
@@ -264,11 +243,11 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
 	      if ((((nis_result *)resp)->status == NIS_CBRESULTS) &&
 		  (cb != NULL))
 		{
-		  __nis_do_callback(&dbp, &((nis_result *)resp)->cookie, cb);
+		  __nis_do_callback(dbp, &((nis_result *)resp)->cookie, cb);
 		  break;
 		}
-	      /* Yes, this is correct. If we doesn't have to start
-		 a callback, look if we have to search another server */
+	      /* Yes, the missing break is correct. If we doesn't have to
+		 start a callback, look if we have to search another server */
 	    case NIS_LOOKUP:
 	    case NIS_ADD:
 	    case NIS_MODIFY:
@@ -278,19 +257,16 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
 	    case NIS_IBREMOVE:
 	    case NIS_IBFIRST:
 	    case NIS_IBNEXT:
-	      if ((((nis_result *)resp)->status == NIS_NOTFOUND) ||
+	      if ((((nis_result *)resp)->status == NIS_SYSTEMERROR) ||
 		  (((nis_result *)resp)->status == NIS_NOSUCHNAME) ||
 		  (((nis_result *)resp)->status == NIS_NOT_ME))
 		{
-		  if (__bind_next (&dbp) == NIS_SUCCESS)
+		  if (__nisbind_next (dbp) == NIS_SUCCESS)
 		    {
-		      while (__bind_connect (&dbp) != NIS_SUCCESS)
+		      while (__nisbind_connect (dbp) != NIS_SUCCESS)
 			{
-			  if (__bind_next (&dbp) != NIS_SUCCESS)
-			    {
-			      __bind_destroy (&dbp);
+			  if (__nisbind_next (dbp) != NIS_SUCCESS)
 			      return NIS_SUCCESS;
-			    }
 			}
 		    }
 		  else
@@ -299,19 +275,16 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
 		}
 	      break;
 	    case NIS_FINDDIRECTORY:
-	      if ((((fd_result *)resp)->status == NIS_NOTFOUND) ||
+	      if ((((fd_result *)resp)->status == NIS_SYSTEMERROR) ||
 		  (((fd_result *)resp)->status == NIS_NOSUCHNAME) ||
 		  (((fd_result *)resp)->status == NIS_NOT_ME))
 		{
-		  if (__bind_next (&dbp) == NIS_SUCCESS)
+		  if (__nisbind_next (dbp) == NIS_SUCCESS)
 		    {
-		      while (__bind_connect (&dbp) != NIS_SUCCESS)
+		      while (__nisbind_connect (dbp) != NIS_SUCCESS)
 			{
-			  if (__bind_next (&dbp) != NIS_SUCCESS)
-			    {
-			      __bind_destroy (&dbp);
-			      return NIS_SUCCESS;
-			    }
+			  if (__nisbind_next (dbp) != NIS_SUCCESS)
+			    return NIS_SUCCESS;
 			}
 		    }
 		  else
@@ -321,19 +294,16 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
 	      break;
 	    case NIS_DUMPLOG: /* log_result */
 	    case NIS_DUMP:
-	      if ((((log_result *)resp)->lr_status == NIS_NOTFOUND) ||
+	      if ((((log_result *)resp)->lr_status == NIS_SYSTEMERROR) ||
 		  (((log_result *)resp)->lr_status == NIS_NOSUCHNAME) ||
 		  (((log_result *)resp)->lr_status == NIS_NOT_ME))
 		{
-		  if (__bind_next (&dbp) == NIS_SUCCESS)
+		  if (__nisbind_next (dbp) == NIS_SUCCESS)
 		    {
-		      while (__bind_connect (&dbp) != NIS_SUCCESS)
+		      while (__nisbind_connect (dbp) != NIS_SUCCESS)
 			{
-			  if (__bind_next (&dbp) != NIS_SUCCESS)
-			    {
-			      __bind_destroy (&dbp);
-			      return NIS_SUCCESS;
-			    }
+			  if (__nisbind_next (dbp) != NIS_SUCCESS)
+			    return NIS_SUCCESS;
 			}
 		    }
 		  else
@@ -344,7 +314,6 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
 	    default:
 	      break;
 	    }
-	  __bind_destroy (&dbp);
 	  retcode = NIS_SUCCESS;
 	}
     }
@@ -353,9 +322,37 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
   return retcode;
 }
 
+nis_error
+__do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
+	       xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp,
+	       u_long flags, nis_cb *cb)
+{
+  dir_binding dbp;
+  nis_error status;
+
+  if (flags & MASTER_ONLY)
+    server_len = 1;
+
+  status = __nisbind_create (&dbp, server, server_len, flags);
+  if (status != NIS_SUCCESS)
+    return status;
+
+  while (__nisbind_connect (&dbp) != NIS_SUCCESS)
+    {
+      if (__nisbind_next (&dbp) != NIS_SUCCESS)
+	return NIS_NAMEUNREACHABLE;
+    }
+
+  status = __do_niscall3 (&dbp, prog, xargs, req, xres, resp, flags, cb);
+
+  __nisbind_destroy (&dbp);
+
+  return status;
+
+}
+
 static directory_obj *
-rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags,
-	       nis_error *status)
+rec_dirsearch (const_nis_name name, directory_obj *dir, nis_error *status)
 {
   fd_result *fd_res;
   XDR xdrs;
@@ -396,7 +393,7 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags,
 	    /* We have found a NIS+ server serving ndomain, now
 	       let us search for "name" */
 	    nis_free_directory (dir);
-	    return rec_dirsearch (name, obj, flags, status);
+	    return rec_dirsearch (name, obj, status);
 	  }
 	else
 	  {
@@ -461,7 +458,7 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags,
 	    /* We have found a NIS+ server serving ndomain, now
 	       let us search for "name" */
 	    nis_free_directory (dir);
-	    return rec_dirsearch (name, obj, flags, status);
+	    return rec_dirsearch (name, obj, status);
 	  }
       }
     break;
@@ -478,7 +475,7 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags,
 /* We try to query the current server for the searched object,
    maybe he know about it ? */
 static directory_obj *
-first_shoot (const_nis_name name, directory_obj *dir, u_long flags)
+first_shoot (const_nis_name name, directory_obj *dir)
 {
   directory_obj *obj;
   fd_result *fd_res;
@@ -516,51 +513,57 @@ first_shoot (const_nis_name name, directory_obj *dir, u_long flags)
 }
 
 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_cb *cb)
+__nisfind_server (const_nis_name name, directory_obj **dir)
 {
-  nis_error retcode;
-  directory_obj *dir = NULL;
-  nis_server *server;
-  u_int server_len;
-  cache2_info cinfo = {-1, -1, -1};
-  int saved_errno = errno;
-
   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)
+  if (*dir == NULL)
     {
       nis_error status;
       directory_obj *obj;
 
-      dir = readColdStartFile ();
-      if (dir == NULL) /* No /var/nis/NIS_COLD_START->no NIS+ installed */
-	{
-	  __set_errno (saved_errno);
-	  return NIS_UNAVAIL;
-	}
+      *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 */
-      obj = first_shoot (name, dir, flags);
+      obj = first_shoot (name, *dir);
       if (obj == NULL)
 	{
-	  dir = rec_dirsearch (name, dir, flags, &status);
-	  if (dir == NULL)
-	    {
-	      __set_errno (saved_errno);
-	      return status;
-	    }
+	  *dir = rec_dirsearch (name, *dir, &status);
+	  if (*dir == NULL)
+	    return status;
 	}
       else
-	dir = obj;
+	*dir = obj;
     }
 
+  return NIS_SUCCESS;
+}
+
+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_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;
@@ -572,9 +575,22 @@ __do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs,
       server_len = dir->do_servers.do_servers_len;
     }
 
+  retcode = __nisbind_create (&bptr, server, server_len, 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);
 
-  retcode = __do_niscall2 (server, server_len, prog, xargs, req, xres, resp,
-			   flags, cb, &cinfo);
+      __nisbind_destroy (&bptr);
+    }
 
   nis_free_directory (dir);
 
diff --git a/nis/nis_checkpoint.c b/nis/nis_checkpoint.c
index f1e860f7b8..15bae8be22 100644
--- a/nis/nis_checkpoint.c
+++ b/nis/nis_checkpoint.c
@@ -58,7 +58,7 @@ nis_checkpoint(const_nis_name dirname)
 	  if (__do_niscall2 (&NIS_RES_OBJECT(res2)->DI_data.do_servers.do_servers_val[i],
 			     1, NIS_CHECKPOINT, (xdrproc_t) _xdr_nis_name,
 			     (caddr_t) &dirname, (xdrproc_t) _xdr_cp_result,
-			     (caddr_t) &cpres, 0, NULL, NULL) != NIS_SUCCESS)
+			     (caddr_t) &cpres, 0, NULL) != NIS_SUCCESS)
 	    NIS_RES_STATUS (res) = NIS_RPCERROR;
 	  else
 	    {
diff --git a/nis/nis_file.c b/nis/nis_file.c
index 94fa4eb865..0ffac68fe2 100644
--- a/nis/nis_file.c
+++ b/nis/nis_file.c
@@ -31,18 +31,26 @@ readColdStartFile (void)
   XDR xdrs;
   FILE *in;
   bool_t status;
-  directory_obj obj;
+  directory_obj *obj = calloc (1, sizeof (directory_obj));
+
+  if (obj == NULL)
+    return NULL;
 
   in = fopen (cold_start_file, "rb");
   if (in == NULL)
     return NULL;
-  memset (&obj, '\0', sizeof (obj));
   xdrstdio_create (&xdrs, in, XDR_DECODE);
-  status = _xdr_directory_obj (&xdrs, &obj);
+  status = _xdr_directory_obj (&xdrs, obj);
   xdr_destroy (&xdrs);
   fclose (in);
 
-  return status ? nis_clone_directory (&obj, NULL) : NULL;
+  if (status)
+    return obj;
+  else
+    {
+      nis_free_directory (obj);
+      return NULL;
+    }
 }
 
 bool_t
@@ -70,19 +78,27 @@ nis_read_obj (const char *name)
   XDR xdrs;
   FILE *in;
   bool_t status;
-  nis_object obj;
+  nis_object *obj = calloc (1, sizeof (nis_object));
+
+  if (obj == NULL)
+    return NULL;
 
   in = fopen (name, "rb");
   if (in == NULL)
     return NULL;
 
-  memset (&obj, '\0', sizeof (obj));
   xdrstdio_create (&xdrs, in, XDR_DECODE);
-  status =_xdr_nis_object (&xdrs, &obj);
+  status =_xdr_nis_object (&xdrs, obj);
   xdr_destroy (&xdrs);
   fclose (in);
 
-  return status ? nis_clone_object (&obj, NULL) : NULL;
+  if (status)
+    return obj;
+  else
+    {
+      nis_free_object (obj);
+      return NULL;
+    }
 }
 
 bool_t
diff --git a/nis/nis_findserv.c b/nis/nis_findserv.c
index 832b6a541d..5b6a74981c 100644
--- a/nis/nis_findserv.c
+++ b/nis/nis_findserv.c
@@ -110,8 +110,25 @@ struct findserv_req
 };
 
 long
-__nis_findfastest (dir_binding * bind)
+__nis_findfastest (dir_binding *bind)
 {
+#if 0
+  unsigned long i, j;
+
+  for (i = 0; i < bind->server_len; i++)
+    for (j = 0; j < bind->server_val[i].ep.ep_len; ++j)
+      if (strcmp (bind->server_val[i].ep.ep_val[j].family, "inet") == 0)
+	if ((bind->server_val[i].ep.ep_val[j].proto == NULL) ||
+	    (bind->server_val[i].ep.ep_val[j].proto[0] ==  '-') ||
+	    (bind->server_val[i].ep.ep_val[j].proto[0] == '\0'))
+	  {
+	    bind->server_used = i;
+	    bind->current_ep = j;
+	    return 1;
+	  }
+
+  return 0;
+#else
   const struct timeval TIMEOUT50 = {5, 0};
   const struct timeval TIMEOUT00 = {0, 0};
   struct findserv_req **pings;
@@ -137,7 +154,7 @@ __nis_findfastest (dir_binding * bind)
     for (j = 0; j < bind->server_val[i].ep.ep_len; ++j)
       if (strcmp (bind->server_val[i].ep.ep_val[j].family, "inet") == 0)
 	if ((bind->server_val[i].ep.ep_val[j].proto == NULL) ||
-	    (strcmp (bind->server_val[i].ep.ep_val[j].proto, "-") == 0) ||
+	    (bind->server_val[i].ep.ep_val[j].proto[0] == '-') ||
 	    (bind->server_val[i].ep.ep_val[j].proto[0] == '\0'))
 	  {
 	    sin.sin_addr.s_addr =
@@ -228,4 +245,5 @@ __nis_findfastest (dir_binding * bind)
   free (pings);
 
   return found;
+#endif
 }
diff --git a/nis/nis_intern.h b/nis/nis_intern.h
index bea4e272ce..9f515bb460 100644
--- a/nis/nis_intern.h
+++ b/nis/nis_intern.h
@@ -24,31 +24,6 @@
 
 __BEGIN_DECLS
 
-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 current_ep;              /* Which endpoint of the server are in use? */
-  u_int trys;                    /* How many server have we tried ? */
-  u_int class;                   /* From which class is server_val ? */
-  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 ? */
-  struct sockaddr_in addr;       /* Server's IP address */
-  int socket;                    /* Server's local socket */
-};
-typedef struct dir_binding dir_binding;
-
-struct cache2_info
-{
-  long server_used;
-  long current_ep;
-  long class;
-};
-typedef struct cache2_info cache2_info;
-
 struct nis_cb
   {
     nis_server *serv;
@@ -66,8 +41,7 @@ extern long __nis_findfastest __P ((dir_binding *bind));
 extern nis_error __do_niscall2 __P ((const nis_server *serv, u_int serv_len,
 				     u_long prog, xdrproc_t xargs, caddr_t req,
 				     xdrproc_t xres, caddr_t resp,
-				     u_long flags, nis_cb *cb,
-				     cache2_info *cinfo));
+				     u_long flags, nis_cb *cb));
 extern nis_error __do_niscall __P ((const_nis_name name, u_long prog,
 				    xdrproc_t xargs, caddr_t req,
 				    xdrproc_t xres, caddr_t resp,
@@ -81,13 +55,6 @@ extern struct nis_cb *__nis_create_callback
 	    const void *userdata, u_long flags));
 extern nis_error __nis_destroy_callback __P ((struct nis_cb *cb));
 
-#ifdef _LIBC
-/* NIS+ Cache functions */
-extern directory_obj *__nis_cache_search __P ((const_nis_name name,
-					       u_long flags,
-					       cache2_info *cinfo));
-#endif
-
 __END_DECLS
 
 #endif
diff --git a/nis/nis_lookup.c b/nis/nis_lookup.c
index 6a2198ac21..df16cceeac 100644
--- a/nis/nis_lookup.c
+++ b/nis/nis_lookup.c
@@ -25,20 +25,20 @@
 nis_result *
 nis_lookup (const_nis_name name, const u_long flags)
 {
-  nis_result *res;
+  nis_result *res = calloc (1, sizeof (nis_result));
   struct ns_request req;
   nis_name *names;
   nis_error status;
+  int link_first_try = 0;
   int count_links = 0;	 /* We will follow only 16 links in the deep */
   int done = 0;
   int name_nr = 0;
   nis_name namebuf[2] = {NULL, NULL};
 
-  res = calloc (1, sizeof (nis_result));
   if (res == NULL)
     return NULL;
 
-  if (flags & EXPAND_NAME)
+  if ((flags & EXPAND_NAME) && (name[strlen (name) - 1] != '.'))
     {
       names = nis_getnames (name);
       if (names == NULL)
@@ -56,51 +56,141 @@ nis_lookup (const_nis_name name, const u_long flags)
   req.ns_name = names[0];
   while (!done)
     {
+      dir_binding bptr;
+      directory_obj *dir = NULL;
       req.ns_object.ns_object_len = 0;
       req.ns_object.ns_object_val = NULL;
-      memset (res, '\0', sizeof (nis_result));
 
-      status = __do_niscall (req.ns_name, NIS_LOOKUP,
-			     (xdrproc_t) _xdr_ns_request,
-			     (caddr_t) & req,
-			     (xdrproc_t) _xdr_nis_result,
-			     (caddr_t) res, flags, NULL);
+      status = __nisfind_server (req.ns_name, &dir);
       if (status != NIS_SUCCESS)
-	NIS_RES_STATUS (res) = status;
+	{
+	  NIS_RES_STATUS (res) = status;
+	  return res;
+	}
 
-      switch (NIS_RES_STATUS (res))
+      status = __nisbind_create (&bptr, dir->do_servers.do_servers_val,
+				 dir->do_servers.do_servers_len, flags);
+      if (status != NIS_SUCCESS)
 	{
-	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 */
+	  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;
+	    }
+	}
+
+      do
+	{
+	  static struct timeval RPCTIMEOUT = {10, 0};
+	  enum clnt_stat result;
+
+	again:
+	  result = clnt_call (bptr.clnt, NIS_LOOKUP,
+			      (xdrproc_t) _xdr_ns_request,
+			      (caddr_t) &req, (xdrproc_t) _xdr_nis_result,
+			      (caddr_t) res, RPCTIMEOUT);
+
+	  if (result != RPC_SUCCESS)
+	    status = NIS_RPCERROR;
+	  else
 	    {
-	      /* if we hit the link limit, bail */
-	      if (count_links > NIS_MAXLINKS)
+	      if (NIS_RES_STATUS (res) == NIS_SUCCESS)
 		{
-		  NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
-		  ++done;
-		  break;
+		    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)
+			  {
+			    NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
+			    break;
+			  }
+			++count_links;
+			req.ns_name =
+			  strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
+			nis_freeresult (res);
+			res = calloc (1, sizeof (nis_result));
+			if (res == NULL)
+			  {
+			    __nisbind_destroy (&bptr);
+			    nis_free_directory (dir);
+			    return NULL;
+			  }
+			link_first_try = 1; /* Try at first the old binding */
+			goto again;
+		      }
 		}
-	      if (count_links)
-		free (req.ns_name);
-	      ++count_links;
-	      req.ns_name = strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
-	      nis_freeresult (res);
-	      res = calloc (1, sizeof (nis_result));
-	      if (res == NULL)
-		return NULL;
+	      else
+		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);
+
+			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;
+			  }
+		      }
+		    else
+		      if (__nisbind_next (&bptr) != NIS_SUCCESS)
+			break; /* No more servers to search */
+
+		    while (__nisbind_connect (&bptr) != NIS_SUCCESS)
+		      {
+			if (__nisbind_next (&bptr) != NIS_SUCCESS)
+			  {
+			    __nisbind_destroy (&bptr);
+			    nis_free_directory (dir);
+			    return res;
+			  }
+		      }
+		    goto again;
+		  }
+	      break;
 	    }
-	  else
-	    ++done;
-	  break;
-	case NIS_CBRESULTS:
-	  /* The callback is handled in __do_niscall2 */
-	  ++done;
-	  break;
-	case NIS_UNAVAIL:
-	  /* NIS+ is not installed, or all servers are down */
+	  link_first_try = 0; /* Set it back */
+	  status= NIS_SUCCESS;
+	}
+      while ((flags & HARD_LOOKUP) && status == NIS_RPCERROR);
+
+      __nisbind_destroy (&bptr);
+      nis_free_directory (dir);
+
+      if (status != NIS_SUCCESS)
+	{
+	  NIS_RES_STATUS (res) = status;
+	  return res;
+	}
+
+      switch (NIS_RES_STATUS (res))
+	{
+	case NIS_PARTIAL:
+	case NIS_SUCCESS:
+	case NIS_S_SUCCESS:
+	case NIS_LINKNAMEERROR: /* We follow to max links */
+	case NIS_UNAVAIL: /* NIS+ is not installed, or all servers are down */
 	  ++done;
 	  break;
 	default:
diff --git a/nis/nis_mkdir.c b/nis/nis_mkdir.c
index 71fc4ba877..5d40daebc5 100644
--- a/nis/nis_mkdir.c
+++ b/nis/nis_mkdir.c
@@ -35,7 +35,7 @@ nis_mkdir (const_nis_name dir, const nis_server *server)
     res2 = __do_niscall2 (server, 1, NIS_MKDIR,
 			  (xdrproc_t) _xdr_nis_name,
 			  (caddr_t) &dir, (xdrproc_t) _xdr_nis_error,
-			  (caddr_t) &res, 0, NULL, NULL);
+			  (caddr_t) &res, 0, NULL);
   if (res2 != NIS_SUCCESS)
     return res2;
 
diff --git a/nis/nis_ping.c b/nis/nis_ping.c
index 1becd4bf89..3fc87551f5 100644
--- a/nis/nis_ping.c
+++ b/nis/nis_ping.c
@@ -62,7 +62,7 @@ nis_ping (const_nis_name dirname, u_long utime, const nis_object *dirobj)
     __do_niscall2 (&obj->DI_data.do_servers.do_servers_val[i], 1,
 		   NIS_PING, (xdrproc_t) _xdr_ping_args,
 		   (caddr_t) &args, (xdrproc_t) xdr_void,
-		   (caddr_t) NULL, 0, NULL, NULL);
+		   (caddr_t) NULL, 0, NULL);
   if (res)
     nis_freeresult (res);
 }
diff --git a/nis/nis_rmdir.c b/nis/nis_rmdir.c
index 1f3e91874c..0cd4458091 100644
--- a/nis/nis_rmdir.c
+++ b/nis/nis_rmdir.c
@@ -33,7 +33,7 @@ nis_rmdir (const_nis_name dir, const nis_server *server)
   res2 = __do_niscall2 (server, 1, NIS_RMDIR,
 			(xdrproc_t) _xdr_nis_name,
 			(caddr_t) &dir, (xdrproc_t) _xdr_nis_error,
-			(caddr_t) &res, 0, NULL, NULL);
+			(caddr_t) &res, 0, NULL);
   if (res2 != NIS_SUCCESS)
     return res2;
 
diff --git a/nis/nis_server.c b/nis/nis_server.c
index aa0f05eb39..84cd5fb827 100644
--- a/nis/nis_server.c
+++ b/nis/nis_server.c
@@ -41,7 +41,7 @@ nis_servstate (const nis_server *serv, const nis_tag *tags,
 
   if (__do_niscall2 (serv, 1, NIS_SERVSTATE, (xdrproc_t) _xdr_nis_taglist,
 		     (caddr_t) &taglist, (xdrproc_t) _xdr_nis_taglist,
-		     (caddr_t) &tagres, 0, NULL, NULL) != RPC_SUCCESS)
+		     (caddr_t) &tagres, 0, NULL) != RPC_SUCCESS)
     return NIS_RPCERROR;
 
   *result = tagres.tags.tags_val;
@@ -67,7 +67,7 @@ nis_stats (const nis_server *serv, const nis_tag *tags,
 
   if (__do_niscall2 (serv, 1, NIS_STATUS, (xdrproc_t) _xdr_nis_taglist,
 		     (caddr_t) &taglist, (xdrproc_t) _xdr_nis_taglist,
-		     (caddr_t) &tagres, 0, NULL, NULL) != RPC_SUCCESS)
+		     (caddr_t) &tagres, 0, NULL) != RPC_SUCCESS)
     return NIS_RPCERROR;
 
   *result = tagres.tags.tags_val;
diff --git a/nis/nis_table.c b/nis/nis_table.c
index ed4b3740dd..e0885ca024 100644
--- a/nis/nis_table.c
+++ b/nis/nis_table.c
@@ -110,6 +110,40 @@ __create_ib_request (const_nis_name name, u_long flags)
   return ibreq;
 }
 
+static struct timeval RPCTIMEOUT = {10, 0};
+
+static char *
+__get_tablepath (char *name, dir_binding *bptr)
+{
+  enum clnt_stat result;
+  nis_result *res = calloc (1, sizeof (nis_result));
+  struct ns_request req;
+
+  if (res == NULL)
+    return NULL;
+
+  req.ns_name = name;
+  req.ns_object.ns_object_len = 0;
+  req.ns_object.ns_object_val = NULL;
+
+  result = clnt_call (bptr->clnt, NIS_LOOKUP, (xdrproc_t) _xdr_ns_request,
+		      (caddr_t) &req, (xdrproc_t) _xdr_nis_result,
+		      (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;
+    }
+  else
+    {
+      nis_freeresult (res);
+      return strdup ("");
+    }
+}
+
 nis_result *
 nis_list (const_nis_name name, u_long flags,
 	  int (*callback) (const_nis_name name,
@@ -120,12 +154,16 @@ nis_list (const_nis_name name, u_long flags,
   nis_result *res = NULL;
   ib_request *ibreq;
   int status;
+  enum clnt_stat clnt_status;
   int count_links = 0;		/* We will only follow NIS_MAXLINKS links! */
   int done = 0;
   nis_name *names;
   nis_name namebuf[2] = {NULL, NULL};
   int name_nr = 0;
   nis_cb *cb = NULL;
+  char *tableptr, *tablepath = NULL;
+  int have_tablepath = 0;
+  int first_try = 0; /* Do we try the old binding at first ? */
 
   res = calloc (1, sizeof (nis_result));
   if (res == NULL)
@@ -164,189 +202,230 @@ nis_list (const_nis_name name, u_long flags,
 
   cb = NULL;
 
-  if (flags & FOLLOW_PATH || flags & ALL_RESULTS)
+  while (!done)
     {
-      nis_result *lres;
-      u_long newflags = flags & ~FOLLOW_PATH & ~ALL_RESULTS;
-      char table_path[NIS_MAXPATH + 3];
-      char *ntable, *p;
-      u_long done = 0, failures = 0;
-
-      while (names[name_nr] != NULL && !done)
-	{
-	  lres = nis_lookup (names[name_nr], newflags | NO_AUTHINFO);
-	  if (lres == NULL || NIS_RES_STATUS (lres) != NIS_SUCCESS)
-	    {
-	      NIS_RES_STATUS (res) = NIS_RES_STATUS (lres);
-	      nis_freeresult (lres);
-	      ++name_nr;
-	      continue;
-	    }
-
-	  /* nis_lookup handles FOLLOW_LINKS,
-	     so we must have a table object.*/
-	  if (__type_of (NIS_RES_OBJECT (lres)) != NIS_TABLE_OBJ)
-	    {
-	      nis_freeresult (lres);
-	      NIS_RES_STATUS (res) = NIS_INVALIDOBJ;
-	      break;
-	    }
+      dir_binding bptr;
+      directory_obj *dir = NULL;
 
-	  /* Save the path, discard everything else.  */
-	  p = __stpncpy (table_path, names[name_nr], NIS_MAXPATH);
-	  *p++ = ':';
-	  p = __stpncpy (p, NIS_RES_OBJECT (lres)->TA_data.ta_path,
-			 NIS_MAXPATH - (p - table_path));
-	  *p = '\0';
-	  nis_freeresult (lres);
-	  free (res);
-	  res = NULL;
+      memset (res, '\0', sizeof (nis_result));
 
-	  p = table_path;
+      status = __nisfind_server (ibreq->ibr_name, &dir);
+      if (status != NIS_SUCCESS)
+        {
+          NIS_RES_STATUS (res) = status;
+          return res;
+        }
 
-	  while (((ntable = strsep (&p, ":")) != NULL) && !done)
-	    {
-	      char *c;
+      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;
+        }
 
-	      if (res != NULL)
-		nis_freeresult (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;
+	  }
 
-	      /* Do the job recursive here!  */
-	      if ((c = strchr(name, ']')) != NULL)
-		{
-		  /* Have indexed name ! */
-		  int index_len = c - name + 2;
-		  char buf[index_len + strlen (ntable) + 1];
-
-		  c = __stpncpy (buf, name, index_len);
-		  strcpy (c, ntable);
-		  res = nis_list (buf, newflags, callback,userdata);
-		}
-	      else
-		res = nis_list (ntable, newflags, callback, userdata);
-	      if (res == NULL)
-		return NULL;
-	      switch (NIS_RES_STATUS (res))
-		{
-		case NIS_SUCCESS:
-		case NIS_CBRESULTS:
-		  if (!(flags & ALL_RESULTS))
-		    done = 1;
-		  break;
-		case NIS_PARTIAL: /* The table is correct, we doesn't found
-				     the entry */
-		  break;
-		default:
-		  if (flags & ALL_RESULTS)
-		    ++failures;
-		  else
-		    done = 1;
-		  break;
-		}
-	    }
-	  if (NIS_RES_STATUS (res) == NIS_SUCCESS && failures)
-	    NIS_RES_STATUS (res) = NIS_S_SUCCESS;
-	  if (NIS_RES_STATUS (res) == NIS_NOTFOUND && failures)
-	    NIS_RES_STATUS (res) = NIS_S_NOTFOUND;
-	  break;
-	}
-    }
-  else
-    {
       if (callback != NULL)
 	{
 	  cb = __nis_create_callback (callback, userdata, flags);
 	  ibreq->ibr_cbhost.ibr_cbhost_len = 1;
 	  ibreq->ibr_cbhost.ibr_cbhost_val = cb->serv;
-	  }
-
-      while (!done)
-	{
-	  memset (res, '\0', sizeof (nis_result));
-
-	  status = __do_niscall (ibreq->ibr_name, NIS_IBLIST,
-				 (xdrproc_t) _xdr_ib_request,
-				 (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
-				 (caddr_t) res, flags, cb);
-	  if (status != NIS_SUCCESS)
-	    NIS_RES_STATUS (res) = status;
+	}
 
-	  switch (NIS_RES_STATUS (res))
-	    {
-	    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 we hit the link limit, bail.  */
-		  if (count_links > NIS_MAXLINKS)
+    again:
+      clnt_status = clnt_call (bptr.clnt, NIS_IBLIST,
+			       (xdrproc_t) _xdr_ib_request, (caddr_t) ibreq,
+			       (xdrproc_t) _xdr_nis_result,
+			       (caddr_t) res, RPCTIMEOUT);
+
+      if (clnt_status != RPC_SUCCESS)
+	NIS_RES_STATUS (res) = NIS_RPCERROR;
+      else
+	switch (NIS_RES_STATUS (res))
+	  { /* start switch */
+	  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.  */
+	      {
+		free (ibreq->ibr_name);
+		/* If we hit the link limit, bail.  */
+		if (count_links > NIS_MAXLINKS)
+		  {
+		    NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
+		    ++done;
+		    break;
+		  }
+		++count_links;
+		ibreq->ibr_name =
+		  strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
+		if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
+		  if (ibreq->ibr_srch.ibr_srch_len == 0)
 		    {
-		      NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
-		      ++done;
-		      break;
+		      ibreq->ibr_srch.ibr_srch_len =
+			NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len;
+		      ibreq->ibr_srch.ibr_srch_val =
+			NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
 		    }
-		  if (count_links)
-		    free (ibreq->ibr_name);
-		  ++count_links;
-		  free (ibreq->ibr_name);
-		  ibreq->ibr_name =
-		    strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
-		  if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
-		    if (ibreq->ibr_srch.ibr_srch_len == 0)
+		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;
+		  }
+		first_try = 1; /* Try at first the old binding */
+		goto again;
+	      }
+	    else if ((flags & FOLLOW_PATH) &&
+		     NIS_RES_STATUS (res) == NIS_PARTIAL)
+	      {
+		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);
+		    nis_freeresult (res);
+		    res = calloc (1, sizeof (nis_result));
+		    if (res == NULL)
 		      {
-			ibreq->ibr_srch.ibr_srch_len =
-			  NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len;
-			ibreq->ibr_srch.ibr_srch_val =
-			  NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
+			if (have_tablepath)
+			  free (tablepath);
+			__nisbind_destroy (&bptr);
+			nis_free_directory (dir);
+			return NULL;
 		      }
-		  nis_freeresult (res);
-		  res = calloc (1, sizeof (nis_result));
-		}
-	      else
-		++done;
-	      break;
-	    case NIS_CBRESULTS:
-	      /* Calback is handled in nis_call.c (__do_niscall2),
-		 but we have to change the error code */
-	      NIS_RES_STATUS (res) = cb->result;
+		    first_try = 1;
+		    goto again;
+		  }
+	      }
+	    else
 	      ++done;
-	      break;
-	    case NIS_UNAVAIL:
-	      /* NIS+ is not installed, or all servers are down.  */
-	      ++done;
-	      break;
-	    default:
-	      /* Try the next domainname if we don't follow a link.  */
-	      if (count_links)
-		{
-		  free (ibreq->ibr_name);
-		  NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
-		  ++done;
-		  break;
-		}
-	      ++name_nr;
-	      if (names[name_nr] == NULL)
-		{
+	    break;
+	  case NIS_CBRESULTS:
+	    if (cb != NULL)
+	      {
+		__nis_do_callback (&bptr, &res->cookie, cb);
+		NIS_RES_STATUS (res) = cb->result;
+
+		if (!(flags & ALL_RESULTS))
 		  ++done;
-		  break;
-		}
-	      ibreq->ibr_name = names[name_nr];
-	      break;
-	    }
+		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);
+		  }
+	      }
+	    break;
+	  case NIS_SYSTEMERROR:
+	  case NIS_NOSUCHNAME:
+	  case NIS_NOT_ME:
+	    /* If we had first tried the old binding, do nothing, but
+	       get a new binding */
+	    if (!first_try)
+	      {
+		if (__nisbind_next (&bptr) != NIS_SUCCESS)
+		  {
+		    ++done;
+		    break; /* No more servers to search */
+		  }
+		while (__nisbind_connect (&bptr) != NIS_SUCCESS)
+		  {
+		    if (__nisbind_next (&bptr) != NIS_SUCCESS)
+		      {
+			++done;
+			break; /* No more servers to search */
+		      }
+		  }
+		goto again;
+	      }
+	    break;
+	  default:
+	    if (!first_try)
+	      {
+		/* Try the next domainname if we don't follow a link.  */
+		if (count_links)
+		  {
+		    free (ibreq->ibr_name);
+		    NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
+		    ++done;
+		    break;
+		  }
+		++name_nr;
+		if (names[name_nr] == NULL)
+		  {
+		    ++done;
+		    break;
+		  }
+		ibreq->ibr_name = names[name_nr];
+		first_try = 1; /* Try old binding at first */
+		goto again;
+	      }
+	    break;
+	  }
+      first_try = 0;
+
+      if (cb)
+	{
+	  __nis_destroy_callback (cb);
+	  ibreq->ibr_cbhost.ibr_cbhost_len = 0;
+	  ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
 	}
-    }				/* End of not FOLLOW_PATH.  */
+
+      __nisbind_destroy (&bptr);
+      nis_free_directory (dir);
+    }
 
   if (names != namebuf)
     nis_freenames (names);
 
-  if (cb)
-    {
-      __nis_destroy_callback (cb);
-      ibreq->ibr_cbhost.ibr_cbhost_len = 0;
-      ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
-    }
-
   nis_free_request (ibreq);
 
   return res;
diff --git a/nis/nis_util.c b/nis/nis_util.c
index 656b1a48c1..2b351e7339 100644
--- a/nis/nis_util.c
+++ b/nis/nis_util.c
@@ -38,7 +38,7 @@ __nis_finddirectory (directory_obj *dir, const_nis_name name)
 			  dir->do_servers.do_servers_len,
 			  NIS_FINDDIRECTORY, (xdrproc_t) _xdr_fd_args,
 			  (caddr_t) &fd_args, (xdrproc_t) _xdr_fd_result,
-			  (caddr_t) fd_res, NO_AUTHINFO|USE_DGRAM, NULL, NULL);
+			  (caddr_t) fd_res, NO_AUTHINFO|USE_DGRAM, NULL);
   if (status != NIS_SUCCESS)
     fd_res->status = status;
 
diff --git a/nis/rpcsvc/nislib.h b/nis/rpcsvc/nislib.h
index 016bedc769..60bf8923d8 100644
--- a/nis/rpcsvc/nislib.h
+++ b/nis/rpcsvc/nislib.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -247,6 +247,35 @@ extern u_long __nis_hash __P ((const void *keyarg, register size_t len));
 extern int __nis_lock_cache __P ((void));
 extern int __nis_unlock_cache __P ((void));
 
+/* (XXX INTERNAL FUNCTIONS, ONLY FOR rpc.nisd AND glibc !!) */
+#if defined (NIS_INTERNAL) || defined (_LIBC)
+
+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 current_ep;              /* Which endpoint of the server are in use? */
+  u_int trys;                    /* How many server have we tried ? */
+  u_int class;                   /* From which class is server_val ? */
+  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 ? */
+  struct sockaddr_in addr;       /* Server's IP address */
+  int socket;                    /* Server's local socket */
+};
+typedef struct dir_binding dir_binding;
+
+extern nis_error __nisbind_create __P ((dir_binding *, const nis_server *,
+					u_int, u_long));
+extern nis_error __nisbind_connect __P ((dir_binding *));
+extern nis_error __nisbind_next __P ((dir_binding *));
+extern void __nisbind_destroy __P ((dir_binding *));
+extern nis_error __nisfind_server __P ((const_nis_name, directory_obj **));
+
+#endif
+
 __END_DECLS
 
 #endif	/* __RPCSVC_NISLIB_H__ */