Add support for callback, FOLLOW_PATH and ALL_RESULTS.
[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 | ALL_RESULTS));
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 NIS_MAXLINKS links! */
174   int done = 0;
175   nis_name *names;
176   nis_name namebuf[2] = {NULL, NULL};
177   int name_nr = 0;
178   nis_cb *cb = NULL;
179
180   res = calloc (1, sizeof (nis_result));
181
182   if (__create_ib_request (name, &ibreq, flags) == NULL)
183     {
184       res->status = NIS_BADNAME;
185       return res;
186     }
187
188   if (flags & EXPAND_NAME)
189     {
190       names = nis_getnames (ibreq.ibr_name);
191       free (ibreq.ibr_name);
192       ibreq.ibr_name = NULL;
193       if (names == NULL)
194         {
195           res->status = NIS_BADNAME;
196           return res;
197         }
198       ibreq.ibr_name = strdup (names[name_nr]);
199     }
200   else
201     {
202       names = namebuf;
203       names[name_nr] = ibreq.ibr_name;
204     }
205
206   cb = NULL;
207
208   if (flags & FOLLOW_PATH)
209     {
210       nis_result *lres;
211       u_long newflags = flags & ~FOLLOW_PATH;
212       char table_path[NIS_MAXPATH + 1];
213       char *ntable, *p;
214       u_long done = 0, failures = 0;
215
216       memset (res, '\0', sizeof (nis_result));
217
218       while (names[name_nr] != NULL && !done)
219         {
220           lres = nis_lookup (names[name_nr], newflags);
221           if (lres == NULL || lres->status != NIS_SUCCESS)
222             {
223               res->status = lres->status;
224               nis_freeresult (lres);
225               ++name_nr;
226               continue;
227               }
228
229           /* nis_lookup handles FOLLOW_LINKS,
230              so we must have a table object.  */
231           if (__type_of (NIS_RES_OBJECT (lres)) != TABLE_OBJ)
232             {
233               nis_freeresult (lres);
234               res->status = NIS_INVALIDOBJ;
235               break;
236             }
237
238           /* Save the path, discard everything else.  */
239           snprintf (table_path, NIS_MAXPATH, "%s:%s", names[name_nr],
240                     NIS_RES_OBJECT (lres)->TA_data.ta_path);
241           nis_freeresult (lres);
242           free (res);
243
244           p = table_path;
245
246           while (((ntable = strsep (&p, ":")) != NULL) && !done)
247             {
248               /* Do the job recursive here!  */
249               res = nis_list (name, newflags, callback, userdata);
250               if (res == NULL)
251                 return NULL;
252               switch (res->status)
253                 {
254                 case NIS_SUCCESS:
255                 case NIS_CBRESULTS:
256                   if (!(flags & ALL_RESULTS))
257                     done = 1;
258                   break;
259                 default:
260                   if (flags & ALL_RESULTS)
261                     failures++;
262                   else
263                     done = 1;
264                   break;
265                   }
266             }
267           if (res->status == NIS_SUCCESS && failures)
268             res->status = NIS_S_SUCCESS;
269           if (res->status == NIS_NOTFOUND && failures)
270             res->status = NIS_S_NOTFOUND;
271           break;
272         }
273     }
274   else
275     {
276       if (callback != NULL)
277         {
278           cb = __nis_create_callback (callback, userdata, flags);
279           ibreq.ibr_cbhost.ibr_cbhost_len = 1;
280           ibreq.ibr_cbhost.ibr_cbhost_val = cb->serv;
281           }
282
283       while (!done)
284         {
285           memset (res, '\0', sizeof (nis_result));
286
287           status = __do_niscall (ibreq.ibr_name, NIS_IBLIST,
288                                  (xdrproc_t) xdr_ib_request,
289                                  (caddr_t) & ibreq, (xdrproc_t) xdr_nis_result,
290                                  (caddr_t) res, flags, cb);
291           if (status != NIS_SUCCESS)
292             res->status = status;
293
294           switch (res->status)
295             {
296             case NIS_PARTIAL:
297             case NIS_SUCCESS:
298             case NIS_S_SUCCESS:
299               if (__type_of (NIS_RES_OBJECT (res)) == LINK_OBJ &&
300                   flags & FOLLOW_LINKS)         /* We are following links.  */
301                 {
302                   /* If we hit the link limit, bail.  */
303                   if (count_links > NIS_MAXLINKS)
304                     {
305                       res->status = NIS_LINKNAMEERROR;
306                       ++done;
307                       break;
308                     }
309                   if (count_links)
310                     free (ibreq.ibr_name);
311                   ++count_links;
312                   free (ibreq.ibr_name);
313                   ibreq.ibr_name =
314                     strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
315                   if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
316                     if (ibreq.ibr_srch.ibr_srch_len == 0)
317                       {
318                         ibreq.ibr_srch.ibr_srch_len =
319                           NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len;
320                         ibreq.ibr_srch.ibr_srch_val =
321                           NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
322                       }
323                   nis_freeresult (res);
324                   res = calloc (1, sizeof (nis_result));
325                 }
326               else
327                 ++done;
328               break;
329             case NIS_CBRESULTS:
330               /* Calback is handled in nis_call.c (__do_niscall2).  */
331               ++done;
332               break;
333             case NIS_UNAVAIL:
334               /* NIS+ is not installed, or all servers are down.  */
335               ++done;
336               break;
337             default:
338               /* Try the next domainname if we don't follow a link.  */
339               if (count_links)
340                 {
341                   free (ibreq.ibr_name);
342                   res->status = NIS_LINKNAMEERROR;
343                   ++done;
344                   break;
345                 }
346               ++name_nr;
347               if (names[name_nr] == NULL)
348                 {
349                   ++done;
350                   break;
351                 }
352               ibreq.ibr_name = names[name_nr];
353               break;
354             }
355         }
356     }                           /* End of not FOLLOW_PATH.  */
357
358   if (names != namebuf)
359     nis_freenames (names);
360
361   nis_free_request (&ibreq);
362
363   if (cb)
364     __nis_destroy_callback (cb);
365
366   return res;
367 }
368
369 nis_result *
370 nis_add_entry (const_nis_name name, const nis_object *obj,
371                u_long flags)
372 {
373   nis_result *res;
374   nis_error status;
375   struct ib_request ibreq;
376   char *p1, *p2, *p3, *p4;
377   char buf1[strlen (name) + 20];
378   char buf4[strlen (name) + 20];
379
380   res = calloc (1, sizeof (nis_result));
381
382   if (__create_ib_request (name, &ibreq, flags) == NULL)
383     {
384       res->status = NIS_BADNAME;
385       return res;
386     }
387
388   ibreq.ibr_flags = flags;
389   ibreq.ibr_obj.ibr_obj_val = nis_clone_object (obj, NULL);
390   ibreq.ibr_obj.ibr_obj_len = 1;
391
392   p1 = ibreq.ibr_obj.ibr_obj_val->zo_name;
393   if (p1 == NULL || strlen (p1) == 0)
394     ibreq.ibr_obj.ibr_obj_val->zo_name =
395       nis_leaf_of_r (name, buf1, sizeof (buf1));
396
397   p2 = ibreq.ibr_obj.ibr_obj_val->zo_owner;
398   if (p2 == NULL || strlen (p2) == 0)
399     ibreq.ibr_obj.ibr_obj_val->zo_owner = nis_local_principal ();
400
401   p3 = ibreq.ibr_obj.ibr_obj_val->zo_group;
402   if (p3 == NULL || strlen (p3) == 0)
403     ibreq.ibr_obj.ibr_obj_val->zo_group = nis_local_group ();
404
405   p4 = ibreq.ibr_obj.ibr_obj_val->zo_domain;
406   ibreq.ibr_obj.ibr_obj_val->zo_domain =
407     nis_domain_of_r (name, buf4, sizeof (buf4));
408
409   if ((status = __do_niscall (ibreq.ibr_name, NIS_IBADD,
410                               (xdrproc_t) xdr_ib_request,
411                               (caddr_t) & ibreq,
412                               (xdrproc_t) xdr_nis_result,
413                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
414     res->status = status;
415
416   ibreq.ibr_obj.ibr_obj_val->zo_name = p1;
417   ibreq.ibr_obj.ibr_obj_val->zo_owner = p2;
418   ibreq.ibr_obj.ibr_obj_val->zo_group = p3;
419   ibreq.ibr_obj.ibr_obj_val->zo_domain = p4;
420
421   nis_free_request (&ibreq);
422
423   return res;
424 }
425
426 nis_result *
427 nis_modify_entry (const_nis_name name, const nis_object *obj,
428                   u_long flags)
429 {
430   nis_result *res;
431   nis_error status;
432   struct ib_request ibreq;
433   char *p1, *p2, *p3, *p4;
434   char buf1[strlen (name) + 20];
435   char buf4[strlen (name) + 20];
436
437   res = calloc (1, sizeof (nis_result));
438
439   if (__create_ib_request (name, &ibreq, flags) == NULL)
440     {
441       res->status = NIS_BADNAME;
442       return res;
443     }
444
445   ibreq.ibr_flags = flags;
446   ibreq.ibr_obj.ibr_obj_val = nis_clone_object (obj, NULL);
447   ibreq.ibr_obj.ibr_obj_len = 1;
448
449   p1 = ibreq.ibr_obj.ibr_obj_val->zo_name;
450   if (p1 == NULL || strlen (p1) == 0)
451     ibreq.ibr_obj.ibr_obj_val->zo_name =
452       nis_leaf_of_r (name, buf1, sizeof (buf1));
453
454   p2 = ibreq.ibr_obj.ibr_obj_val->zo_owner;
455   if (p2 == NULL || strlen (p2) == 0)
456     ibreq.ibr_obj.ibr_obj_val->zo_owner = nis_local_principal ();
457
458   p3 = ibreq.ibr_obj.ibr_obj_val->zo_group;
459   if (p3 == NULL || strlen (p3) == 0)
460     ibreq.ibr_obj.ibr_obj_val->zo_group = nis_local_group ();
461
462   p4 = ibreq.ibr_obj.ibr_obj_val->zo_domain;
463   ibreq.ibr_obj.ibr_obj_val->zo_domain =
464     nis_domain_of_r (name, buf4, sizeof (buf4));
465
466   if ((status = __do_niscall (ibreq.ibr_name, NIS_IBMODIFY,
467                               (xdrproc_t) xdr_ib_request,
468                               (caddr_t) & ibreq, (xdrproc_t) xdr_nis_result,
469                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
470     res->status = status;
471
472   ibreq.ibr_obj.ibr_obj_val->zo_name = p1;
473   ibreq.ibr_obj.ibr_obj_val->zo_owner = p2;
474   ibreq.ibr_obj.ibr_obj_val->zo_group = p3;
475   ibreq.ibr_obj.ibr_obj_val->zo_domain = p4;
476
477   nis_free_request (&ibreq);
478
479   return res;
480 }
481
482 nis_result *
483 nis_remove_entry (const_nis_name name, const nis_object *obj,
484                   u_long flags)
485 {
486   nis_result *res;
487   struct ib_request ibreq;
488   nis_error status;
489
490   res = calloc (1, sizeof (nis_result));
491
492   if (__create_ib_request (name, &ibreq, flags) == NULL)
493     {
494       res->status = NIS_BADNAME;
495       return res;
496     }
497
498   ibreq.ibr_flags = flags;
499   if (obj != NULL)
500     {
501       ibreq.ibr_obj.ibr_obj_val = nis_clone_object (obj, NULL);
502       ibreq.ibr_obj.ibr_obj_len = 1;
503     }
504
505   if ((status = __do_niscall (ibreq.ibr_name, NIS_IBREMOVE,
506                               (xdrproc_t) xdr_ib_request,
507                               (caddr_t) & ibreq, (xdrproc_t) xdr_nis_result,
508                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
509     res->status = status;
510
511   nis_free_request (&ibreq);
512
513   return res;
514 }
515
516 nis_result *
517 nis_first_entry (const_nis_name name)
518 {
519   nis_result *res;
520   struct ib_request ibreq;
521   nis_error status;
522
523   res = calloc (1, sizeof (nis_result));
524
525   if (__create_ib_request (name, &ibreq, 0) == NULL)
526     {
527       res->status = NIS_BADNAME;
528       return res;
529     }
530
531   if ((status = __do_niscall (ibreq.ibr_name, NIS_IBFIRST,
532                               (xdrproc_t) xdr_ib_request,
533                               (caddr_t) & ibreq, (xdrproc_t) xdr_nis_result,
534                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
535     res->status = status;
536
537   nis_free_request (&ibreq);
538
539   return res;
540 }
541
542 nis_result *
543 nis_next_entry (const_nis_name name, const netobj *cookie)
544 {
545   nis_result *res;
546   struct ib_request ibreq;
547   nis_error status;
548
549   res = calloc (1, sizeof (nis_result));
550
551   if (__create_ib_request (name, &ibreq, 0) == NULL)
552     {
553       res->status = NIS_BADNAME;
554       return res;
555     }
556
557   if (cookie != NULL)
558     {
559       ibreq.ibr_cookie.n_bytes = malloc (cookie->n_len);
560       if (ibreq.ibr_cookie.n_bytes == NULL)
561         {
562           res->status = NIS_NOMEMORY;
563           free (res);
564           return NULL;
565         }
566       memcpy (ibreq.ibr_cookie.n_bytes, cookie->n_bytes, cookie->n_len);
567       ibreq.ibr_cookie.n_len = cookie->n_len;
568     }
569
570   if ((status = __do_niscall (ibreq.ibr_name, NIS_IBNEXT,
571                               (xdrproc_t) xdr_ib_request,
572                               (caddr_t) & ibreq, (xdrproc_t) xdr_nis_result,
573                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
574     res->status = status;
575
576   nis_free_request (&ibreq);
577
578   return res;
579 }