]> git.ipfire.org Git - thirdparty/glibc.git/blame - nis/nis_call.c
Update.
[thirdparty/glibc.git] / nis / nis_call.c
CommitLineData
ac9f45cf 1/* Copyright (C) 1997, 1998 Free Software Foundation, Inc.
e61abf83
UD
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
36a8586d 20#include <errno.h>
2d7da676 21#include <fcntl.h>
e61abf83
UD
22#include <string.h>
23#include <rpc/rpc.h>
24#include <rpc/auth.h>
25#include <rpcsvc/nis.h>
26#include <sys/socket.h>
27#include <netinet/in.h>
28#include <arpa/inet.h>
29#include "nis_intern.h"
30
cc3fa755
UD
31static struct timeval RPCTIMEOUT = {10, 0};
32static struct timeval UDPTIMEOUT = {5, 0};
2d7da676 33
3996f34b 34unsigned long
e61abf83
UD
35inetstr2int (const char *str)
36{
37 char buffer[strlen (str) + 3];
38 size_t buflen;
39 size_t i, j;
40
41 buflen = stpcpy (buffer, str) - buffer;
42
43 j = 0;
44 for (i = 0; i < buflen; ++i)
45 if (buffer[i] == '.')
46 {
47 ++j;
48 if (j == 4)
49 {
50 buffer[i] = '\0';
51 break;
52 }
53 }
54
55 return inet_addr (buffer);
56}
57
2d7da676
UD
58static void
59__bind_destroy (dir_binding *bind)
e61abf83 60{
2d7da676 61 if (bind->clnt != NULL)
e61abf83 62 {
2d7da676
UD
63 if (bind->use_auth)
64 auth_destroy (bind->clnt->cl_auth);
65 clnt_destroy (bind->clnt);
66 }
67 free (bind->server_val);
68 free (bind);
69}
70
71static nis_error
72__bind_next (dir_binding *bind)
73{
3996f34b 74 u_int j;
2d7da676
UD
75
76 if (bind->clnt != NULL)
77 {
78 if (bind->use_auth)
79 auth_destroy (bind->clnt->cl_auth);
80 clnt_destroy (bind->clnt);
81 bind->clnt = NULL;
82 }
3996f34b
UD
83
84 if (bind->trys >= bind->server_len)
85 return NIS_FAIL;
86
87 for (j = bind->current_ep + 1;
88 j < bind->server_val[bind->server_used].ep.ep_len; ++j)
89 if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].family,
90 "inet") == 0)
91 if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].proto,
92 "-") == 0)
93 {
94 bind->current_ep = j;
95 return NIS_SUCCESS;
96 }
97
98 ++bind->trys;
99 ++bind->server_used;
100 if (bind->server_used >= bind->server_len)
101 bind->server_used = 0;
102
650425ce 103 for (j = 0; j < bind->server_val[bind->server_used].ep.ep_len; ++j)
3996f34b
UD
104 if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].family,
105 "inet") == 0)
106 if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].proto,
107 "-") == 0)
108 {
109 bind->current_ep = j;
110 return NIS_SUCCESS;
111 }
112
113 return NIS_FAIL;
2d7da676
UD
114}
115
116static nis_error
117__bind_connect (dir_binding *dbp)
118{
119 struct sockaddr_in check;
120 nis_server *serv;
121 int checklen;
2d7da676
UD
122
123 if (dbp == NULL)
124 return NIS_FAIL;
125
126 serv = &dbp->server_val[dbp->server_used];
127
128 memset (&dbp->addr, '\0', sizeof (dbp->addr));
129 dbp->addr.sin_family = AF_INET;
3996f34b
UD
130
131 dbp->addr.sin_addr.s_addr =
132 inetstr2int (serv->ep.ep_val[dbp->current_ep].uaddr);
133
2d7da676
UD
134 if (dbp->addr.sin_addr.s_addr == 0)
135 return NIS_FAIL;
136
137 dbp->socket = RPC_ANYSOCK;
138 if (dbp->use_udp)
139 dbp->clnt = clntudp_create (&dbp->addr, NIS_PROG, NIS_VERSION,
cc3fa755 140 UDPTIMEOUT, &dbp->socket);
2d7da676
UD
141 else
142 dbp->clnt = clnttcp_create (&dbp->addr, NIS_PROG, NIS_VERSION,
143 &dbp->socket, 0, 0);
3996f34b 144
2d7da676
UD
145 if (dbp->clnt == NULL)
146 return NIS_RPCERROR;
3996f34b 147
cc3fa755 148 clnt_control (dbp->clnt, CLSET_TIMEOUT, (caddr_t)&RPCTIMEOUT);
2d7da676
UD
149 /* If the program exists, close the socket */
150 if (fcntl (dbp->socket, F_SETFD, 1) == -1)
151 perror (_("fcntl: F_SETFD"));
3996f34b 152
2d7da676
UD
153 if (dbp->use_auth)
154 {
2d7da676 155 if (serv->key_type == NIS_PK_DH)
e61abf83 156 {
2d7da676
UD
157 char netname[MAXNETNAMELEN+1];
158 char *p;
3996f34b 159
2d7da676
UD
160 p = stpcpy (netname, "unix.");
161 strncpy (p, serv->name,MAXNETNAMELEN-5);
162 netname[MAXNETNAMELEN] = '\0';
163 p = strchr (netname, '.');
164 *p = '@';
165 dbp->clnt->cl_auth =
166 authdes_pk_create (netname, &serv->pkey, 300, NULL, NULL);
167 if (!dbp->clnt->cl_auth)
168 dbp->clnt->cl_auth = authunix_create_default ();
e61abf83 169 }
2d7da676 170 else
2d7da676
UD
171 dbp->clnt->cl_auth = authunix_create_default ();
172 dbp->use_auth = TRUE;
173 }
3996f34b 174
2d7da676
UD
175 /* Get port for sanity checks later */
176 checklen = sizeof (struct sockaddr_in);
177 memset (&check, 0, checklen);
178 if (dbp->use_udp)
179 bind (dbp->socket, (struct sockaddr *)&check, checklen);
180 check.sin_family = AF_INET;
181 if (!getsockname (dbp->socket, (struct sockaddr *)&check, &checklen))
182 dbp->port = check.sin_port;
183
184 dbp->create = time (NULL);
185
186 return NIS_SUCCESS;
187}
26dee9c4 188
2d7da676 189static dir_binding *
ac9f45cf
UD
190__bind_create (const nis_server *serv_val, u_int serv_len, u_long flags,
191 cache2_info *cinfo)
2d7da676
UD
192{
193 dir_binding *dbp;
194 u_int i;
3996f34b 195
2d7da676
UD
196 dbp = calloc (1, sizeof (dir_binding));
197 if (dbp == NULL)
198 return NULL;
3996f34b 199
2d7da676
UD
200 dbp->server_len = serv_len;
201 dbp->server_val = calloc (1, sizeof (nis_server) * serv_len);
202 if (dbp->server_val == NULL)
203 {
204 free (dbp);
205 return NULL;
206 }
3996f34b
UD
207
208 if (flags & USE_DGRAM)
209 dbp->use_udp = TRUE;
210 else
211 dbp->use_udp = FALSE;
212
213 if (flags & NO_AUTHINFO)
214 dbp->use_auth = FALSE;
215 else
216 dbp->use_auth = TRUE;
217
218 if (flags & MASTER_ONLY)
219 dbp->master_only = TRUE;
220 else
221 dbp->master_only = FALSE;
222
223 dbp->trys = 1;
224
2d7da676
UD
225 for (i = 0; i < serv_len; ++i)
226 {
227 if (serv_val[i].name != NULL)
228 dbp->server_val[i].name = strdup (serv_val[i].name);
3996f34b 229
2d7da676
UD
230 dbp->server_val[i].ep.ep_len = serv_val[i].ep.ep_len;
231 if (dbp->server_val[i].ep.ep_len > 0)
26dee9c4 232 {
2d7da676 233 unsigned long j;
3996f34b 234
2d7da676
UD
235 dbp->server_val[i].ep.ep_val =
236 malloc (serv_val[i].ep.ep_len * sizeof (endpoint));
237 for (j = 0; j < dbp->server_val[i].ep.ep_len; ++j)
26dee9c4 238 {
2d7da676
UD
239 if (serv_val[i].ep.ep_val[j].uaddr)
240 dbp->server_val[i].ep.ep_val[j].uaddr =
241 strdup (serv_val[i].ep.ep_val[j].uaddr);
242 else
243 dbp->server_val[i].ep.ep_val[j].uaddr = NULL;
244 if (serv_val[i].ep.ep_val[j].family)
245 dbp->server_val[i].ep.ep_val[j].family =
246 strdup (serv_val[i].ep.ep_val[j].family);
247 else
248 dbp->server_val[i].ep.ep_val[j].family = NULL;
249 if (serv_val[i].ep.ep_val[j].proto)
250 dbp->server_val[i].ep.ep_val[j].proto =
251 strdup (serv_val[i].ep.ep_val[j].proto);
252 else
253 dbp->server_val[i].ep.ep_val[j].proto = NULL;
26dee9c4 254 }
26dee9c4 255 }
2d7da676
UD
256 else
257 dbp->server_val[i].ep.ep_val = NULL;
258 dbp->server_val[i].key_type = serv_val[i].key_type;
259 dbp->server_val[i].pkey.n_len = serv_val[i].pkey.n_len;
260 if (serv_val[i].pkey.n_len > 0)
261 {
262 dbp->server_val[i].pkey.n_bytes =
263 malloc (serv_val[i].pkey.n_len);
264 if (dbp->server_val[i].pkey.n_bytes == NULL)
265 return NULL;
266 memcpy (dbp->server_val[i].pkey.n_bytes, serv_val[i].pkey.n_bytes,
267 serv_val[i].pkey.n_len);
268 }
269 else
270 dbp->server_val[i].pkey.n_bytes = NULL;
e61abf83 271 }
2d7da676 272
ac9f45cf
UD
273 dbp->class = -1;
274 if (cinfo != NULL && cinfo->server_used >= 0)
275 {
276 dbp->server_used = cinfo->server_used;
277 dbp->current_ep = cinfo->current_ep;
278 dbp->class = cinfo->class;
279 }
280 else if (__nis_findfastest (dbp) < 1)
3996f34b
UD
281 {
282 __bind_destroy (dbp);
283 return NULL;
284 }
2d7da676
UD
285
286 return dbp;
e61abf83
UD
287}
288
289nis_error
43b0e40f
UD
290__do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
291 xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp,
ac9f45cf 292 u_long flags, nis_cb *cb, cache2_info *cinfo)
e61abf83 293{
2d7da676
UD
294 enum clnt_stat result;
295 nis_error retcode;
296 dir_binding *dbp;
297
3996f34b 298 if (flags & MASTER_ONLY)
2d7da676 299 server_len = 1;
3996f34b 300
ac9f45cf
UD
301 dbp = __bind_create (server, server_len, flags, cinfo);
302 if (dbp == NULL)
a5a0310d 303 return NIS_NAMEUNREACHABLE;
2d7da676 304 while (__bind_connect (dbp) != NIS_SUCCESS)
e61abf83 305 {
2d7da676 306 if (__bind_next (dbp) != NIS_SUCCESS)
e61abf83 307 {
2d7da676
UD
308 __bind_destroy (dbp);
309 return NIS_NAMEUNREACHABLE;
e61abf83
UD
310 }
311 }
312
2d7da676 313 do
43b0e40f 314 {
2d7da676 315 again:
cc3fa755 316 result = clnt_call (dbp->clnt, prog, xargs, req, xres, resp, RPCTIMEOUT);
3996f34b 317
43b0e40f
UD
318 if (result != RPC_SUCCESS)
319 {
2d7da676
UD
320 clnt_perror (dbp->clnt, "__do_niscall2: clnt_call");
321 __bind_destroy (dbp);
322 retcode = NIS_RPCERROR;
43b0e40f
UD
323 }
324 else
2d7da676
UD
325 {
326 switch (prog)
327 {
650425ce
UD
328 case NIS_IBLIST:
329 if ((((nis_result *)resp)->status == NIS_CBRESULTS) &&
330 (cb != NULL))
331 {
332 __nis_do_callback(dbp, &((nis_result *)resp)->cookie, cb);
333 break;
334 }
335 /* Yes, this is correct. If we doesn't have to start
336 a callback, look if we have to search another server */
2d7da676
UD
337 case NIS_LOOKUP:
338 case NIS_ADD:
339 case NIS_MODIFY:
340 case NIS_REMOVE:
2d7da676
UD
341 case NIS_IBADD:
342 case NIS_IBMODIFY:
343 case NIS_IBREMOVE:
344 case NIS_IBFIRST:
345 case NIS_IBNEXT:
650425ce
UD
346 if ((((nis_result *)resp)->status == NIS_NOTFOUND) ||
347 (((nis_result *)resp)->status == NIS_NOSUCHNAME) ||
348 (((nis_result *)resp)->status == NIS_NOT_ME))
3996f34b
UD
349 {
350 if (__bind_next (dbp) == NIS_SUCCESS)
650425ce
UD
351 {
352 while (__bind_connect (dbp) != NIS_SUCCESS)
353 {
354 if (__bind_next (dbp) != NIS_SUCCESS)
355 {
356 __bind_destroy (dbp);
357 return NIS_SUCCESS;
358 }
359 }
360 }
361 else
362 break; /* No more servers to search in */
2d7da676 363 goto again;
3996f34b 364 }
a5a0310d 365 break;
2d7da676 366 case NIS_FINDDIRECTORY:
650425ce
UD
367 if ((((fd_result *)resp)->status == NIS_NOTFOUND) ||
368 (((fd_result *)resp)->status == NIS_NOSUCHNAME) ||
369 (((fd_result *)resp)->status == NIS_NOT_ME))
3996f34b
UD
370 {
371 if (__bind_next (dbp) == NIS_SUCCESS)
650425ce
UD
372 {
373 while (__bind_connect (dbp) != NIS_SUCCESS)
374 {
375 if (__bind_next (dbp) != NIS_SUCCESS)
376 {
377 __bind_destroy (dbp);
378 return NIS_SUCCESS;
379 }
380 }
381 }
382 else
383 break; /* No more servers to search in */
2d7da676 384 goto again;
3996f34b 385 }
2d7da676
UD
386 break;
387 case NIS_DUMPLOG: /* log_result */
388 case NIS_DUMP:
650425ce
UD
389 if ((((log_result *)resp)->lr_status == NIS_NOTFOUND) ||
390 (((log_result *)resp)->lr_status == NIS_NOSUCHNAME) ||
391 (((log_result *)resp)->lr_status == NIS_NOT_ME))
3996f34b
UD
392 {
393 if (__bind_next (dbp) == NIS_SUCCESS)
650425ce
UD
394 {
395 while (__bind_connect (dbp) != NIS_SUCCESS)
396 {
397 if (__bind_next (dbp) != NIS_SUCCESS)
398 {
399 __bind_destroy (dbp);
400 return NIS_SUCCESS;
401 }
402 }
403 }
404 else
405 break; /* No more servers to search in */
3996f34b
UD
406 goto again;
407 }
2d7da676 408 break;
2d7da676
UD
409 default:
410 break;
411 }
412 __bind_destroy (dbp);
413 retcode = NIS_SUCCESS;
414 }
43b0e40f 415 }
2d7da676 416 while ((flags & HARD_LOOKUP) && retcode == NIS_RPCERROR);
3996f34b
UD
417
418 return retcode;
43b0e40f
UD
419}
420
421static directory_obj *
3996f34b
UD
422rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags,
423 nis_error *status)
43b0e40f 424{
2d7da676
UD
425 fd_result *fd_res;
426 XDR xdrs;
43b0e40f
UD
427 char domain [strlen (name) + 3];
428
429 nis_domain_of_r (name, domain, sizeof (domain));
430 if (strncmp (domain, "org_dir.", 8) == 0)
431 {
432 char tmp[strlen (name) + 3];
433
434 nis_domain_of_r (domain, tmp, sizeof (tmp));
435 strcpy (domain, tmp);
436 }
437 else
438 if (strncmp (domain, "groups_dir.", 11) == 0)
439 {
440 char tmp[strlen (name) + 3];
441
442 nis_domain_of_r (domain, tmp, sizeof (tmp));
443 strcpy (domain, tmp);
444 }
445 else
446 {
447 /* We have no grous_dir or org_dir, so try the complete name */
448 strcpy (domain, name);
449 }
450
451 switch (nis_dir_cmp (domain, dir->do_name))
452 {
453 case SAME_NAME:
3996f34b 454 *status = NIS_SUCCESS;
43b0e40f
UD
455 return dir;
456 case NOT_SEQUENTIAL:
457 /* NOT_SEQUENTIAL means, go one up and try it there ! */
458 case HIGHER_NAME:
459 { /* We need data from a parent domain */
460 directory_obj *obj;
461 char ndomain [strlen (name) + 3];
462
463 nis_domain_of_r (dir->do_name, ndomain, sizeof (ndomain));
464
465 /* The root server of our domain is a replica of the parent
466 domain ! (Now I understand why a root server must be a
467 replica of the parent domain) */
2d7da676 468 fd_res = __nis_finddirectory (dir, ndomain);
3996f34b 469 *status = fd_res->status;
2d7da676
UD
470 if (fd_res->status != NIS_SUCCESS)
471 {
472 nis_free_directory (dir);
af6f3906 473 __free_fdresult (fd_res);
2d7da676
UD
474 return NULL;
475 }
2d7da676
UD
476 obj = calloc(1, sizeof(directory_obj));
477 xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val,
478 fd_res->dir_data.dir_data_len, XDR_DECODE);
479 xdr_directory_obj(&xdrs, obj);
480 xdr_destroy(&xdrs);
dfd2257a 481 __free_fdresult (fd_res);
43b0e40f
UD
482 if (obj != NULL)
483 {
484 /* We have found a NIS+ server serving ndomain, now
485 let us search for "name" */
486 nis_free_directory (dir);
3996f34b 487 return rec_dirsearch (name, obj, flags, status);
43b0e40f
UD
488 }
489 else
490 {
491 /* Ups, very bad. Are we already the root server ? */
492 nis_free_directory (dir);
493 return NULL;
494 }
495 }
2d7da676 496 break;
43b0e40f
UD
497 case LOWER_NAME:
498 {
499 directory_obj *obj;
500 char leaf [strlen (name) + 3];
501 char ndomain [strlen (name) + 3];
714a562f 502 char *cp;
3996f34b 503
43b0e40f
UD
504 do
505 {
506 if (strlen (domain) == 0)
507 {
508 nis_free_directory (dir);
509 return NULL;
510 }
511 nis_leaf_of_r (domain, leaf, sizeof (leaf));
512 nis_domain_of_r (domain, ndomain, sizeof (ndomain));
513 strcpy (domain, ndomain);
514 }
515 while (nis_dir_cmp (domain, dir->do_name) != SAME_NAME);
714a562f
UD
516 cp = strchr (leaf, '\0');
517 *cp++ = '.';
518 strcpy (cp, domain);
3996f34b 519
2d7da676 520 fd_res = __nis_finddirectory (dir, leaf);
3996f34b 521 *status = fd_res->status;
2d7da676 522 if (fd_res->status != NIS_SUCCESS)
43b0e40f 523 {
2d7da676 524 nis_free_directory (dir);
af6f3906 525 __free_fdresult (fd_res);
2d7da676
UD
526 return NULL;
527 }
2d7da676
UD
528 obj = calloc(1, sizeof(directory_obj));
529 xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val,
530 fd_res->dir_data.dir_data_len, XDR_DECODE);
531 xdr_directory_obj(&xdrs, obj);
532 xdr_destroy(&xdrs);
dfd2257a 533 __free_fdresult (fd_res);
2d7da676
UD
534 if (obj != NULL)
535 {
536 /* We have found a NIS+ server serving ndomain, now
537 let us search for "name" */
538 nis_free_directory (dir);
3996f34b 539 return rec_dirsearch (name, obj, flags, status);
43b0e40f
UD
540 }
541 }
2d7da676 542 break;
43b0e40f
UD
543 case BAD_NAME:
544 nis_free_directory (dir);
3996f34b 545 *status = NIS_BADNAME;
43b0e40f
UD
546 return NULL;
547 }
548 nis_free_directory (dir);
3996f34b 549 *status = NIS_FAIL;
43b0e40f
UD
550 return NULL;
551}
552
553nis_error
554__do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs,
650425ce
UD
555 caddr_t req, xdrproc_t xres, caddr_t resp, u_long flags,
556 nis_cb *cb)
43b0e40f 557{
2d7da676 558 nis_error retcode;
43b0e40f 559 directory_obj *dir = NULL;
2d7da676 560 nis_server *server;
43b0e40f 561 u_int server_len;
ac9f45cf 562 cache2_info cinfo = {-1, -1, -1};
36a8586d 563 int saved_errno = errno;
43b0e40f 564
2d7da676
UD
565 if (name == NULL)
566 return NIS_BADNAME;
43b0e40f 567
ac9f45cf
UD
568 /* Search in local cache. In the moment, we ignore the fastest server */
569 if (!(flags & NO_CACHE))
570 dir = __nis_cache_search (name, flags, &cinfo);
571
2d7da676 572 if (dir == NULL)
43b0e40f 573 {
3996f34b 574 nis_error status;
2d7da676
UD
575 dir = readColdStartFile ();
576 if (dir == NULL) /* No /var/nis/NIS_COLD_START->no NIS+ installed */
36a8586d
UD
577 {
578 __set_errno (saved_errno);
579 return NIS_UNAVAIL;
580 }
3996f34b
UD
581
582 dir = rec_dirsearch (name, dir, flags, &status);
43b0e40f 583 if (dir == NULL)
3996f34b 584 return status;
43b0e40f 585 }
43b0e40f 586
3996f34b 587 if (flags & MASTER_ONLY)
2d7da676
UD
588 {
589 server = dir->do_servers.do_servers_val;
590 server_len = 1;
591 }
592 else
593 {
594 server = dir->do_servers.do_servers_val;
595 server_len = dir->do_servers.do_servers_len;
596 }
3996f34b
UD
597
598
2d7da676 599 retcode = __do_niscall2 (server, server_len, prog, xargs, req, xres, resp,
ac9f45cf 600 flags, cb, &cinfo);
3996f34b 601
2d7da676 602 nis_free_directory (dir);
43b0e40f 603
2d7da676 604 return retcode;
e61abf83 605}