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};
35 inetstr2int (const char *str
)
37 char buffer
[strlen (str
) + 3];
41 buflen
= stpcpy (buffer
, str
) - buffer
;
44 for (i
= 0; i
< buflen
; ++i
)
55 return inet_addr (buffer
);
59 __bind_destroy (dir_binding
*bind
)
61 if (bind
->clnt
!= NULL
)
64 auth_destroy (bind
->clnt
->cl_auth
);
65 clnt_destroy (bind
->clnt
);
67 free (bind
->server_val
);
72 __bind_next (dir_binding
*bind
)
76 if (bind
->clnt
!= NULL
)
79 auth_destroy (bind
->clnt
->cl_auth
);
80 clnt_destroy (bind
->clnt
);
84 if (bind
->trys
>= bind
->server_len
)
87 for (j
= bind
->current_ep
+ 1;
88 j
< bind
->server_val
[bind
->server_used
].ep
.ep_len
; ++j
)
89 if (strcmp (bind
->server_val
[bind
->server_used
].ep
.ep_val
[j
].family
,
91 if (strcmp (bind
->server_val
[bind
->server_used
].ep
.ep_val
[j
].proto
,
100 if (bind
->server_used
>= bind
->server_len
)
101 bind
->server_used
= 0;
103 for (j
= 0; j
< bind
->server_val
[bind
->server_used
].ep
.ep_len
; ++j
)
104 if (strcmp (bind
->server_val
[bind
->server_used
].ep
.ep_val
[j
].family
,
106 if (strcmp (bind
->server_val
[bind
->server_used
].ep
.ep_val
[j
].proto
,
109 bind
->current_ep
= j
;
117 __bind_connect (dir_binding
*dbp
)
119 struct sockaddr_in check
;
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 dbp
->socket
= RPC_ANYSOCK
;
139 dbp
->clnt
= clntudp_create (&dbp
->addr
, NIS_PROG
, NIS_VERSION
,
140 UDPTIMEOUT
, &dbp
->socket
);
142 dbp
->clnt
= clnttcp_create (&dbp
->addr
, NIS_PROG
, NIS_VERSION
,
145 if (dbp
->clnt
== NULL
)
148 clnt_control (dbp
->clnt
, CLSET_TIMEOUT
, (caddr_t
)&RPCTIMEOUT
);
149 /* If the program exists, close the socket */
150 if (fcntl (dbp
->socket
, F_SETFD
, 1) == -1)
151 perror (_("fcntl: F_SETFD"));
155 if (serv
->key_type
== NIS_PK_DH
)
157 char netname
[MAXNETNAMELEN
+1];
160 p
= stpcpy (netname
, "unix.");
161 strncpy (p
, serv
->name
,MAXNETNAMELEN
-5);
162 netname
[MAXNETNAMELEN
] = '\0';
163 p
= strchr (netname
, '.');
166 authdes_pk_create (netname
, &serv
->pkey
, 300, NULL
, NULL
);
167 if (!dbp
->clnt
->cl_auth
)
168 dbp
->clnt
->cl_auth
= authunix_create_default ();
171 dbp
->clnt
->cl_auth
= authunix_create_default ();
172 dbp
->use_auth
= TRUE
;
175 /* Get port for sanity checks later */
176 checklen
= sizeof (struct sockaddr_in
);
177 memset (&check
, 0, checklen
);
179 bind (dbp
->socket
, (struct sockaddr
*)&check
, checklen
);
180 check
.sin_family
= AF_INET
;
181 if (!getsockname (dbp
->socket
, (struct sockaddr
*)&check
, &checklen
))
182 dbp
->port
= check
.sin_port
;
184 dbp
->create
= time (NULL
);
190 __bind_create (const nis_server
*serv_val
, u_int serv_len
, u_long flags
,
196 dbp
= calloc (1, sizeof (dir_binding
));
200 dbp
->server_len
= serv_len
;
201 dbp
->server_val
= calloc (1, sizeof (nis_server
) * serv_len
);
202 if (dbp
->server_val
== NULL
)
208 if (flags
& USE_DGRAM
)
211 dbp
->use_udp
= FALSE
;
213 if (flags
& NO_AUTHINFO
)
214 dbp
->use_auth
= FALSE
;
216 dbp
->use_auth
= TRUE
;
218 if (flags
& MASTER_ONLY
)
219 dbp
->master_only
= TRUE
;
221 dbp
->master_only
= FALSE
;
225 for (i
= 0; i
< serv_len
; ++i
)
227 if (serv_val
[i
].name
!= NULL
)
228 dbp
->server_val
[i
].name
= strdup (serv_val
[i
].name
);
230 dbp
->server_val
[i
].ep
.ep_len
= serv_val
[i
].ep
.ep_len
;
231 if (dbp
->server_val
[i
].ep
.ep_len
> 0)
235 dbp
->server_val
[i
].ep
.ep_val
=
236 malloc (serv_val
[i
].ep
.ep_len
* sizeof (endpoint
));
237 for (j
= 0; j
< dbp
->server_val
[i
].ep
.ep_len
; ++j
)
239 if (serv_val
[i
].ep
.ep_val
[j
].uaddr
)
240 dbp
->server_val
[i
].ep
.ep_val
[j
].uaddr
=
241 strdup (serv_val
[i
].ep
.ep_val
[j
].uaddr
);
243 dbp
->server_val
[i
].ep
.ep_val
[j
].uaddr
= NULL
;
244 if (serv_val
[i
].ep
.ep_val
[j
].family
)
245 dbp
->server_val
[i
].ep
.ep_val
[j
].family
=
246 strdup (serv_val
[i
].ep
.ep_val
[j
].family
);
248 dbp
->server_val
[i
].ep
.ep_val
[j
].family
= NULL
;
249 if (serv_val
[i
].ep
.ep_val
[j
].proto
)
250 dbp
->server_val
[i
].ep
.ep_val
[j
].proto
=
251 strdup (serv_val
[i
].ep
.ep_val
[j
].proto
);
253 dbp
->server_val
[i
].ep
.ep_val
[j
].proto
= NULL
;
257 dbp
->server_val
[i
].ep
.ep_val
= NULL
;
258 dbp
->server_val
[i
].key_type
= serv_val
[i
].key_type
;
259 dbp
->server_val
[i
].pkey
.n_len
= serv_val
[i
].pkey
.n_len
;
260 if (serv_val
[i
].pkey
.n_len
> 0)
262 dbp
->server_val
[i
].pkey
.n_bytes
=
263 malloc (serv_val
[i
].pkey
.n_len
);
264 if (dbp
->server_val
[i
].pkey
.n_bytes
== NULL
)
266 memcpy (dbp
->server_val
[i
].pkey
.n_bytes
, serv_val
[i
].pkey
.n_bytes
,
267 serv_val
[i
].pkey
.n_len
);
270 dbp
->server_val
[i
].pkey
.n_bytes
= NULL
;
274 if (cinfo
!= NULL
&& cinfo
->server_used
>= 0)
276 dbp
->server_used
= cinfo
->server_used
;
277 dbp
->current_ep
= cinfo
->current_ep
;
278 dbp
->class = cinfo
->class;
280 else if (__nis_findfastest (dbp
) < 1)
282 __bind_destroy (dbp
);
290 __do_niscall2 (const nis_server
*server
, u_int server_len
, u_long prog
,
291 xdrproc_t xargs
, caddr_t req
, xdrproc_t xres
, caddr_t resp
,
292 u_long flags
, nis_cb
*cb
, cache2_info
*cinfo
)
294 enum clnt_stat result
;
298 if (flags
& MASTER_ONLY
)
301 dbp
= __bind_create (server
, server_len
, flags
, cinfo
);
303 return NIS_NAMEUNREACHABLE
;
304 while (__bind_connect (dbp
) != NIS_SUCCESS
)
306 if (__bind_next (dbp
) != NIS_SUCCESS
)
308 __bind_destroy (dbp
);
309 return NIS_NAMEUNREACHABLE
;
316 result
= clnt_call (dbp
->clnt
, prog
, xargs
, req
, xres
, resp
, RPCTIMEOUT
);
318 if (result
!= RPC_SUCCESS
)
320 clnt_perror (dbp
->clnt
, "__do_niscall2: clnt_call");
321 __bind_destroy (dbp
);
322 retcode
= NIS_RPCERROR
;
329 if ((((nis_result
*)resp
)->status
== NIS_CBRESULTS
) &&
332 __nis_do_callback(dbp
, &((nis_result
*)resp
)->cookie
, cb
);
335 /* Yes, this is correct. If we doesn't have to start
336 a callback, look if we have to search another server */
346 if ((((nis_result
*)resp
)->status
== NIS_NOTFOUND
) ||
347 (((nis_result
*)resp
)->status
== NIS_NOSUCHNAME
) ||
348 (((nis_result
*)resp
)->status
== NIS_NOT_ME
))
350 if (__bind_next (dbp
) == NIS_SUCCESS
)
352 while (__bind_connect (dbp
) != NIS_SUCCESS
)
354 if (__bind_next (dbp
) != NIS_SUCCESS
)
356 __bind_destroy (dbp
);
362 break; /* No more servers to search in */
366 case NIS_FINDDIRECTORY
:
367 if ((((fd_result
*)resp
)->status
== NIS_NOTFOUND
) ||
368 (((fd_result
*)resp
)->status
== NIS_NOSUCHNAME
) ||
369 (((fd_result
*)resp
)->status
== NIS_NOT_ME
))
371 if (__bind_next (dbp
) == NIS_SUCCESS
)
373 while (__bind_connect (dbp
) != NIS_SUCCESS
)
375 if (__bind_next (dbp
) != NIS_SUCCESS
)
377 __bind_destroy (dbp
);
383 break; /* No more servers to search in */
387 case NIS_DUMPLOG
: /* log_result */
389 if ((((log_result
*)resp
)->lr_status
== NIS_NOTFOUND
) ||
390 (((log_result
*)resp
)->lr_status
== NIS_NOSUCHNAME
) ||
391 (((log_result
*)resp
)->lr_status
== NIS_NOT_ME
))
393 if (__bind_next (dbp
) == NIS_SUCCESS
)
395 while (__bind_connect (dbp
) != NIS_SUCCESS
)
397 if (__bind_next (dbp
) != NIS_SUCCESS
)
399 __bind_destroy (dbp
);
405 break; /* No more servers to search in */
412 __bind_destroy (dbp
);
413 retcode
= NIS_SUCCESS
;
416 while ((flags
& HARD_LOOKUP
) && retcode
== NIS_RPCERROR
);
421 static directory_obj
*
422 rec_dirsearch (const_nis_name name
, directory_obj
*dir
, u_long flags
,
427 char domain
[strlen (name
) + 3];
429 nis_domain_of_r (name
, domain
, sizeof (domain
));
430 if (strncmp (domain
, "org_dir.", 8) == 0)
432 char tmp
[strlen (name
) + 3];
434 nis_domain_of_r (domain
, tmp
, sizeof (tmp
));
435 strcpy (domain
, tmp
);
438 if (strncmp (domain
, "groups_dir.", 11) == 0)
440 char tmp
[strlen (name
) + 3];
442 nis_domain_of_r (domain
, tmp
, sizeof (tmp
));
443 strcpy (domain
, tmp
);
447 /* We have no grous_dir or org_dir, so try the complete name */
448 strcpy (domain
, name
);
451 switch (nis_dir_cmp (domain
, dir
->do_name
))
454 *status
= NIS_SUCCESS
;
457 /* NOT_SEQUENTIAL means, go one up and try it there ! */
459 { /* We need data from a parent domain */
461 char ndomain
[strlen (name
) + 3];
463 nis_domain_of_r (dir
->do_name
, ndomain
, sizeof (ndomain
));
465 /* The root server of our domain is a replica of the parent
466 domain ! (Now I understand why a root server must be a
467 replica of the parent domain) */
468 fd_res
= __nis_finddirectory (dir
, ndomain
);
469 *status
= fd_res
->status
;
470 if (fd_res
->status
!= NIS_SUCCESS
)
472 nis_free_directory (dir
);
473 __free_fdresult (fd_res
);
476 obj
= calloc(1, sizeof(directory_obj
));
477 xdrmem_create(&xdrs
, fd_res
->dir_data
.dir_data_val
,
478 fd_res
->dir_data
.dir_data_len
, XDR_DECODE
);
479 xdr_directory_obj(&xdrs
, obj
);
481 __free_fdresult (fd_res
);
484 /* We have found a NIS+ server serving ndomain, now
485 let us search for "name" */
486 nis_free_directory (dir
);
487 return rec_dirsearch (name
, obj
, flags
, status
);
491 /* Ups, very bad. Are we already the root server ? */
492 nis_free_directory (dir
);
500 char leaf
[strlen (name
) + 3];
501 char ndomain
[strlen (name
) + 3];
506 if (strlen (domain
) == 0)
508 nis_free_directory (dir
);
511 nis_leaf_of_r (domain
, leaf
, sizeof (leaf
));
512 nis_domain_of_r (domain
, ndomain
, sizeof (ndomain
));
513 strcpy (domain
, ndomain
);
515 while (nis_dir_cmp (domain
, dir
->do_name
) != SAME_NAME
);
516 cp
= strchr (leaf
, '\0');
520 fd_res
= __nis_finddirectory (dir
, leaf
);
521 *status
= fd_res
->status
;
522 if (fd_res
->status
!= NIS_SUCCESS
)
524 nis_free_directory (dir
);
525 __free_fdresult (fd_res
);
528 obj
= calloc(1, sizeof(directory_obj
));
529 xdrmem_create(&xdrs
, fd_res
->dir_data
.dir_data_val
,
530 fd_res
->dir_data
.dir_data_len
, XDR_DECODE
);
531 xdr_directory_obj(&xdrs
, obj
);
533 __free_fdresult (fd_res
);
536 /* We have found a NIS+ server serving ndomain, now
537 let us search for "name" */
538 nis_free_directory (dir
);
539 return rec_dirsearch (name
, obj
, flags
, status
);
544 nis_free_directory (dir
);
545 *status
= NIS_BADNAME
;
548 nis_free_directory (dir
);
554 __do_niscall (const_nis_name name
, u_long prog
, xdrproc_t xargs
,
555 caddr_t req
, xdrproc_t xres
, caddr_t resp
, u_long flags
,
559 directory_obj
*dir
= NULL
;
562 cache2_info cinfo
= {-1, -1, -1};
563 int saved_errno
= errno
;
568 /* Search in local cache. In the moment, we ignore the fastest server */
569 if (!(flags
& NO_CACHE
))
570 dir
= __nis_cache_search (name
, flags
, &cinfo
);
575 dir
= readColdStartFile ();
576 if (dir
== NULL
) /* No /var/nis/NIS_COLD_START->no NIS+ installed */
578 __set_errno (saved_errno
);
582 dir
= rec_dirsearch (name
, dir
, flags
, &status
);
585 __set_errno (saved_errno
);
590 if (flags
& MASTER_ONLY
)
592 server
= dir
->do_servers
.do_servers_val
;
597 server
= dir
->do_servers
.do_servers_val
;
598 server_len
= dir
->do_servers
.do_servers_len
;
602 retcode
= __do_niscall2 (server
, server_len
, prog
, xargs
, req
, xres
, resp
,
605 nis_free_directory (dir
);
607 __set_errno (saved_errno
);