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