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