(nis_list): Don't try the next server if network is unreachable.
[kopensolaris-gnu/glibc.git] / nis / nis_table.c
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.
4
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.
9
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.
14
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.  */
19
20 #include <string.h>
21 #include <rpcsvc/nis.h>
22 #include <rpcsvc/nislib.h>
23 #include "nis_intern.h"
24
25 static void
26 splitname (const_nis_name name, nis_name *ibr_name, int *srch_len,
27            nis_attr **srch_val)
28 {
29   char *cptr, *key, *val, *next;
30   int size;
31
32   if (name == NULL)
33     return;
34
35   cptr = strdup (name);
36   if (srch_len)
37     *srch_len = 0;
38   if (srch_val)
39     *srch_val = NULL;
40   size = 0;
41
42   /* Not of "[key=value,key=value,...],foo.." format? */
43   if (cptr[0] != '[')
44     {
45       *ibr_name = cptr;
46       return;
47     }
48
49   *ibr_name = strchr (cptr, ']');
50   if (*ibr_name == NULL || (*ibr_name)[1] != ',')
51     {
52       free (cptr);
53       *ibr_name = NULL;
54       return;
55     }
56
57   *ibr_name[0] = '\0';
58   *ibr_name += 2;
59   *ibr_name = strdup (*ibr_name);
60
61   if (srch_len == NULL || srch_val == NULL)
62     {
63       free (cptr);
64       return;
65     }
66
67   key = (cptr) + 1;
68   do
69     {
70       next = strchr (key, ',');
71       if (next)
72         {
73           next[0] = '\0';
74           ++next;
75         }
76
77       val = strchr (key, '=');
78       if (!val)
79         {
80           free (cptr);
81           *srch_val = malloc (sizeof (nis_attr));
82           if (*srch_val == NULL)
83             {
84               free (cptr);
85               free (*ibr_name);
86               *ibr_name = NULL;
87               return;
88             }
89           (*srch_val)[0].zattr_val.zattr_val_len = 0;
90           (*srch_val)[0].zattr_val.zattr_val_val = NULL;
91           return;
92         }
93
94       val[0] = '\0';
95       ++val;
96
97       if ((*srch_len) + 1 >= size)
98         {
99           size += 10;
100           if (size == 10)
101             *srch_val = malloc (size * sizeof (char *));
102           else
103             *srch_val = realloc (val, size * sizeof (char *));
104           if (*srch_val == NULL)
105             {
106               free (cptr);
107               free (*ibr_name);
108               *ibr_name = NULL;
109               return;
110             }
111         }
112
113       (*srch_val)[*srch_len].zattr_ndx = strdup (key);
114       if (((*srch_val)[*srch_len].zattr_ndx) == NULL)
115         {
116           free (cptr);
117           free (*ibr_name);
118           *ibr_name = NULL;
119           return;
120         }
121       (*srch_val)[*srch_len].zattr_val.zattr_val_len = strlen (val) + 1;
122       (*srch_val)[*srch_len].zattr_val.zattr_val_val = strdup (val);
123       if ((*srch_val)[*srch_len].zattr_val.zattr_val_val == NULL)
124         {
125           free (cptr);
126           free (*ibr_name);
127           *ibr_name = NULL;
128           return;
129         }
130       ++(*srch_len);
131
132       key = next;
133
134     }
135   while (next);
136
137   free (cptr);
138 }
139
140 static struct ib_request *
141 __create_ib_request (const_nis_name name, struct ib_request *ibreq,
142                      u_long flags)
143 {
144   splitname (name, &ibreq->ibr_name, &ibreq->ibr_srch.ibr_srch_len,
145              &ibreq->ibr_srch.ibr_srch_val);
146   if (ibreq->ibr_name == NULL)
147     return NULL;
148
149   ibreq->ibr_flags = (flags & (RETURN_RESULT | ADD_OVERWRITE | REM_MULTIPLE |
150                                MOD_SAMEOBJ | ADD_RESERVED | REM_RESERVED |
151                                MOD_EXCLUSIVE));
152   ibreq->ibr_obj.ibr_obj_len = 0;
153   ibreq->ibr_obj.ibr_obj_val = NULL;
154   ibreq->ibr_cbhost.ibr_cbhost_len = 0;
155   ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
156   ibreq->ibr_bufsize = 0;
157   ibreq->ibr_cookie.n_len = 0;
158   ibreq->ibr_cookie.n_bytes = NULL;
159
160   return ibreq;
161 }
162
163 nis_result *
164 nis_list (const_nis_name name, u_long flags,
165           int (*callback) (const_nis_name name,
166                            const nis_object *object,
167                            const void *userdata),
168           const void *userdata)
169 {
170   nis_result *res = NULL;
171   struct ib_request ibreq;
172   int status;
173   int count_links = 0;      /* We will only follow 16 links! */
174   int done = 0;
175   nis_name *names;
176   nis_name namebuf[2] = {NULL, NULL};
177   int name_nr = 0;
178
179   res = calloc (1, sizeof (nis_result));
180
181   if (__create_ib_request (name, &ibreq, flags) == NULL)
182     {
183       res->status = NIS_BADNAME;
184       return res;
185     }
186
187   if (flags & EXPAND_NAME)
188     {
189       names = nis_getnames (ibreq.ibr_name);
190       free (ibreq.ibr_name);
191       ibreq.ibr_name = NULL;
192       if (names == NULL)
193         {
194           res->status = NIS_BADNAME;
195           return res;
196         }
197       ibreq.ibr_name = strdup (names[name_nr]);
198     }
199   else
200     names = namebuf;
201
202   while (!done)
203     {
204       memset (res, '\0', sizeof (nis_result));
205
206       status = __do_niscall (ibreq.ibr_name, NIS_IBLIST,
207                              (xdrproc_t) xdr_ib_request,
208                              (caddr_t) &ibreq, (xdrproc_t) xdr_nis_result,
209                              (caddr_t) res, flags);
210       if (status != NIS_SUCCESS)
211         res->status = status;
212
213       switch (res->status)
214         {
215         case NIS_PARTIAL:
216         case NIS_SUCCESS:
217         case NIS_S_SUCCESS:
218           if (__type_of(NIS_RES_OBJECT (res)) == LINK_OBJ &&
219               flags & FOLLOW_LINKS) /* We are following links */
220             {
221               /* if we hit the link limit, bail */
222               if (count_links > NIS_MAXLINKS)
223                 {
224                   res->status = NIS_LINKNAMEERROR;
225                   ++done;
226                   break;
227                 }
228               if (count_links)
229                 free (ibreq.ibr_name);
230               ++count_links;
231               free (ibreq.ibr_name);
232               ibreq.ibr_name = strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
233               if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
234                 if (ibreq.ibr_srch.ibr_srch_len == 0)
235                   {
236                     ibreq.ibr_srch.ibr_srch_len =
237                       NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len;
238                     ibreq.ibr_srch.ibr_srch_val =
239                       NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
240                   }
241               nis_freeresult (res);
242               res = calloc (1, sizeof (nis_result));
243             }
244           else
245             ++done;
246           break;
247         case NIS_CBRESULTS:
248           /* XXX Implement CALLBACK here ! */
249           ++done;
250           break;
251         case NIS_UNAVAIL:  
252           /* NIS+ is not installed, or all servers are down */
253           ++done;
254           break;
255         default:
256           /* Try the next domainname if we don't follow a link */
257           if (count_links)
258             {
259               free (ibreq.ibr_name);
260               res->status = NIS_LINKNAMEERROR;
261               ++done;
262               break;
263             }
264           ++name_nr;
265           if (names[name_nr] == NULL)
266             {
267               ++done;
268               break;
269             }
270           ibreq.ibr_name = names[name_nr];
271           break;
272         }
273     }
274
275   if (names != namebuf)
276     nis_freenames (names);
277
278   nis_free_request (&ibreq);
279
280   if (callback != NULL &&
281       (res->status == NIS_SUCCESS || res->status == NIS_S_SUCCESS))
282     {
283       unsigned int i;
284
285       for (i = 0; i < res->objects.objects_len; ++i)
286         if ((*callback) (name, &(res->objects.objects_val)[i], userdata) != 0)
287           break;
288     }
289
290   return res;
291 }
292
293 nis_result *
294 nis_add_entry (const_nis_name name, const nis_object *obj,
295                u_long flags)
296 {
297   nis_result *res;
298   nis_error status;
299   struct ib_request ibreq;
300   char *p1, *p2, *p3, *p4;
301   char buf1 [strlen (name) + 20];
302   char buf4 [strlen (name) + 20];
303
304   res = calloc (1, sizeof (nis_result));
305
306   if (__create_ib_request (name, &ibreq, flags) == NULL)
307     {
308       res->status = NIS_BADNAME;
309       return res;
310     }
311
312   ibreq.ibr_flags = flags;
313   ibreq.ibr_obj.ibr_obj_val = nis_clone_object (obj, NULL);
314   ibreq.ibr_obj.ibr_obj_len = 1;
315
316   p1 = ibreq.ibr_obj.ibr_obj_val->zo_name;
317   if (p1 == NULL || strlen (p1) == 0)
318     ibreq.ibr_obj.ibr_obj_val->zo_name =
319       nis_leaf_of_r (name, buf1, sizeof (buf1));
320
321   p2 = ibreq.ibr_obj.ibr_obj_val->zo_owner;
322   if (p2 == NULL || strlen (p2) == 0)
323     ibreq.ibr_obj.ibr_obj_val->zo_owner = nis_local_principal ();
324
325   p3 = ibreq.ibr_obj.ibr_obj_val->zo_group;
326   if (p3 == NULL || strlen (p3) == 0)
327     ibreq.ibr_obj.ibr_obj_val->zo_group = nis_local_group ();
328
329   p4 = ibreq.ibr_obj.ibr_obj_val->zo_domain;
330   ibreq.ibr_obj.ibr_obj_val->zo_domain =
331     nis_domain_of_r (name, buf4, sizeof (buf4));
332
333   if ((status = __do_niscall (ibreq.ibr_name, NIS_IBADD,
334                               (xdrproc_t) xdr_ib_request,
335                               (caddr_t) &ibreq,
336                               (xdrproc_t) xdr_nis_result,
337                               (caddr_t) res, 0)) != NIS_SUCCESS)
338     res->status = status;
339
340   ibreq.ibr_obj.ibr_obj_val->zo_name = p1;
341   ibreq.ibr_obj.ibr_obj_val->zo_owner = p2;
342   ibreq.ibr_obj.ibr_obj_val->zo_group = p3;
343   ibreq.ibr_obj.ibr_obj_val->zo_domain = p4;
344
345   nis_free_request (&ibreq);
346
347   return res;
348 }
349
350 nis_result *
351 nis_modify_entry (const_nis_name name, const nis_object *obj,
352                   u_long flags)
353 {
354   nis_result *res;
355   nis_error status;
356   struct ib_request ibreq;
357   char *p1, *p2, *p3, *p4;
358   char buf1 [strlen (name) + 20];
359   char buf4 [strlen (name) + 20];
360
361   res = calloc (1, sizeof (nis_result));
362
363   if (__create_ib_request (name, &ibreq, flags) == NULL)
364     {
365       res->status = NIS_BADNAME;
366       return res;
367     }
368
369   ibreq.ibr_flags = flags;
370   ibreq.ibr_obj.ibr_obj_val = nis_clone_object (obj, NULL);
371   ibreq.ibr_obj.ibr_obj_len = 1;
372
373   p1 = ibreq.ibr_obj.ibr_obj_val->zo_name;
374   if (p1 == NULL || strlen (p1) == 0)
375     ibreq.ibr_obj.ibr_obj_val->zo_name =
376       nis_leaf_of_r (name, buf1, sizeof (buf1));
377
378   p2 = ibreq.ibr_obj.ibr_obj_val->zo_owner;
379   if (p2 == NULL || strlen (p2) == 0)
380     ibreq.ibr_obj.ibr_obj_val->zo_owner = nis_local_principal ();
381
382   p3 = ibreq.ibr_obj.ibr_obj_val->zo_group;
383   if (p3 == NULL || strlen (p3) == 0)
384     ibreq.ibr_obj.ibr_obj_val->zo_group = nis_local_group ();
385
386   p4 = ibreq.ibr_obj.ibr_obj_val->zo_domain;
387   ibreq.ibr_obj.ibr_obj_val->zo_domain =
388     nis_domain_of_r (name, buf4, sizeof (buf4));
389
390   if ((status = __do_niscall (ibreq.ibr_name, NIS_IBMODIFY,
391                               (xdrproc_t) xdr_ib_request,
392                               (caddr_t) & ibreq, (xdrproc_t) xdr_nis_result,
393                               (caddr_t) res, 0)) != NIS_SUCCESS)
394     res->status = status;
395
396   ibreq.ibr_obj.ibr_obj_val->zo_name = p1;
397   ibreq.ibr_obj.ibr_obj_val->zo_owner = p2;
398   ibreq.ibr_obj.ibr_obj_val->zo_group = p3;
399   ibreq.ibr_obj.ibr_obj_val->zo_domain = p4;
400
401   nis_free_request (&ibreq);
402
403   return res;
404 }
405
406 nis_result *
407 nis_remove_entry (const_nis_name name, const nis_object *obj,
408                   u_long flags)
409 {
410   nis_result *res;
411   struct ib_request ibreq;
412   nis_error status;
413
414   res = calloc (1, sizeof (nis_result));
415
416   if (__create_ib_request (name, &ibreq, flags) == NULL)
417     {
418       res->status = NIS_BADNAME;
419       return res;
420     }
421
422   ibreq.ibr_flags = flags;
423   if (obj != NULL)
424     {
425       ibreq.ibr_obj.ibr_obj_val = nis_clone_object (obj, NULL);
426       ibreq.ibr_obj.ibr_obj_len = 1;
427     }
428
429   if ((status = __do_niscall (ibreq.ibr_name, NIS_IBREMOVE,
430                               (xdrproc_t) xdr_ib_request,
431                               (caddr_t) & ibreq, (xdrproc_t) xdr_nis_result,
432                               (caddr_t) res, 0)) != NIS_SUCCESS)
433     res->status = status;
434
435   nis_free_request (&ibreq);
436
437   return res;
438 }
439
440 nis_result *
441 nis_first_entry (const_nis_name name)
442 {
443   nis_result *res;
444   struct ib_request ibreq;
445   nis_error status;
446
447   res = calloc (1, sizeof (nis_result));
448
449   if (__create_ib_request (name, &ibreq, 0) == NULL)
450     {
451       res->status = NIS_BADNAME;
452       return res;
453     }
454
455   if ((status = __do_niscall (ibreq.ibr_name, NIS_IBFIRST,
456                               (xdrproc_t) xdr_ib_request,
457                               (caddr_t) &ibreq, (xdrproc_t) xdr_nis_result,
458                               (caddr_t) res, 0)) != NIS_SUCCESS)
459     res->status = status;
460
461   nis_free_request (&ibreq);
462
463   return res;
464 }
465
466 nis_result *
467 nis_next_entry (const_nis_name name, const netobj *cookie)
468 {
469   nis_result *res;
470   struct ib_request ibreq;
471   nis_error status;
472
473   res = calloc (1, sizeof (nis_result));
474
475   if (__create_ib_request (name, &ibreq, 0) == NULL)
476     {
477       res->status = NIS_BADNAME;
478       return res;
479     }
480
481   if (cookie != NULL)
482     {
483       ibreq.ibr_cookie.n_bytes = malloc (cookie->n_len);
484       if (ibreq.ibr_cookie.n_bytes == NULL)
485         {
486           res->status = NIS_NOMEMORY;
487           free (res);
488           return NULL;
489         }
490       memcpy (ibreq.ibr_cookie.n_bytes, cookie->n_bytes, cookie->n_len);
491       ibreq.ibr_cookie.n_len = cookie->n_len;
492     }
493
494   if ((status = __do_niscall (ibreq.ibr_name, NIS_IBNEXT,
495                               (xdrproc_t) xdr_ib_request,
496                               (caddr_t) &ibreq, (xdrproc_t) xdr_nis_result,
497                               (caddr_t) res, 0)) != NIS_SUCCESS)
498     res->status = status;
499
500   nis_free_request (&ibreq);
501
502   return res;
503 }