(_IO_init): Set _vtable_offset to 0.
[glibc/history.git] / nis / nis_call.c
blobcea508e5b65eac5b76adc725e24d227f4ad8f912
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. */
20 #include <fcntl.h>
21 #include <string.h>
22 #include <rpc/rpc.h>
23 #include <rpc/auth.h>
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 RPCTIMEOUT = {10, 0};
31 static struct timeval UDPTIMEOUT = {5, 0};
33 unsigned long
34 inetstr2int (const char *str)
36 char buffer[strlen (str) + 3];
37 size_t buflen;
38 size_t i, j;
40 buflen = stpcpy (buffer, str) - buffer;
42 j = 0;
43 for (i = 0; i < buflen; ++i)
44 if (buffer[i] == '.')
46 ++j;
47 if (j == 4)
49 buffer[i] = '\0';
50 break;
54 return inet_addr (buffer);
57 static void
58 __bind_destroy (dir_binding *bind)
60 if (bind->clnt != NULL)
62 if (bind->use_auth)
63 auth_destroy (bind->clnt->cl_auth);
64 clnt_destroy (bind->clnt);
66 free (bind->server_val);
67 free (bind);
70 static nis_error
71 __bind_next (dir_binding *bind)
73 u_int j;
75 if (bind->clnt != NULL)
77 if (bind->use_auth)
78 auth_destroy (bind->clnt->cl_auth);
79 clnt_destroy (bind->clnt);
80 bind->clnt = NULL;
83 if (bind->trys >= bind->server_len)
84 return NIS_FAIL;
86 for (j = bind->current_ep + 1;
87 j < bind->server_val[bind->server_used].ep.ep_len; ++j)
88 if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].family,
89 "inet") == 0)
90 if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].proto,
91 "-") == 0)
93 bind->current_ep = j;
94 return NIS_SUCCESS;
97 ++bind->trys;
98 ++bind->server_used;
99 if (bind->server_used >= bind->server_len)
100 bind->server_used = 0;
102 for (j = 0; j < bind->server_val[bind->server_used].ep.ep_len; ++j)
103 if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].family,
104 "inet") == 0)
105 if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].proto,
106 "-") == 0)
108 bind->current_ep = j;
109 return NIS_SUCCESS;
112 return NIS_FAIL;
115 static nis_error
116 __bind_connect (dir_binding *dbp)
118 struct sockaddr_in check;
119 nis_server *serv;
120 int checklen;
122 if (dbp == NULL)
123 return NIS_FAIL;
125 serv = &dbp->server_val[dbp->server_used];
127 memset (&dbp->addr, '\0', sizeof (dbp->addr));
128 dbp->addr.sin_family = AF_INET;
130 dbp->addr.sin_addr.s_addr =
131 inetstr2int (serv->ep.ep_val[dbp->current_ep].uaddr);
133 if (dbp->addr.sin_addr.s_addr == 0)
134 return NIS_FAIL;
136 dbp->socket = RPC_ANYSOCK;
137 if (dbp->use_udp)
138 dbp->clnt = clntudp_create (&dbp->addr, NIS_PROG, NIS_VERSION,
139 UDPTIMEOUT, &dbp->socket);
140 else
141 dbp->clnt = clnttcp_create (&dbp->addr, NIS_PROG, NIS_VERSION,
142 &dbp->socket, 0, 0);
144 if (dbp->clnt == NULL)
145 return NIS_RPCERROR;
147 clnt_control (dbp->clnt, CLSET_TIMEOUT, (caddr_t)&RPCTIMEOUT);
148 /* If the program exists, close the socket */
149 if (fcntl (dbp->socket, F_SETFD, 1) == -1)
150 perror (_("fcntl: F_SETFD"));
152 if (dbp->use_auth)
154 if (serv->key_type == NIS_PK_DH)
156 char netname[MAXNETNAMELEN+1];
157 char *p;
159 p = stpcpy (netname, "unix.");
160 strncpy (p, serv->name,MAXNETNAMELEN-5);
161 netname[MAXNETNAMELEN] = '\0';
162 p = strchr (netname, '.');
163 *p = '@';
164 dbp->clnt->cl_auth =
165 authdes_pk_create (netname, &serv->pkey, 300, NULL, NULL);
166 if (!dbp->clnt->cl_auth)
167 dbp->clnt->cl_auth = authunix_create_default ();
169 else
170 dbp->clnt->cl_auth = authunix_create_default ();
171 dbp->use_auth = TRUE;
174 /* Get port for sanity checks later */
175 checklen = sizeof (struct sockaddr_in);
176 memset (&check, 0, checklen);
177 if (dbp->use_udp)
178 bind (dbp->socket, (struct sockaddr *)&check, checklen);
179 check.sin_family = AF_INET;
180 if (!getsockname (dbp->socket, (struct sockaddr *)&check, &checklen))
181 dbp->port = check.sin_port;
183 dbp->create = time (NULL);
185 return NIS_SUCCESS;
188 static dir_binding *
189 __bind_create (const nis_server *serv_val, u_int serv_len, u_long flags)
191 dir_binding *dbp;
192 u_int i;
194 dbp = calloc (1, sizeof (dir_binding));
195 if (dbp == NULL)
196 return NULL;
198 dbp->server_len = serv_len;
199 dbp->server_val = calloc (1, sizeof (nis_server) * serv_len);
200 if (dbp->server_val == NULL)
202 free (dbp);
203 return NULL;
206 if (flags & USE_DGRAM)
207 dbp->use_udp = TRUE;
208 else
209 dbp->use_udp = FALSE;
211 if (flags & NO_AUTHINFO)
212 dbp->use_auth = FALSE;
213 else
214 dbp->use_auth = TRUE;
216 if (flags & MASTER_ONLY)
217 dbp->master_only = TRUE;
218 else
219 dbp->master_only = FALSE;
221 dbp->trys = 1;
223 for (i = 0; i < serv_len; ++i)
225 if (serv_val[i].name != NULL)
226 dbp->server_val[i].name = strdup (serv_val[i].name);
228 dbp->server_val[i].ep.ep_len = serv_val[i].ep.ep_len;
229 if (dbp->server_val[i].ep.ep_len > 0)
231 unsigned long j;
233 dbp->server_val[i].ep.ep_val =
234 malloc (serv_val[i].ep.ep_len * sizeof (endpoint));
235 for (j = 0; j < dbp->server_val[i].ep.ep_len; ++j)
237 if (serv_val[i].ep.ep_val[j].uaddr)
238 dbp->server_val[i].ep.ep_val[j].uaddr =
239 strdup (serv_val[i].ep.ep_val[j].uaddr);
240 else
241 dbp->server_val[i].ep.ep_val[j].uaddr = NULL;
242 if (serv_val[i].ep.ep_val[j].family)
243 dbp->server_val[i].ep.ep_val[j].family =
244 strdup (serv_val[i].ep.ep_val[j].family);
245 else
246 dbp->server_val[i].ep.ep_val[j].family = NULL;
247 if (serv_val[i].ep.ep_val[j].proto)
248 dbp->server_val[i].ep.ep_val[j].proto =
249 strdup (serv_val[i].ep.ep_val[j].proto);
250 else
251 dbp->server_val[i].ep.ep_val[j].proto = NULL;
254 else
255 dbp->server_val[i].ep.ep_val = NULL;
256 dbp->server_val[i].key_type = serv_val[i].key_type;
257 dbp->server_val[i].pkey.n_len = serv_val[i].pkey.n_len;
258 if (serv_val[i].pkey.n_len > 0)
260 dbp->server_val[i].pkey.n_bytes =
261 malloc (serv_val[i].pkey.n_len);
262 if (dbp->server_val[i].pkey.n_bytes == NULL)
263 return NULL;
264 memcpy (dbp->server_val[i].pkey.n_bytes, serv_val[i].pkey.n_bytes,
265 serv_val[i].pkey.n_len);
267 else
268 dbp->server_val[i].pkey.n_bytes = NULL;
271 if (__nis_findfastest (dbp) < 1)
273 __bind_destroy (dbp);
274 return NULL;
277 return dbp;
280 nis_error
281 __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
282 xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp,
283 u_long flags, nis_cb *cb)
285 enum clnt_stat result;
286 nis_error retcode;
287 dir_binding *dbp;
289 if (flags & MASTER_ONLY)
290 server_len = 1;
292 if ((dbp = __bind_create (server, server_len, flags)) == NULL)
293 return NIS_NAMEUNREACHABLE;
294 while (__bind_connect (dbp) != NIS_SUCCESS)
296 if (__bind_next (dbp) != NIS_SUCCESS)
298 __bind_destroy (dbp);
299 return NIS_NAMEUNREACHABLE;
305 again:
306 result = clnt_call (dbp->clnt, prog, xargs, req, xres, resp, RPCTIMEOUT);
308 if (result != RPC_SUCCESS)
310 clnt_perror (dbp->clnt, "__do_niscall2: clnt_call");
311 __bind_destroy (dbp);
312 retcode = NIS_RPCERROR;
314 else
316 switch (prog)
318 case NIS_IBLIST:
319 if ((((nis_result *)resp)->status == NIS_CBRESULTS) &&
320 (cb != NULL))
322 __nis_do_callback(dbp, &((nis_result *)resp)->cookie, cb);
323 break;
325 /* Yes, this is correct. If we doesn't have to start
326 a callback, look if we have to search another server */
327 case NIS_LOOKUP:
328 case NIS_ADD:
329 case NIS_MODIFY:
330 case NIS_REMOVE:
331 case NIS_IBADD:
332 case NIS_IBMODIFY:
333 case NIS_IBREMOVE:
334 case NIS_IBFIRST:
335 case NIS_IBNEXT:
336 if ((((nis_result *)resp)->status == NIS_NOTFOUND) ||
337 (((nis_result *)resp)->status == NIS_NOSUCHNAME) ||
338 (((nis_result *)resp)->status == NIS_NOT_ME))
340 if (__bind_next (dbp) == NIS_SUCCESS)
342 while (__bind_connect (dbp) != NIS_SUCCESS)
344 if (__bind_next (dbp) != NIS_SUCCESS)
346 __bind_destroy (dbp);
347 return NIS_SUCCESS;
351 else
352 break; /* No more servers to search in */
353 goto again;
355 break;
356 case NIS_FINDDIRECTORY:
357 if ((((fd_result *)resp)->status == NIS_NOTFOUND) ||
358 (((fd_result *)resp)->status == NIS_NOSUCHNAME) ||
359 (((fd_result *)resp)->status == NIS_NOT_ME))
361 if (__bind_next (dbp) == NIS_SUCCESS)
363 while (__bind_connect (dbp) != NIS_SUCCESS)
365 if (__bind_next (dbp) != NIS_SUCCESS)
367 __bind_destroy (dbp);
368 return NIS_SUCCESS;
372 else
373 break; /* No more servers to search in */
374 goto again;
376 break;
377 case NIS_DUMPLOG: /* log_result */
378 case NIS_DUMP:
379 if ((((log_result *)resp)->lr_status == NIS_NOTFOUND) ||
380 (((log_result *)resp)->lr_status == NIS_NOSUCHNAME) ||
381 (((log_result *)resp)->lr_status == NIS_NOT_ME))
383 if (__bind_next (dbp) == NIS_SUCCESS)
385 while (__bind_connect (dbp) != NIS_SUCCESS)
387 if (__bind_next (dbp) != NIS_SUCCESS)
389 __bind_destroy (dbp);
390 return NIS_SUCCESS;
394 else
395 break; /* No more servers to search in */
396 goto again;
398 break;
399 default:
400 break;
402 __bind_destroy (dbp);
403 retcode = NIS_SUCCESS;
406 while ((flags & HARD_LOOKUP) && retcode == NIS_RPCERROR);
408 return retcode;
411 static directory_obj *
412 rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags,
413 nis_error *status)
415 fd_result *fd_res;
416 XDR xdrs;
417 char domain [strlen (name) + 3];
419 nis_domain_of_r (name, domain, sizeof (domain));
420 if (strncmp (domain, "org_dir.", 8) == 0)
422 char tmp[strlen (name) + 3];
424 nis_domain_of_r (domain, tmp, sizeof (tmp));
425 strcpy (domain, tmp);
427 else
428 if (strncmp (domain, "groups_dir.", 11) == 0)
430 char tmp[strlen (name) + 3];
432 nis_domain_of_r (domain, tmp, sizeof (tmp));
433 strcpy (domain, tmp);
435 else
437 /* We have no grous_dir or org_dir, so try the complete name */
438 strcpy (domain, name);
441 switch (nis_dir_cmp (domain, dir->do_name))
443 case SAME_NAME:
444 *status = NIS_SUCCESS;
445 return dir;
446 case NOT_SEQUENTIAL:
447 /* NOT_SEQUENTIAL means, go one up and try it there ! */
448 case HIGHER_NAME:
449 { /* We need data from a parent domain */
450 directory_obj *obj;
451 char ndomain [strlen (name) + 3];
453 nis_domain_of_r (dir->do_name, ndomain, sizeof (ndomain));
455 /* The root server of our domain is a replica of the parent
456 domain ! (Now I understand why a root server must be a
457 replica of the parent domain) */
458 fd_res = __nis_finddirectory (dir, ndomain);
459 *status = fd_res->status;
460 if (fd_res->status != NIS_SUCCESS)
462 nis_free_directory (dir);
463 __free_fdresult (fd_res);
464 return NULL;
466 obj = calloc(1, sizeof(directory_obj));
467 xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val,
468 fd_res->dir_data.dir_data_len, XDR_DECODE);
469 xdr_directory_obj(&xdrs, obj);
470 xdr_destroy(&xdrs);
471 __free_fdresult (fd_res);
472 if (obj != NULL)
474 /* We have found a NIS+ server serving ndomain, now
475 let us search for "name" */
476 nis_free_directory (dir);
477 return rec_dirsearch (name, obj, flags, status);
479 else
481 /* Ups, very bad. Are we already the root server ? */
482 nis_free_directory (dir);
483 return NULL;
486 break;
487 case LOWER_NAME:
489 directory_obj *obj;
490 char leaf [strlen (name) + 3];
491 char ndomain [strlen (name) + 3];
492 char *cp;
496 if (strlen (domain) == 0)
498 nis_free_directory (dir);
499 return NULL;
501 nis_leaf_of_r (domain, leaf, sizeof (leaf));
502 nis_domain_of_r (domain, ndomain, sizeof (ndomain));
503 strcpy (domain, ndomain);
505 while (nis_dir_cmp (domain, dir->do_name) != SAME_NAME);
506 cp = strchr (leaf, '\0');
507 *cp++ = '.';
508 strcpy (cp, domain);
510 fd_res = __nis_finddirectory (dir, leaf);
511 *status = fd_res->status;
512 if (fd_res->status != NIS_SUCCESS)
514 nis_free_directory (dir);
515 __free_fdresult (fd_res);
516 return NULL;
518 obj = calloc(1, sizeof(directory_obj));
519 xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val,
520 fd_res->dir_data.dir_data_len, XDR_DECODE);
521 xdr_directory_obj(&xdrs, obj);
522 xdr_destroy(&xdrs);
523 __free_fdresult (fd_res);
524 if (obj != NULL)
526 /* We have found a NIS+ server serving ndomain, now
527 let us search for "name" */
528 nis_free_directory (dir);
529 return rec_dirsearch (name, obj, flags, status);
532 break;
533 case BAD_NAME:
534 nis_free_directory (dir);
535 *status = NIS_BADNAME;
536 return NULL;
538 nis_free_directory (dir);
539 *status = NIS_FAIL;
540 return NULL;
543 nis_error
544 __do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs,
545 caddr_t req, xdrproc_t xres, caddr_t resp, u_long flags,
546 nis_cb *cb)
548 nis_error retcode;
549 directory_obj *dir = NULL;
550 nis_server *server;
551 u_int server_len;
553 if (name == NULL)
554 return NIS_BADNAME;
556 if (dir == NULL)
558 nis_error status;
559 dir = readColdStartFile ();
560 if (dir == NULL) /* No /var/nis/NIS_COLD_START->no NIS+ installed */
561 return NIS_UNAVAIL;
563 dir = rec_dirsearch (name, dir, flags, &status);
564 if (dir == NULL)
565 return status;
568 if (flags & MASTER_ONLY)
570 server = dir->do_servers.do_servers_val;
571 server_len = 1;
573 else
575 server = dir->do_servers.do_servers_val;
576 server_len = dir->do_servers.do_servers_len;
580 retcode = __do_niscall2 (server, server_len, prog, xargs, req, xres, resp,
581 flags, cb);
583 nis_free_directory (dir);
585 return retcode;