Update.
[glibc.git] / nis / nis_call.c
blob17f67abbde25b6470362b66d18f267084acee9d2
1 /* Copyright (C) 1997 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
20 #include <string.h>
21 #include <rpc/rpc.h>
22 #include <rpc/auth.h>
23 #include <rpcsvc/nis.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include "nis_intern.h"
29 static struct timeval TIMEOUT = {25, 0};
30 static int const MAXTRIES = 3;
32 static unsigned long
33 inetstr2int (const char *str)
35 char buffer[strlen (str) + 3];
36 size_t buflen;
37 size_t i, j;
39 buflen = stpcpy (buffer, str) - buffer;
41 j = 0;
42 for (i = 0; i < buflen; ++i)
43 if (buffer[i] == '.')
45 ++j;
46 if (j == 4)
48 buffer[i] = '\0';
49 break;
53 return inet_addr (buffer);
56 static CLIENT *
57 __nis_dobind (const nis_server *server, u_long flags)
59 struct sockaddr_in clnt_saddr;
60 int clnt_sock;
61 size_t i;
62 CLIENT *client = NULL;
64 memset (&clnt_saddr, '\0', sizeof clnt_saddr);
65 clnt_saddr.sin_family = AF_INET;
66 for (i = 0; i < server->ep.ep_len; i++)
68 if (strcmp (server->ep.ep_val[i].family,"loopback") == 0)
70 if (server->ep.ep_val[i].uaddr[i] == '-')
71 clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
72 else
73 if (strcmp (server->ep.ep_val[i].proto,"udp") == 0)
75 if ((flags & USE_DGRAM) == USE_DGRAM)
76 clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
77 else
78 continue;
80 else
81 if (strcmp (server->ep.ep_val[i].proto,"tcp") == 0)
83 if ((flags & USE_DGRAM) == USE_DGRAM)
84 continue;
85 else
86 clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
89 else
90 if (strcmp (server->ep.ep_val[i].family,"inet") == 0)
92 if (server->ep.ep_val[i].uaddr[i] == '-')
93 clnt_saddr.sin_addr.s_addr =
94 inetstr2int (server->ep.ep_val[i].uaddr);
95 else
96 if (strcmp (server->ep.ep_val[i].proto,"udp") == 0)
98 if ((flags & USE_DGRAM) == USE_DGRAM)
99 clnt_saddr.sin_addr.s_addr =
100 inetstr2int (server->ep.ep_val[i].uaddr);
101 else
102 continue;
104 else
105 if (strcmp (server->ep.ep_val[i].proto,"tcp") == 0)
107 if ((flags & USE_DGRAM) == USE_DGRAM)
108 continue;
109 else
110 clnt_saddr.sin_addr.s_addr =
111 inetstr2int (server->ep.ep_val[i].uaddr);
114 else
115 continue;
117 clnt_sock = RPC_ANYSOCK;
118 if ((flags & USE_DGRAM) == USE_DGRAM)
119 client = clntudp_create (&clnt_saddr, NIS_PROG, NIS_VERSION,
120 TIMEOUT, &clnt_sock);
121 else
122 client = clnttcp_create (&clnt_saddr, NIS_PROG, NIS_VERSION,
123 &clnt_sock, 0, 0);
125 if (client == NULL)
126 continue;
127 if (clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
128 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS)
130 clnt_destroy (client);
131 continue;
134 if ((flags & NO_AUTHINFO) != NO_AUTHINFO)
136 #if defined(HAVE_SECURE_RPC)
137 if (server->key_type == NIS_PK_DH && getenv ("NO_SECURE_RPC") == NULL)
139 char netname[MAXNETNAMELEN+1];
140 char *p;
142 p = stpcpy (netname, "unix.");
143 strncpy (p, server->name,MAXNETNAMELEN-5);
144 netname[MAXNETNAMELEN] = '\0';
145 p = strchr (netname, '.');
146 *p = '@';
147 client->cl_auth =
148 authdes_pk_create (netname, &server->pkey, 300, NULL, NULL);
149 if (!client->cl_auth)
150 client->cl_auth = authunix_create_default ();
152 else
153 #endif
154 client->cl_auth = authunix_create_default ();
156 return client;
159 return NULL;
162 nis_error
163 __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
164 xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp,
165 u_long flags)
167 CLIENT *clnt;
168 int try, result;
170 try = 0;
171 result = NIS_NAMEUNREACHABLE;
173 if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1)
174 server_len = 1; /* The first entry is the master */
176 while (try < MAXTRIES && result != RPC_SUCCESS)
178 unsigned int i;
180 if ((flags & HARD_LOOKUP) == 0)
181 ++try;
183 for (i = 0; i < server_len; i++)
185 if ((clnt = __nis_dobind (&server[i], flags)) == NULL)
186 continue;
188 result = clnt_call (clnt, prog, xargs, req, xres, resp, TIMEOUT);
190 if (result != RPC_SUCCESS)
192 clnt_perror (clnt, "do_niscall: clnt_call");
193 clnt_destroy (clnt);
194 result = NIS_RPCERROR;
196 else
197 clnt_destroy (clnt);
201 return result;
204 static directory_obj *
205 dir_lookup (const_nis_name name, nis_server *serv, u_long flags)
207 CLIENT *clnt;
208 int try, result;
209 nis_result *res;
210 struct ns_request req;
211 directory_obj *dir;
213 res = calloc (1, sizeof (nis_result));
214 req.ns_name = (char *)name;
215 req.ns_object.ns_object_len = 0;
216 req.ns_object.ns_object_val = NULL;
217 try = 0;
218 result = NIS_NAMEUNREACHABLE;
220 while (try < MAXTRIES && result != RPC_SUCCESS)
222 if ((clnt = __nis_dobind (serv, flags)) == NULL)
223 continue;
225 result = clnt_call (clnt, NIS_LOOKUP, (xdrproc_t) xdr_ns_request,
226 (caddr_t) &req, (xdrproc_t) xdr_nis_result,
227 (caddr_t) res, TIMEOUT);
229 if (result != RPC_SUCCESS)
231 clnt_perror (clnt, "do_niscall: clnt_call");
232 clnt_destroy (clnt);
233 result = NIS_RPCERROR;
235 else
236 clnt_destroy (clnt);
238 if (result != RPC_SUCCESS || res->status != NIS_SUCCESS)
239 return NULL;
241 dir = nis_clone_directory (&res->objects.objects_val->DI_data, NULL);
242 nis_freeresult (res);
244 return dir;
247 static directory_obj *
248 rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
250 char domain [strlen (name) + 3];
252 nis_domain_of_r (name, domain, sizeof (domain));
253 if (strncmp (domain, "org_dir.", 8) == 0)
255 char tmp[strlen (name) + 3];
257 nis_domain_of_r (domain, tmp, sizeof (tmp));
258 strcpy (domain, tmp);
260 else
261 if (strncmp (domain, "groups_dir.", 11) == 0)
263 char tmp[strlen (name) + 3];
265 nis_domain_of_r (domain, tmp, sizeof (tmp));
266 strcpy (domain, tmp);
268 else
270 /* We have no grous_dir or org_dir, so try the complete name */
271 strcpy (domain, name);
274 switch (nis_dir_cmp (domain, dir->do_name))
276 case SAME_NAME:
277 return dir;
278 case NOT_SEQUENTIAL:
279 /* NOT_SEQUENTIAL means, go one up and try it there ! */
280 case HIGHER_NAME:
281 { /* We need data from a parent domain */
282 directory_obj *obj;
283 char ndomain [strlen (name) + 3];
285 nis_domain_of_r (dir->do_name, ndomain, sizeof (ndomain));
287 /* The root server of our domain is a replica of the parent
288 domain ! (Now I understand why a root server must be a
289 replica of the parent domain) */
290 obj = dir_lookup (ndomain, dir->do_servers.do_servers_val,
291 flags);
292 if (obj != NULL)
294 /* We have found a NIS+ server serving ndomain, now
295 let us search for "name" */
296 nis_free_directory (dir);
297 return rec_dirsearch (name, obj, flags);
299 else
301 /* Ups, very bad. Are we already the root server ? */
302 nis_free_directory (dir);
303 return NULL;
306 break;
307 case LOWER_NAME:
309 directory_obj *obj;
310 char leaf [strlen (name) + 3];
311 char ndomain [strlen (name) + 3];
312 u_int i;
316 if (strlen (domain) == 0)
318 nis_free_directory (dir);
319 return NULL;
321 nis_leaf_of_r (domain, leaf, sizeof (leaf));
322 nis_domain_of_r (domain, ndomain, sizeof (ndomain));
323 strcpy (domain, ndomain);
325 while (nis_dir_cmp (domain, dir->do_name) != SAME_NAME);
326 strcat (leaf, ".");
327 strcat (leaf, domain);
329 for (i = 0; i < dir->do_servers.do_servers_len; ++i)
331 obj = dir_lookup (leaf, &dir->do_servers.do_servers_val[i],
332 flags);
333 if (obj != NULL)
335 /* We have found a NIS+ server serving ndomain, now
336 let us search for "name" */
337 nis_free_directory (dir);
338 return rec_dirsearch (name, obj, flags);
342 break;
343 case BAD_NAME:
344 nis_free_directory (dir);
345 return NULL;
347 nis_free_directory (dir);
348 return NULL;
351 nis_error
352 __do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs,
353 caddr_t req, xdrproc_t xres, caddr_t resp, u_long flags)
355 nis_error result;
356 directory_obj *dir = NULL;
357 const nis_server *server;
358 u_int server_len;
361 dir = readColdStartFile ();
362 if (dir == NULL) /* No /var/nis/NIS_COLD_START -> no NIS+ installed */
363 return NIS_UNAVAIL;
365 if (name != NULL)
367 dir = rec_dirsearch (name, dir, flags);
368 if (dir == NULL)
370 if (nis_dir_cmp (nis_local_directory(), name) == NOT_SEQUENTIAL)
371 return NIS_NAMEUNREACHABLE;
372 else
373 return NIS_NOTFOUND;
376 server = dir->do_servers.do_servers_val;
377 server_len = dir->do_servers.do_servers_len;
379 if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1)
380 server_len = 1; /* The first entry is the master */
382 result = __do_niscall2 (server, server_len, prog, xargs, req, xres,
383 resp, flags);
384 if (dir != NULL)
385 nis_free_directory (dir);
387 return result;