1 /* Copyright (C) 1997 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. */
24 #include <rpcsvc/nis.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include "nis_intern.h"
30 static struct timeval TIMEOUT
= {10, 0};
33 inetstr2int (const char *str
)
35 char buffer
[strlen (str
) + 3];
39 buflen
= stpcpy (buffer
, str
) - buffer
;
42 for (i
= 0; i
< buflen
; ++i
)
53 return inet_addr (buffer
);
57 __bind_destroy (dir_binding
*bind
)
59 if (bind
->clnt
!= NULL
)
62 auth_destroy (bind
->clnt
->cl_auth
);
63 clnt_destroy (bind
->clnt
);
65 free (bind
->server_val
);
70 __bind_next (dir_binding
*bind
)
74 if (bind
->clnt
!= NULL
)
77 auth_destroy (bind
->clnt
->cl_auth
);
78 clnt_destroy (bind
->clnt
);
82 if (bind
->trys
>= bind
->server_len
)
85 for (j
= bind
->current_ep
+ 1;
86 j
< bind
->server_val
[bind
->server_used
].ep
.ep_len
; ++j
)
87 if (strcmp (bind
->server_val
[bind
->server_used
].ep
.ep_val
[j
].family
,
89 if (strcmp (bind
->server_val
[bind
->server_used
].ep
.ep_val
[j
].proto
,
98 if (bind
->server_used
>= bind
->server_len
)
99 bind
->server_used
= 0;
101 for (j
= 0; j
< bind
->server_val
[bind
->server_used
].ep
.ep_len
; ++j
)
102 if (strcmp (bind
->server_val
[bind
->server_used
].ep
.ep_val
[j
].family
,
104 if (strcmp (bind
->server_val
[bind
->server_used
].ep
.ep_val
[j
].proto
,
107 bind
->current_ep
= j
;
115 __bind_connect (dir_binding
*dbp
)
117 struct sockaddr_in check
;
124 serv
= &dbp
->server_val
[dbp
->server_used
];
126 memset (&dbp
->addr
, '\0', sizeof (dbp
->addr
));
127 dbp
->addr
.sin_family
= AF_INET
;
129 dbp
->addr
.sin_addr
.s_addr
=
130 inetstr2int (serv
->ep
.ep_val
[dbp
->current_ep
].uaddr
);
132 if (dbp
->addr
.sin_addr
.s_addr
== 0)
135 dbp
->socket
= RPC_ANYSOCK
;
137 dbp
->clnt
= clntudp_create (&dbp
->addr
, NIS_PROG
, NIS_VERSION
,
138 TIMEOUT
, &dbp
->socket
);
140 dbp
->clnt
= clnttcp_create (&dbp
->addr
, NIS_PROG
, NIS_VERSION
,
143 if (dbp
->clnt
== NULL
)
146 clnt_control (dbp
->clnt
, CLSET_TIMEOUT
, (caddr_t
)&TIMEOUT
);
147 /* If the program exists, close the socket */
148 if (fcntl (dbp
->socket
, F_SETFD
, 1) == -1)
149 perror (_("fcntl: F_SETFD"));
153 if (serv
->key_type
== NIS_PK_DH
)
155 char netname
[MAXNETNAMELEN
+1];
158 p
= stpcpy (netname
, "unix.");
159 strncpy (p
, serv
->name
,MAXNETNAMELEN
-5);
160 netname
[MAXNETNAMELEN
] = '\0';
161 p
= strchr (netname
, '.');
164 authdes_pk_create (netname
, &serv
->pkey
, 300, NULL
, NULL
);
165 if (!dbp
->clnt
->cl_auth
)
166 dbp
->clnt
->cl_auth
= authunix_create_default ();
169 dbp
->clnt
->cl_auth
= authunix_create_default ();
170 dbp
->use_auth
= TRUE
;
173 /* Get port for sanity checks later */
174 checklen
= sizeof (struct sockaddr_in
);
175 memset (&check
, 0, checklen
);
177 bind (dbp
->socket
, (struct sockaddr
*)&check
, checklen
);
178 check
.sin_family
= AF_INET
;
179 if (!getsockname (dbp
->socket
, (struct sockaddr
*)&check
, &checklen
))
180 dbp
->port
= check
.sin_port
;
182 dbp
->create
= time (NULL
);
188 __bind_create (const nis_server
*serv_val
, u_int serv_len
, u_long flags
)
193 dbp
= calloc (1, sizeof (dir_binding
));
197 dbp
->server_len
= serv_len
;
198 dbp
->server_val
= calloc (1, sizeof (nis_server
) * serv_len
);
199 if (dbp
->server_val
== NULL
)
205 if (flags
& USE_DGRAM
)
208 dbp
->use_udp
= FALSE
;
210 if (flags
& NO_AUTHINFO
)
211 dbp
->use_auth
= FALSE
;
213 dbp
->use_auth
= TRUE
;
215 if (flags
& MASTER_ONLY
)
216 dbp
->master_only
= TRUE
;
218 dbp
->master_only
= FALSE
;
222 for (i
= 0; i
< serv_len
; ++i
)
224 if (serv_val
[i
].name
!= NULL
)
225 dbp
->server_val
[i
].name
= strdup (serv_val
[i
].name
);
227 dbp
->server_val
[i
].ep
.ep_len
= serv_val
[i
].ep
.ep_len
;
228 if (dbp
->server_val
[i
].ep
.ep_len
> 0)
232 dbp
->server_val
[i
].ep
.ep_val
=
233 malloc (serv_val
[i
].ep
.ep_len
* sizeof (endpoint
));
234 for (j
= 0; j
< dbp
->server_val
[i
].ep
.ep_len
; ++j
)
236 if (serv_val
[i
].ep
.ep_val
[j
].uaddr
)
237 dbp
->server_val
[i
].ep
.ep_val
[j
].uaddr
=
238 strdup (serv_val
[i
].ep
.ep_val
[j
].uaddr
);
240 dbp
->server_val
[i
].ep
.ep_val
[j
].uaddr
= NULL
;
241 if (serv_val
[i
].ep
.ep_val
[j
].family
)
242 dbp
->server_val
[i
].ep
.ep_val
[j
].family
=
243 strdup (serv_val
[i
].ep
.ep_val
[j
].family
);
245 dbp
->server_val
[i
].ep
.ep_val
[j
].family
= NULL
;
246 if (serv_val
[i
].ep
.ep_val
[j
].proto
)
247 dbp
->server_val
[i
].ep
.ep_val
[j
].proto
=
248 strdup (serv_val
[i
].ep
.ep_val
[j
].proto
);
250 dbp
->server_val
[i
].ep
.ep_val
[j
].proto
= NULL
;
254 dbp
->server_val
[i
].ep
.ep_val
= NULL
;
255 dbp
->server_val
[i
].key_type
= serv_val
[i
].key_type
;
256 dbp
->server_val
[i
].pkey
.n_len
= serv_val
[i
].pkey
.n_len
;
257 if (serv_val
[i
].pkey
.n_len
> 0)
259 dbp
->server_val
[i
].pkey
.n_bytes
=
260 malloc (serv_val
[i
].pkey
.n_len
);
261 if (dbp
->server_val
[i
].pkey
.n_bytes
== NULL
)
263 memcpy (dbp
->server_val
[i
].pkey
.n_bytes
, serv_val
[i
].pkey
.n_bytes
,
264 serv_val
[i
].pkey
.n_len
);
267 dbp
->server_val
[i
].pkey
.n_bytes
= NULL
;
270 if (__nis_findfastest (dbp
) < 1)
272 __bind_destroy (dbp
);
280 __do_niscall2 (const nis_server
*server
, u_int server_len
, u_long prog
,
281 xdrproc_t xargs
, caddr_t req
, xdrproc_t xres
, caddr_t resp
,
282 u_long flags
, nis_cb
*cb
)
284 enum clnt_stat result
;
288 if (flags
& MASTER_ONLY
)
291 if ((dbp
= __bind_create (server
, server_len
, flags
)) == NULL
)
292 return NIS_NAMEUNREACHABLE
;
293 while (__bind_connect (dbp
) != NIS_SUCCESS
)
295 if (__bind_next (dbp
) != NIS_SUCCESS
)
297 __bind_destroy (dbp
);
298 return NIS_NAMEUNREACHABLE
;
305 result
= clnt_call (dbp
->clnt
, prog
, xargs
, req
, xres
, resp
, TIMEOUT
);
307 if (result
!= RPC_SUCCESS
)
309 clnt_perror (dbp
->clnt
, "__do_niscall2: clnt_call");
310 __bind_destroy (dbp
);
311 retcode
= NIS_RPCERROR
;
318 if ((((nis_result
*)resp
)->status
== NIS_CBRESULTS
) &&
321 __nis_do_callback(dbp
, &((nis_result
*)resp
)->cookie
, cb
);
324 /* Yes, this is correct. If we doesn't have to start
325 a callback, look if we have to search another server */
335 if ((((nis_result
*)resp
)->status
== NIS_NOTFOUND
) ||
336 (((nis_result
*)resp
)->status
== NIS_NOSUCHNAME
) ||
337 (((nis_result
*)resp
)->status
== NIS_NOT_ME
))
339 if (__bind_next (dbp
) == NIS_SUCCESS
)
341 while (__bind_connect (dbp
) != NIS_SUCCESS
)
343 if (__bind_next (dbp
) != NIS_SUCCESS
)
345 __bind_destroy (dbp
);
351 break; /* No more servers to search in */
355 case NIS_FINDDIRECTORY
:
356 if ((((fd_result
*)resp
)->status
== NIS_NOTFOUND
) ||
357 (((fd_result
*)resp
)->status
== NIS_NOSUCHNAME
) ||
358 (((fd_result
*)resp
)->status
== NIS_NOT_ME
))
360 if (__bind_next (dbp
) == NIS_SUCCESS
)
362 while (__bind_connect (dbp
) != NIS_SUCCESS
)
364 if (__bind_next (dbp
) != NIS_SUCCESS
)
366 __bind_destroy (dbp
);
372 break; /* No more servers to search in */
376 case NIS_DUMPLOG
: /* log_result */
378 if ((((log_result
*)resp
)->lr_status
== NIS_NOTFOUND
) ||
379 (((log_result
*)resp
)->lr_status
== NIS_NOSUCHNAME
) ||
380 (((log_result
*)resp
)->lr_status
== NIS_NOT_ME
))
382 if (__bind_next (dbp
) == NIS_SUCCESS
)
384 while (__bind_connect (dbp
) != NIS_SUCCESS
)
386 if (__bind_next (dbp
) != NIS_SUCCESS
)
388 __bind_destroy (dbp
);
394 break; /* No more servers to search in */
401 __bind_destroy (dbp
);
402 retcode
= NIS_SUCCESS
;
405 while ((flags
& HARD_LOOKUP
) && retcode
== NIS_RPCERROR
);
410 static directory_obj
*
411 rec_dirsearch (const_nis_name name
, directory_obj
*dir
, u_long flags
,
416 char domain
[strlen (name
) + 3];
418 nis_domain_of_r (name
, domain
, sizeof (domain
));
419 if (strncmp (domain
, "org_dir.", 8) == 0)
421 char tmp
[strlen (name
) + 3];
423 nis_domain_of_r (domain
, tmp
, sizeof (tmp
));
424 strcpy (domain
, tmp
);
427 if (strncmp (domain
, "groups_dir.", 11) == 0)
429 char tmp
[strlen (name
) + 3];
431 nis_domain_of_r (domain
, tmp
, sizeof (tmp
));
432 strcpy (domain
, tmp
);
436 /* We have no grous_dir or org_dir, so try the complete name */
437 strcpy (domain
, name
);
440 switch (nis_dir_cmp (domain
, dir
->do_name
))
443 *status
= NIS_SUCCESS
;
446 /* NOT_SEQUENTIAL means, go one up and try it there ! */
448 { /* We need data from a parent domain */
450 char ndomain
[strlen (name
) + 3];
452 nis_domain_of_r (dir
->do_name
, ndomain
, sizeof (ndomain
));
454 /* The root server of our domain is a replica of the parent
455 domain ! (Now I understand why a root server must be a
456 replica of the parent domain) */
457 fd_res
= __nis_finddirectory (dir
, ndomain
);
458 *status
= fd_res
->status
;
459 if (fd_res
->status
!= NIS_SUCCESS
)
461 nis_free_directory (dir
);
462 xdr_free((xdrproc_t
)xdr_fd_result
, (caddr_t
)fd_res
);
465 obj
= calloc(1, sizeof(directory_obj
));
466 xdrmem_create(&xdrs
, fd_res
->dir_data
.dir_data_val
,
467 fd_res
->dir_data
.dir_data_len
, XDR_DECODE
);
468 xdr_directory_obj(&xdrs
, obj
);
470 __free_fdresult (fd_res
);
473 /* We have found a NIS+ server serving ndomain, now
474 let us search for "name" */
475 nis_free_directory (dir
);
476 return rec_dirsearch (name
, obj
, flags
, status
);
480 /* Ups, very bad. Are we already the root server ? */
481 nis_free_directory (dir
);
489 char leaf
[strlen (name
) + 3];
490 char ndomain
[strlen (name
) + 3];
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
);
504 while (nis_dir_cmp (domain
, dir
->do_name
) != SAME_NAME
);
505 cp
= strchr (leaf
, '\0');
509 fd_res
= __nis_finddirectory (dir
, leaf
);
510 *status
= fd_res
->status
;
511 if (fd_res
->status
!= NIS_SUCCESS
)
513 nis_free_directory (dir
);
514 xdr_free((xdrproc_t
)xdr_fd_result
, (caddr_t
)fd_res
);
517 obj
= calloc(1, sizeof(directory_obj
));
518 xdrmem_create(&xdrs
, fd_res
->dir_data
.dir_data_val
,
519 fd_res
->dir_data
.dir_data_len
, XDR_DECODE
);
520 xdr_directory_obj(&xdrs
, obj
);
522 __free_fdresult (fd_res
);
525 /* We have found a NIS+ server serving ndomain, now
526 let us search for "name" */
527 nis_free_directory (dir
);
528 return rec_dirsearch (name
, obj
, flags
, status
);
533 nis_free_directory (dir
);
534 *status
= NIS_BADNAME
;
537 nis_free_directory (dir
);
543 __do_niscall (const_nis_name name
, u_long prog
, xdrproc_t xargs
,
544 caddr_t req
, xdrproc_t xres
, caddr_t resp
, u_long flags
,
548 directory_obj
*dir
= NULL
;
558 dir
= readColdStartFile ();
559 if (dir
== NULL
) /* No /var/nis/NIS_COLD_START->no NIS+ installed */
562 dir
= rec_dirsearch (name
, dir
, flags
, &status
);
567 if (flags
& MASTER_ONLY
)
569 server
= dir
->do_servers
.do_servers_val
;
574 server
= dir
->do_servers
.do_servers_val
;
575 server_len
= dir
->do_servers
.do_servers_len
;
579 retcode
= __do_niscall2 (server
, server_len
, prog
, xargs
, req
, xres
, resp
,
582 nis_free_directory (dir
);