]>
git.ipfire.org Git - thirdparty/glibc.git/blob - nis/nis_call.c
1 /* Copyright (C) 1997, 1998 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.
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.
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.
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. */
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"
31 static struct timeval RPCTIMEOUT
= {10, 0};
32 static struct timeval UDPTIMEOUT
= {5, 0};
34 extern u_short
__pmap_getnisport (struct sockaddr_in
*address
, u_long program
,
35 u_long version
, u_int protocol
);
38 inetstr2int (const char *str
)
40 char buffer
[strlen (str
) + 3];
44 buflen
= stpcpy (buffer
, str
) - buffer
;
47 for (i
= 0; i
< buflen
; ++i
)
58 return inet_addr (buffer
);
62 __bind_destroy (dir_binding
*bind
)
64 if (bind
->clnt
!= NULL
)
67 auth_destroy (bind
->clnt
->cl_auth
);
68 clnt_destroy (bind
->clnt
);
70 free (bind
->server_val
);
75 __bind_next (dir_binding
*bind
)
79 if (bind
->clnt
!= NULL
)
82 auth_destroy (bind
->clnt
->cl_auth
);
83 clnt_destroy (bind
->clnt
);
87 if (bind
->trys
>= bind
->server_len
)
90 for (j
= bind
->current_ep
+ 1;
91 j
< bind
->server_val
[bind
->server_used
].ep
.ep_len
; ++j
)
92 if (strcmp (bind
->server_val
[bind
->server_used
].ep
.ep_val
[j
].family
,
94 if (strcmp (bind
->server_val
[bind
->server_used
].ep
.ep_val
[j
].proto
,
103 if (bind
->server_used
>= bind
->server_len
)
104 bind
->server_used
= 0;
106 for (j
= 0; j
< bind
->server_val
[bind
->server_used
].ep
.ep_len
; ++j
)
107 if (strcmp (bind
->server_val
[bind
->server_used
].ep
.ep_val
[j
].family
,
109 if (strcmp (bind
->server_val
[bind
->server_used
].ep
.ep_val
[j
].proto
,
112 bind
->current_ep
= j
;
120 __bind_connect (dir_binding
*dbp
)
122 struct sockaddr_in check
;
129 serv
= &dbp
->server_val
[dbp
->server_used
];
131 memset (&dbp
->addr
, '\0', sizeof (dbp
->addr
));
132 dbp
->addr
.sin_family
= AF_INET
;
134 dbp
->addr
.sin_addr
.s_addr
=
135 inetstr2int (serv
->ep
.ep_val
[dbp
->current_ep
].uaddr
);
137 if (dbp
->addr
.sin_addr
.s_addr
== 0)
140 /* Check, if the host is online and rpc.nisd is running. Much faster
141 then the clnt*_create functions: */
142 if (__pmap_getnisport (&dbp
->addr
, NIS_PROG
, NIS_VERSION
, IPPROTO_UDP
) == 0)
145 dbp
->socket
= RPC_ANYSOCK
;
147 dbp
->clnt
= clntudp_create (&dbp
->addr
, NIS_PROG
, NIS_VERSION
,
148 UDPTIMEOUT
, &dbp
->socket
);
150 dbp
->clnt
= clnttcp_create (&dbp
->addr
, NIS_PROG
, NIS_VERSION
,
153 if (dbp
->clnt
== NULL
)
156 clnt_control (dbp
->clnt
, CLSET_TIMEOUT
, (caddr_t
)&RPCTIMEOUT
);
157 /* If the program exists, close the socket */
158 if (fcntl (dbp
->socket
, F_SETFD
, 1) == -1)
159 perror (_("fcntl: F_SETFD"));
163 if (serv
->key_type
== NIS_PK_DH
&& key_secretkey_is_set ())
165 char netname
[MAXNETNAMELEN
+1];
168 p
= stpcpy (netname
, "unix.");
169 strncpy (p
, serv
->name
,MAXNETNAMELEN
-5);
170 netname
[MAXNETNAMELEN
] = '\0';
171 p
= strchr (netname
, '.');
174 authdes_pk_create (netname
, &serv
->pkey
, 300, NULL
, NULL
);
175 if (!dbp
->clnt
->cl_auth
)
176 dbp
->clnt
->cl_auth
= authunix_create_default ();
179 dbp
->clnt
->cl_auth
= authunix_create_default ();
180 dbp
->use_auth
= TRUE
;
183 /* Get port for sanity checks later */
184 checklen
= sizeof (struct sockaddr_in
);
185 memset (&check
, 0, checklen
);
187 bind (dbp
->socket
, (struct sockaddr
*)&check
, checklen
);
188 check
.sin_family
= AF_INET
;
189 if (!getsockname (dbp
->socket
, (struct sockaddr
*)&check
, &checklen
))
190 dbp
->port
= check
.sin_port
;
192 dbp
->create
= time (NULL
);
198 __bind_create (const nis_server
*serv_val
, u_int serv_len
, u_long flags
,
204 dbp
= calloc (1, sizeof (dir_binding
));
208 dbp
->server_len
= serv_len
;
209 dbp
->server_val
= calloc (1, sizeof (nis_server
) * serv_len
);
210 if (dbp
->server_val
== NULL
)
216 if (flags
& USE_DGRAM
)
219 dbp
->use_udp
= FALSE
;
221 if (flags
& NO_AUTHINFO
)
222 dbp
->use_auth
= FALSE
;
224 dbp
->use_auth
= TRUE
;
226 if (flags
& MASTER_ONLY
)
227 dbp
->master_only
= TRUE
;
229 dbp
->master_only
= FALSE
;
231 /* We try the first server */
234 for (i
= 0; i
< serv_len
; ++i
)
236 if (serv_val
[i
].name
!= NULL
)
237 dbp
->server_val
[i
].name
= strdup (serv_val
[i
].name
);
239 dbp
->server_val
[i
].ep
.ep_len
= serv_val
[i
].ep
.ep_len
;
240 if (dbp
->server_val
[i
].ep
.ep_len
> 0)
244 dbp
->server_val
[i
].ep
.ep_val
=
245 malloc (serv_val
[i
].ep
.ep_len
* sizeof (endpoint
));
246 for (j
= 0; j
< dbp
->server_val
[i
].ep
.ep_len
; ++j
)
248 if (serv_val
[i
].ep
.ep_val
[j
].uaddr
)
249 dbp
->server_val
[i
].ep
.ep_val
[j
].uaddr
=
250 strdup (serv_val
[i
].ep
.ep_val
[j
].uaddr
);
252 dbp
->server_val
[i
].ep
.ep_val
[j
].uaddr
= NULL
;
253 if (serv_val
[i
].ep
.ep_val
[j
].family
)
254 dbp
->server_val
[i
].ep
.ep_val
[j
].family
=
255 strdup (serv_val
[i
].ep
.ep_val
[j
].family
);
257 dbp
->server_val
[i
].ep
.ep_val
[j
].family
= NULL
;
258 if (serv_val
[i
].ep
.ep_val
[j
].proto
)
259 dbp
->server_val
[i
].ep
.ep_val
[j
].proto
=
260 strdup (serv_val
[i
].ep
.ep_val
[j
].proto
);
262 dbp
->server_val
[i
].ep
.ep_val
[j
].proto
= NULL
;
266 dbp
->server_val
[i
].ep
.ep_val
= NULL
;
267 dbp
->server_val
[i
].key_type
= serv_val
[i
].key_type
;
268 dbp
->server_val
[i
].pkey
.n_len
= serv_val
[i
].pkey
.n_len
;
269 if (serv_val
[i
].pkey
.n_len
> 0)
271 dbp
->server_val
[i
].pkey
.n_bytes
=
272 malloc (serv_val
[i
].pkey
.n_len
);
273 if (dbp
->server_val
[i
].pkey
.n_bytes
== NULL
)
275 memcpy (dbp
->server_val
[i
].pkey
.n_bytes
, serv_val
[i
].pkey
.n_bytes
,
276 serv_val
[i
].pkey
.n_len
);
279 dbp
->server_val
[i
].pkey
.n_bytes
= NULL
;
283 if (cinfo
!= NULL
&& cinfo
->server_used
>= 0)
285 dbp
->server_used
= cinfo
->server_used
;
286 dbp
->current_ep
= cinfo
->current_ep
;
287 dbp
->class = cinfo
->class;
289 else if (__nis_findfastest (dbp
) < 1)
291 __bind_destroy (dbp
);
299 __do_niscall2 (const nis_server
*server
, u_int server_len
, u_long prog
,
300 xdrproc_t xargs
, caddr_t req
, xdrproc_t xres
, caddr_t resp
,
301 u_long flags
, nis_cb
*cb
, cache2_info
*cinfo
)
303 enum clnt_stat result
;
307 if (flags
& MASTER_ONLY
)
310 dbp
= __bind_create (server
, server_len
, flags
, cinfo
);
312 return NIS_NAMEUNREACHABLE
;
313 while (__bind_connect (dbp
) != NIS_SUCCESS
)
315 if (__bind_next (dbp
) != NIS_SUCCESS
)
317 __bind_destroy (dbp
);
318 return NIS_NAMEUNREACHABLE
;
325 result
= clnt_call (dbp
->clnt
, prog
, xargs
, req
, xres
, resp
, RPCTIMEOUT
);
327 if (result
!= RPC_SUCCESS
)
329 __bind_destroy (dbp
);
330 retcode
= NIS_RPCERROR
;
337 if ((((nis_result
*)resp
)->status
== NIS_CBRESULTS
) &&
340 __nis_do_callback(dbp
, &((nis_result
*)resp
)->cookie
, cb
);
343 /* Yes, this is correct. If we doesn't have to start
344 a callback, look if we have to search another server */
354 if ((((nis_result
*)resp
)->status
== NIS_NOTFOUND
) ||
355 (((nis_result
*)resp
)->status
== NIS_NOSUCHNAME
) ||
356 (((nis_result
*)resp
)->status
== NIS_NOT_ME
))
358 if (__bind_next (dbp
) == NIS_SUCCESS
)
360 while (__bind_connect (dbp
) != NIS_SUCCESS
)
362 if (__bind_next (dbp
) != NIS_SUCCESS
)
364 __bind_destroy (dbp
);
370 break; /* No more servers to search in */
374 case NIS_FINDDIRECTORY
:
375 if ((((fd_result
*)resp
)->status
== NIS_NOTFOUND
) ||
376 (((fd_result
*)resp
)->status
== NIS_NOSUCHNAME
) ||
377 (((fd_result
*)resp
)->status
== NIS_NOT_ME
))
379 if (__bind_next (dbp
) == NIS_SUCCESS
)
381 while (__bind_connect (dbp
) != NIS_SUCCESS
)
383 if (__bind_next (dbp
) != NIS_SUCCESS
)
385 __bind_destroy (dbp
);
391 break; /* No more servers to search in */
395 case NIS_DUMPLOG
: /* log_result */
397 if ((((log_result
*)resp
)->lr_status
== NIS_NOTFOUND
) ||
398 (((log_result
*)resp
)->lr_status
== NIS_NOSUCHNAME
) ||
399 (((log_result
*)resp
)->lr_status
== NIS_NOT_ME
))
401 if (__bind_next (dbp
) == NIS_SUCCESS
)
403 while (__bind_connect (dbp
) != NIS_SUCCESS
)
405 if (__bind_next (dbp
) != NIS_SUCCESS
)
407 __bind_destroy (dbp
);
413 break; /* No more servers to search in */
420 __bind_destroy (dbp
);
421 retcode
= NIS_SUCCESS
;
424 while ((flags
& HARD_LOOKUP
) && retcode
== NIS_RPCERROR
);
429 static directory_obj
*
430 rec_dirsearch (const_nis_name name
, directory_obj
*dir
, u_long flags
,
436 switch (nis_dir_cmp (name
, dir
->do_name
))
439 *status
= NIS_SUCCESS
;
442 /* NOT_SEQUENTIAL means, go one up and try it there ! */
444 { /* We need data from a parent domain */
446 char ndomain
[strlen (name
) + 3];
448 nis_domain_of_r (dir
->do_name
, ndomain
, sizeof (ndomain
));
450 /* The root server of our domain is a replica of the parent
451 domain ! (Now I understand why a root server must be a
452 replica of the parent domain) */
453 fd_res
= __nis_finddirectory (dir
, ndomain
);
454 *status
= fd_res
->status
;
455 if (fd_res
->status
!= NIS_SUCCESS
)
457 /* Try the current directory obj, maybe it works */
458 __free_fdresult (fd_res
);
461 obj
= calloc(1, sizeof(directory_obj
));
462 xdrmem_create(&xdrs
, fd_res
->dir_data
.dir_data_val
,
463 fd_res
->dir_data
.dir_data_len
, XDR_DECODE
);
464 xdr_directory_obj(&xdrs
, obj
);
466 __free_fdresult (fd_res
);
469 /* We have found a NIS+ server serving ndomain, now
470 let us search for "name" */
471 nis_free_directory (dir
);
472 return rec_dirsearch (name
, obj
, flags
, status
);
476 /* Ups, very bad. Are we already the root server ? */
477 nis_free_directory (dir
);
485 char leaf
[strlen (name
) + 3];
486 char domain
[strlen (name
) + 3];
487 char ndomain
[strlen (name
) + 3];
491 strcpy (domain
, name
);
495 if (strlen (domain
) == 0)
497 nis_free_directory (dir
);
500 nis_leaf_of_r (domain
, leaf
, sizeof (leaf
));
501 nis_domain_of_r (domain
, ndomain
, sizeof (ndomain
));
502 strcpy (domain
, ndomain
);
505 while (nis_dir_cmp (domain
, dir
->do_name
) != SAME_NAME
);
509 /* We have found the directory above. Use it. */
513 cp
= strchr (leaf
, '\0');
517 fd_res
= __nis_finddirectory (dir
, leaf
);
518 *status
= fd_res
->status
;
519 if (fd_res
->status
!= NIS_SUCCESS
)
521 /* Try the current directory object, maybe it works */
522 __free_fdresult (fd_res
);
525 obj
= calloc(1, sizeof(directory_obj
));
526 xdrmem_create(&xdrs
, fd_res
->dir_data
.dir_data_val
,
527 fd_res
->dir_data
.dir_data_len
, XDR_DECODE
);
528 xdr_directory_obj(&xdrs
, obj
);
530 __free_fdresult (fd_res
);
533 /* We have found a NIS+ server serving ndomain, now
534 let us search for "name" */
535 nis_free_directory (dir
);
536 return rec_dirsearch (name
, obj
, flags
, status
);
541 nis_free_directory (dir
);
542 *status
= NIS_BADNAME
;
545 nis_free_directory (dir
);
550 /* We try to query the current server for the searched object,
551 maybe he know about it ? */
552 static directory_obj
*
553 first_shoot (const_nis_name name
, directory_obj
*dir
, u_long flags
)
558 char domain
[strlen (name
) + 3];
560 if (nis_dir_cmp (name
, dir
->do_name
) == SAME_NAME
)
563 nis_domain_of_r (name
, domain
, sizeof (domain
));
565 if (nis_dir_cmp (domain
, dir
->do_name
) == SAME_NAME
)
568 fd_res
= __nis_finddirectory (dir
, domain
);
569 if (fd_res
->status
!= NIS_SUCCESS
)
571 __free_fdresult (fd_res
);
574 obj
= calloc(1, sizeof(directory_obj
));
577 xdrmem_create(&xdrs
, fd_res
->dir_data
.dir_data_val
,
578 fd_res
->dir_data
.dir_data_len
, XDR_DECODE
);
579 xdr_directory_obj(&xdrs
, obj
);
581 __free_fdresult (fd_res
);
584 nis_free_directory (dir
);
591 __do_niscall (const_nis_name name
, u_long prog
, xdrproc_t xargs
,
592 caddr_t req
, xdrproc_t xres
, caddr_t resp
, u_long flags
,
596 directory_obj
*dir
= NULL
;
599 cache2_info cinfo
= {-1, -1, -1};
600 int saved_errno
= errno
;
605 /* Search in local cache. In the moment, we ignore the fastest server */
606 if (!(flags
& NO_CACHE
))
607 dir
= __nis_cache_search (name
, flags
, &cinfo
);
614 dir
= readColdStartFile ();
615 if (dir
== NULL
) /* No /var/nis/NIS_COLD_START->no NIS+ installed */
617 __set_errno (saved_errno
);
621 /* Try at first, if servers in "dir" know our object */
622 obj
= first_shoot (name
, dir
, flags
);
625 dir
= rec_dirsearch (name
, dir
, flags
, &status
);
628 __set_errno (saved_errno
);
636 if (flags
& MASTER_ONLY
)
638 server
= dir
->do_servers
.do_servers_val
;
643 server
= dir
->do_servers
.do_servers_val
;
644 server_len
= dir
->do_servers
.do_servers_len
;
648 retcode
= __do_niscall2 (server
, server_len
, prog
, xargs
, req
, xres
, resp
,
651 nis_free_directory (dir
);
653 __set_errno (saved_errno
);