summaryrefslogtreecommitdiff
path: root/nis/nis_call.c
diff options
context:
space:
mode:
Diffstat (limited to 'nis/nis_call.c')
-rw-r--r--nis/nis_call.c211
1 files changed, 189 insertions, 22 deletions
diff --git a/nis/nis_call.c b/nis/nis_call.c
index a92f1445f4..17f67abbde 100644
--- a/nis/nis_call.c
+++ b/nis/nis_call.c
@@ -160,36 +160,19 @@ __nis_dobind (const nis_server *server, u_long flags)
}
nis_error
-__do_niscall (const nis_server *serv, int serv_len, u_long prog,
- xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp,
- u_long flags)
+__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;
- directory_obj *dir = NULL;
- const nis_server *server;
int try, result;
- unsigned int server_len;
- if (serv == NULL || serv_len == 0)
- {
- dir = readColdStartFile ();
- if (dir == NULL) /* No /var/nis/NIS_COLD_START -> no NIS+ installed */
- return NIS_UNAVAIL;
- server = dir->do_servers.do_servers_val;
- server_len = dir->do_servers.do_servers_len;
- }
- else
- {
- server = serv;
- server_len = serv_len;
- }
+ try = 0;
+ result = NIS_NAMEUNREACHABLE;
if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1)
server_len = 1; /* The first entry is the master */
- try = 0;
- result = NIS_NAMEUNREACHABLE;
-
while (try < MAXTRIES && result != RPC_SUCCESS)
{
unsigned int i;
@@ -215,7 +198,191 @@ __do_niscall (const nis_server *serv, int serv_len, u_long prog,
}
}
+ 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)
+ {
+ 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);
+
+ if (result != RPC_SUCCESS)
+ {
+ clnt_perror (clnt, "do_niscall: clnt_call");
+ clnt_destroy (clnt);
+ result = NIS_RPCERROR;
+ }
+ else
+ clnt_destroy (clnt);
+ }
+ 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;
+}
+
+static directory_obj *
+rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
+{
+ char domain [strlen (name) + 3];
+
+ nis_domain_of_r (name, domain, sizeof (domain));
+ if (strncmp (domain, "org_dir.", 8) == 0)
+ {
+ char tmp[strlen (name) + 3];
+
+ nis_domain_of_r (domain, tmp, sizeof (tmp));
+ strcpy (domain, tmp);
+ }
+ else
+ if (strncmp (domain, "groups_dir.", 11) == 0)
+ {
+ char tmp[strlen (name) + 3];
+
+ nis_domain_of_r (domain, tmp, sizeof (tmp));
+ strcpy (domain, tmp);
+ }
+ else
+ {
+ /* We have no grous_dir or org_dir, so try the complete name */
+ strcpy (domain, name);
+ }
+
+ switch (nis_dir_cmp (domain, dir->do_name))
+ {
+ case SAME_NAME:
+ return dir;
+ case NOT_SEQUENTIAL:
+ /* NOT_SEQUENTIAL means, go one up and try it there ! */
+ case HIGHER_NAME:
+ { /* We need data from a parent domain */
+ directory_obj *obj;
+ char ndomain [strlen (name) + 3];
+
+ nis_domain_of_r (dir->do_name, ndomain, sizeof (ndomain));
+
+ /* 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);
+ 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);
+ }
+ else
+ {
+ /* Ups, very bad. Are we already the root server ? */
+ nis_free_directory (dir);
+ return NULL;
+ }
+ }
+ break;
+ case LOWER_NAME:
+ {
+ directory_obj *obj;
+ char leaf [strlen (name) + 3];
+ char ndomain [strlen (name) + 3];
+ u_int i;
+
+ do
+ {
+ if (strlen (domain) == 0)
+ {
+ nis_free_directory (dir);
+ return NULL;
+ }
+ nis_leaf_of_r (domain, leaf, sizeof (leaf));
+ nis_domain_of_r (domain, ndomain, sizeof (ndomain));
+ strcpy (domain, ndomain);
+ }
+ while (nis_dir_cmp (domain, dir->do_name) != SAME_NAME);
+ strcat (leaf, ".");
+ strcat (leaf, domain);
+
+ for (i = 0; i < dir->do_servers.do_servers_len; ++i)
+ {
+ 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);
+ }
+ }
+ }
+ break;
+ case BAD_NAME:
+ nis_free_directory (dir);
+ return NULL;
+ }
+ nis_free_directory (dir);
+ return NULL;
+}
+
+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;
+ directory_obj *dir = NULL;
+ const nis_server *server;
+ u_int server_len;
+
+
+ dir = readColdStartFile ();
+ if (dir == NULL) /* No /var/nis/NIS_COLD_START -> no NIS+ installed */
+ return NIS_UNAVAIL;
+
+ if (name != NULL)
+ {
+ 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;
+ }
+ }
+ 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);
+
return result;
}