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>
31 #include "nis_intern.h"
33 static struct timeval RPCTIMEOUT
= {10, 0};
34 static struct timeval UDPTIMEOUT
= {5, 0};
36 extern u_short
__pmap_getnisport (struct sockaddr_in
*address
, u_long program
,
37 u_long version
, u_int protocol
);
40 inetstr2int (const char *str
)
42 char buffer
[strlen (str
) + 3];
46 buflen
= stpcpy (buffer
, str
) - buffer
;
49 for (i
= 0; i
< buflen
; ++i
)
60 return inet_addr (buffer
);
64 __bind_destroy (dir_binding
*bind
)
66 if (bind
->clnt
!= NULL
)
69 auth_destroy (bind
->clnt
->cl_auth
);
70 clnt_destroy (bind
->clnt
);
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 (bind
->server_val
[bind
->server_used
].ep
.ep_val
[j
].proto
[0] == '-')
111 bind
->current_ep
= j
;
119 __bind_connect (dir_binding
*dbp
)
126 serv
= &dbp
->server_val
[dbp
->server_used
];
128 memset (&dbp
->addr
, '\0', sizeof (dbp
->addr
));
129 dbp
->addr
.sin_family
= AF_INET
;
131 dbp
->addr
.sin_addr
.s_addr
=
132 inetstr2int (serv
->ep
.ep_val
[dbp
->current_ep
].uaddr
);
134 if (dbp
->addr
.sin_addr
.s_addr
== 0)
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)
142 dbp
->socket
= RPC_ANYSOCK
;
144 dbp
->clnt
= clntudp_create (&dbp
->addr
, NIS_PROG
, NIS_VERSION
,
145 UDPTIMEOUT
, &dbp
->socket
);
147 dbp
->clnt
= clnttcp_create (&dbp
->addr
, NIS_PROG
, NIS_VERSION
,
150 if (dbp
->clnt
== NULL
)
153 clnt_control (dbp
->clnt
, CLSET_TIMEOUT
, (caddr_t
)&RPCTIMEOUT
);
154 /* If the program exists, close the socket */
155 if (fcntl (dbp
->socket
, F_SETFD
, 1) == -1)
156 perror (_("fcntl: F_SETFD"));
160 if (serv
->key_type
== NIS_PK_DH
&& key_secretkey_is_set ())
162 char netname
[MAXNETNAMELEN
+1];
165 p
= stpcpy (netname
, "unix.");
166 strncpy (p
, serv
->name
,MAXNETNAMELEN
-5);
167 netname
[MAXNETNAMELEN
] = '\0';
168 p
= strchr (netname
, '.');
171 authdes_pk_create (netname
, &serv
->pkey
, 300, NULL
, NULL
);
172 if (!dbp
->clnt
->cl_auth
)
173 dbp
->clnt
->cl_auth
= authunix_create_default ();
176 dbp
->clnt
->cl_auth
= authunix_create_default ();
177 dbp
->use_auth
= TRUE
;
184 __bind_create (dir_binding
*dbp
, const nis_server
*serv_val
, u_int serv_len
,
185 u_long flags
, cache2_info
*cinfo
)
189 dbp
->server_len
= serv_len
;
190 dbp
->server_val
= (nis_server
*)serv_val
;
192 if (flags
& USE_DGRAM
)
195 dbp
->use_udp
= FALSE
;
197 if (flags
& NO_AUTHINFO
)
198 dbp
->use_auth
= FALSE
;
200 dbp
->use_auth
= TRUE
;
202 if (flags
& MASTER_ONLY
)
203 dbp
->master_only
= TRUE
;
205 dbp
->master_only
= FALSE
;
207 /* We try the first server */
211 if (cinfo
!= NULL
&& cinfo
->server_used
>= 0)
213 dbp
->server_used
= cinfo
->server_used
;
214 dbp
->current_ep
= cinfo
->current_ep
;
215 dbp
->class = cinfo
->class;
217 else if (__nis_findfastest (dbp
) < 1)
219 __bind_destroy (dbp
);
220 return NIS_NAMEUNREACHABLE
;
227 __do_niscall2 (const nis_server
*server
, u_int server_len
, u_long prog
,
228 xdrproc_t xargs
, caddr_t req
, xdrproc_t xres
, caddr_t resp
,
229 u_long flags
, nis_cb
*cb
, cache2_info
*cinfo
)
231 enum clnt_stat result
;
235 if (flags
& MASTER_ONLY
)
238 if (__bind_create (&dbp
, server
, server_len
, flags
, cinfo
) != NIS_SUCCESS
)
239 return NIS_NAMEUNREACHABLE
;
240 while (__bind_connect (&dbp
) != NIS_SUCCESS
)
242 if (__bind_next (&dbp
) != NIS_SUCCESS
)
244 __bind_destroy (&dbp
);
245 return NIS_NAMEUNREACHABLE
;
252 result
= clnt_call (dbp
.clnt
, prog
, xargs
, req
, xres
, resp
, RPCTIMEOUT
);
254 if (result
!= RPC_SUCCESS
)
256 __bind_destroy (&dbp
);
257 retcode
= NIS_RPCERROR
;
264 if ((((nis_result
*)resp
)->status
== NIS_CBRESULTS
) &&
267 __nis_do_callback(&dbp
, &((nis_result
*)resp
)->cookie
, cb
);
270 /* Yes, this is correct. If we doesn't have to start
271 a callback, look if we have to search another server */
281 if ((((nis_result
*)resp
)->status
== NIS_NOTFOUND
) ||
282 (((nis_result
*)resp
)->status
== NIS_NOSUCHNAME
) ||
283 (((nis_result
*)resp
)->status
== NIS_NOT_ME
))
285 if (__bind_next (&dbp
) == NIS_SUCCESS
)
287 while (__bind_connect (&dbp
) != NIS_SUCCESS
)
289 if (__bind_next (&dbp
) != NIS_SUCCESS
)
291 __bind_destroy (&dbp
);
297 break; /* No more servers to search in */
301 case NIS_FINDDIRECTORY
:
302 if ((((fd_result
*)resp
)->status
== NIS_NOTFOUND
) ||
303 (((fd_result
*)resp
)->status
== NIS_NOSUCHNAME
) ||
304 (((fd_result
*)resp
)->status
== NIS_NOT_ME
))
306 if (__bind_next (&dbp
) == NIS_SUCCESS
)
308 while (__bind_connect (&dbp
) != NIS_SUCCESS
)
310 if (__bind_next (&dbp
) != NIS_SUCCESS
)
312 __bind_destroy (&dbp
);
318 break; /* No more servers to search in */
322 case NIS_DUMPLOG
: /* log_result */
324 if ((((log_result
*)resp
)->lr_status
== NIS_NOTFOUND
) ||
325 (((log_result
*)resp
)->lr_status
== NIS_NOSUCHNAME
) ||
326 (((log_result
*)resp
)->lr_status
== NIS_NOT_ME
))
328 if (__bind_next (&dbp
) == NIS_SUCCESS
)
330 while (__bind_connect (&dbp
) != NIS_SUCCESS
)
332 if (__bind_next (&dbp
) != NIS_SUCCESS
)
334 __bind_destroy (&dbp
);
340 break; /* No more servers to search in */
347 __bind_destroy (&dbp
);
348 retcode
= NIS_SUCCESS
;
351 while ((flags
& HARD_LOOKUP
) && retcode
== NIS_RPCERROR
);
356 static directory_obj
*
357 rec_dirsearch (const_nis_name name
, directory_obj
*dir
, u_long flags
,
363 switch (nis_dir_cmp (name
, dir
->do_name
))
366 *status
= NIS_SUCCESS
;
369 /* NOT_SEQUENTIAL means, go one up and try it there ! */
371 { /* We need data from a parent domain */
373 char ndomain
[strlen (name
) + 3];
375 nis_domain_of_r (dir
->do_name
, ndomain
, sizeof (ndomain
));
377 /* The root server of our domain is a replica of the parent
378 domain ! (Now I understand why a root server must be a
379 replica of the parent domain) */
380 fd_res
= __nis_finddirectory (dir
, ndomain
);
381 *status
= fd_res
->status
;
382 if (fd_res
->status
!= NIS_SUCCESS
)
384 /* Try the current directory obj, maybe it works */
385 __free_fdresult (fd_res
);
388 obj
= calloc(1, sizeof(directory_obj
));
389 xdrmem_create(&xdrs
, fd_res
->dir_data
.dir_data_val
,
390 fd_res
->dir_data
.dir_data_len
, XDR_DECODE
);
391 _xdr_directory_obj(&xdrs
, obj
);
393 __free_fdresult (fd_res
);
396 /* We have found a NIS+ server serving ndomain, now
397 let us search for "name" */
398 nis_free_directory (dir
);
399 return rec_dirsearch (name
, obj
, flags
, status
);
403 /* Ups, very bad. Are we already the root server ? */
404 nis_free_directory (dir
);
412 size_t namelen
= strlen (name
);
413 char leaf
[namelen
+ 3];
414 char domain
[namelen
+ 3];
415 char ndomain
[namelen
+ 3];
419 strcpy (domain
, name
);
423 if (domain
[0] == '\0')
425 nis_free_directory (dir
);
428 nis_leaf_of_r (domain
, leaf
, sizeof (leaf
));
429 nis_domain_of_r (domain
, ndomain
, sizeof (ndomain
));
430 strcpy (domain
, ndomain
);
433 while (nis_dir_cmp (domain
, dir
->do_name
) != SAME_NAME
);
437 /* We have found the directory above. Use it. */
441 cp
= strchr (leaf
, '\0');
445 fd_res
= __nis_finddirectory (dir
, leaf
);
446 *status
= fd_res
->status
;
447 if (fd_res
->status
!= NIS_SUCCESS
)
449 /* Try the current directory object, maybe it works */
450 __free_fdresult (fd_res
);
453 obj
= calloc(1, sizeof(directory_obj
));
454 xdrmem_create(&xdrs
, fd_res
->dir_data
.dir_data_val
,
455 fd_res
->dir_data
.dir_data_len
, XDR_DECODE
);
456 _xdr_directory_obj(&xdrs
, obj
);
458 __free_fdresult (fd_res
);
461 /* We have found a NIS+ server serving ndomain, now
462 let us search for "name" */
463 nis_free_directory (dir
);
464 return rec_dirsearch (name
, obj
, flags
, status
);
469 nis_free_directory (dir
);
470 *status
= NIS_BADNAME
;
473 nis_free_directory (dir
);
478 /* We try to query the current server for the searched object,
479 maybe he know about it ? */
480 static directory_obj
*
481 first_shoot (const_nis_name name
, directory_obj
*dir
, u_long flags
)
486 char domain
[strlen (name
) + 3];
488 if (nis_dir_cmp (name
, dir
->do_name
) == SAME_NAME
)
491 nis_domain_of_r (name
, domain
, sizeof (domain
));
493 if (nis_dir_cmp (domain
, dir
->do_name
) == SAME_NAME
)
496 fd_res
= __nis_finddirectory (dir
, domain
);
497 if (fd_res
->status
!= NIS_SUCCESS
)
499 __free_fdresult (fd_res
);
502 obj
= calloc(1, sizeof(directory_obj
));
505 xdrmem_create(&xdrs
, fd_res
->dir_data
.dir_data_val
,
506 fd_res
->dir_data
.dir_data_len
, XDR_DECODE
);
507 _xdr_directory_obj (&xdrs
, obj
);
509 __free_fdresult (fd_res
);
512 nis_free_directory (dir
);
519 __do_niscall (const_nis_name name
, u_long prog
, xdrproc_t xargs
,
520 caddr_t req
, xdrproc_t xres
, caddr_t resp
, u_long flags
,
524 directory_obj
*dir
= NULL
;
527 cache2_info cinfo
= {-1, -1, -1};
528 int saved_errno
= errno
;
533 /* Search in local cache. In the moment, we ignore the fastest server */
534 if (!(flags
& NO_CACHE
))
535 dir
= __nis_cache_search (name
, flags
, &cinfo
);
542 dir
= readColdStartFile ();
543 if (dir
== NULL
) /* No /var/nis/NIS_COLD_START->no NIS+ installed */
545 __set_errno (saved_errno
);
549 /* Try at first, if servers in "dir" know our object */
550 obj
= first_shoot (name
, dir
, flags
);
553 dir
= rec_dirsearch (name
, dir
, flags
, &status
);
556 __set_errno (saved_errno
);
564 if (flags
& MASTER_ONLY
)
566 server
= dir
->do_servers
.do_servers_val
;
571 server
= dir
->do_servers
.do_servers_val
;
572 server_len
= dir
->do_servers
.do_servers_len
;
576 retcode
= __do_niscall2 (server
, server_len
, prog
, xargs
, req
, xres
, resp
,
579 nis_free_directory (dir
);
581 __set_errno (saved_errno
);