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