* nscd/connections.c (restart): If we want to switch back to the
[glibc.git] / nis / nis_table.c
blobf56b499f6001e6f88b41c8a4022acf490fab2b0a
1 /* Copyright (c) 1997-1999,2003,2004,2005,2006 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.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 Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the 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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #include <string.h>
21 #include <rpcsvc/nis.h>
23 #include "nis_xdr.h"
24 #include "nis_intern.h"
27 static struct ib_request *
28 __create_ib_request (const_nis_name name, unsigned int flags)
30 struct ib_request *ibreq = calloc (1, sizeof (struct ib_request));
31 nis_attr *search_val = NULL;
32 size_t search_len = 0;
33 size_t size = 0;
35 if (ibreq == NULL)
36 return NULL;
38 ibreq->ibr_flags = flags;
40 char *cptr = strdupa (name);
42 /* Not of "[key=value,key=value,...],foo.." format? */
43 if (cptr[0] != '[')
45 ibreq->ibr_name = strdup (cptr);
46 if (ibreq->ibr_name == NULL)
48 free (ibreq);
49 return NULL;
51 return ibreq;
54 /* "[key=value,...],foo" format */
55 ibreq->ibr_name = strchr (cptr, ']');
56 if (ibreq->ibr_name == NULL || ibreq->ibr_name[1] != ',')
58 /* The object has not really been built yet so we use free. */
59 free (ibreq);
60 return NULL;
63 /* Check if we have an entry of "[key=value,],bar". If, remove the "," */
64 if (ibreq->ibr_name[-1] == ',')
65 ibreq->ibr_name[-1] = '\0';
66 else
67 ibreq->ibr_name[0] = '\0';
68 ibreq->ibr_name += 2;
69 ibreq->ibr_name = strdup (ibreq->ibr_name);
70 if (ibreq->ibr_name == NULL)
72 free_null:
73 while (search_len-- > 0)
75 free (search_val[search_len].zattr_ndx);
76 free (search_val[search_len].zattr_val.zattr_val_val);
78 free (search_val);
79 nis_free_request (ibreq);
80 return NULL;
83 ++cptr; /* Remove "[" */
85 while (cptr != NULL && cptr[0] != '\0')
87 char *key = cptr;
88 char *val = strchr (cptr, '=');
90 cptr = strchr (key, ',');
91 if (cptr != NULL)
92 *cptr++ = '\0';
94 if (!val)
96 nis_free_request (ibreq);
97 return NULL;
99 *val++ = '\0';
100 if ((search_len + 1) >= size)
102 size += 1;
103 nis_attr *newp = realloc (search_val, size * sizeof (nis_attr));
104 if (newp == NULL)
105 goto free_null;
106 search_val = newp;
108 search_val[search_len].zattr_ndx = strdup (key);
109 if ((search_val[search_len].zattr_ndx) == NULL)
110 goto free_null;
112 search_val[search_len].zattr_val.zattr_val_len = strlen (val) + 1;
113 search_val[search_len].zattr_val.zattr_val_val = strdup (val);
114 if (search_val[search_len].zattr_val.zattr_val_val == NULL)
116 free (search_val[search_len].zattr_ndx);
117 goto free_null;
120 ++search_len;
123 ibreq->ibr_srch.ibr_srch_val = search_val;
124 ibreq->ibr_srch.ibr_srch_len = search_len;
126 return ibreq;
129 static const struct timeval RPCTIMEOUT = {10, 0};
131 static char *
132 __get_tablepath (char *name, dir_binding *bptr)
134 enum clnt_stat result;
135 nis_result res;
136 struct ns_request req;
138 memset (&res, '\0', sizeof (res));
140 req.ns_name = name;
141 req.ns_object.ns_object_len = 0;
142 req.ns_object.ns_object_val = NULL;
144 result = clnt_call (bptr->clnt, NIS_LOOKUP, (xdrproc_t) _xdr_ns_request,
145 (caddr_t) &req, (xdrproc_t) _xdr_nis_result,
146 (caddr_t) &res, RPCTIMEOUT);
148 const char *cptr;
149 if (result == RPC_SUCCESS && NIS_RES_STATUS (&res) == NIS_SUCCESS
150 && __type_of (NIS_RES_OBJECT (&res)) == NIS_TABLE_OBJ)
151 cptr = NIS_RES_OBJECT (&res)->TA_data.ta_path;
152 else
153 cptr = "";
155 return strdup (cptr);
158 nis_result *
159 nis_list (const_nis_name name, unsigned int flags,
160 int (*callback) (const_nis_name name,
161 const nis_object *object,
162 const void *userdata),
163 const void *userdata)
165 nis_result *res = calloc (1, sizeof (nis_result));
166 ib_request *ibreq;
167 int status;
168 enum clnt_stat clnt_status;
169 int count_links = 0; /* We will only follow NIS_MAXLINKS links! */
170 int done = 0;
171 nis_name *names;
172 nis_name namebuf[2] = {NULL, NULL};
173 int name_nr = 0;
174 nis_cb *cb = NULL;
175 char *tableptr;
176 char *tablepath = NULL;
177 int first_try = 0; /* Do we try the old binding at first ? */
179 if (res == NULL)
180 return NULL;
182 if (name == NULL)
184 NIS_RES_STATUS (res) = NIS_BADNAME;
185 return res;
188 if ((ibreq = __create_ib_request (name, flags)) == NULL)
190 NIS_RES_STATUS (res) = NIS_BADNAME;
191 return res;
194 if ((flags & EXPAND_NAME)
195 && ibreq->ibr_name[strlen (ibreq->ibr_name) - 1] != '.')
197 names = nis_getnames (ibreq->ibr_name);
198 free (ibreq->ibr_name);
199 ibreq->ibr_name = NULL;
200 if (names == NULL)
202 nis_free_request (ibreq);
203 NIS_RES_STATUS (res) = NIS_BADNAME;
204 return res;
206 ibreq->ibr_name = strdup (names[name_nr]);
207 if (ibreq->ibr_name == NULL)
209 nis_freenames (names);
210 nis_free_request (ibreq);
211 NIS_RES_STATUS (res) = NIS_NOMEMORY;
212 return res;
215 else
217 names = namebuf;
218 names[name_nr] = ibreq->ibr_name;
221 cb = NULL;
223 while (!done)
225 dir_binding bptr;
226 directory_obj *dir = NULL;
228 memset (res, '\0', sizeof (nis_result));
230 status = __nisfind_server (ibreq->ibr_name, &dir);
231 if (status != NIS_SUCCESS)
233 NIS_RES_STATUS (res) = status;
234 goto fail3;
237 status = __nisbind_create (&bptr, dir->do_servers.do_servers_val,
238 dir->do_servers.do_servers_len, flags);
239 if (status != NIS_SUCCESS)
241 NIS_RES_STATUS (res) = status;
242 goto fail2;
245 while (__nisbind_connect (&bptr) != NIS_SUCCESS)
246 if (__nisbind_next (&bptr) != NIS_SUCCESS)
248 NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
249 goto fail;
252 if (callback != NULL)
254 cb = __nis_create_callback (callback, userdata, flags);
255 ibreq->ibr_cbhost.ibr_cbhost_len = 1;
256 ibreq->ibr_cbhost.ibr_cbhost_val = cb->serv;
259 again:
260 clnt_status = clnt_call (bptr.clnt, NIS_IBLIST,
261 (xdrproc_t) _xdr_ib_request, (caddr_t) ibreq,
262 (xdrproc_t) _xdr_nis_result,
263 (caddr_t) res, RPCTIMEOUT);
265 if (clnt_status != RPC_SUCCESS)
266 NIS_RES_STATUS (res) = NIS_RPCERROR;
267 else
268 switch (NIS_RES_STATUS (res))
269 { /* start switch */
270 case NIS_PARTIAL:
271 case NIS_SUCCESS:
272 case NIS_S_SUCCESS:
273 if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ
274 && (flags & FOLLOW_LINKS)) /* We are following links. */
276 free (ibreq->ibr_name);
277 ibreq->ibr_name = NULL;
278 /* If we hit the link limit, bail. */
279 if (count_links > NIS_MAXLINKS)
281 NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
282 ++done;
283 break;
285 ++count_links;
286 ibreq->ibr_name =
287 strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
288 if (ibreq->ibr_name == NULL)
290 NIS_RES_STATUS (res) = NIS_NOMEMORY;
291 fail:
292 __nisbind_destroy (&bptr);
293 fail2:
294 nis_free_directory (dir);
295 fail3:
296 free (tablepath);
297 if (cb)
299 __nis_destroy_callback (cb);
300 ibreq->ibr_cbhost.ibr_cbhost_len = 0;
301 ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
303 if (names != namebuf)
304 nis_freenames (names);
305 nis_free_request (ibreq);
306 return res;
308 if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
309 if (ibreq->ibr_srch.ibr_srch_len == 0)
311 ibreq->ibr_srch.ibr_srch_len =
312 NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len;
313 ibreq->ibr_srch.ibr_srch_val =
314 NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
316 /* The following is a non-obvious optimization. A
317 nis_freeresult call would call xdr_free as the
318 following code. But it also would unnecessarily
319 free the result structure. We avoid this here
320 along with the necessary tests. */
321 #if 1
322 xdr_free ((xdrproc_t) _xdr_nis_result, (char *)res);
323 memset (res, '\0', sizeof (*res));
324 #else
325 nis_freeresult (res);
326 res = calloc (1, sizeof (nis_result));
327 if (res == NULL)
328 goto fail;
329 #endif
330 first_try = 1; /* Try at first the old binding */
331 goto again;
333 else if ((flags & FOLLOW_PATH)
334 && NIS_RES_STATUS (res) == NIS_PARTIAL)
336 if (tablepath == NULL)
338 tablepath = __get_tablepath (ibreq->ibr_name, &bptr);
339 tableptr = tablepath;
341 if (tableptr == NULL)
343 ++done;
344 break;
346 free (ibreq->ibr_name);
347 ibreq->ibr_name = strsep (&tableptr, ":");
348 if (ibreq->ibr_name == NULL || ibreq->ibr_name[0] == '\0')
350 ibreq->ibr_name = strdup ("");
351 if (ibreq->ibr_name == NULL)
353 NIS_RES_STATUS (res) = NIS_NOMEMORY;
354 goto fail;
356 ++done;
358 else
360 ibreq->ibr_name = strdup (ibreq->ibr_name);
361 /* The following is a non-obvious optimization. A
362 nis_freeresult call would call xdr_free as the
363 following code. But it also would unnecessarily
364 free the result structure. We avoid this here
365 along with the necessary tests. */
366 #if 1
367 xdr_free ((xdrproc_t) _xdr_nis_result, (char *)res);
368 memset (res, '\0', sizeof (*res));
369 if (ibreq->ibr_name == NULL)
371 NIS_RES_STATUS (res) = NIS_NOMEMORY;
372 goto fail;
374 #else
375 nis_freeresult (res);
376 res = calloc (1, sizeof (nis_result));
377 if (res == NULL || ibreq->ibr_name == NULL)
379 free (res);
380 res = NULL;
381 goto fail;
383 #endif
384 first_try = 1;
385 goto again;
388 else
389 ++done;
390 break;
391 case NIS_CBRESULTS:
392 if (cb != NULL)
394 __nis_do_callback (&bptr, &res->cookie, cb);
395 NIS_RES_STATUS (res) = cb->result;
397 if (!(flags & ALL_RESULTS))
398 ++done;
399 else
401 if (tablepath == NULL)
403 tablepath = __get_tablepath (ibreq->ibr_name, &bptr);
404 tableptr = tablepath;
406 if (tableptr == NULL)
408 ++done;
409 break;
411 free (ibreq->ibr_name);
412 ibreq->ibr_name = strsep (&tableptr, ":");
413 if (ibreq->ibr_name == NULL || ibreq->ibr_name[0] == '\0')
415 ibreq->ibr_name = strdup ("");
416 ++done;
418 else
419 ibreq->ibr_name = strdup (ibreq->ibr_name);
420 if (ibreq->ibr_name == NULL)
422 NIS_RES_STATUS (res) = NIS_NOMEMORY;
423 goto fail;
427 break;
428 case NIS_SYSTEMERROR:
429 case NIS_NOSUCHNAME:
430 case NIS_NOT_ME:
431 /* If we had first tried the old binding, do nothing, but
432 get a new binding */
433 if (!first_try)
435 if (__nisbind_next (&bptr) != NIS_SUCCESS)
437 ++done;
438 break; /* No more servers to search */
440 while (__nisbind_connect (&bptr) != NIS_SUCCESS)
442 if (__nisbind_next (&bptr) != NIS_SUCCESS)
444 ++done;
445 break; /* No more servers to search */
448 goto again;
450 break;
451 default:
452 if (!first_try)
454 /* Try the next domainname if we don't follow a link. */
455 free (ibreq->ibr_name);
456 ibreq->ibr_name = NULL;
457 if (count_links)
459 NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
460 ++done;
461 break;
463 ++name_nr;
464 if (names[name_nr] == NULL)
466 ++done;
467 break;
469 ibreq->ibr_name = strdup (names[name_nr]);
470 if (ibreq->ibr_name == NULL)
472 NIS_RES_STATUS (res) = NIS_NOMEMORY;
473 goto fail;
475 first_try = 1; /* Try old binding at first */
476 goto again;
478 break;
480 first_try = 0;
482 if (cb)
484 __nis_destroy_callback (cb);
485 ibreq->ibr_cbhost.ibr_cbhost_len = 0;
486 ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
487 cb = NULL;
490 __nisbind_destroy (&bptr);
491 nis_free_directory (dir);
494 free (tablepath);
496 if (names != namebuf)
497 nis_freenames (names);
499 nis_free_request (ibreq);
501 return res;
503 libnsl_hidden_def (nis_list)
505 nis_result *
506 nis_add_entry (const_nis_name name, const nis_object *obj2, unsigned int flags)
508 nis_result *res = calloc (1, sizeof (nis_result));
509 if (res == NULL)
510 return NULL;
512 if (name == NULL)
514 NIS_RES_STATUS (res) = NIS_BADNAME;
515 return res;
518 size_t namelen = strlen (name);
519 char buf1[namelen + 20];
520 char buf4[namelen + 20];
522 ib_request *ibreq = __create_ib_request (name, flags);
523 if (ibreq == NULL)
525 NIS_RES_STATUS (res) = NIS_BADNAME;
526 return res;
529 nis_object obj;
530 memcpy (&obj, obj2, sizeof (nis_object));
532 if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
533 obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1));
535 if (obj.zo_owner == NULL || strlen (obj.zo_owner) == 0)
536 obj.zo_owner = nis_local_principal ();
538 if (obj.zo_group == NULL || strlen (obj.zo_group) == 0)
539 obj.zo_group = nis_local_group ();
541 obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4));
543 ibreq->ibr_obj.ibr_obj_val = nis_clone_object (&obj, NULL);
544 if (ibreq->ibr_obj.ibr_obj_val == NULL)
546 nis_free_request (ibreq);
547 NIS_RES_STATUS (res) = NIS_NOMEMORY;
548 return res;
550 ibreq->ibr_obj.ibr_obj_len = 1;
552 nis_error status = __do_niscall (ibreq->ibr_name, NIS_IBADD,
553 (xdrproc_t) _xdr_ib_request,
554 (caddr_t) ibreq,
555 (xdrproc_t) _xdr_nis_result,
556 (caddr_t) res, 0, NULL);
557 if (status != NIS_SUCCESS)
558 NIS_RES_STATUS (res) = status;
560 nis_free_request (ibreq);
562 return res;
565 nis_result *
566 nis_modify_entry (const_nis_name name, const nis_object *obj2,
567 unsigned int flags)
569 nis_object obj;
570 nis_result *res;
571 nis_error status;
572 ib_request *ibreq;
573 size_t namelen = strlen (name);
574 char buf1[namelen + 20];
575 char buf4[namelen + 20];
577 res = calloc (1, sizeof (nis_result));
578 if (res == NULL)
579 return NULL;
581 if (( ibreq =__create_ib_request (name, flags)) == NULL)
583 NIS_RES_STATUS (res) = NIS_BADNAME;
584 return res;
587 memcpy (&obj, obj2, sizeof (nis_object));
589 if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
590 obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1));
592 if (obj.zo_owner == NULL || strlen (obj.zo_owner) == 0)
593 obj.zo_owner = nis_local_principal ();
595 if (obj.zo_group == NULL || strlen (obj.zo_group) == 0)
596 obj.zo_group = nis_local_group ();
598 obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4));
600 ibreq->ibr_obj.ibr_obj_val = nis_clone_object (&obj, NULL);
601 if (ibreq->ibr_obj.ibr_obj_val == NULL)
603 nis_free_request (ibreq);
604 NIS_RES_STATUS (res) = NIS_NOMEMORY;
605 return res;
607 ibreq->ibr_obj.ibr_obj_len = 1;
609 if ((status = __do_niscall (ibreq->ibr_name, NIS_IBMODIFY,
610 (xdrproc_t) _xdr_ib_request,
611 (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
612 (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
613 NIS_RES_STATUS (res) = status;
615 nis_free_request (ibreq);
617 return res;
620 nis_result *
621 nis_remove_entry (const_nis_name name, const nis_object *obj,
622 unsigned int flags)
624 nis_result *res;
625 ib_request *ibreq;
626 nis_error status;
628 res = calloc (1, sizeof (nis_result));
629 if (res == NULL)
630 return NULL;
632 if (name == NULL)
634 NIS_RES_STATUS (res) = NIS_BADNAME;
635 return res;
638 if ((ibreq =__create_ib_request (name, flags)) == NULL)
640 NIS_RES_STATUS (res) = NIS_BADNAME;
641 return res;
644 if (obj != NULL)
646 ibreq->ibr_obj.ibr_obj_val = nis_clone_object (obj, NULL);
647 if (ibreq->ibr_obj.ibr_obj_val == NULL)
649 nis_free_request (ibreq);
650 NIS_RES_STATUS (res) = NIS_NOMEMORY;
651 return res;
653 ibreq->ibr_obj.ibr_obj_len = 1;
656 if ((status = __do_niscall (ibreq->ibr_name, NIS_IBREMOVE,
657 (xdrproc_t) _xdr_ib_request,
658 (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
659 (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
660 NIS_RES_STATUS (res) = status;
662 nis_free_request (ibreq);
664 return res;
667 nis_result *
668 nis_first_entry (const_nis_name name)
670 nis_result *res;
671 ib_request *ibreq;
672 nis_error status;
674 res = calloc (1, sizeof (nis_result));
675 if (res == NULL)
676 return NULL;
678 if (name == NULL)
680 NIS_RES_STATUS (res) = NIS_BADNAME;
681 return res;
684 ibreq = __create_ib_request (name, 0);
685 if (ibreq == NULL)
687 NIS_RES_STATUS (res) = NIS_BADNAME;
688 return res;
691 status = __do_niscall (ibreq->ibr_name, NIS_IBFIRST,
692 (xdrproc_t) _xdr_ib_request,
693 (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
694 (caddr_t) res, 0, NULL);
696 if (status != NIS_SUCCESS)
697 NIS_RES_STATUS (res) = status;
699 nis_free_request (ibreq);
701 return res;
704 nis_result *
705 nis_next_entry (const_nis_name name, const netobj *cookie)
707 nis_result *res;
708 ib_request *ibreq;
709 nis_error status;
711 res = calloc (1, sizeof (nis_result));
712 if (res == NULL)
713 return NULL;
715 if (name == NULL)
717 NIS_RES_STATUS (res) = NIS_BADNAME;
718 return res;
721 ibreq = __create_ib_request (name, 0);
722 if (ibreq == NULL)
724 NIS_RES_STATUS (res) = NIS_BADNAME;
725 return res;
728 if (cookie != NULL)
730 ibreq->ibr_cookie.n_bytes = cookie->n_bytes;
731 ibreq->ibr_cookie.n_len = cookie->n_len;
734 status = __do_niscall (ibreq->ibr_name, NIS_IBNEXT,
735 (xdrproc_t) _xdr_ib_request,
736 (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
737 (caddr_t) res, 0, NULL);
739 if (status != NIS_SUCCESS)
740 NIS_RES_STATUS (res) = status;
742 if (cookie != NULL)
744 /* Don't give cookie free, it is not from us */
745 ibreq->ibr_cookie.n_bytes = NULL;
746 ibreq->ibr_cookie.n_len = 0;
749 nis_free_request (ibreq);
751 return res;