]> git.ipfire.org Git - thirdparty/glibc.git/blob - nis/nis_call.c
Update.
[thirdparty/glibc.git] / nis / nis_call.c
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.
4
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.
9
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.
14
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. */
19
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"
28
29 static struct timeval TIMEOUT = {25, 0};
30 static int const MAXTRIES = 3;
31
32 static unsigned long
33 inetstr2int (const char *str)
34 {
35 char buffer[strlen (str) + 3];
36 size_t buflen;
37 size_t i, j;
38
39 buflen = stpcpy (buffer, str) - buffer;
40
41 j = 0;
42 for (i = 0; i < buflen; ++i)
43 if (buffer[i] == '.')
44 {
45 ++j;
46 if (j == 4)
47 {
48 buffer[i] = '\0';
49 break;
50 }
51 }
52
53 return inet_addr (buffer);
54 }
55
56 static CLIENT *
57 __nis_dobind (const nis_server *server, u_long flags)
58 {
59 struct sockaddr_in clnt_saddr;
60 int clnt_sock;
61 size_t i;
62 CLIENT *client = NULL;
63
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++)
67 {
68 if (strcmp (server->ep.ep_val[i].family,"loopback") == 0)
69 {
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)
74 {
75 if ((flags & USE_DGRAM) == USE_DGRAM)
76 clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
77 else
78 continue;
79 }
80 else
81 if (strcmp (server->ep.ep_val[i].proto,"tcp") == 0)
82 {
83 if ((flags & USE_DGRAM) == USE_DGRAM)
84 continue;
85 else
86 clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
87 }
88 }
89 else
90 if (strcmp (server->ep.ep_val[i].family,"inet") == 0)
91 {
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)
97 {
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;
103 }
104 else
105 if (strcmp (server->ep.ep_val[i].proto,"tcp") == 0)
106 {
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);
112 }
113 }
114 else
115 continue;
116
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);
124
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)
129 {
130 clnt_destroy (client);
131 continue;
132 }
133
134 if ((flags & NO_AUTHINFO) != NO_AUTHINFO)
135 {
136 #if defined(HAVE_SECURE_RPC)
137 if (server->key_type == NIS_PK_DH && getenv ("NO_SECURE_RPC") == NULL)
138 {
139 char netname[MAXNETNAMELEN+1];
140 char *p;
141
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 ();
151 }
152 else
153 #endif
154 client->cl_auth = authunix_create_default ();
155 }
156 return client;
157 }
158
159 return NULL;
160 }
161
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)
166 {
167 CLIENT *clnt;
168 int try, result;
169
170 try = 0;
171 result = NIS_NAMEUNREACHABLE;
172
173 if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1)
174 server_len = 1; /* The first entry is the master */
175
176 while (try < MAXTRIES && result != RPC_SUCCESS)
177 {
178 unsigned int i;
179
180 if ((flags & HARD_LOOKUP) == 0)
181 ++try;
182
183 for (i = 0; i < server_len; i++)
184 {
185 if ((clnt = __nis_dobind (&server[i], flags)) == NULL)
186 continue;
187
188 result = clnt_call (clnt, prog, xargs, req, xres, resp, TIMEOUT);
189
190 if (result != RPC_SUCCESS)
191 {
192 clnt_perror (clnt, "do_niscall: clnt_call");
193 clnt_destroy (clnt);
194 result = NIS_RPCERROR;
195 }
196 else
197 clnt_destroy (clnt);
198 }
199 }
200
201 return result;
202 }
203
204 static directory_obj *
205 dir_lookup (const_nis_name name, nis_server *serv, u_long flags)
206 {
207 CLIENT *clnt;
208 int try, result;
209 nis_result *res;
210 struct ns_request req;
211 directory_obj *dir;
212
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;
219
220 while (try < MAXTRIES && result != RPC_SUCCESS)
221 {
222 if ((clnt = __nis_dobind (serv, flags)) == NULL)
223 continue;
224
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);
228
229 if (result != RPC_SUCCESS)
230 {
231 clnt_perror (clnt, "do_niscall: clnt_call");
232 clnt_destroy (clnt);
233 result = NIS_RPCERROR;
234 }
235 else
236 clnt_destroy (clnt);
237 }
238 if (result != RPC_SUCCESS || res->status != NIS_SUCCESS)
239 return NULL;
240
241 dir = nis_clone_directory (&res->objects.objects_val->DI_data, NULL);
242 nis_freeresult (res);
243
244 return dir;
245 }
246
247 static directory_obj *
248 rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
249 {
250 char domain [strlen (name) + 3];
251
252 nis_domain_of_r (name, domain, sizeof (domain));
253 if (strncmp (domain, "org_dir.", 8) == 0)
254 {
255 char tmp[strlen (name) + 3];
256
257 nis_domain_of_r (domain, tmp, sizeof (tmp));
258 strcpy (domain, tmp);
259 }
260 else
261 if (strncmp (domain, "groups_dir.", 11) == 0)
262 {
263 char tmp[strlen (name) + 3];
264
265 nis_domain_of_r (domain, tmp, sizeof (tmp));
266 strcpy (domain, tmp);
267 }
268 else
269 {
270 /* We have no grous_dir or org_dir, so try the complete name */
271 strcpy (domain, name);
272 }
273
274 switch (nis_dir_cmp (domain, dir->do_name))
275 {
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];
284
285 nis_domain_of_r (dir->do_name, ndomain, sizeof (ndomain));
286
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)
293 {
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);
298 }
299 else
300 {
301 /* Ups, very bad. Are we already the root server ? */
302 nis_free_directory (dir);
303 return NULL;
304 }
305 }
306 break;
307 case LOWER_NAME:
308 {
309 directory_obj *obj;
310 char leaf [strlen (name) + 3];
311 char ndomain [strlen (name) + 3];
312 u_int i;
313
314 do
315 {
316 if (strlen (domain) == 0)
317 {
318 nis_free_directory (dir);
319 return NULL;
320 }
321 nis_leaf_of_r (domain, leaf, sizeof (leaf));
322 nis_domain_of_r (domain, ndomain, sizeof (ndomain));
323 strcpy (domain, ndomain);
324 }
325 while (nis_dir_cmp (domain, dir->do_name) != SAME_NAME);
326 strcat (leaf, ".");
327 strcat (leaf, domain);
328
329 for (i = 0; i < dir->do_servers.do_servers_len; ++i)
330 {
331 obj = dir_lookup (leaf, &dir->do_servers.do_servers_val[i],
332 flags);
333 if (obj != NULL)
334 {
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);
339 }
340 }
341 }
342 break;
343 case BAD_NAME:
344 nis_free_directory (dir);
345 return NULL;
346 }
347 nis_free_directory (dir);
348 return NULL;
349 }
350
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)
354 {
355 nis_error result;
356 directory_obj *dir = NULL;
357 const nis_server *server;
358 u_int server_len;
359
360
361 dir = readColdStartFile ();
362 if (dir == NULL) /* No /var/nis/NIS_COLD_START -> no NIS+ installed */
363 return NIS_UNAVAIL;
364
365 if (name != NULL)
366 {
367 dir = rec_dirsearch (name, dir, flags);
368 if (dir == NULL)
369 {
370 if (nis_dir_cmp (nis_local_directory(), name) == NOT_SEQUENTIAL)
371 return NIS_NAMEUNREACHABLE;
372 else
373 return NIS_NOTFOUND;
374 }
375 }
376 server = dir->do_servers.do_servers_val;
377 server_len = dir->do_servers.do_servers_len;
378
379 if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1)
380 server_len = 1; /* The first entry is the master */
381
382 result = __do_niscall2 (server, server_len, prog, xargs, req, xres,
383 resp, flags);
384 if (dir != NULL)
385 nis_free_directory (dir);
386
387 return result;
388 }