summaryrefslogtreecommitdiff
path: root/nis
diff options
context:
space:
mode:
Diffstat (limited to 'nis')
-rw-r--r--nis/Makefile3
-rw-r--r--nis/TODO1
-rw-r--r--nis/lckcache.c8
-rw-r--r--nis/nis_call.c251
-rw-r--r--nis/nis_findserv.c251
-rw-r--r--nis/nis_intern.h24
-rw-r--r--nis/nis_lookup.c4
-rw-r--r--nis/nis_ping.c8
-rw-r--r--nis/nis_table.c6
-rw-r--r--nis/nis_util.c16
-rw-r--r--nis/nss_compat/compat-grp.c29
-rw-r--r--nis/nss_compat/compat-pwd.c43
-rw-r--r--nis/nss_compat/compat-spwd.c29
-rw-r--r--nis/ypclnt.c16
14 files changed, 535 insertions, 154 deletions
diff --git a/nis/Makefile b/nis/Makefile
index c10c175e7d..e7dd50c1d9 100644
--- a/nis/Makefile
+++ b/nis/Makefile
@@ -50,7 +50,8 @@ libnsl-routines = yp_xdr ypclnt ypupdate_xdr \
nis_verifygroup nis_ismember nis_addmember nis_util\
nis_removemember nis_creategroup nis_destroygroup\
nis_print_group_entry nis_domain_of nis_domain_of_r\
- nis_modify nis_remove nis_add nis_defaults lckcache
+ nis_modify nis_remove nis_add nis_defaults lckcache\
+ nis_findserv
libnsl-map = libnsl.map
libnss_compat-routines := $(addprefix compat-,grp pwd spwd) nisplus-parser
diff --git a/nis/TODO b/nis/TODO
index 0fe695d78b..f34bc09a06 100644
--- a/nis/TODO
+++ b/nis/TODO
@@ -9,4 +9,3 @@
* Missing flags:
- FOLLOW_PATH (nis_list, not supported)
- ALL_RESULTS (nis_list, not supported, needs server callback)
- - NO_CACHE (__do_niscall, cache not supported yet)
diff --git a/nis/lckcache.c b/nis/lckcache.c
index ead577372e..f8c0a97296 100644
--- a/nis/lckcache.c
+++ b/nis/lckcache.c
@@ -1,6 +1,6 @@
/* Handle locking of NIS+ cache file.
- Copyright (C) 1996 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library and based on shadow/lckfile.c.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
@@ -30,7 +30,7 @@
/* How long to wait for getting the lock before returning with an
error. */
-#define TIMEOUT 15 /* sec */
+#define TIMEOUT 5 /* sec */
/* File descriptor for lock file. */
@@ -141,7 +141,7 @@ __nis_lock_cache (void)
memset (&fl, '\0', sizeof (struct flock));
fl.l_type = F_RDLCK;
fl.l_whence = SEEK_SET;
- result = fcntl (lock_fd, F_SETLK, &fl);
+ result = fcntl (lock_fd, F_SETLKW, &fl);
RETURN_CLEAR_ALARM (result);
}
diff --git a/nis/nis_call.c b/nis/nis_call.c
index f25b8017a5..1dfb12944a 100644
--- a/nis/nis_call.c
+++ b/nis/nis_call.c
@@ -29,30 +29,7 @@
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
+unsigned long
inetstr2int (const char *str)
{
char buffer[strlen (str) + 3];
@@ -92,12 +69,7 @@ __bind_destroy (dir_binding *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;
+ u_int j;
if (bind->clnt != NULL)
{
@@ -106,8 +78,38 @@ __bind_next (dir_binding *bind)
clnt_destroy (bind->clnt);
bind->clnt = NULL;
}
-
- return NIS_SUCCESS;
+
+ if (bind->trys >= bind->server_len)
+ return NIS_FAIL;
+
+ for (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)
+ if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].proto,
+ "-") == 0)
+ {
+ bind->current_ep = j;
+ return NIS_SUCCESS;
+ }
+
+ ++bind->trys;
+ ++bind->server_used;
+ if (bind->server_used >= bind->server_len)
+ bind->server_used = 0;
+
+ for (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)
+ if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].proto,
+ "-") == 0)
+ {
+ bind->current_ep = j;
+ return NIS_SUCCESS;
+ }
+
+ return NIS_FAIL;
}
static nis_error
@@ -116,7 +118,6 @@ __bind_connect (dir_binding *dbp)
struct sockaddr_in check;
nis_server *serv;
int checklen;
- u_int i;
if (dbp == NULL)
return NIS_FAIL;
@@ -125,26 +126,10 @@ __bind_connect (dir_binding *dbp)
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 (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 (serv->ep.ep_val[i].proto, "tcp") == 0)
- dbp->addr.sin_addr.s_addr =
- inetstr2int (serv->ep.ep_val[i].uaddr);
- }
- else
- continue;
- }
+
+ dbp->addr.sin_addr.s_addr =
+ inetstr2int (serv->ep.ep_val[dbp->current_ep].uaddr);
+
if (dbp->addr.sin_addr.s_addr == 0)
return NIS_FAIL;
@@ -155,15 +140,15 @@ __bind_connect (dir_binding *dbp)
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)
@@ -171,7 +156,7 @@ __bind_connect (dir_binding *dbp)
{
char netname[MAXNETNAMELEN+1];
char *p;
-
+
p = stpcpy (netname, "unix.");
strncpy (p, serv->name,MAXNETNAMELEN-5);
netname[MAXNETNAMELEN] = '\0';
@@ -187,7 +172,7 @@ __bind_connect (dir_binding *dbp)
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);
@@ -207,11 +192,11 @@ __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)
@@ -219,17 +204,34 @@ __bind_create (const nis_server *serv_val, u_int serv_len, u_long flags)
free (dbp);
return NULL;
}
-
+
+ if (flags & USE_DGRAM)
+ dbp->use_udp = TRUE;
+ else
+ dbp->use_udp = FALSE;
+
+ 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;
+
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)
{
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)
@@ -267,24 +269,12 @@ __bind_create (const nis_server *serv_val, u_int serv_len, u_long flags)
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;
-
- 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;
+ if (__nis_findfastest (dbp) < 1)
+ {
+ __bind_destroy (dbp);
+ return NULL;
+ }
return dbp;
}
@@ -298,10 +288,11 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
nis_error retcode;
dir_binding *dbp;
- if (flags & MASTER_ONLY)
+ if (flags & MASTER_ONLY)
server_len = 1;
-
- dbp = __bind_create (server, server_len, flags);
+
+ if ((dbp = __bind_create (server, server_len, flags)) == NULL)
+ return NIS_UNAVAIL;
while (__bind_connect (dbp) != NIS_SUCCESS)
{
if (__bind_next (dbp) != NIS_SUCCESS)
@@ -315,7 +306,7 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
{
again:
result = clnt_call (dbp->clnt, prog, xargs, req, xres, resp, TIMEOUT);
-
+
if (result != RPC_SUCCESS)
{
clnt_perror (dbp->clnt, "__do_niscall2: clnt_call");
@@ -336,25 +327,56 @@ __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 *)xres)->status != NIS_SUCCESS) &&
- (((nis_result *)xres)->status != NIS_S_SUCCESS))
- if (__bind_next (dbp) == NIS_SUCCESS)
+ if ((((nis_result *)xres)->status == NIS_NOTFOUND) ||
+ (((nis_result *)xres)->status == NIS_NOSUCHNAME) ||
+ (((nis_result *)xres)->status == NIS_NOT_ME))
+ {
+ if (__bind_next (dbp) == NIS_SUCCESS)
+ while (__bind_connect (dbp) != NIS_SUCCESS)
+ {
+ if (__bind_next (dbp) != NIS_SUCCESS)
+ {
+ __bind_destroy (dbp);
+ return NIS_SUCCESS;
+ }
+ }
goto again;
+ }
case NIS_FINDDIRECTORY:
- if (((fd_result *)xres)->status != NIS_SUCCESS)
- if (__bind_next (dbp) == NIS_SUCCESS)
+ if ((((fd_result *)xres)->status == NIS_NOTFOUND) ||
+ (((fd_result *)xres)->status == NIS_NOSUCHNAME) ||
+ (((fd_result *)xres)->status == NIS_NOT_ME))
+ {
+ if (__bind_next (dbp) == NIS_SUCCESS)
+ while (__bind_connect (dbp) != NIS_SUCCESS)
+ {
+ if (__bind_next (dbp) != NIS_SUCCESS)
+ {
+ __bind_destroy (dbp);
+ return NIS_SUCCESS;
+ }
+ }
goto again;
- break;
-#if 0
- case NIS_STATUS: /* nis_taglist */
- case NIS_SERVSTATE:
+ }
break;
case NIS_DUMPLOG: /* log_result */
case NIS_DUMP:
+ if ((((log_result *)xres)->lr_status == NIS_NOTFOUND) ||
+ (((log_result *)xres)->lr_status == NIS_NOSUCHNAME) ||
+ (((log_result *)xres)->lr_status == NIS_NOT_ME))
+ {
+ if (__bind_next (dbp) == NIS_SUCCESS)
+ while (__bind_connect (dbp) != NIS_SUCCESS)
+ {
+ if (__bind_next (dbp) != NIS_SUCCESS)
+ {
+ __bind_destroy (dbp);
+ return NIS_SUCCESS;
+ }
+ }
+ goto again;
+ }
break;
- case NIS_CHECKPOINT: /* cp_result */
- break;
-#endif
default:
break;
}
@@ -363,12 +385,13 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
}
}
while ((flags & HARD_LOOKUP) && retcode == NIS_RPCERROR);
-
- return retcode;
+
+ return retcode;
}
static directory_obj *
-rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
+rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags,
+ nis_error *status)
{
fd_result *fd_res;
XDR xdrs;
@@ -399,6 +422,7 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
switch (nis_dir_cmp (domain, dir->do_name))
{
case SAME_NAME:
+ *status = NIS_SUCCESS;
return dir;
case NOT_SEQUENTIAL:
/* NOT_SEQUENTIAL means, go one up and try it there ! */
@@ -413,6 +437,7 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
domain ! (Now I understand why a root server must be a
replica of the parent domain) */
fd_res = __nis_finddirectory (dir, ndomain);
+ *status = fd_res->status;
if (fd_res->status != NIS_SUCCESS)
{
nis_free_directory (dir);
@@ -431,7 +456,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);
+ return rec_dirsearch (name, obj, flags, status);
}
else
{
@@ -447,7 +472,7 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
char leaf [strlen (name) + 3];
char ndomain [strlen (name) + 3];
char *cp;
-
+
do
{
if (strlen (domain) == 0)
@@ -463,8 +488,9 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
cp = strchr (leaf, '\0');
*cp++ = '.';
strcpy (cp, domain);
-
+
fd_res = __nis_finddirectory (dir, leaf);
+ *status = fd_res->status;
if (fd_res->status != NIS_SUCCESS)
{
nis_free_directory (dir);
@@ -483,15 +509,17 @@ 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);
+ return rec_dirsearch (name, obj, flags, status);
}
}
break;
case BAD_NAME:
nis_free_directory (dir);
+ *status = NIS_BADNAME;
return NULL;
}
nis_free_directory (dir);
+ *status = NIS_FAIL;
return NULL;
}
@@ -509,19 +537,20 @@ __do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs,
if ((flags & NO_CACHE) != NO_CACHE)
dir = __cache_search (name);
-
+
if (dir == NULL)
{
+ nis_error status;
dir = readColdStartFile ();
if (dir == NULL) /* No /var/nis/NIS_COLD_START->no NIS+ installed */
return NIS_UNAVAIL;
-
- dir = rec_dirsearch (name, dir, flags);
+
+ dir = rec_dirsearch (name, dir, flags, &status);
if (dir == NULL)
- return NIS_NOTFOUND;
+ return status;
}
- if (flags & MASTER_ONLY)
+ if (flags & MASTER_ONLY)
{
server = dir->do_servers.do_servers_val;
server_len = 1;
@@ -531,11 +560,11 @@ __do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs,
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 retcode;
diff --git a/nis/nis_findserv.c b/nis/nis_findserv.c
new file mode 100644
index 0000000000..a04abd8056
--- /dev/null
+++ b/nis/nis_findserv.c
@@ -0,0 +1,251 @@
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <rpcsvc/nis.h>
+
+#include "nis_intern.h"
+
+/* Private data kept per client handle, from sunrpc/clnt_udp.c */
+struct cu_data
+ {
+ int cu_sock;
+ bool_t cu_closeit;
+ struct sockaddr_in cu_raddr;
+ int cu_rlen;
+ struct timeval cu_wait;
+ struct timeval cu_total;
+ struct rpc_err cu_error;
+ XDR cu_outxdrs;
+ u_int cu_xdrpos;
+ u_int cu_sendsz;
+ char *cu_outbuf;
+ u_int cu_recvsz;
+ char cu_inbuf[1];
+ };
+
+
+/* The following is the original routine from sunrpc/pm_getport.c.
+ The only change is the much shorter timeout. */
+/*
+ * pmap_getport.c
+ * Client interface to pmap rpc service.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+/*
+ * Find the mapped port for program,version.
+ * Calls the pmap service remotely to do the lookup.
+ * Returns 0 if no map exists.
+ */
+static u_short
+__pmap_getport (struct sockaddr_in *address, u_long program,
+ u_long version, u_int protocol)
+{
+ const struct timeval timeout = {1, 0};
+ const struct timeval tottimeout = {1, 0};
+ u_short port = 0;
+ int socket = -1;
+ CLIENT *client;
+ struct pmap parms;
+
+ address->sin_port = htons (PMAPPORT);
+ client = clntudp_bufcreate (address, PMAPPROG, PMAPVERS, timeout, &socket,
+ RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+ if (client != (CLIENT *) NULL)
+ {
+ parms.pm_prog = program;
+ parms.pm_vers = version;
+ parms.pm_prot = protocol;
+ parms.pm_port = 0; /* not needed or used */
+ if (CLNT_CALL (client, PMAPPROC_GETPORT, (xdrproc_t) xdr_pmap,
+ (caddr_t) & parms, (xdrproc_t) xdr_u_short,
+ (caddr_t) & port, tottimeout) != RPC_SUCCESS)
+ {
+ rpc_createerr.cf_stat = RPC_PMAPFAILURE;
+ clnt_geterr (client, &rpc_createerr.cf_error);
+ }
+ else if (port == 0)
+ {
+ rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
+ }
+ CLNT_DESTROY (client);
+ }
+ /* (void)close(socket); CLNT_DESTROY already closed it */
+ address->sin_port = 0;
+ return port;
+}
+
+/* Transmit to NULLPROC, return immediately. */
+static void *
+nis_null_3_send (void *argp, CLIENT * clnt)
+{
+ static char clnt_res;
+ struct timeval TIMEOUT = {0, 0};
+
+ memset ((char *) &clnt_res, 0, sizeof (clnt_res));
+ if (clnt_call (clnt, NULLPROC,
+ (xdrproc_t) xdr_void, (caddr_t) argp,
+ (xdrproc_t) xdr_void, (caddr_t) & clnt_res,
+ TIMEOUT) != RPC_SUCCESS)
+ return NULL;
+ return (void *) &clnt_res;
+}
+
+/* Receive request from NULLPROC asynchronously. */
+static void *
+nis_null_3_recv (void *argp, CLIENT * clnt)
+{
+ static char clnt_res;
+ struct timeval TIMEOUT = {0, 0};
+
+ memset ((char *) &clnt_res, 0, sizeof (clnt_res));
+ if (clnt_call (clnt, NULLPROC,
+ (xdrproc_t) NULL, (caddr_t) argp,
+ (xdrproc_t) xdr_void, (caddr_t) & clnt_res,
+ TIMEOUT) != RPC_SUCCESS)
+ return NULL;
+ return (void *) &clnt_res;
+}
+
+/* This is now the public functions, which should find the fastest server */
+
+struct findserv_req
+{
+ struct sockaddr_in sin;
+ u_long xid;
+ u_int server_nr;
+ u_int server_ep;
+};
+
+long
+__nis_findfastest (dir_binding * bind)
+{
+ struct timeval TIMEOUT = {5, 0};
+ struct findserv_req **pings;
+ struct sockaddr_in sin;
+ int found = -1;
+ time_t xid_seed, xid_lookup;
+ int sock, dontblock = 1;
+ CLIENT *clnt;
+ void *foo = NULL;
+ u_long i, j, pings_count, pings_max;
+ struct cu_data *cu;
+
+ pings_max = bind->server_len * 2; /* Reserve a little bit more memory
+ for multihomed hosts */
+ pings_count = 0;
+ pings = malloc (sizeof (struct findserv_req *) * pings_max);
+ xid_seed = time (NULL) ^ getpid ();
+
+ memset (&sin, '\0', sizeof (sin));
+ sin.sin_family = AF_INET;
+ 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 (strcmp (bind->server_val[i].ep.ep_val[j].proto, "-") == 0)
+ {
+ sin.sin_addr.s_addr =
+ inetstr2int (bind->server_val[i].ep.ep_val[j].uaddr);
+ if (sin.sin_addr.s_addr == 0)
+ continue;
+ sin.sin_port = htons (__pmap_getport (&sin, NIS_PROG,
+ NIS_VERSION, IPPROTO_UDP));
+ if (sin.sin_port == 0)
+ continue;
+
+ if (pings_count >= pings_max)
+ {
+ pings_max += 10;
+ pings = realloc (pings, sizeof (struct findserv_req) *
+ pings_max);
+ }
+ pings[pings_count] = calloc (1, sizeof (struct findserv_req));
+ memcpy ((char *) &pings[pings_count]->sin, (char *) &sin,
+ sizeof (sin));
+ pings[pings_count]->xid = xid_seed;
+ pings[pings_count]->server_nr = i;
+ pings[pings_count]->server_ep = j;
+ ++xid_seed;
+ ++pings_count;
+ }
+
+ /* Make sure at least one server was assigned */
+ if (pings_count == 0)
+ {
+ free (pings);
+ return -1;
+ }
+
+ /* Create RPC handle */
+ sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ clnt = clntudp_create (&sin, NIS_PROG, NIS_VERSION, TIMEOUT, &sock);
+ if (clnt == NULL)
+ {
+ close (sock);
+ for (i = 0; i < pings_count; ++i)
+ free (pings[i]);
+ free (pings);
+ return -1;
+ }
+ clnt->cl_auth = authunix_create_default ();
+ cu = (struct cu_data *) clnt->cl_private;
+ TIMEOUT.tv_sec = 0;
+ clnt_control (clnt, CLSET_TIMEOUT, (char *) &TIMEOUT);
+ ioctl (sock, FIONBIO, &dontblock);
+
+ /* Send to all servers the NULLPROC */
+ for (i = 0; i < pings_count; ++i)
+ {
+ /* clntudp_call() will increment, subtract one */
+ *((u_int32_t *) (cu->cu_outbuf)) = pings[i]->xid - 1;
+ bcopy ((char *) &pings[i]->sin, (char *) &cu->cu_raddr,
+ sizeof (struct sockaddr_in));
+ nis_null_3_send (foo, clnt);
+ }
+
+ /* Receive reply */
+ nis_null_3_recv (foo, clnt);
+
+ xid_lookup = *((u_int32_t *) (cu->cu_inbuf));
+ for (i = 0; i < pings_count; i++)
+ {
+ if (pings[i]->xid == xid_lookup)
+ {
+ bind->server_used = pings[i]->server_nr;
+ bind->current_ep = pings[i]->server_ep;
+ found = 1;
+ }
+ }
+
+ auth_destroy (clnt->cl_auth);
+ clnt_destroy (clnt);
+ close (sock);
+
+ for (i = 0; i < pings_count; ++i)
+ free (pings[i]);
+ free (pings);
+
+ return found;
+}
diff --git a/nis/nis_intern.h b/nis/nis_intern.h
index a7cb785e40..fdc392ad7f 100644
--- a/nis/nis_intern.h
+++ b/nis/nis_intern.h
@@ -24,12 +24,32 @@
__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 ? */
+ 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;
+
+extern unsigned long inetstr2int __P ((const char *str));
+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,
+ xdrproc_t xres, caddr_t resp,
u_long flags));
extern nis_error __do_niscall __P ((const_nis_name name, u_long prog,
- xdrproc_t xargs, caddr_t req,
+ xdrproc_t xargs, caddr_t req,
xdrproc_t xres, caddr_t resp,
u_long flags));
#if defined (HAVE_SECURE_RPC)
diff --git a/nis/nis_lookup.c b/nis/nis_lookup.c
index 82db7b0b25..6224b1f2c4 100644
--- a/nis/nis_lookup.c
+++ b/nis/nis_lookup.c
@@ -96,6 +96,10 @@ nis_lookup (const_nis_name name, const u_long flags)
/* XXX Implement CALLBACK here ! */
++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)
diff --git a/nis/nis_ping.c b/nis/nis_ping.c
index 941adfbda4..4ec34ce4c0 100644
--- a/nis/nis_ping.c
+++ b/nis/nis_ping.c
@@ -34,7 +34,7 @@ nis_ping (const_nis_name dirname, u_long utime, const nis_object *dirobj)
if (dirobj == NULL)
{
- res = nis_lookup (dirname, EXPAND_NAME + FOLLOW_LINKS);
+ res = nis_lookup (dirname, MASTER_ONLY);
if (res->status != NIS_SUCCESS && res->status != NIS_S_SUCCESS)
return;
obj = res->objects.objects_val;
@@ -44,7 +44,11 @@ nis_ping (const_nis_name dirname, u_long utime, const nis_object *dirobj)
/* Check if obj is really a diryectory object */
if (obj->zo_data.zo_type != DIRECTORY_OBJ)
- abort ();
+ {
+ if (res != NULL)
+ nis_freeresult (res);
+ return;
+ }
if (dirname == NULL)
args.dir = obj->DI_data.do_name;
diff --git a/nis/nis_table.c b/nis/nis_table.c
index 16fd1e68ec..a3bfa2c0cc 100644
--- a/nis/nis_table.c
+++ b/nis/nis_table.c
@@ -248,7 +248,11 @@ nis_list (const_nis_name name, u_long flags,
/* XXX Implement CALLBACK here ! */
++done;
break;
- default:
+ 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)
{
diff --git a/nis/nis_util.c b/nis/nis_util.c
index 4e39d6fb6a..b6eef9b227 100644
--- a/nis/nis_util.c
+++ b/nis/nis_util.c
@@ -24,6 +24,7 @@
fd_result *
__nis_finddirectory (directory_obj *dir, const_nis_name name)
{
+ nis_error status;
fd_args fd_args;
fd_result *fd_res;
@@ -31,13 +32,14 @@ __nis_finddirectory (directory_obj *dir, const_nis_name name)
fd_args.requester = nis_local_host();
fd_res = calloc (1, sizeof (fd_result));
- if (__do_niscall2 (dir->do_servers.do_servers_val,
- dir->do_servers.do_servers_len, NIS_FINDDIRECTORY,
- (xdrproc_t) xdr_fd_args,
- (caddr_t) &fd_args, (xdrproc_t) xdr_fd_result,
- (caddr_t) fd_res, NO_AUTHINFO|USE_DGRAM) != NIS_SUCCESS)
- fd_res->status = NIS_RPCERROR;
-
+ if ((status = __do_niscall2 (dir->do_servers.do_servers_val,
+ dir->do_servers.do_servers_len,
+ NIS_FINDDIRECTORY, (xdrproc_t) xdr_fd_args,
+ (caddr_t) &fd_args, (xdrproc_t) xdr_fd_result,
+ (caddr_t) fd_res,
+ NO_AUTHINFO|USE_DGRAM)) != NIS_SUCCESS)
+ fd_res->status = status;
+
return fd_res;
}
diff --git a/nis/nss_compat/compat-grp.c b/nis/nss_compat/compat-grp.c
index 9726784b2d..35ae2f7b02 100644
--- a/nis/nss_compat/compat-grp.c
+++ b/nis/nss_compat/compat-grp.c
@@ -18,6 +18,7 @@
Boston, MA 02111-1307, USA. */
#include <errno.h>
+#include <fcntl.h>
#include <nss.h>
#include <grp.h>
#include <ctype.h>
@@ -132,6 +133,26 @@ internal_setgrent (ent_t *ent)
if (ent->stream == NULL)
status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+ else
+ {
+ /* We have to make sure the file is `closed on exec'. */
+ int result, flags;
+
+ result = flags = fcntl (fileno (ent->stream), F_GETFD, 0);
+ if (result >= 0)
+ {
+ flags |= FD_CLOEXEC;
+ result = fcntl (fileno (ent->stream), F_SETFD, flags);
+ }
+ if (result < 0)
+ {
+ /* Something went wrong. Close the stream and return a
+ failure. */
+ fclose (ent->stream);
+ ent->stream = NULL;
+ status = NSS_STATUS_UNAVAIL;
+ }
+ }
}
else
rewind (ent->stream);
@@ -277,7 +298,7 @@ getgrent_next_nis (struct group *result, ent_t *ent, char *buffer,
if (!save_nis_first)
free (save_oldkey);
}
-
+
if (parse_res &&
in_blacklist (result->gr_name, strlen (result->gr_name), ent))
parse_res = 0; /* if result->gr_name in blacklist,search next entry */
@@ -297,7 +318,7 @@ getgrent_next_nisplus (struct group *result, ent_t *ent, char *buffer,
{
nis_result *save_oldres;
bool_t save_nis_first;
-
+
if (ent->nis_first)
{
save_oldres = ent->result;
@@ -324,7 +345,7 @@ getgrent_next_nisplus (struct group *result, ent_t *ent, char *buffer,
return niserr2nss (ent->result->status);
}
}
- if ((parse_res = _nss_nisplus_parse_grent (ent->result, 0, result,
+ if ((parse_res = _nss_nisplus_parse_grent (ent->result, 0, result,
buffer, buflen)) == -1)
{
nis_freeresult (ent->result);
@@ -370,7 +391,7 @@ getgrent_next_file_plusgroup (struct group *result, char *buffer,
nis_freeresult (res);
return status;
}
- if ((parse_res = _nss_nisplus_parse_grent (res, 0, result, buffer,
+ if ((parse_res = _nss_nisplus_parse_grent (res, 0, result, buffer,
buflen)) == -1)
{
__set_errno (ERANGE);
diff --git a/nis/nss_compat/compat-pwd.c b/nis/nss_compat/compat-pwd.c
index af1267922c..6fac0f46c6 100644
--- a/nis/nss_compat/compat-pwd.c
+++ b/nis/nss_compat/compat-pwd.c
@@ -21,6 +21,7 @@
#include <pwd.h>
#include <errno.h>
#include <ctype.h>
+#include <fcntl.h>
#include <netdb.h>
#include <string.h>
#include <bits/libc-lock.h>
@@ -232,6 +233,26 @@ internal_setpwent (ent_t *ent)
if (ent->stream == NULL)
status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+ else
+ {
+ /* We have to make sure the file is `closed on exec'. */
+ int result, flags;
+
+ result = flags = fcntl (fileno (ent->stream), F_GETFD, 0);
+ if (result >= 0)
+ {
+ flags |= FD_CLOEXEC;
+ result = fcntl (fileno (ent->stream), F_SETFD, flags);
+ }
+ if (result < 0)
+ {
+ /* Something went wrong. Close the stream and return a
+ failure. */
+ fclose (ent->stream);
+ ent->stream = NULL;
+ status = NSS_STATUS_UNAVAIL;
+ }
+ }
}
else
rewind (ent->stream);
@@ -274,7 +295,7 @@ internal_endpwent (ent_t *ent)
if (ent->netgroup)
__internal_endnetgrent (&ent->netgrdata);
-
+
ent->nis = ent->first = ent->netgroup = 0;
if (ent->oldkey != NULL)
@@ -432,13 +453,13 @@ getpwent_next_nisplus_netgr (struct passwd *result, ent_t *ent, char *group,
give_pwd_free (&ent->pwd);
return NSS_STATUS_RETURN;
}
-
+
if (user == NULL || user[0] == '-')
continue;
-
+
if (domain != NULL && strcmp (ypdomain, domain) != 0)
continue;
-
+
p2len = pwd_need_buflen (&ent->pwd);
if (p2len > buflen)
{
@@ -457,7 +478,7 @@ getpwent_next_nisplus_netgr (struct passwd *result, ent_t *ent, char *group,
nis_freeresult (nisres);
continue;
}
- if ((parse_res = _nss_nisplus_parse_pwent (nisres, result, buffer,
+ if ((parse_res = _nss_nisplus_parse_pwent (nisres, result, buffer,
buflen)) == -1)
{
nis_freeresult (nisres);
@@ -551,7 +572,7 @@ getpwent_next_nisplus (struct passwd *result, ent_t *ent, char *buffer,
if (!saved_first)
nis_freeresult (saved_res);
}
-
+
if (parse_res &&
in_blacklist (result->pw_name, strlen (result->pw_name), ent))
parse_res = 0; /* if result->pw_name in blacklist,search next entry */
@@ -592,7 +613,7 @@ getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer,
bool_t saved_first;
char *saved_oldkey;
int saved_oldlen;
-
+
if (ent->first)
{
if (yp_first (domain, "passwd.byname", &outkey, &outkeylen,
@@ -602,7 +623,7 @@ getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer,
give_pwd_free (&ent->pwd);
return NSS_STATUS_UNAVAIL;
}
-
+
saved_first = TRUE;
saved_oldkey = ent->oldkey;
saved_oldlen = ent->oldkeylen;
@@ -699,7 +720,7 @@ getpwent_next_file_plususer (struct passwd *result, char *buffer,
nis_freeresult (res);
return status;
}
- if ((parse_res = _nss_nisplus_parse_pwent (res, result, buffer,
+ if ((parse_res = _nss_nisplus_parse_pwent (res, result, buffer,
buflen)) == -1)
{
nis_freeresult (res);
@@ -713,10 +734,10 @@ getpwent_next_file_plususer (struct passwd *result, char *buffer,
char *domain;
char *outval;
int outvallen;
-
+
if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
return NSS_STATUS_TRYAGAIN;
-
+
if (yp_match (domain, "passwd.byname", &result->pw_name[1],
strlen (result->pw_name) - 1, &outval, &outvallen)
!= YPERR_SUCCESS)
diff --git a/nis/nss_compat/compat-spwd.c b/nis/nss_compat/compat-spwd.c
index 61a703c1ea..a4c6201c2d 100644
--- a/nis/nss_compat/compat-spwd.c
+++ b/nis/nss_compat/compat-spwd.c
@@ -20,6 +20,7 @@
#include <nss.h>
#include <errno.h>
#include <ctype.h>
+#include <fcntl.h>
#include <netdb.h>
#include <shadow.h>
#include <string.h>
@@ -184,6 +185,26 @@ internal_setspent (ent_t *ent)
if (ent->stream == NULL)
status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+ else
+ {
+ /* We have to make sure the file is `closed on exec'. */
+ int result, flags;
+
+ result = flags = fcntl (fileno (ent->stream), F_GETFD, 0);
+ if (result >= 0)
+ {
+ flags |= FD_CLOEXEC;
+ result = fcntl (fileno (ent->stream), F_SETFD, flags);
+ }
+ if (result < 0)
+ {
+ /* Something went wrong. Close the stream and return a
+ failure. */
+ fclose (ent->stream);
+ ent->stream = NULL;
+ status = NSS_STATUS_UNAVAIL;
+ }
+ }
}
else
rewind (ent->stream);
@@ -305,10 +326,10 @@ getspent_next_nis_netgr (struct spwd *result, ent_t *ent, char *group,
give_spwd_free (&ent->pwd);
return NSS_STATUS_RETURN;
}
-
+
if (user == NULL || user[0] == '-')
continue;
-
+
if (domain != NULL && strcmp (ypdomain, domain) != 0)
continue;
@@ -651,7 +672,7 @@ getspent_next_file_plususer (struct spwd *result, char *buffer,
nis_freeresult (res);
return status;
}
- if ((parse_res = _nss_nisplus_parse_spent (res, result, buffer,
+ if ((parse_res = _nss_nisplus_parse_spent (res, result, buffer,
buflen)) == -1)
{
nis_freeresult (res);
@@ -735,7 +756,7 @@ getspent_next_file (struct spwd *result, ent_t *ent,
__set_errno (ERANGE);
return NSS_STATUS_TRYAGAIN;
}
-
+
if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-')
/* This is a real entry. */
break;
diff --git a/nis/ypclnt.c b/nis/ypclnt.c
index 85597144b2..7c9efec70a 100644
--- a/nis/ypclnt.c
+++ b/nis/ypclnt.c
@@ -130,12 +130,15 @@ __yp_bind (const char *domain, dom_binding ** ypdb)
(caddr_t) &ypbr, TIMEOUT) != RPC_SUCCESS)
{
clnt_destroy (client);
+ close (clnt_sock);
if (is_new)
free (ysd);
return YPERR_YPBIND;
}
clnt_destroy (client);
+ close (clnt_sock);
+
if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
{
switch (ypbr.ypbind_resp_u.ypbind_error)
@@ -174,7 +177,10 @@ __yp_bind (const char *domain, dom_binding ** ypdb)
}
if (ysd->dom_client)
- clnt_destroy (ysd->dom_client);
+ {
+ clnt_destroy (ysd->dom_client);
+ close (ysd->dom_socket);
+ }
ysd->dom_socket = RPC_ANYSOCK;
ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG, YPVERS,
TIMEOUT, &ysd->dom_socket);
@@ -635,18 +641,16 @@ yp_all (const char *indomain, const char *inmap,
(caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
(caddr_t) &status, TIMEOUT);
+ clnt_destroy (clnt);
+ close (clnt_sock);
if (result != RPC_SUCCESS)
{
clnt_perror (ydb->dom_client, "yp_all: clnt_call");
- clnt_destroy (clnt);
__yp_unbind (ydb);
result = YPERR_RPC;
}
else
- {
- clnt_destroy (clnt);
- result = YPERR_SUCCESS;
- }
+ result = YPERR_SUCCESS;
__libc_lock_unlock (ypbindlist_lock);